json/src/json.h

577 lines
18 KiB
C
Raw Normal View History

2014-12-30 13:47:28 +03:00
/*!
@file
@copyright The code is licensed under the MIT License
<http://opensource.org/licenses/MIT>,
Copyright (c) 2013-2015 Niels Lohmann.
2014-12-30 13:47:28 +03:00
@author Niels Lohmann <http://nlohmann.me>
@see https://github.com/nlohmann/json
*/
2013-07-04 12:49:03 +04:00
#pragma once
2014-12-28 11:11:01 +03:00
#include <initializer_list> // std::initializer_list
#include <iostream> // std::istream, std::ostream
#include <map> // std::map
#include <string> // std::string
#include <vector> // std::vector
2015-01-09 19:40:14 +03:00
#include <iterator> // std::iterator
2015-01-20 23:15:14 +03:00
#include <limits> // std::numeric_limits
#include <functional> // std::hash
2014-12-28 11:11:01 +03:00
namespace nlohmann
{
2014-12-28 11:11:01 +03:00
/*!
2014-12-30 13:47:28 +03:00
@brief JSON for Modern C++
2014-12-28 11:11:01 +03:00
The size of a JSON object is 16 bytes: 8 bytes for the value union whose
largest item is a pointer type and another 8 byte for an element of the
type union. The latter only needs 1 byte - the remaining 7 bytes are wasted
due to alignment.
@see http://stackoverflow.com/questions/7758580/writing-your-own-stl-container/7759622#7759622
@bug Numbers are currently handled too generously. There are several formats
that are forbidden by the standard, but are accepted by the parser.
2015-01-04 22:43:25 +03:00
@todo Implement json::insert(), json::emplace(), json::emplace_back, json::erase
2014-12-28 11:11:01 +03:00
*/
2015-01-04 22:43:25 +03:00
class json
2014-12-28 11:11:01 +03:00
{
2015-01-21 19:42:45 +03:00
public:
// forward declaration to friend this class
2014-12-28 11:11:01 +03:00
class iterator;
class const_iterator;
2015-01-21 17:43:24 +03:00
public:
// container types
2015-01-21 19:42:45 +03:00
/// the type of elements in a JSON class
using value_type = json;
2015-01-21 19:42:45 +03:00
/// the type of element references
using reference = json&;
2015-01-21 19:42:45 +03:00
/// the type of const element references
using const_reference = const json&;
2015-01-21 19:42:45 +03:00
/// the type of pointers to elements
using pointer = json*;
2015-01-21 19:42:45 +03:00
/// the type of const pointers to elements
using const_pointer = const json*;
2015-01-21 19:42:45 +03:00
/// a type to represent differences between iterators
using difference_type = std::ptrdiff_t;
2015-01-21 19:42:45 +03:00
/// a type to represent container sizes
using size_type = std::size_t;
2015-01-21 19:42:45 +03:00
/// an iterator for a JSON container
using iterator = json::iterator;
/// a const iterator for a JSON container
using const_iterator = json::const_iterator;
/// a reverse iterator for a JSON container
using reverse_iterator = std::reverse_iterator<iterator>;
/// a const reverse iterator for a JSON container
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
2014-12-28 11:11:01 +03:00
/// a type for an object
2015-01-04 22:43:25 +03:00
using object_t = std::map<std::string, json>;
2014-12-28 11:11:01 +03:00
/// a type for an array
2015-01-04 22:43:25 +03:00
using array_t = std::vector<json>;
2014-12-28 11:11:01 +03:00
/// a type for a string
using string_t = std::string;
/// a type for a Boolean
using boolean_t = bool;
/// a type for an integer number
using number_t = int64_t;
2014-12-28 11:11:01 +03:00
/// a type for a floating point number
using number_float_t = double;
/// a type for list initialization
2015-01-04 22:43:25 +03:00
using list_init_t = std::initializer_list<json>;
2014-12-28 11:11:01 +03:00
/// a JSON value
union value
{
/// array as pointer to array_t
array_t* array;
/// object as pointer to object_t
object_t* object;
/// string as pointer to string_t
string_t* string;
/// Boolean
boolean_t boolean;
/// number (integer)
number_t number;
/// number (float)
number_float_t number_float;
/// default constructor
value() = default;
/// constructor for arrays
value(array_t*);
/// constructor for objects
value(object_t*);
/// constructor for strings
value(string_t*);
/// constructor for Booleans
value(boolean_t);
/// constructor for numbers (integer)
value(number_t);
/// constructor for numbers (float)
value(number_float_t);
};
/// possible types of a JSON object
enum class value_t : uint8_t
{
/// ordered collection of values
array = 0,
/// unordered set of name/value pairs
object,
/// null value
null,
/// string value
string,
/// Boolean value
boolean,
/// number value (integer)
number,
/// number value (float)
number_float
};
2014-12-28 11:11:01 +03:00
public:
/// create an object according to given type
json(const value_t);
2014-12-28 11:11:01 +03:00
/// create a null object
2015-01-24 22:33:06 +03:00
json() noexcept;
2014-12-28 11:11:01 +03:00
/// create a null object
2015-01-04 22:43:25 +03:00
json(std::nullptr_t) noexcept;
2014-12-28 11:11:01 +03:00
/// create a string object from a C++ string
json(const std::string&);
2014-12-28 11:11:01 +03:00
/// create a string object from a C++ string (move)
json(std::string&&);
2014-12-28 11:11:01 +03:00
/// create a string object from a C string
json(const char*);
2014-12-28 11:11:01 +03:00
/// create a Boolean object
2015-01-04 22:43:25 +03:00
json(const bool) noexcept;
2014-12-28 11:11:01 +03:00
/// create an array
json(const array_t&);
2014-12-28 11:11:01 +03:00
/// create an array (move)
json(array_t&&);
2014-12-28 11:11:01 +03:00
/// create an object
json(const object_t&);
2014-12-28 11:11:01 +03:00
/// create an object (move)
json(object_t&&);
2014-12-28 11:11:01 +03:00
/// create from an initializer list (to an array or object)
2015-01-24 22:33:06 +03:00
json(list_init_t, bool = true, value_t = value_t::array);
2014-12-28 11:11:01 +03:00
2015-01-21 19:42:45 +03:00
/*!
@brief create a number object (integer)
@param n an integer number to wrap in a JSON object
*/
template<typename T, typename
std::enable_if<
std::numeric_limits<T>::is_integer, T>::type
= 0>
json(const T n) noexcept
2015-01-24 22:33:06 +03:00
: final_type_(0), type_(value_t::number),
value_(static_cast<number_t>(n))
{}
2015-01-21 19:42:45 +03:00
/*!
@brief create a number object (float)
@param n a floating point number to wrap in a JSON object
*/
template<typename T, typename = typename
std::enable_if<
std::is_floating_point<T>::value>::type
>
json(const T n) noexcept
2015-01-24 22:33:06 +03:00
: final_type_(0), type_(value_t::number_float),
value_(static_cast<number_float_t>(n))
{}
2015-01-21 19:42:45 +03:00
/*!
@brief create an array object
@param v any type of container whose elements can be use to construct
JSON objects (e.g., std::vector, std::set, std::array)
2015-01-23 20:27:58 +03:00
@note For some reason, we need to explicitly forbid JSON iterator types.
2015-01-21 19:42:45 +03:00
*/
template <class V, typename
std::enable_if<
not std::is_same<V, json::iterator>::value and
2015-01-23 20:27:58 +03:00
not std::is_same<V, json::const_iterator>::value and
not std::is_same<V, json::reverse_iterator>::value and
not std::is_same<V, json::const_reverse_iterator>::value and
std::is_constructible<json, typename V::value_type>::value, int>::type
= 0>
json(const V& v) : json(array_t(v.begin(), v.end()))
{}
2015-01-21 19:42:45 +03:00
/*!
@brief create a JSON object
@param v any type of associative container whose elements can be use to
construct JSON objects (e.g., std::map<std::string, *>)
*/
template <class V, typename
std::enable_if<
std::is_constructible<std::string, typename V::key_type>::value and
std::is_constructible<json, typename V::mapped_type>::value, int>::type
= 0>
json(const V& v) : json(object_t(v.begin(), v.end()))
{}
2014-12-28 11:11:01 +03:00
/// copy constructor
json(const json&);
2014-12-28 11:11:01 +03:00
/// move constructor
2015-01-04 22:43:25 +03:00
json(json&&) noexcept;
2014-12-28 11:11:01 +03:00
/// copy assignment
2015-01-04 22:43:25 +03:00
json& operator=(json) noexcept;
2014-12-28 11:11:01 +03:00
/// destructor
2015-01-04 22:43:25 +03:00
~json() noexcept;
2014-12-28 11:11:01 +03:00
2015-01-24 22:33:06 +03:00
/// explicit keyword to force array creation
static json array(list_init_t = list_init_t());
/// explicit keyword to force object creation
static json object(list_init_t = list_init_t());
2014-12-28 11:11:01 +03:00
/// create from string representation
2015-01-04 22:43:25 +03:00
static json parse(const std::string&);
2014-12-28 11:11:01 +03:00
/// create from string representation
2015-01-04 22:43:25 +03:00
static json parse(const char*);
2014-12-28 11:11:01 +03:00
private:
/// return the type as string
2015-01-07 00:05:32 +03:00
std::string type_name() const noexcept;
2014-12-28 11:11:01 +03:00
/// dump the object (with pretty printer)
2015-01-07 00:05:32 +03:00
std::string dump(const bool, const unsigned int, unsigned int = 0) const noexcept;
2015-01-11 00:04:57 +03:00
/// replaced a character in a string with another string
void replaceChar(std::string& str, char c, const std::string& replacement) const;
/// escapes special characters to safely dump the string
std::string escapeString(const std::string&) const;
2014-12-28 11:11:01 +03:00
public:
/// explicit value conversion
template<typename T>
T get() const;
/// implicit conversion to string representation
2015-01-12 15:03:41 +03:00
operator std::string() const;
2014-12-28 11:11:01 +03:00
/// implicit conversion to integer (only for numbers)
operator int() const;
/// implicit conversion to integer (only for numbers)
operator int64_t() const;
2014-12-28 11:11:01 +03:00
/// implicit conversion to double (only for numbers)
operator double() const;
/// implicit conversion to Boolean (only for Booleans)
operator bool() const;
/// implicit conversion to JSON vector (not for objects)
operator array_t() const;
/// implicit conversion to JSON map (only for objects)
operator object_t() const;
/// serialize to stream
2015-01-04 22:43:25 +03:00
friend std::ostream& operator<<(std::ostream& o, const json& j)
2014-12-28 11:11:01 +03:00
{
o << j.dump();
2014-12-28 11:11:01 +03:00
return o;
}
/// serialize to stream
2015-01-04 22:43:25 +03:00
friend std::ostream& operator>>(const json& j, std::ostream& o)
2014-12-28 11:11:01 +03:00
{
o << j.dump();
2014-12-28 11:11:01 +03:00
return o;
}
/// deserialize from stream
2015-01-04 22:43:25 +03:00
friend std::istream& operator>>(std::istream& i, json& j)
2014-12-28 11:11:01 +03:00
{
2015-01-04 22:43:25 +03:00
j = parser(i).parse();
2014-12-28 11:11:01 +03:00
return i;
}
/// deserialize from stream
2015-01-04 22:43:25 +03:00
friend std::istream& operator<<(json& j, std::istream& i)
2014-12-28 11:11:01 +03:00
{
2015-01-04 22:43:25 +03:00
j = parser(i).parse();
2014-12-28 11:11:01 +03:00
return i;
}
/// explicit serialization
2015-01-07 00:05:32 +03:00
std::string dump(int = -1) const noexcept;
2014-12-28 11:11:01 +03:00
/// add constructible objects to an array
template<class T, typename std::enable_if<std::is_constructible<json, T>::value>::type = 0>
json & operator+=(const T& o)
{
push_back(json(o));
return *this;
}
2014-12-28 11:11:01 +03:00
/// add an object/array to an array
2015-01-04 22:43:25 +03:00
json& operator+=(const json&);
2014-12-28 11:11:01 +03:00
/// add a pair to an object
2015-01-04 22:43:25 +03:00
json& operator+=(const object_t::value_type&);
2014-12-28 11:11:01 +03:00
/// add a list of elements to array or list of pairs to object
2015-01-04 22:43:25 +03:00
json& operator+=(list_init_t);
2014-12-28 11:11:01 +03:00
/// add constructible objects to an array
template<class T, typename std::enable_if<std::is_constructible<json, T>::value>::type = 0>
void push_back(const T& o)
{
push_back(json(o));
}
2014-12-28 11:11:01 +03:00
/// add an object/array to an array
2015-01-04 22:43:25 +03:00
void push_back(const json&);
2014-12-28 11:11:01 +03:00
/// add an object/array to an array (move)
2015-01-04 22:43:25 +03:00
void push_back(json&&);
2014-12-28 11:11:01 +03:00
/// add a pair to an object
void push_back(const object_t::value_type&);
/// add a list of elements to array or list of pairs to object
void push_back(list_init_t);
/// operator to set an element in an array
2015-01-23 20:27:58 +03:00
reference operator[](const int);
2014-12-28 11:11:01 +03:00
/// operator to get an element in an array
2015-01-23 20:27:58 +03:00
const_reference operator[](const int) const;
2014-12-28 11:11:01 +03:00
/// operator to get an element in an array
reference at(const int);
2014-12-28 11:11:01 +03:00
/// operator to get an element in an array
const_reference at(const int) const;
2014-12-28 11:11:01 +03:00
/// operator to set an element in an object
reference operator[](const std::string&);
2014-12-28 11:11:01 +03:00
/// operator to set an element in an object
reference operator[](const char*);
2014-12-28 11:11:01 +03:00
/// operator to get an element in an object
const_reference operator[](const std::string&) const;
2015-01-23 20:27:58 +03:00
/// operator to get an element in an object
const_reference operator[](const char*) const;
2014-12-28 11:11:01 +03:00
/// operator to set an element in an object
reference at(const std::string&);
2014-12-28 11:11:01 +03:00
/// operator to set an element in an object
reference at(const char*);
2014-12-28 11:11:01 +03:00
/// operator to get an element in an object
const_reference at(const std::string&) const;
2014-12-28 16:57:21 +03:00
/// operator to get an element in an object
const_reference at(const char*) const;
2014-12-28 11:11:01 +03:00
/// return the number of stored values
size_type size() const noexcept;
/// return the maximal number of values that can be stored
size_type max_size() const noexcept;
2014-12-28 11:11:01 +03:00
/// checks whether object is empty
bool empty() const noexcept;
/// removes all elements from compounds and resets values to default
void clear() noexcept;
/// swaps content with other object
void swap(json&) noexcept;
2014-12-28 11:11:01 +03:00
/// return the type of the object
value_t type() const noexcept;
2014-12-28 11:11:01 +03:00
/// find an element in an object (returns end() iterator otherwise)
iterator find(const std::string&);
/// find an element in an object (returns end() iterator otherwise)
const_iterator find(const std::string&) const;
/// find an element in an object (returns end() iterator otherwise)
iterator find(const char*);
/// find an element in an object (returns end() iterator otherwise)
const_iterator find(const char*) const;
/// lexicographically compares the values
2015-01-04 22:43:25 +03:00
bool operator==(const json&) const noexcept;
2014-12-28 11:11:01 +03:00
/// lexicographically compares the values
2015-01-04 22:43:25 +03:00
bool operator!=(const json&) const noexcept;
2014-12-28 11:11:01 +03:00
/// returns an iterator to the beginning (array/object)
iterator begin() noexcept;
/// returns an iterator to the end (array/object)
iterator end() noexcept;
/// returns an iterator to the beginning (array/object)
const_iterator begin() const noexcept;
/// returns an iterator to the end (array/object)
const_iterator end() const noexcept;
/// returns an iterator to the beginning (array/object)
const_iterator cbegin() const noexcept;
/// returns an iterator to the end (array/object)
const_iterator cend() const noexcept;
2015-01-21 19:42:45 +03:00
/// returns a reverse iterator to the beginning
reverse_iterator rbegin() noexcept;
/// returns a reverse iterator to the end
reverse_iterator rend() noexcept;
/// returns a reverse iterator to the beginning
const_reverse_iterator crbegin() const noexcept;
/// returns a reverse iterator to the end
const_reverse_iterator crend() const noexcept;
2014-12-28 11:11:01 +03:00
private:
2015-01-24 22:33:06 +03:00
/// whether the type is final
unsigned final_type_ : 1;
2014-12-28 11:11:01 +03:00
/// the type of this object
value_t type_ = value_t::null;
2014-12-28 11:11:01 +03:00
/// the payload
2015-01-05 01:09:30 +03:00
value value_ {};
2014-12-28 11:11:01 +03:00
2015-01-21 19:42:45 +03:00
public:
2014-12-28 11:11:01 +03:00
/// an iterator
2015-01-21 19:42:45 +03:00
class iterator : public std::iterator<std::bidirectional_iterator_tag, json>
2014-12-28 11:11:01 +03:00
{
2015-01-04 22:43:25 +03:00
friend class json;
friend class json::const_iterator;
2015-01-21 19:42:45 +03:00
2014-12-28 11:11:01 +03:00
public:
iterator() = default;
2015-01-21 17:43:24 +03:00
iterator(json*, bool);
2014-12-28 11:11:01 +03:00
iterator(const iterator&);
~iterator();
iterator& operator=(iterator);
bool operator==(const iterator&) const;
bool operator!=(const iterator&) const;
iterator& operator++();
2015-01-21 19:42:45 +03:00
iterator& operator--();
2015-01-04 22:43:25 +03:00
json& operator*() const;
json* operator->() const;
2014-12-28 11:11:01 +03:00
/// getter for the key (in case of objects)
std::string key() const;
/// getter for the value
2015-01-04 22:43:25 +03:00
json& value() const;
2014-12-28 11:11:01 +03:00
private:
/// a JSON value
2015-01-05 01:09:30 +03:00
json* object_ = nullptr;
2014-12-28 11:11:01 +03:00
/// an iterator for JSON arrays
2015-01-05 01:09:30 +03:00
array_t::iterator* vi_ = nullptr;
2014-12-28 11:11:01 +03:00
/// an iterator for JSON objects
2015-01-05 01:09:30 +03:00
object_t::iterator* oi_ = nullptr;
2015-01-21 17:43:24 +03:00
/// whether iterator points to a valid object
bool invalid = true;
2014-12-28 11:11:01 +03:00
};
/// a const iterator
2015-01-21 19:42:45 +03:00
class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const json>
2014-12-28 11:11:01 +03:00
{
2015-01-04 22:43:25 +03:00
friend class json;
2014-12-28 11:11:01 +03:00
public:
const_iterator() = default;
2015-01-21 17:43:24 +03:00
const_iterator(const json*, bool);
2014-12-28 11:11:01 +03:00
const_iterator(const const_iterator&);
const_iterator(const json::iterator&);
2014-12-28 11:11:01 +03:00
~const_iterator();
const_iterator& operator=(const_iterator);
bool operator==(const const_iterator&) const;
bool operator!=(const const_iterator&) const;
const_iterator& operator++();
2015-01-21 19:42:45 +03:00
const_iterator& operator--();
2015-01-04 22:43:25 +03:00
const json& operator*() const;
const json* operator->() const;
2014-12-28 11:11:01 +03:00
/// getter for the key (in case of objects)
std::string key() const;
/// getter for the value
2015-01-04 22:43:25 +03:00
const json& value() const;
2014-12-28 11:11:01 +03:00
private:
2013-07-10 16:33:17 +04:00
/// a JSON value
2015-01-05 01:09:30 +03:00
const json* object_ = nullptr;
2014-12-28 11:11:01 +03:00
/// an iterator for JSON arrays
2015-01-05 01:09:30 +03:00
array_t::const_iterator* vi_ = nullptr;
2014-12-28 11:11:01 +03:00
/// an iterator for JSON objects
2015-01-05 01:09:30 +03:00
object_t::const_iterator* oi_ = nullptr;
2015-01-21 17:43:24 +03:00
/// whether iterator reached past the end
bool invalid = true;
2014-12-28 11:11:01 +03:00
};
private:
/// a helper class to parse a JSON object
2015-01-04 22:43:25 +03:00
class parser
2014-12-28 11:11:01 +03:00
{
public:
/// a parser reading from a C string
2015-01-04 22:43:25 +03:00
parser(const char*);
2014-12-28 11:11:01 +03:00
/// a parser reading from a C++ string
2015-01-04 22:43:25 +03:00
parser(const std::string&);
2014-12-28 11:11:01 +03:00
/// a parser reading from an input stream
2015-01-04 22:43:25 +03:00
parser(std::istream&);
2014-12-28 11:11:01 +03:00
/// destructor of the parser
2015-01-04 22:43:25 +03:00
~parser() = default;
2014-12-28 11:11:01 +03:00
// no copy constructor
2015-01-04 22:43:25 +03:00
parser(const parser&) = delete;
2014-12-28 11:11:01 +03:00
// no copy assignment
2015-01-04 22:43:25 +03:00
parser& operator=(parser) = delete;
2014-12-28 11:11:01 +03:00
2015-01-02 19:19:40 +03:00
/// parse and return a JSON object
2015-01-04 22:43:25 +03:00
json parse();
2014-12-28 11:11:01 +03:00
private:
/// read the next character, stripping whitespace
bool next();
/// raise an exception with an error message
[[noreturn]] inline void error(const std::string&) const;
2014-12-28 11:11:01 +03:00
/// parse a quoted string
2015-01-03 19:18:17 +03:00
inline std::string parseString();
/// transforms a unicode codepoint to it's UTF-8 presentation
std::string codePointToUTF8(unsigned int codePoint) const;
/// parses 4 hex characters that represent a unicode code point
inline unsigned int parse4HexCodePoint();
2015-01-10 18:49:10 +03:00
/// parses \uXXXX[\uXXXX] unicode escape characters
inline std::string parseUnicodeEscape();
2014-12-28 11:11:01 +03:00
/// parse a Boolean "true"
2015-01-02 17:29:36 +03:00
inline void parseTrue();
2014-12-28 11:11:01 +03:00
/// parse a Boolean "false"
2015-01-02 17:29:36 +03:00
inline void parseFalse();
2014-12-28 11:11:01 +03:00
/// parse a null object
2015-01-02 17:29:36 +03:00
inline void parseNull();
2014-12-28 11:11:01 +03:00
/// a helper function to expect a certain character
2015-01-03 19:18:17 +03:00
inline void expect(const char);
2014-12-28 11:11:01 +03:00
private:
/// a buffer of the input
2015-01-05 01:09:30 +03:00
std::string buffer_ {};
2014-12-28 11:11:01 +03:00
/// the current character
2015-01-05 01:09:30 +03:00
char current_ {};
2014-12-28 11:11:01 +03:00
/// the position inside the input buffer
std::size_t pos_ = 0;
2014-12-28 11:11:01 +03:00
};
2013-07-04 12:49:03 +04:00
};
2014-12-28 11:11:01 +03:00
}
2014-12-28 11:11:01 +03:00
/// user-defined literal operator to create JSON objects from strings
nlohmann::json operator "" _json(const char*, std::size_t);
// specialization of std::swap, and std::hash
namespace std
{
template <>
/// swaps the values of two JSON objects
inline void swap(nlohmann::json& j1,
nlohmann::json& j2) noexcept(
is_nothrow_move_constructible<nlohmann::json>::value and
is_nothrow_move_assignable<nlohmann::json>::value
)
{
j1.swap(j2);
}
template <>
/// hash value for JSON objects
struct hash<nlohmann::json>
{
size_t operator()(const nlohmann::json& j) const
{
// a naive hashing via the string representation
return hash<std::string>()(j.dump());
}
};
}