json/src/JSON.h

440 lines
13 KiB
C
Raw Normal View History

2014-12-30 10:47:28 +00:00
/*!
@file
@copyright The code is licensed under the MIT License
<http://opensource.org/licenses/MIT>,
Copyright (c) 2013-2014 Niels Lohmann.
@author Niels Lohmann <http://nlohmann.me>
@see https://github.com/nlohmann/json
*/
2013-07-04 08:49:03 +00:00
#pragma once
2014-12-28 08:11:01 +00:00
#include <initializer_list> // std::initializer_list
#include <iostream> // std::istream, std::ostream
#include <map> // std::map
#include <mutex> // std::mutex
#include <string> // std::string
#include <vector> // std::vector
/*!
2014-12-30 10:47:28 +00:00
@brief JSON for Modern C++
2014-12-28 08:11:01 +00: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.
@todo Implement JSON::swap()
@todo Implement JSON::insert(), JSON::emplace(), JSON::emplace_back, JSON::erase
@todo Implement JSON::reverse_iterator, JSON::const_reverse_iterator,
JSON::rbegin(), JSON::rend(), JSON::crbegin(), JSON::crend()?
*/
class JSON
{
// forward declaration to friend this class
2014-12-28 08:11:01 +00:00
public:
class iterator;
class const_iterator;
public:
/// possible types of a JSON object
enum class value_type : 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
};
/// a type for an object
using object_t = std::map<std::string, JSON>;
/// a type for an array
using array_t = std::vector<JSON>;
/// 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 = int;
/// a type for a floating point number
using number_float_t = double;
/// a type for list initialization
using list_init_t = std::initializer_list<JSON>;
/// 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);
};
public:
/// create an object according to given type
JSON(const value_type) noexcept;
/// create a null object
JSON() = default;
/// create a null object
JSON(std::nullptr_t) noexcept;
/// create a string object from a C++ string
JSON(const std::string&) noexcept;
/// create a string object from a C++ string (move)
JSON(std::string&&) noexcept;
/// create a string object from a C string
JSON(const char*) noexcept;
/// create a Boolean object
JSON(const bool) noexcept;
/// create a number object
JSON(const int) noexcept;
/// create a number object
JSON(const double) noexcept;
/// create an array
JSON(const array_t&) noexcept;
/// create an array (move)
JSON(array_t&&) noexcept;
/// create an object
JSON(const object_t&) noexcept;
/// create an object (move)
JSON(object_t&&) noexcept;
/// create from an initializer list (to an array or object)
JSON(list_init_t) noexcept;
/// copy constructor
JSON(const JSON&) noexcept;
/// move constructor
JSON(JSON&&) noexcept;
/// copy assignment
JSON& operator=(JSON) noexcept;
/// destructor
~JSON() noexcept;
/// create from string representation
2014-12-28 16:09:38 +00:00
static JSON parse(const std::string&);
2014-12-28 08:11:01 +00:00
/// create from string representation
static JSON parse(const char*);
private:
/// return the type as string
const std::string _typename() const noexcept;
public:
/// explicit value conversion
template<typename T>
T get() const;
/// implicit conversion to string representation
operator const std::string() const;
/// implicit conversion to integer (only for numbers)
operator int() const;
/// 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;
/// write to stream
friend std::ostream& operator<<(std::ostream& o, const JSON& j)
{
o << j.toString();
return o;
}
/// write to stream
friend std::ostream& operator>>(const JSON& j, std::ostream& o)
{
o << j.toString();
return o;
}
/// read from stream
friend std::istream& operator>>(std::istream& i, JSON& j)
{
Parser(i).parse(j);
return i;
}
/// read from stream
friend std::istream& operator<<(JSON& j, std::istream& i)
{
Parser(i).parse(j);
return i;
}
/// explicit conversion to string representation (C++ style)
const std::string toString() const noexcept;
/// add an object/array to an array
JSON& operator+=(const JSON&);
/// add a string to an array
JSON& operator+=(const std::string&);
/// add a null object to an array
JSON& operator+=(const std::nullptr_t);
/// add a string to an array
JSON& operator+=(const char*);
/// add a Boolean to an array
JSON& operator+=(bool);
/// add a number to an array
JSON& operator+=(int);
/// add a number to an array
JSON& operator+=(double);
/// add a pair to an object
JSON& operator+=(const object_t::value_type&);
/// add a list of elements to array or list of pairs to object
JSON& operator+=(list_init_t);
/// add an object/array to an array
void push_back(const JSON&);
/// add an object/array to an array (move)
void push_back(JSON&&);
/// add a string to an array
void push_back(const std::string&);
/// add a null object to an array
void push_back(const std::nullptr_t);
/// add a string to an array
void push_back(const char*);
/// add a Boolean to an array
void push_back(bool);
/// add a number to an array
void push_back(int);
/// add a number to an array
void push_back(double);
/// 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
JSON& operator[](const int);
/// operator to get an element in an array
const JSON& operator[](const int) const;
/// operator to get an element in an array
JSON& at(const int);
/// operator to get an element in an array
const JSON& at(const int) const;
/// operator to set an element in an object
2014-12-28 11:50:52 +00:00
JSON& operator[](const std::string&);
2014-12-28 08:11:01 +00:00
/// operator to set an element in an object
JSON& operator[](const char*);
/// operator to get an element in an object
const JSON& operator[](const std::string&) const;
/// operator to set an element in an object
2014-12-28 11:50:52 +00:00
JSON& at(const std::string&);
2014-12-28 08:11:01 +00:00
/// operator to set an element in an object
JSON& at(const char*);
/// operator to get an element in an object
const JSON& at(const std::string&) const;
2014-12-28 13:57:21 +00:00
/// operator to get an element in an object
const JSON& at(const char*) const;
2014-12-28 08:11:01 +00:00
/// return the number of stored values
size_t size() const noexcept;
/// checks whether object is empty
bool empty() const noexcept;
/// removes all elements from compounds and resets values to default
void clear() noexcept;
/// return the type of the object
value_type type() const noexcept;
/// 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
bool operator==(const JSON&) const noexcept;
/// lexicographically compares the values
2014-12-28 11:50:52 +00:00
bool operator!=(const JSON&) const noexcept;
2014-12-28 08:11:01 +00: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;
private:
/// the type of this object
value_type _type = value_type::null;
/// the payload
value _value {};
private:
/// mutex to guard payload
static std::mutex _token;
public:
/// an iterator
class iterator
{
friend class JSON;
friend class JSON::const_iterator;
public:
iterator() = default;
iterator(JSON*);
iterator(const iterator&);
~iterator();
iterator& operator=(iterator);
bool operator==(const iterator&) const;
bool operator!=(const iterator&) const;
iterator& operator++();
JSON& operator*() const;
JSON* operator->() const;
/// getter for the key (in case of objects)
std::string key() const;
/// getter for the value
JSON& value() const;
private:
/// a JSON value
JSON* _object = nullptr;
/// an iterator for JSON arrays
array_t::iterator* _vi = nullptr;
/// an iterator for JSON objects
object_t::iterator* _oi = nullptr;
};
/// a const iterator
class const_iterator
{
friend class JSON;
public:
const_iterator() = default;
const_iterator(const JSON*);
const_iterator(const const_iterator&);
const_iterator(const iterator&);
~const_iterator();
const_iterator& operator=(const_iterator);
bool operator==(const const_iterator&) const;
bool operator!=(const const_iterator&) const;
const_iterator& operator++();
const JSON& operator*() const;
const JSON* operator->() const;
/// getter for the key (in case of objects)
std::string key() const;
/// getter for the value
const JSON& value() const;
private:
2013-07-10 12:33:17 +00:00
/// a JSON value
2014-12-28 08:11:01 +00:00
const JSON* _object = nullptr;
/// an iterator for JSON arrays
array_t::const_iterator* _vi = nullptr;
/// an iterator for JSON objects
object_t::const_iterator* _oi = nullptr;
};
private:
/// a helper class to parse a JSON object
class Parser
{
public:
/// a parser reading from a C string
Parser(const char*);
/// a parser reading from a C++ string
2014-12-28 16:09:38 +00:00
Parser(const std::string&);
2014-12-28 08:11:01 +00:00
/// a parser reading from an input stream
Parser(std::istream&);
/// destructor of the parser
2015-01-02 14:29:36 +00:00
~Parser() = default;
2014-12-28 08:11:01 +00:00
// no copy constructor
Parser(const Parser&) = delete;
// no copy assignment
Parser& operator=(Parser) = delete;
/// parse into a given JSON object
void parse(JSON&);
private:
/// read the next character, stripping whitespace
bool next();
/// raise an exception with an error message
2015-01-02 14:29:36 +00:00
inline void error(const std::string&) __attribute__((noreturn));
2014-12-28 08:11:01 +00:00
/// parse a quoted string
std::string parseString();
/// parse a Boolean "true"
2015-01-02 14:29:36 +00:00
inline void parseTrue();
2014-12-28 08:11:01 +00:00
/// parse a Boolean "false"
2015-01-02 14:29:36 +00:00
inline void parseFalse();
2014-12-28 08:11:01 +00:00
/// parse a null object
2015-01-02 14:29:36 +00:00
inline void parseNull();
2014-12-28 08:11:01 +00:00
/// a helper function to expect a certain character
void expect(const char);
private:
/// a buffer of the input
2015-01-02 14:29:36 +00:00
std::string _buffer {};
2014-12-28 08:11:01 +00:00
/// the current character
char _current {};
/// the position inside the input buffer
size_t _pos = 0;
};
2013-07-04 08:49:03 +00:00
};
2014-12-28 08:11:01 +00:00
/// user-defined literal operator to create JSON objects from strings
JSON operator "" _json(const char*, size_t);