data.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <cc/data.h>
  16. #include <cassert>
  17. #include <climits>
  18. #include <map>
  19. #include <cstdio>
  20. #include <iostream>
  21. #include <string>
  22. #include <sstream>
  23. #include <boost/algorithm/string.hpp> // for iequals
  24. #include <cmath>
  25. using namespace std;
  26. namespace isc {
  27. namespace data {
  28. std::string
  29. Element::str() const {
  30. std::stringstream ss;
  31. toJSON(ss);
  32. return (ss.str());
  33. }
  34. std::string
  35. Element::toWire() const {
  36. std::stringstream ss;
  37. toJSON(ss);
  38. return (ss.str());
  39. }
  40. void
  41. Element::toWire(std::ostream& ss) const {
  42. toJSON(ss);
  43. }
  44. //
  45. // The following methods are effectively empty, and their parameters are
  46. // unused. To silence compilers that warn unused function parameters,
  47. // we specify a (compiler dependent) special keyword when available.
  48. // It's defined in config.h, and to avoid including this header file from
  49. // installed files we define the methods here.
  50. //
  51. bool
  52. Element::getValue(long int&) {
  53. return (false);
  54. }
  55. bool
  56. Element::getValue(double&) {
  57. return (false);
  58. }
  59. bool
  60. Element::getValue(bool&) {
  61. return (false);
  62. }
  63. bool
  64. Element::getValue(std::string&) {
  65. return (false);
  66. }
  67. bool
  68. Element::getValue(std::vector<ConstElementPtr>&) {
  69. return (false);
  70. }
  71. bool
  72. Element::getValue(std::map<std::string, ConstElementPtr>&) {
  73. return (false);
  74. }
  75. bool
  76. Element::setValue(const long int) {
  77. return (false);
  78. }
  79. bool
  80. Element::setValue(const double) {
  81. return (false);
  82. }
  83. bool
  84. Element::setValue(const bool) {
  85. return (false);
  86. }
  87. bool
  88. Element::setValue(const std::string&) {
  89. return (false);
  90. }
  91. bool
  92. Element::setValue(const std::vector<ConstElementPtr>&) {
  93. return (false);
  94. }
  95. bool
  96. Element::setValue(const std::map<std::string, ConstElementPtr>&) {
  97. return (false);
  98. }
  99. ConstElementPtr
  100. Element::get(const int) const {
  101. isc_throw(TypeError, "get(int) called on a non-list Element");
  102. }
  103. void
  104. Element::set(const size_t, ConstElementPtr) {
  105. isc_throw(TypeError, "set(int, element) called on a non-list Element");
  106. }
  107. void
  108. Element::add(ConstElementPtr) {
  109. isc_throw(TypeError, "add() called on a non-list Element");
  110. }
  111. void
  112. Element::remove(const int) {
  113. isc_throw(TypeError, "remove(int) called on a non-list Element");
  114. }
  115. size_t
  116. Element::size() const {
  117. isc_throw(TypeError, "size() called on a non-list Element");
  118. }
  119. ConstElementPtr
  120. Element::get(const std::string&) const {
  121. isc_throw(TypeError, "get(string) called on a non-map Element");
  122. }
  123. void
  124. Element::set(const std::string&, ConstElementPtr) {
  125. isc_throw(TypeError, "set(name, element) called on a non-map Element");
  126. }
  127. void
  128. Element::remove(const std::string&) {
  129. isc_throw(TypeError, "remove(string) called on a non-map Element");
  130. }
  131. bool
  132. Element::contains(const std::string&) const {
  133. isc_throw(TypeError, "contains(string) called on a non-map Element");
  134. }
  135. ConstElementPtr
  136. Element::find(const std::string&) const {
  137. isc_throw(TypeError, "find(string) called on a non-map Element");
  138. }
  139. bool
  140. Element::find(const std::string&, ConstElementPtr) const {
  141. return (false);
  142. }
  143. namespace {
  144. inline void
  145. throwJSONError(const std::string& error, const std::string& file, int line,
  146. int pos)
  147. {
  148. std::stringstream ss;
  149. ss << error << " in " + file + ":" << line << ":" << pos;
  150. isc_throw(JSONError, ss.str());
  151. }
  152. }
  153. std::ostream&
  154. operator<<(std::ostream &out, const Element& e) {
  155. return (out << e.str());
  156. }
  157. bool
  158. operator==(const Element& a, const Element& b) {
  159. return (a.equals(b));
  160. }
  161. bool operator!=(const Element& a, const Element& b) {
  162. return (!a.equals(b));
  163. };
  164. //
  165. // factory functions
  166. //
  167. ElementPtr
  168. Element::create() {
  169. return (ElementPtr(new NullElement()));
  170. }
  171. ElementPtr
  172. Element::create(const long int i) {
  173. return (ElementPtr(new IntElement(i)));
  174. }
  175. ElementPtr
  176. Element::create(const double d) {
  177. return (ElementPtr(new DoubleElement(d)));
  178. }
  179. ElementPtr
  180. Element::create(const std::string& s) {
  181. return (ElementPtr(new StringElement(s)));
  182. }
  183. ElementPtr
  184. Element::create(const bool b) {
  185. return (ElementPtr(new BoolElement(b)));
  186. }
  187. ElementPtr
  188. Element::createList() {
  189. return (ElementPtr(new ListElement()));
  190. }
  191. ElementPtr
  192. Element::createMap() {
  193. return (ElementPtr(new MapElement()));
  194. }
  195. //
  196. // helper functions for fromJSON factory
  197. //
  198. namespace {
  199. bool
  200. char_in(const char c, const char *chars) {
  201. for (size_t i = 0; i < strlen(chars); ++i) {
  202. if (chars[i] == c) {
  203. return (true);
  204. }
  205. }
  206. return (false);
  207. }
  208. void
  209. skip_chars(std::istream &in, const char *chars, int& line, int& pos) {
  210. char c = in.peek();
  211. while (char_in(c, chars) && c != EOF) {
  212. if (c == '\n') {
  213. ++line;
  214. pos = 1;
  215. } else {
  216. ++pos;
  217. }
  218. in.get();
  219. c = in.peek();
  220. }
  221. }
  222. // skip on the input stream to one of the characters in chars
  223. // if another character is found this function returns false
  224. // unless that character is specified in the optional may_skip
  225. //
  226. // the character found is left on the stream
  227. void
  228. skip_to(std::istream &in, const std::string& file, int& line,
  229. int& pos, const char* chars, const char* may_skip="")
  230. {
  231. char c = in.get();
  232. ++pos;
  233. while (c != EOF) {
  234. if (c == '\n') {
  235. pos = 1;
  236. ++line;
  237. }
  238. if (char_in(c, may_skip)) {
  239. c = in.get();
  240. ++pos;
  241. } else if (char_in(c, chars)) {
  242. while(char_in(in.peek(), may_skip)) {
  243. if (in.peek() == '\n') {
  244. pos = 1;
  245. ++line;
  246. }
  247. in.get();
  248. ++pos;
  249. }
  250. in.putback(c);
  251. --pos;
  252. return;
  253. } else {
  254. throwJSONError(std::string("'") + c + "' read, one of \"" + chars + "\" expected", file, line, pos);
  255. }
  256. }
  257. throwJSONError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos);
  258. }
  259. // TODO: Should we check for all other official escapes here (and
  260. // error on the rest)?
  261. std::string
  262. str_from_stringstream(std::istream &in, const std::string& file, const int line,
  263. int& pos) throw (JSONError)
  264. {
  265. char c = 0;
  266. std::stringstream ss;
  267. c = in.get();
  268. ++pos;
  269. if (c == '"') {
  270. c = in.get();
  271. ++pos;
  272. } else {
  273. throwJSONError("String expected", file, line, pos);
  274. }
  275. while (c != EOF && c != '"') {
  276. ss << c;
  277. if (c == '\\' && in.peek() == '"') {
  278. ss << in.get();
  279. ++pos;
  280. }
  281. c = in.get();
  282. ++pos;
  283. }
  284. return (ss.str());
  285. }
  286. std::string
  287. word_from_stringstream(std::istream &in, int& pos) {
  288. std::stringstream ss;
  289. while (isalpha(in.peek())) {
  290. ss << (char) in.get();
  291. }
  292. pos += ss.str().size();
  293. return (ss.str());
  294. }
  295. static std::string
  296. number_from_stringstream(std::istream &in, int& pos) {
  297. std::stringstream ss;
  298. while (isdigit(in.peek()) || in.peek() == '+' || in.peek() == '-' ||
  299. in.peek() == '.' || in.peek() == 'e' || in.peek() == 'E') {
  300. ss << (char) in.get();
  301. }
  302. pos += ss.str().size();
  303. return (ss.str());
  304. }
  305. // Should we change from IntElement and DoubleElement to NumberElement
  306. // that can also hold an e value? (and have specific getters if the
  307. // value is larger than an int can handle)
  308. ElementPtr
  309. from_stringstream_number(std::istream &in, int &pos) {
  310. long int i = 0;
  311. double d = 0.0;
  312. bool is_double = false;
  313. char *endptr;
  314. std::string number = number_from_stringstream(in, pos);
  315. i = strtol(number.c_str(), &endptr, 10);
  316. if (*endptr != '\0') {
  317. d = strtod(number.c_str(), &endptr);
  318. is_double = true;
  319. if (*endptr != '\0') {
  320. isc_throw(JSONError, std::string("Bad number: ") + number);
  321. } else {
  322. if (d == HUGE_VAL || d == -HUGE_VAL) {
  323. isc_throw(JSONError, std::string("Number overflow: ") + number);
  324. }
  325. }
  326. } else {
  327. if (i == LONG_MAX || i == LONG_MIN) {
  328. isc_throw(JSONError, std::string("Number overflow: ") + number);
  329. }
  330. }
  331. if (is_double) {
  332. return (Element::create(d));
  333. } else {
  334. return (Element::create(i));
  335. }
  336. }
  337. ElementPtr
  338. from_stringstream_bool(std::istream &in, const std::string& file,
  339. const int line, int& pos)
  340. {
  341. const std::string word = word_from_stringstream(in, pos);
  342. if (boost::iequals(word, "True")) {
  343. return (Element::create(true));
  344. } else if (boost::iequals(word, "False")) {
  345. return (Element::create(false));
  346. } else {
  347. throwJSONError(std::string("Bad boolean value: ") + word, file, line, pos);
  348. // above is a throw shortcurt, return empty is never reached
  349. return (ElementPtr());
  350. }
  351. }
  352. ElementPtr
  353. from_stringstream_null(std::istream &in, const std::string& file,
  354. const int line, int& pos)
  355. {
  356. const std::string word = word_from_stringstream(in, pos);
  357. if (boost::iequals(word, "null")) {
  358. return (Element::create());
  359. } else {
  360. throwJSONError(std::string("Bad null value: ") + word, file, line, pos);
  361. return (ElementPtr());
  362. }
  363. }
  364. ElementPtr
  365. from_stringstream_string(std::istream& in, const std::string& file, int& line,
  366. int& pos)
  367. {
  368. return (Element::create(str_from_stringstream(in, file, line, pos)));
  369. }
  370. ElementPtr
  371. from_stringstream_list(std::istream &in, const std::string& file, int& line,
  372. int& pos)
  373. {
  374. char c = 0;
  375. ElementPtr list = Element::createList();
  376. ConstElementPtr cur_list_element;
  377. skip_chars(in, " \t\n", line, pos);
  378. while (c != EOF && c != ']') {
  379. if (in.peek() != ']') {
  380. cur_list_element = Element::fromJSON(in, file, line, pos);
  381. list->add(cur_list_element);
  382. skip_to(in, file, line, pos, ",]", " \t\n");
  383. }
  384. c = in.get();
  385. pos++;
  386. }
  387. return (list);
  388. }
  389. ElementPtr
  390. from_stringstream_map(std::istream &in, const std::string& file, int& line,
  391. int& pos)
  392. {
  393. ElementPtr map = Element::createMap();
  394. skip_chars(in, " \t\n", line, pos);
  395. char c = in.peek();
  396. if (c == '}') {
  397. // empty map, skip closing curly
  398. c = in.get();
  399. } else {
  400. while (c != EOF && c != '}') {
  401. std::string key = str_from_stringstream(in, file, line, pos);
  402. skip_to(in, file, line, pos, ":", " \t\n");
  403. // skip the :
  404. in.get();
  405. pos++;
  406. ConstElementPtr value = Element::fromJSON(in, file, line, pos);
  407. map->set(key, value);
  408. skip_to(in, file, line, pos, ",}", " \t\n");
  409. c = in.get();
  410. pos++;
  411. }
  412. }
  413. return (map);
  414. }
  415. }
  416. std::string
  417. Element::typeToName(Element::types type) {
  418. switch (type) {
  419. case Element::integer:
  420. return (std::string("integer"));
  421. case Element::real:
  422. return (std::string("real"));
  423. case Element::boolean:
  424. return (std::string("boolean"));
  425. case Element::string:
  426. return (std::string("string"));
  427. case Element::list:
  428. return (std::string("list"));
  429. case Element::map:
  430. return (std::string("map"));
  431. case Element::null:
  432. return (std::string("null"));
  433. case Element::any:
  434. return (std::string("any"));
  435. default:
  436. return (std::string("unknown"));
  437. }
  438. }
  439. Element::types
  440. Element::nameToType(const std::string& type_name) {
  441. if (type_name == "integer") {
  442. return (Element::integer);
  443. } else if (type_name == "real") {
  444. return (Element::real);
  445. } else if (type_name == "boolean") {
  446. return (Element::boolean);
  447. } else if (type_name == "string") {
  448. return (Element::string);
  449. } else if (type_name == "list") {
  450. return (Element::list);
  451. } else if (type_name == "map") {
  452. return (Element::map);
  453. } else if (type_name == "null") {
  454. return (Element::null);
  455. } else if (type_name == "any") {
  456. return (Element::any);
  457. } else {
  458. isc_throw(TypeError, type_name + " is not a valid type name");
  459. }
  460. }
  461. ElementPtr
  462. Element::fromJSON(std::istream& in) throw(JSONError) {
  463. int line = 1, pos = 1;
  464. return (fromJSON(in, "<istream>", line, pos));
  465. }
  466. ElementPtr
  467. Element::fromJSON(std::istream& in, const std::string& file_name)
  468. throw(JSONError)
  469. {
  470. int line = 1, pos = 1;
  471. return (fromJSON(in, file_name, line, pos));
  472. }
  473. ElementPtr
  474. Element::fromJSON(std::istream &in, const std::string& file, int& line,
  475. int& pos) throw(JSONError)
  476. {
  477. char c = 0;
  478. ElementPtr element;
  479. bool el_read = false;
  480. skip_chars(in, " \n\t", line, pos);
  481. while (c != EOF && !el_read) {
  482. c = in.get();
  483. pos++;
  484. switch(c) {
  485. case '1':
  486. case '2':
  487. case '3':
  488. case '4':
  489. case '5':
  490. case '6':
  491. case '7':
  492. case '8':
  493. case '9':
  494. case '0':
  495. case '-':
  496. case '+':
  497. case '.':
  498. in.putback(c);
  499. element = from_stringstream_number(in, pos);
  500. el_read = true;
  501. break;
  502. case 't':
  503. case 'T':
  504. case 'f':
  505. case 'F':
  506. in.putback(c);
  507. element = from_stringstream_bool(in, file, line, pos);
  508. el_read = true;
  509. break;
  510. case 'n':
  511. case 'N':
  512. in.putback(c);
  513. element = from_stringstream_null(in, file, line, pos);
  514. el_read = true;
  515. break;
  516. case '"':
  517. in.putback('"');
  518. element = from_stringstream_string(in, file, line, pos);
  519. el_read = true;
  520. break;
  521. case '[':
  522. element = from_stringstream_list(in, file, line, pos);
  523. el_read = true;
  524. break;
  525. case '{':
  526. element = from_stringstream_map(in, file, line, pos);
  527. el_read = true;
  528. break;
  529. case EOF:
  530. break;
  531. default:
  532. throwJSONError(std::string("error: unexpected character ") + c, file, line, pos);
  533. break;
  534. }
  535. }
  536. if (el_read) {
  537. return (element);
  538. } else {
  539. isc_throw(JSONError, "nothing read");
  540. }
  541. }
  542. ElementPtr
  543. Element::fromJSON(const std::string &in) {
  544. std::stringstream ss;
  545. ss << in;
  546. return (fromJSON(ss, "<string>"));
  547. }
  548. // to JSON format
  549. void
  550. IntElement::toJSON(std::ostream& ss) const {
  551. ss << intValue();
  552. }
  553. void
  554. DoubleElement::toJSON(std::ostream& ss) const {
  555. ss << doubleValue();
  556. }
  557. void
  558. BoolElement::toJSON(std::ostream& ss) const {
  559. if (boolValue()) {
  560. ss << "true";
  561. } else {
  562. ss << "false";
  563. }
  564. }
  565. void
  566. NullElement::toJSON(std::ostream& ss) const {
  567. ss << "null";
  568. }
  569. void
  570. StringElement::toJSON(std::ostream& ss) const {
  571. ss << "\"";
  572. ss << stringValue();
  573. ss << "\"";
  574. }
  575. void
  576. ListElement::toJSON(std::ostream& ss) const {
  577. ss << "[ ";
  578. const std::vector<ConstElementPtr>& v = listValue();
  579. for (std::vector<ConstElementPtr>::const_iterator it = v.begin();
  580. it != v.end(); ++it) {
  581. if (it != v.begin()) {
  582. ss << ", ";
  583. }
  584. (*it)->toJSON(ss);
  585. }
  586. ss << " ]";
  587. }
  588. void
  589. MapElement::toJSON(std::ostream& ss) const {
  590. ss << "{ ";
  591. const std::map<std::string, ConstElementPtr>& m = mapValue();
  592. for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
  593. it != m.end(); ++it) {
  594. if (it != m.begin()) {
  595. ss << ", ";
  596. }
  597. ss << "\"" << (*it).first << "\": ";
  598. if ((*it).second) {
  599. (*it).second->toJSON(ss);
  600. } else {
  601. ss << "None";
  602. }
  603. }
  604. ss << " }";
  605. }
  606. // throws when one of the types in the path (except the one
  607. // we're looking for) is not a MapElement
  608. // returns 0 if it could simply not be found
  609. // should that also be an exception?
  610. ConstElementPtr
  611. MapElement::find(const std::string& id) const {
  612. const size_t sep = id.find('/');
  613. if (sep == std::string::npos) {
  614. return (get(id));
  615. } else {
  616. ConstElementPtr ce = get(id.substr(0, sep));
  617. if (ce) {
  618. // ignore trailing slash
  619. if (sep + 1 != id.size()) {
  620. return (ce->find(id.substr(sep + 1)));
  621. } else {
  622. return (ce);
  623. }
  624. } else {
  625. return (ElementPtr());
  626. }
  627. }
  628. }
  629. ElementPtr
  630. Element::fromWire(const std::string& s) {
  631. std::stringstream ss;
  632. ss << s;
  633. int line = 0, pos = 0;
  634. return (fromJSON(ss, "<wire>", line, pos));
  635. }
  636. ElementPtr
  637. Element::fromWire(std::stringstream& in, int) {
  638. //
  639. // Check protocol version
  640. //
  641. //for (int i = 0 ; i < 4 ; ++i) {
  642. // const unsigned char version_byte = get_byte(in);
  643. // if (PROTOCOL_VERSION[i] != version_byte) {
  644. // throw DecodeError("Protocol version incorrect");
  645. // }
  646. //}
  647. //length -= 4;
  648. int line = 0, pos = 0;
  649. return (fromJSON(in, "<wire>", line, pos));
  650. }
  651. void
  652. MapElement::set(const std::string& key, ConstElementPtr value) {
  653. m[key] = value;
  654. }
  655. bool
  656. MapElement::find(const std::string& id, ConstElementPtr t) const {
  657. try {
  658. ConstElementPtr p = find(id);
  659. if (p) {
  660. t = p;
  661. return (true);
  662. }
  663. } catch (const TypeError& e) {
  664. // ignore
  665. }
  666. return (false);
  667. }
  668. bool
  669. IntElement::equals(const Element& other) const {
  670. return (other.getType() == Element::integer) &&
  671. (i == other.intValue());
  672. }
  673. bool
  674. DoubleElement::equals(const Element& other) const {
  675. return (other.getType() == Element::real) &&
  676. (d == other.doubleValue());
  677. }
  678. bool
  679. BoolElement::equals(const Element& other) const {
  680. return (other.getType() == Element::boolean) &&
  681. (b == other.boolValue());
  682. }
  683. bool
  684. NullElement::equals(const Element& other) const {
  685. return (other.getType() == Element::null);
  686. }
  687. bool
  688. StringElement::equals(const Element& other) const {
  689. return (other.getType() == Element::string) &&
  690. (s == other.stringValue());
  691. }
  692. bool
  693. ListElement::equals(const Element& other) const {
  694. if (other.getType() == Element::list) {
  695. const int s = size();
  696. if (s != other.size()) {
  697. return (false);
  698. }
  699. for (int i = 0; i < s; ++i) {
  700. if (!get(i)->equals(*other.get(i))) {
  701. return (false);
  702. }
  703. }
  704. return (true);
  705. } else {
  706. return (false);
  707. }
  708. }
  709. bool
  710. MapElement::equals(const Element& other) const {
  711. if (other.getType() == Element::map) {
  712. const std::map<std::string, ConstElementPtr>& m = mapValue();
  713. for (std::map<std::string, ConstElementPtr>::const_iterator it =
  714. m.begin();
  715. it != m.end() ; ++it) {
  716. if (other.contains((*it).first)) {
  717. if (!get((*it).first)->equals(*other.get((*it).first))) {
  718. return (false);
  719. }
  720. } else {
  721. return (false);
  722. }
  723. }
  724. // quickly walk through the other map too, to see if there's
  725. // anything in there that we don't have. We don't need to
  726. // compare those elements; if one of them is missing we
  727. // differ (and if it's not missing the loop above has checked
  728. // it)
  729. std::map<std::string, ConstElementPtr>::const_iterator it;
  730. for (it = other.mapValue().begin();
  731. it != other.mapValue().end();
  732. ++it) {
  733. if (!contains((*it).first)) {
  734. return (false);
  735. }
  736. }
  737. return (true);
  738. } else {
  739. return (false);
  740. }
  741. }
  742. bool
  743. isNull(ConstElementPtr p) {
  744. return (!p);
  745. }
  746. void
  747. removeIdentical(ElementPtr a, ConstElementPtr b) {
  748. if (!b) {
  749. return;
  750. }
  751. if (a->getType() != Element::map || b->getType() != Element::map) {
  752. isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
  753. }
  754. const std::map<std::string, ConstElementPtr>& m = a->mapValue();
  755. for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
  756. it != m.end() ; ++it) {
  757. if (b->contains((*it).first)) {
  758. if (a->get((*it).first)->equals(*b->get((*it).first))) {
  759. a->remove((*it).first);
  760. }
  761. }
  762. }
  763. }
  764. ConstElementPtr
  765. removeIdentical(ConstElementPtr a, ConstElementPtr b) {
  766. ElementPtr result = Element::createMap();
  767. if (!b) {
  768. return (result);
  769. }
  770. if (a->getType() != Element::map || b->getType() != Element::map) {
  771. isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
  772. }
  773. const std::map<std::string, ConstElementPtr>& m = a->mapValue();
  774. for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
  775. it != m.end() ; ++it) {
  776. if (!b->contains((*it).first) ||
  777. !a->get((*it).first)->equals(*b->get((*it).first))) {
  778. result->set((*it).first, (*it).second);
  779. }
  780. }
  781. return (result);
  782. }
  783. void
  784. merge(ElementPtr element, ConstElementPtr other) {
  785. if (element->getType() != Element::map ||
  786. other->getType() != Element::map) {
  787. isc_throw(TypeError, "merge arguments not MapElements");
  788. }
  789. const std::map<std::string, ConstElementPtr>& m = other->mapValue();
  790. for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
  791. it != m.end() ; ++it) {
  792. if ((*it).second && (*it).second->getType() != Element::null) {
  793. element->set((*it).first, (*it).second);
  794. } else if (element->contains((*it).first)) {
  795. element->remove((*it).first);
  796. }
  797. }
  798. }
  799. }
  800. }