root/lang/cplusplus/picojson/trunk/picojson.h

Revision 38824, 20.7 kB (checked in by kazuho, 16 months ago)

remove unnecessary friend decl. and comparison logic, use #defines instead of copy&paste

Line 
1/* Copyright 2009 Cybozu Labs, Inc.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain the above copyright notice,
7 *    this list of conditions and the following disclaimer.
8 * 2. Redistributions in binary form must reproduce the above copyright notice,
9 *    this list of conditions and the following disclaimer in the documentation
10 *    and/or other materials provided with the distribution.
11 *
12 * THIS SOFTWARE IS PROVIDED BY CYBOZU LABS, INC. ``AS IS'' AND ANY EXPRESS OR
13 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
15 * EVENT SHALL CYBOZU LABS, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
16 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 *
23 * The views and conclusions contained in the software and documentation are
24 * those of the authors and should not be interpreted as representing official
25 * policies, either expressed or implied, of Cybozu Labs, Inc.
26 *
27 */
28#ifndef picojson_h
29#define picojson_h
30
31#include <cassert>
32#include <cstdio>
33#include <cstdlib>
34#include <cstring>
35#include <iostream>
36#include <iterator>
37#include <map>
38#include <string>
39#include <vector>
40
41#ifdef _MSC_VER
42    #define SNPRINTF _snprintf_s
43    #pragma warning(push)
44    #pragma warning(disable : 4244) // conversion from int to char
45#else
46    #define SNPRINTF snprintf
47#endif
48
49namespace picojson {
50 
51  enum {
52    null_type,
53    boolean_type,
54    number_type,
55    string_type,
56    array_type,
57    object_type
58  };
59 
60  struct null {};
61 
62  class value {
63  public:
64    typedef std::vector<value> array;
65    typedef std::map<std::string, value> object;
66  protected:
67    int type_;
68    union {
69      bool boolean_;
70      double number_;
71      std::string* string_;
72      array* array_;
73      object* object_;
74    };
75  public:
76    value();
77    value(int type, bool);
78    explicit value(bool b);
79    explicit value(double n);
80    explicit value(const std::string& s);
81    explicit value(const array& a);
82    explicit value(const object& o);
83    ~value();
84    value(const value& x);
85    value& operator=(const value& x);
86    template <typename T> bool is() const;
87    template <typename T> const T& get() const;
88    template <typename T> T& get();
89    operator bool() const;
90    const value& get(size_t idx) const;
91    const value& get(const std::string& key) const;
92    std::string to_str() const;
93    template <typename Iter> void serialize(Iter os) const;
94    std::string serialize() const;
95  };
96 
97  typedef value::array array;
98  typedef value::object object;
99 
100  inline value::value() : type_(null_type) {}
101 
102  inline value::value(int type, bool) : type_(type) {
103    switch (type) {
104#define INIT(p, v) case p##type: p = v; break
105      INIT(boolean_, false);
106      INIT(number_, 0.0);
107      INIT(string_, new std::string());
108      INIT(array_, new array());
109      INIT(object_, new object());
110#undef INIT
111    default: break;
112    }
113  }
114 
115  inline value::value(bool b) : type_(boolean_type) {
116    boolean_ = b;
117  }
118 
119  inline value::value(double n) : type_(number_type) {
120    number_ = n;
121  }
122 
123  inline value::value(const std::string& s) : type_(string_type) {
124    string_ = new std::string(s);
125  }
126 
127  inline value::value(const array& a) : type_(array_type) {
128    array_ = new array(a);
129  }
130 
131  inline value::value(const object& o) : type_(object_type) {
132    object_ = new object(o);
133  }
134 
135  inline value::~value() {
136    switch (type_) {
137#define DEINIT(p) case p##type: delete p; break
138      DEINIT(string_);
139      DEINIT(array_);
140      DEINIT(object_);
141#undef DEINIT
142    default: break;
143    }
144  }
145 
146  inline value::value(const value& x) : type_(x.type_) {
147    switch (type_) {
148#define INIT(p, v) case p##type: p = v; break
149      INIT(boolean_, x.boolean_);
150      INIT(number_, x.number_);
151      INIT(string_, new std::string(*x.string_));
152      INIT(array_, new array(*x.array_));
153      INIT(object_, new object(*x.object_));
154#undef INIT
155    default: break;
156    }
157  }
158 
159  inline value& value::operator=(const value& x) {
160    if (this != &x) {
161      this->~value();
162      new (this) value(x);
163    }
164    return *this;
165  }
166 
167#define IS(ctype, jtype)                             \
168  template <> inline bool value::is<ctype>() const { \
169    return type_ == jtype##_type;                    \
170  }
171  IS(null, null)
172  IS(bool, boolean)
173  IS(int, number)
174  IS(double, number)
175  IS(std::string, string)
176  IS(array, array)
177  IS(object, object)
178#undef IS
179 
180#define GET(ctype, var)                                       \
181  template <> inline const ctype& value::get<ctype>() const { \
182    return var;                                               \
183  }                                                           \
184  template <> inline ctype& value::get<ctype>() {             \
185    return var;                                               \
186  }
187  GET(bool, boolean_)
188  GET(double, number_)
189  GET(std::string, *string_)
190  GET(array, *array_)
191  GET(object, *object_)
192#undef GET
193 
194  inline value::operator bool() const {
195    switch (type_) {
196    case null_type:
197      return false;
198    case boolean_type:
199      return boolean_;
200    case number_type:
201      return number_ != 0;
202    case string_type:
203      return ! string_->empty();
204    default:
205      return true;
206    }
207  }
208 
209  inline const value& value::get(size_t idx) const {
210    static value s_null;
211    assert(is<array>());
212    return idx < array_->size() ? (*array_)[idx] : s_null;
213  }
214
215  inline const value& value::get(const std::string& key) const {
216    static value s_null;
217    assert(is<object>());
218    object::const_iterator i = object_->find(key);
219    return i != object_->end() ? i->second : s_null;
220  }
221 
222  inline std::string value::to_str() const {
223    switch (type_) {
224    case null_type:      return "null";
225    case boolean_type:   return boolean_ ? "true" : "false";
226    case number_type:    {
227      char buf[256];
228      SNPRINTF(buf, sizeof(buf), "%f", number_);
229      return buf;
230    }
231    case string_type:    return *string_;
232    case array_type:     return "array";
233    case object_type:    return "object";
234    default:             assert(0);
235#ifdef _MSC_VER
236      __assume(0);
237#endif
238    }
239  }
240 
241  template <typename Iter> void copy(const std::string& s, Iter oi) {
242    std::copy(s.begin(), s.end(), oi);
243  }
244 
245  template <typename Iter> void serialize_str(const std::string& s, Iter oi) {
246    *oi++ = '"';
247    for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
248      switch (*i) {
249#define MAP(val, sym) case val: copy(sym, oi); break
250        MAP('"', "\\\"");
251        MAP('\\', "\\\\");
252        MAP('/', "\\/");
253        MAP('\b', "\\b");
254        MAP('\f', "\\f");
255        MAP('\n', "\\n");
256        MAP('\r', "\\r");
257        MAP('\t', "\\t");
258#undef MAP
259      default:
260        if ((unsigned char)*i < 0x20 || *i == 0x7f) {
261          char buf[7];
262          SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff);
263          copy(buf, buf + 6, oi);
264          } else {
265          *oi++ = *i;
266        }
267        break;
268      }
269    }
270    *oi++ = '"';
271  }
272 
273  template <typename Iter> void value::serialize(Iter oi) const {
274    switch (type_) {
275    case string_type:
276      serialize_str(*string_, oi);
277      break;
278    case array_type: {
279      *oi++ = '[';
280      for (array::const_iterator i = array_->begin(); i != array_->end(); ++i) {
281        if (i != array_->begin()) {
282          *oi++ = ',';
283        }
284        i->serialize(oi);
285      }
286      *oi++ = ']';
287      break;
288    }
289    case object_type: {
290      *oi++ = '{';
291      for (object::const_iterator i = object_->begin();
292           i != object_->end();
293           ++i) {
294        if (i != object_->begin()) {
295          *oi++ = ',';
296        }
297        serialize_str(i->first, oi);
298        *oi++ = ':';
299        i->second.serialize(oi);
300      }
301      *oi++ = '}';
302      break;
303    }
304    default:
305      copy(to_str(), oi);
306      break;
307    }
308  }
309 
310  inline std::string value::serialize() const {
311    std::string s;
312    serialize(std::back_inserter(s));
313    return s;
314  }
315 
316  template <typename Iter> class input {
317  protected:
318    Iter cur_, end_;
319    int last_ch_;
320    bool ungot_;
321    int line_;
322  public:
323    input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {}
324    int getc() {
325      if (ungot_) {
326        ungot_ = false;
327        return last_ch_;
328      }
329      if (cur_ == end_) {
330        last_ch_ = -1;
331        return -1;
332      }
333      if (last_ch_ == '\n') {
334        line_++;
335      }
336      last_ch_ = *cur_++ & 0xff;
337      return last_ch_;
338    }
339    void ungetc() {
340      if (last_ch_ != -1) {
341        assert(! ungot_);
342        ungot_ = true;
343      }
344    }
345    Iter cur() const { return cur_; }
346    int line() const { return line_; }
347    void skip_ws() {
348      while (1) {
349        int ch = getc();
350        if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) {
351          ungetc();
352          break;
353        }
354      }
355    }
356    int expect(int expect) {
357      skip_ws();
358      if (getc() != expect) {
359        ungetc();
360        return false;
361      }
362      return true;
363    }
364    bool match(const std::string& pattern) {
365      for (std::string::const_iterator pi(pattern.begin());
366           pi != pattern.end();
367           ++pi) {
368        if (getc() != *pi) {
369          ungetc();
370          return false;
371        }
372      }
373      return true;
374    }
375  };
376 
377  template<typename Iter> inline int _parse_quadhex(input<Iter> &in) {
378    int uni_ch = 0, hex;
379    for (int i = 0; i < 4; i++) {
380      if ((hex = in.getc()) == -1) {
381        return -1;
382      }
383      if ('0' <= hex && hex <= '9') {
384        hex -= '0';
385      } else if ('A' <= hex && hex <= 'F') {
386        hex -= 'A' - 0xa;
387      } else if ('a' <= hex && hex <= 'f') {
388        hex -= 'a' - 0xa;
389      } else {
390        in.ungetc();
391        return -1;
392      }
393      uni_ch = uni_ch * 16 + hex;
394    }
395    return uni_ch;
396  }
397 
398  template<typename Iter> inline bool _parse_codepoint(std::string& out, input<Iter>& in) {
399    int uni_ch;
400    if ((uni_ch = _parse_quadhex(in)) == -1) {
401      return false;
402    }
403    if (0xd800 <= uni_ch && uni_ch <= 0xdfff) {
404      if (0xdc00 <= uni_ch) {
405        // a second 16-bit of a surrogate pair appeared
406        return false;
407      }
408      // first 16-bit of surrogate pair, get the next one
409      if (in.getc() != '\\' || in.getc() != 'u') {
410        in.ungetc();
411        return false;
412      }
413      int second = _parse_quadhex(in);
414      if (! (0xdc00 <= second && second <= 0xdfff)) {
415        return false;
416      }
417      uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff);
418      uni_ch += 0x10000;
419    }
420    if (uni_ch < 0x80) {
421      out.push_back(uni_ch);
422    } else {
423      if (uni_ch < 0x800) {
424        out.push_back(0xc0 | (uni_ch >> 6));
425      } else {
426        if (uni_ch < 0x10000) {
427          out.push_back(0xe0 | (uni_ch >> 12));
428        } else {
429          out.push_back(0xf0 | (uni_ch >> 18));
430          out.push_back(0x80 | ((uni_ch >> 12) & 0x3f));
431        }
432        out.push_back(0x80 | ((uni_ch >> 6) & 0x3f));
433      }
434      out.push_back(0x80 | (uni_ch & 0x3f));
435    }
436    return true;
437  }
438 
439  template<typename Iter> inline bool _parse_string(value& out, input<Iter>& in) {
440    // gcc 4.1 cannot compile if the below two lines are merged into one :-(
441    out = value(string_type, false);
442    std::string& s = out.get<std::string>();
443    while (1) {
444      int ch = in.getc();
445      if (ch < ' ') {
446        in.ungetc();
447        return false;
448      } else if (ch == '"') {
449        return true;
450      } else if (ch == '\\') {
451        if ((ch = in.getc()) == -1) {
452          return false;
453        }
454        switch (ch) {
455#define MAP(sym, val) case sym: s.push_back(val); break
456          MAP('"', '\"');
457          MAP('\\', '\\');
458          MAP('/', '/');
459          MAP('b', '\b');
460          MAP('f', '\f');
461          MAP('n', '\n');
462          MAP('r', '\r');
463          MAP('t', '\t');
464#undef MAP
465        case 'u':
466          if (! _parse_codepoint(s, in)) {
467            return false;
468          }
469          break;
470        default:
471          return false;
472        }
473      } else {
474        s.push_back(ch);
475      }
476    }
477    return false;
478  }
479 
480  template <typename Iter> inline bool _parse_array(value& out, input<Iter>& in) {
481    out = value(array_type, false);
482    array& a = out.get<array>();
483    if (in.expect(']')) {
484      return true;
485    }
486    do {
487      a.push_back(value());
488      if (! _parse(a.back(), in)) {
489        return false;
490      }
491    } while (in.expect(','));
492    return in.expect(']');
493  }
494 
495  template <typename Iter> inline bool _parse_object(value& out, input<Iter>& in) {
496    out = value(object_type, false);
497    object& o = out.get<object>();
498    if (in.expect('}')) {
499      return true;
500    }
501    do {
502      value key, val;
503      if (in.expect('"')
504          && _parse_string(key, in)
505          && in.expect(':')
506          && _parse(val, in)) {
507        o[key.to_str()] = val;
508      } else {
509        return false;
510      }
511    } while (in.expect(','));
512    return in.expect('}');
513  }
514 
515  template <typename Iter> inline bool _parse_number(value& out, input<Iter>& in) {
516    std::string num_str;
517    while (1) {
518      int ch = in.getc();
519      if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == '.'
520          || ch == 'e' || ch == 'E') {
521        num_str.push_back(ch);
522      } else {
523        in.ungetc();
524        break;
525      }
526    }
527    char* endp;
528    out = value(strtod(num_str.c_str(), &endp));
529    return endp == num_str.c_str() + num_str.size();
530  }
531 
532  template <typename Iter> inline bool _parse(value& out, input<Iter>& in) {
533    in.skip_ws();
534    int ch = in.getc();
535    switch (ch) {
536#define IS(ch, text, val) case ch: \
537      if (in.match(text)) { \
538        out = val; \
539        return true; \
540      } else { \
541        return false; \
542      }
543      IS('n', "ull", value());
544      IS('f', "alse", value(false));
545      IS('t', "rue", value(true));
546#undef IS
547    case '"':
548      return _parse_string(out, in);
549    case '[':
550      return _parse_array(out, in);
551    case '{':
552      return _parse_object(out, in);
553    default:
554      if (('0' <= ch && ch <= '9') || ch == '-') {
555        in.ungetc();
556        return _parse_number(out, in);
557      }
558      break;
559    }
560    in.ungetc();
561    return false;
562  }
563 
564  // obsolete, use the version below
565  template <typename Iter> inline std::string parse(value& out, Iter& pos, const Iter& last) {
566    std::string err;
567    pos = parse(out, pos, last, &err);
568    return err;
569  }
570 
571  template <typename Iter> inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) {
572    input<Iter> in(first, last);
573    if (! _parse(out, in) && err != NULL) {
574      char buf[64];
575      SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line());
576      *err = buf;
577      while (1) {
578        int ch = in.getc();
579        if (ch == -1 || ch == '\n') {
580          break;
581        } else if (ch >= ' ') {
582          err->push_back(ch);
583        }
584      }
585    }
586    return in.cur();
587  }
588 
589  inline std::string parse(value& out, std::istream& is) {
590    std::string err;
591    parse(out, std::istreambuf_iterator<char>(is.rdbuf()),
592          std::istreambuf_iterator<char>(), &err);
593    return err;
594  }
595 
596  template <typename T> struct last_error_t {
597    static std::string s;
598  };
599  template <typename T> std::string last_error_t<T>::s;
600 
601  inline void set_last_error(const std::string& s) {
602    last_error_t<bool>::s = s;
603  }
604 
605  inline const std::string& get_last_error() {
606    return last_error_t<bool>::s;
607  }
608
609  bool operator==(const value& x, const value& y) {
610    if (x.is<null>())
611      return y.is<null>();
612#define PICOJSON_CMP(type)                                      \
613    if (x.is<type>())                                           \
614      return y.is<type>() && x.get<type>() == y.get<type>()
615    PICOJSON_CMP(bool);
616    PICOJSON_CMP(double);
617    PICOJSON_CMP(std::string);
618    PICOJSON_CMP(array);
619    PICOJSON_CMP(object);
620#undef PICOJSON_CMP
621    assert(0);
622#ifdef _MSC_VER
623    __assume(0);
624#endif
625    return false;
626  }
627 
628  inline bool operator!=(const value& x, const value& y) {
629    return ! (x == y);
630  }
631}
632
633inline std::istream& operator>>(std::istream& is, picojson::value& x)
634{
635  picojson::set_last_error(std::string());
636  std::string err = picojson::parse(x, is);
637  if (! err.empty()) {
638    picojson::set_last_error(err);
639    is.setstate(std::ios::failbit);
640  }
641  return is;
642}
643
644inline std::ostream& operator<<(std::ostream& os, const picojson::value& x)
645{
646  x.serialize(std::ostream_iterator<char>(os));
647  return os;
648}
649#ifdef _MSC_VER
650    #pragma warning(pop)
651#endif
652
653#endif
654#ifdef TEST_PICOJSON
655#ifdef _MSC_VER
656    #pragma warning(disable : 4127) // conditional expression is constant
657#endif
658
659using namespace std;
660 
661static void plan(int num)
662{
663  printf("1..%d\n", num);
664}
665
666static void ok(bool b, const char* name = "")
667{
668  static int n = 1;
669  printf("%s %d - %s\n", b ? "ok" : "ng", n++, name);
670}
671
672template <typename T> void is(const T& x, const T& y, const char* name = "")
673{
674  if (x == y) {
675    ok(true, name);
676  } else {
677    ok(false, name);
678  }
679}
680
681#include <algorithm>
682
683int main(void)
684{
685  plan(61);
686 
687#define TEST(in, type, cmp, serialize_test) {                           \
688    picojson::value v;                                                  \
689    const char* s = in;                                                 \
690    string err = picojson::parse(v, s, s + strlen(s));                  \
691    ok(err.empty(), in " no error");                                    \
692    ok(v.is<type>(), in " check type");                                 \
693    is(v.get<type>(), cmp, in " correct output");                       \
694    is(*s, '\0', in " read to eof");                                    \
695    if (serialize_test) {                                               \
696      is(v.serialize(), string(in), in " serialize");                   \
697    }                                                                   \
698  }
699  TEST("false", bool, false, true);
700  TEST("true", bool, true, true);
701  TEST("90.5", double, 90.5, false);
702  TEST("\"hello\"", string, string("hello"), true);
703  TEST("\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"", string, string("\"\\/\b\f\n\r\t"),
704       true);
705  TEST("\"\\u0061\\u30af\\u30ea\\u30b9\"", string,
706       string("a\xe3\x82\xaf\xe3\x83\xaa\xe3\x82\xb9"), false);
707  TEST("\"\\ud840\\udc0b\"", string, string("\xf0\xa0\x80\x8b"), false);
708#undef TEST
709
710#define TEST(type, expr) {                                             \
711    picojson::value v;                                                 \
712    const char *s = expr;                                              \
713    string err = picojson::parse(v, s, s + strlen(s));                 \
714    ok(err.empty(), "empty " #type " no error");                       \
715    ok(v.is<picojson::type>(), "empty " #type " check type");          \
716    ok(v.get<picojson::type>().empty(), "check " #type " array size"); \
717  }
718  TEST(array, "[]");
719  TEST(object, "{}");
720#undef TEST
721 
722  {
723    picojson::value v;
724    const char *s = "[1,true,\"hello\"]";
725    string err = picojson::parse(v, s, s + strlen(s));
726    ok(err.empty(), "array no error");
727    ok(v.is<picojson::array>(), "array check type");
728    is(v.get<picojson::array>().size(), size_t(3), "check array size");
729    ok(v.get(0).is<double>(), "check array[0] type");
730    is(v.get(0).get<double>(), 1.0, "check array[0] value");
731    ok(v.get(1).is<bool>(), "check array[1] type");
732    ok(v.get(1).get<bool>(), "check array[1] value");
733    ok(v.get(2).is<string>(), "check array[2] type");
734    is(v.get(2).get<string>(), string("hello"), "check array[2] value");
735  }
736 
737  {
738    picojson::value v;
739    const char *s = "{ \"a\": true }";
740    string err = picojson::parse(v, s, s + strlen(s));
741    ok(err.empty(), "object no error");
742    ok(v.is<picojson::object>(), "object check type");
743    is(v.get<picojson::object>().size(), size_t(1), "check object size");
744    ok(v.get("a").is<bool>(), "check property exists");
745    is(v.get("a").get<bool>(), true,
746       "check property value");
747    is(v.serialize(), string("{\"a\":true}"), "serialize object");
748  }
749
750#define TEST(json, msg) do {                            \
751    picojson::value v;                                  \
752    const char *s = json;                               \
753    string err = picojson::parse(v, s, s + strlen(s));  \
754    is(err, string("syntax error at line " msg), msg);  \
755  } while (0)
756  TEST("falsoa", "1 near: oa");
757  TEST("{]", "1 near: ]");
758  TEST("\n\bbell", "2 near: bell");
759  TEST("\"abc\nd\"", "1 near: ");
760#undef TEST
761 
762  {
763    picojson::value v1, v2;
764    const char *s;
765    string err;
766    s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
767    err = picojson::parse(v1, s, s + strlen(s));
768    s = "{ \"d\": 2.0, \"b\": true, \"a\": [1,2,\"three\"] }";
769    err = picojson::parse(v2, s, s + strlen(s));
770    ok((v1 == v2), "check == operator in deep comparison");
771  }
772
773  {
774    picojson::value v1, v2;
775    const char *s;
776    string err;
777    s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
778    err = picojson::parse(v1, s, s + strlen(s));
779    s = "{ \"d\": 2.0, \"a\": [1,\"three\"], \"b\": true }";
780    err = picojson::parse(v2, s, s + strlen(s));
781    ok((v1 != v2), "check != operator for array in deep comparison");
782  }
783
784  {
785    picojson::value v1, v2;
786    const char *s;
787    string err;
788    s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
789    err = picojson::parse(v1, s, s + strlen(s));
790    s = "{ \"d\": 2.0, \"a\": [1,2,\"three\"], \"b\": false }";
791    err = picojson::parse(v2, s, s + strlen(s));
792    ok((v1 != v2), "check != operator for object in deep comparison");
793  }
794
795  {
796    picojson::value v1, v2;
797    const char *s;
798    string err;
799    s = "{ \"b\": true, \"a\": [1,2,\"three\"], \"d\": 2 }";
800    err = picojson::parse(v1, s, s + strlen(s));
801    picojson::object& o = v1.get<picojson::object>();
802    o.erase("b");
803    picojson::array& a = o["a"].get<picojson::array>();
804    picojson::array::iterator i;
805    i = std::remove(a.begin(), a.end(), picojson::value(std::string("three")));
806    a.erase(i, a.end());
807    s = "{ \"a\": [1,2], \"d\": 2 }";
808    err = picojson::parse(v2, s, s + strlen(s));
809    ok((v1 == v2), "check erase()");
810  }
811
812  return 0;
813}
814
815#endif
Note: See TracBrowser for help on using the browser.