#ifndef _library__json__hpp__included__ #define _library__json__hpp__included__ #include #include #include #include #include #include #include "utf8.hpp" namespace JSON { class node; struct number_tag { const static int id = 2; node operator()(double v) const; node operator()(uint64_t v) const; node operator()(int64_t v) const; bool operator==(const int& n) const { return n == id; } bool operator!=(const int& n) const { return !(*this == n); } operator int() { return id; } }; struct string_tag { const static int id = 3; node operator()(const std::string& s) const; node operator()(const std::u32string& s) const; bool operator==(const int& n) const { return n == id; } bool operator!=(const int& n) const { return !(*this == n); } operator int() { return id; } }; struct boolean_tag { const static int id = 1; node operator()(bool v); bool operator==(const int& n) const { return n == id; } bool operator!=(const int& n) const { return !(*this == n); } operator int() { return id; } }; struct array_tag { const static int id = 4; node operator()() const; bool operator==(const int& n) const { return n == id; } bool operator!=(const int& n) const { return !(*this == n); } operator int() { return id; } }; struct object_tag { const static int id = 5; node operator()() const; bool operator==(const int& n) const { return n == id; } bool operator!=(const int& n) const { return !(*this == n); } operator int() { return id; } }; struct null_tag { const static int id = 0; node operator()() const; bool operator==(const int& n) const { return n == id; } bool operator!=(const int& n) const { return !(*this == n); } operator int() { return id; } }; extern number_tag number; extern string_tag string; extern boolean_tag boolean; extern array_tag array; extern object_tag object; extern null_tag null; node i(int64_t n); node u(uint64_t n); node f(double n); node b(bool bl); node s(const std::string& st); node s(const std::u32string& st); node n(); enum errorcode { ERR_OK = 0, //All OK. ERR_NOT_A_NUMBER, //Not a number in operation expecting one. ERR_NOT_A_STRING, //Not a string in operation expecting one. ERR_NOT_A_BOOLEAN, //Not a boolean in operation expecting one. ERR_NOT_AN_ARRAY, //Not an array in operation expecting one. ERR_NOT_AN_OBJECT, //Not an object in operation expecting one. ERR_NOT_ARRAY_NOR_OBJECT, //Not array nor object in operation expecting either. ERR_INDEX_INVALID, //Non-existent index accessed. ERR_KEY_INVALID, //Non-existent key accessed. ERR_INSTANCE_INVALID, //Non-existent instance (of key) accessed. ERR_POINTER_TRAILING_ESCAPE, //JSON pointer has trailing escape. ERR_POINTER_INVALID_ESCAPE, //JSON pointer has invalid escape. ERR_BAD_HEX, //Bad hexadecimal character. ERR_INVALID_SURROGATE, //Invalid surrogate escape sequence. ERR_INVALID_ESCAPE, //Invalid escape sequence. ERR_TRUNCATED_STRING, //Truncated string. ERR_UNKNOWN_TYPE, //Unknown value type. ERR_GARBAGE_AFTER_END, //Garbage after end of JSON. ERR_TRUNCATED_JSON, //JSON truncated. ERR_UNEXPECTED_COMMA, //Unexpected ','. ERR_UNEXPECTED_COLON, //Unexpected ':'. ERR_UNEXPECTED_RIGHT_BRACE, //Unexpected '}'. ERR_UNEXPECTED_RIGHT_BRACKET, //Unexpected ']'. ERR_INVALID_NUMBER, //Bad number syntax. ERR_EXPECTED_STRING_KEY, //Object key is not a string. ERR_EXPECTED_COLON, //Expected ':' here. ERR_EXPECTED_COMMA, //Expected ',' here. ERR_UNKNOWN_CHARACTER, //Unknown token type. ERR_POINTER_BAD_APPEND, //Bad JSON pointer append. ERR_POINTER_BAD_INDEX, //Bad JSON pointer index. ERR_ITERATOR_END, //Iterator already at end. ERR_ITERATOR_DELETED, //Iterator points to deleted object. ERR_WRONG_OBJECT, //Iterator points to wrong object. ERR_ILLEGAL_CHARACTER, //Illegal character generated by escape. ERR_CONTROL_CHARACTER, //Control character in string. ERR_UNKNOWN_SUBTYPE, //Unknown value subtype. ERR_PATCH_BAD, //Bad JSON patch. ERR_PATCH_TEST_FAILED, //TEST operation in patch failed. ERR_PATCH_ILLEGAL_MOVE, //MOVE operation in patch illegal. }; extern const char* error_desc[]; struct error : public std::runtime_error { error(errorcode _code) : runtime_error(error_desc[_code]), code(_code) {} errorcode get_code() { return code; } private: errorcode code; }; /** * A JSON node. */ class node { public: /** * Type of node. */ /** * Construct null object. */ node() throw(); /** * Construct object of specified type. */ node(null_tag) throw(); node(boolean_tag, bool b) throw(); node(string_tag, const std::u32string& str) throw(std::bad_alloc); node(string_tag, const std::string& str) throw(std::bad_alloc); node(number_tag, double n) throw(); node(number_tag, int64_t n) throw(); node(number_tag, uint64_t n) throw(); node(array_tag) throw(); node(object_tag) throw(); /** * Compare nodes. */ bool operator==(const node& n) const; bool operator!=(const node& n) const { return !(*this == n); } /** * Copy Constructor. */ node(const node& _node) throw(std::bad_alloc); /** * Construct object from description. */ node(const std::string& doc) throw(std::bad_alloc, error); /** * Serialize document. */ std::string serialize() const throw(std::bad_alloc, error); /** * Get type of node. */ int type() const throw(); /** * Get double numeric value (NT_NUMBER). */ double as_double() const throw(error); /** * Get int64_t value (NT_NUMBER). */ int64_t as_int() const throw(error); /** * Get uint64_t value (NT_NUMBER). */ uint64_t as_uint() const throw(error); /** * Read the string as UTF-8 (NT_STRING). */ const std::u32string& as_string() const throw(std::bad_alloc, error); std::string as_string8() const throw(std::bad_alloc, error) { return to_u8string(as_string()); } /** * Get boolean value (NT_BOOLEAN). */ bool as_bool() const throw(error); /** * Read number of indices in array (NT_ARRAY). */ size_t index_count() const throw(error); /** * Read specified index from array (NT_ARRAY). */ const node& index(size_t idx) const throw(error); /** * Read number of indices in object key (NT_OBJECT). */ size_t field_count(const std::u32string& key) const throw(error); size_t field_count(const std::string& key) const throw(std::bad_alloc, error) { return field_count(to_u32string(key)); } /** * Specified field exists (NT_OBJECT) */ bool field_exists(const std::u32string& key) const throw(error); bool field_exists(const std::string& key) const throw(std::bad_alloc, error) { return field_exists(to_u32string(key)); } /** * Read specified key from object (NT_OBJECT). */ const node& field(const std::u32string& key, size_t subindex = 0) const throw(error); const node& field(const std::string& key, size_t subindex = 0) const throw(std::bad_alloc, error) { return field(to_u32string(key), subindex); } /** * Apply JSON pointer (RFC 6901). */ const node& follow(const std::u32string& pointer) const throw(std::bad_alloc, error); const node& follow(const std::string& pointer) const throw(std::bad_alloc, error) { return follow(to_u32string(pointer)); } /** * Set value of node (any). */ node& operator=(const node& node) throw(std::bad_alloc); /** * Set value of node. */ node& set(null_tag) throw(); node& set(boolean_tag, bool number) throw(); node& set(number_tag, double number) throw(); node& set(number_tag, int64_t number) throw(); node& set(number_tag, uint64_t number) throw(); node& set(string_tag, const std::u32string& key) throw(std::bad_alloc); node& set(string_tag tag, const std::string& key) throw(std::bad_alloc) { return set(tag, to_u32string(key)); } /** * Read/Write specified index from array (NT_ARRAY). */ node& index(size_t index) throw(error); /** * Append new element to array (NT_ARRAY). */ node& append(const node& node) throw(std::bad_alloc, error); /** * Read/Write specified key from object (NT_OBJECT). */ node& field(const std::u32string& key, size_t subindex = 0) throw(error); node& field(const std::string& key, size_t subindex = 0) throw(std::bad_alloc, error) { return field(to_u32string(key), subindex); } /** * Insert new element to object (NT_OBJECT). */ node& insert(const std::u32string& key, const node& node) throw(std::bad_alloc, error); node& insert(const std::string& key, const node& node) throw(std::bad_alloc, error) { return insert(to_u32string(key), node); } /** * Apply JSON pointer (RFC 6901). */ node& follow(const std::u32string& pointer) throw(std::bad_alloc, error); node& follow(const std::string& pointer) throw(std::bad_alloc, error) { return follow(to_u32string(pointer)); } /** * Return node specified by JSON pointer (RFC 6901). If the last component doesn't exist, it is created as NULL. */ node& operator[](const std::u32string& pointer) throw(std::bad_alloc, error); node& operator[](const std::string& pointer) throw(std::bad_alloc, error) { return (*this)[to_u32string(pointer)]; } /** * Create node at specified pointer and return it. */ node& insert_node(const std::u32string& pointer, const node& nwn) throw(std::bad_alloc, error); node& insert_node(const std::string& pointer, const node& nwn) throw(std::bad_alloc, error) { return insert_node(to_u32string(pointer), nwn); } /** * Delete a node by pointer and return what was deleted. */ node delete_node(const std::u32string& pointer) throw(std::bad_alloc, error); node delete_node(const std::string& pointer) throw(std::bad_alloc, error) { return delete_node(to_u32string(pointer)); } /** * Synonym for follow(). */ const node& operator[](const std::u32string& pointer) const throw(std::bad_alloc, error) { return follow(pointer); } const node& operator[](const std::string& pointer) const throw(std::bad_alloc, error) { return follow(pointer); } /** * Delete an array index. The rest are shifted. */ void erase_index(size_t idx) throw(error); /** * Delete an array field. The rest are shifted. */ void erase_field(const std::u32string& fld, size_t idx = 0) throw(error); void erase_field(const std::string& fld, size_t idx = 0) throw(std::bad_alloc, error) { erase_field(to_u32string(fld), idx); } /** * Delete an entiere array field. */ void erase_field_all(const std::u32string& fld) throw(error); void erase_field_all(const std::string& fld) throw(std::bad_alloc, error) { erase_field_all(to_u32string(fld)); } /** * Apply a JSON patch. */ node patch(const node& patch) const throw(std::bad_alloc, error); /** * Clear entiere array or object. */ void clear() throw(error); /** * Iterator. */ class iterator { public: typedef std::forward_iterator_tag iterator_category; typedef node value_type; typedef int difference_type; typedef node& reference; typedef node* pointer; iterator() throw(); iterator(node& n) throw(error); std::u32string key() throw(std::bad_alloc, error); std::string key8() throw(std::bad_alloc, error) { return to_u8string(key()); } size_t index() throw(error); node& operator*() throw(error); node* operator->() throw(error); iterator operator++(int) throw(error); iterator& operator++() throw(error); bool operator==(const iterator& i) throw(); bool operator!=(const iterator& i) throw(); private: friend class node; node* n; size_t idx; std::u32string _key; }; /** * Constant iterator. */ class const_iterator { public: typedef std::forward_iterator_tag iterator_category; typedef node value_type; typedef int difference_type; typedef const node& reference; typedef const node* pointer; const_iterator() throw(); const_iterator(const node& n) throw(error); std::u32string key() throw(std::bad_alloc, error); std::string key8() throw(std::bad_alloc, error) { return to_u8string(key()); } size_t index() throw(error); const node& operator*() throw(error); const node* operator->() throw(error); const_iterator operator++(int) throw(error); const_iterator& operator++() throw(error); bool operator==(const const_iterator& i) throw(); bool operator!=(const const_iterator& i) throw(); private: const node* n; size_t idx; std::u32string _key; }; /** * Iterators */ const_iterator begin() const throw(error) { return const_iterator(*this); } const_iterator end() const throw() { return const_iterator(); } iterator begin() throw(error) { return iterator(*this); } iterator end() throw() { return iterator(); } /** * Delete item pointed by iterator. The rest are shifted and new iterator is returned. */ iterator erase(iterator itr) throw(error); private: class number_holder { public: number_holder() { sub = 0; n.n0 = 0; } number_holder(const std::string& expr, size_t& ptr, size_t len); template T to() const { switch(sub) { case 0: return n.n0; case 1: return n.n1; case 2: return n.n2; } return 0; } template void from(T val); void write(std::ostream& s) const; bool operator==(const number_holder& h) const; private: template bool cmp(const T& num) const; unsigned sub; union { double n0; uint64_t n1; int64_t n2; } n; }; friend class iterator; friend class const_iterator; void fixup_nodes(const node& _node); void ctor(const std::string& doc, size_t& ptr, size_t len) throw(std::bad_alloc, error); node(const std::string& doc, size_t& ptr, size_t len) throw(std::bad_alloc, error); template void set_helper(T v) { std::u32string tmp; vtype = number; _number.from(v); std::swap(_string, tmp); xarray.clear(); xobject.clear(); } template T get_number_helper() const { if(vtype != number) throw error(ERR_NOT_A_NUMBER); return _number.to(); } int vtype; number_holder _number; bool _boolean; std::u32string _string; std::list xarray; std::vector xarray_index; std::map> xobject; }; } bool operator==(const int& n, const JSON::number_tag& v); bool operator==(const int& n, const JSON::string_tag& v); bool operator==(const int& n, const JSON::boolean_tag& v); bool operator==(const int& n, const JSON::array_tag& v); bool operator==(const int& n, const JSON::object_tag& v); bool operator==(const int& n, const JSON::null_tag& v); bool operator!=(const int& n, const JSON::number_tag& v); bool operator!=(const int& n, const JSON::string_tag& v); bool operator!=(const int& n, const JSON::boolean_tag& v); bool operator!=(const int& n, const JSON::array_tag& v); bool operator!=(const int& n, const JSON::object_tag& v); bool operator!=(const int& n, const JSON::null_tag& v); #endif