data.cc 22 KB

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