data.cc 21 KB

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