diff C++/modules/Json/json.h @ 485:898d8b29a4f1

Switch to lowercase filenames
author David Demelier <markand@malikania.fr>
date Thu, 12 Nov 2015 21:53:36 +0100
parents C++/modules/Json/Json.h@3ee3f3e53ee3
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Json/json.h	Thu Nov 12 21:53:36 2015 +0100
@@ -0,0 +1,1161 @@
+/*
+ * json.h -- C++14 JSON manipulation using jansson parser
+ *
+ * Copyright (c) 2013-2015 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _JSON_H_
+#define _JSON_H_
+
+/**
+ * @file json.h
+ * @brief Jansson C++14 wrapper
+ *
+ * These classes can be used to build or parse JSON documents using jansson library. It is designed to be safe
+ * and explicit. It does not implement implicit sharing like jansson so when you access (e.g. Value::toObject) values
+ * you get real copies, thus when you read big documents it can has a performance cost.
+ */
+
+#include <cassert>
+#include <exception>
+#include <initializer_list>
+#include <map>
+#include <string>
+#include <utility>
+#include <deque>
+
+/**
+ * Json namespace.
+ */
+namespace json {
+
+/**
+ * @enum Type
+ * @brief Type of Value.
+ */
+enum class Type {
+	Array,		//!< Value is an array []
+	Boolean,	//!< Value is boolean
+	Int,		//!< Value is integer
+	Real,		//!< Value is float
+	Object,		//!< Value is object {}
+	String,		//!< Value is unicode string
+	Null		//!< Value is defined to null
+};
+
+/**
+ * @class Error
+ * @brief Error description.
+ */
+class Error : public std::exception {
+private:
+	std::string m_text;
+	std::string m_source;
+	int m_line;
+	int m_column;
+	int m_position;
+
+public:
+	/**
+	 * Create the error.
+	 *
+	 * @param text the text message
+	 * @param source the source (e.g. file name)
+	 * @param line the line number
+	 * @param column the column number
+	 * @param position the position
+	 */
+	inline Error(std::string text, std::string source, int line, int column, int position) noexcept
+		: m_text{std::move(text)}
+		, m_source{std::move(source)}
+		, m_line{line}
+		, m_column{column}
+		, m_position{position}
+	{
+	}
+
+	/**
+	 * Get the error message.
+	 *
+	 * @return the text
+	 */
+	inline const std::string &text() const noexcept
+	{
+		return m_text;
+	}
+
+	/**
+	 * Get the source (e.g. a file name).
+	 *
+	 * @return the source
+	 */
+	inline const std::string &source() const noexcept
+	{
+		return m_source;
+	}
+
+	/**
+	 * Get the line.
+	 *
+	 * @return the line
+	 */
+	inline int line() const noexcept
+	{
+		return m_line;
+	}
+
+	/**
+	 * Get the column.
+	 *
+	 * @return the column
+	 */
+	inline int column() const noexcept
+	{
+		return m_column;
+	}
+
+	/**
+	 * Get the position.
+	 *
+	 * @return the position
+	 */
+	inline int position() const noexcept
+	{
+		return m_position;
+	}
+
+	/**
+	 * Get the error message.
+	 *
+	 * @return the message
+	 */
+	const char *what() const noexcept override
+	{
+		return m_text.c_str();
+	}
+};
+
+/**
+ * @class Buffer
+ * @brief Open JSON document from text.
+ */
+class Buffer {
+public:
+	std::string text;	//!< The JSON text
+};
+
+/**
+ * @class File
+ * @brief Open JSON document from a file.
+ */
+class File {
+public:
+	std::string path;	//!< The path to the file
+};
+
+/**
+ * @class Value
+ * @brief Generic JSON value wrapper.
+ */
+class Value {
+private:
+	Type m_type{Type::Null};
+
+	union {
+		double m_number;
+		bool m_boolean;
+		int m_integer;
+		std::string m_string;
+		std::deque<Value> m_array;
+		std::map<std::string, Value> m_object;
+	};
+
+	void copy(const Value &);
+	void move(Value &&);
+	std::string toJson(int indent, int current) const;
+
+	/**
+	 * @class BaseIterator
+	 * @brief This is the base class for iterator and const_iterator
+	 *
+	 * This iterator works for both arrays and objects. Because of that purpose, it is only available
+	 * as forward iterator.
+	 *
+	 * When iterator comes from an object, you can use key() otherwise you can use index().
+	 */
+	template <typename ValueType, typename ArrayIteratorType, typename ObjectIteratorType>
+	class BaseIterator : public std::iterator<std::forward_iterator_tag, ValueType> {
+	private:
+		friend class Value;
+
+		ValueType &m_value;
+		ArrayIteratorType m_ita;
+		ObjectIteratorType m_itm;
+
+		inline void increment()
+		{
+			if (m_value.isObject()) {
+				m_itm++;
+			} else {
+				m_ita++;
+			}
+		}
+
+		BaseIterator(ValueType &value, ObjectIteratorType it)
+			: m_value(value)
+			, m_itm(it)
+		{
+		}
+
+		BaseIterator(ValueType &value, ArrayIteratorType it)
+			: m_value(value)
+			, m_ita(it)
+		{
+		}
+
+	public:
+		/**
+		 * Get the iterator key (for objects).
+		 *
+		 * @pre iterator must be dereferenceable
+		 * @pre iterator must come from object
+		 * @return the key
+		 */
+		inline const std::string &key() const noexcept
+		{
+			assert(m_value.isObject());
+			assert(m_itm != m_value.m_object.end());
+
+			return m_itm->first;
+		}
+
+		/**
+		 * Get the iterator position (for arrays).
+		 *
+		 * @pre iterator must be dereferenceable
+		 * @pre iterator must come from arrays
+		 * @return the index
+		 */
+		inline unsigned index() const noexcept
+		{
+			assert(m_value.isArray());
+			assert(m_ita != m_value.m_array.end());
+
+			return std::distance(m_value.m_array.begin(), m_ita);
+		}
+
+		/**
+		 * Dereference the iterator.
+		 *
+		 * @pre iterator be dereferenceable
+		 * @return the value
+		 */
+		inline ValueType &operator*() noexcept
+		{
+			assert((m_value.isArray()  && m_ita != m_value.m_array.end()) ||
+			       (m_value.isObject() && m_itm != m_value.m_object.end()));
+
+			return (m_value.m_type == Type::Object) ? m_itm->second : *m_ita;
+		}
+
+		/**
+		 * Dereference the iterator as a pointer.
+		 *
+		 * @pre iterator must be dereferenceable
+		 * @return the value
+		 */
+		inline ValueType *operator->() noexcept
+		{
+			assert((m_value.isArray()  && m_ita != m_value.m_array.end()) ||
+			       (m_value.isObject() && m_itm != m_value.m_object.end()));
+
+			return (m_value.m_type == Type::Object) ? &m_itm->second : &(*m_ita);
+		}
+
+		/**
+		 * Increment the iterator. (Prefix version).
+		 *
+		 * @pre iterator must be dereferenceable
+		 * @return *this;
+		 */
+		inline BaseIterator &operator++() noexcept
+		{
+			assert((m_value.isArray()  && m_ita != m_value.m_array.end()) ||
+			       (m_value.isObject() && m_itm != m_value.m_object.end()));
+
+			increment();
+
+			return *this;
+		}
+
+		/**
+		 * Increment the iterator. (Postfix version).
+		 *
+		 * @pre iterator must be dereferenceable
+		 * @return *this;
+		 */
+		inline BaseIterator &operator++(int) noexcept
+		{
+			assert((m_value.isArray()  && m_ita != m_value.m_array.end()) ||
+			       (m_value.isObject() && m_itm != m_value.m_object.end()));
+
+			increment();
+
+			return *this;
+		}
+
+		/**
+		 * Compare two iterators.
+		 *
+		 * @param it1 the first iterator
+		 * @param it2 the second iterator
+		 * @return true if they are same
+		 */
+		bool operator==(const BaseIterator &it) const noexcept
+		{
+			if (m_value.isObject() && it.m_value.isObject())
+				return m_itm == it.m_itm;
+			if (m_value.isArray() && it.m_value.isArray())
+				return m_ita == it.m_ita;
+
+			return false;
+		}
+
+		/**
+		 * Test if the iterator is different.
+		 *
+		 * @param it the iterator
+		 * @return true if they are different
+		 */
+		inline bool operator!=(const BaseIterator &it) const noexcept
+		{
+			return !(*this == it);
+		}
+	};
+
+public:
+	/**
+	 * Forward iterator.
+	 */
+	using iterator = BaseIterator<Value, typename std::deque<Value>::iterator, typename std::map<std::string, Value>::iterator>;
+
+	/**
+	 * Const forward iterator.
+	 */
+	using const_iterator = BaseIterator<const Value, typename std::deque<Value>::const_iterator, typename std::map<std::string, Value>::const_iterator>;
+
+	/**
+	 * Construct a null value.
+	 */
+	inline Value()
+	{
+	}
+
+	/**
+	 * Create a value with a specified type, this is usually only needed when you want to create an object or
+	 * an array.
+	 *
+	 * For any other types, initialize with sane default value.
+	 *
+	 * @param type the type
+	 */
+	Value(Type type);
+
+	/**
+	 * Construct a null value.
+	 */
+	inline Value(std::nullptr_t) noexcept
+		: m_type{Type::Null}
+	{
+	}
+
+	/**
+	 * Construct a boolean value.
+	 *
+	 * @param value the boolean value
+	 */
+	inline Value(bool value) noexcept
+		: m_type{Type::Boolean}
+		, m_boolean{value}
+	{
+	}
+
+	/**
+	 * Create value from integer.
+	 *
+	 * @param value the value
+	 */
+	inline Value(int value) noexcept
+		: m_type{Type::Int}
+		, m_integer{value}
+	{
+	}
+
+	/**
+	 * Construct a value from a C-string.
+	 *
+	 * @param value the C-string
+	 */
+	inline Value(const char *value)
+		: m_type{Type::String}
+	{
+		new (&m_string) std::string{value ? value : ""};
+	}
+
+	/**
+	 * Construct a number value.
+	 *
+	 * @param value the real value
+	 */
+	inline Value(double value) noexcept
+		: m_type{Type::Real}
+		, m_number{value}
+	{
+	}
+
+	/**
+	 * Construct a string value.
+	 *
+	 * @param value the string
+	 */
+	inline Value(std::string value) noexcept
+		: m_type{Type::String}
+	{
+		new (&m_string) std::string{std::move(value)};
+	}
+
+	/**
+	 * Create an object from a map.
+	 *
+	 * @param values the values
+	 * @see fromObject
+	 */
+	inline Value(std::map<std::string, Value> values)
+		: Value{Type::Object}
+	{
+		for (const auto &pair : values) {
+			insert(pair.first, pair.second);
+		}
+	}
+
+	/**
+	 * Create an array from a deque.
+	 *
+	 * @param values the values
+	 * @see fromArray
+	 */
+	inline Value(std::deque<Value> values)
+		: Value{Type::Array}
+	{
+		for (Value value : values) {
+			append(std::move(value));
+		}
+	}
+
+	/**
+	 * Construct a value from a buffer.
+	 *
+	 * @param buffer the text
+	 * @throw Error on errors
+	 */
+	Value(const Buffer &buffer);
+
+	/**
+	 * Construct a value from a file.
+	 *
+	 * @param file the file
+	 * @throw Error on errors
+	 */
+	Value(const File &file);
+
+	/**
+	 * Move constructor.
+	 *
+	 * @param other the value to move from
+	 */
+	inline Value(Value &&other)
+	{
+		move(std::move(other));
+	}
+
+	/**
+	 * Copy constructor.
+	 *
+	 * @param other the value to copy from
+	 */
+	inline Value(const Value &other)
+	{
+		copy(other);
+	}
+
+	/**
+	 * Copy operator.
+	 *
+	 * @param other the value to copy from
+	 * @return *this
+	 */
+	inline Value &operator=(const Value &other)
+	{
+		copy(other);
+
+		return *this;
+	}
+
+	/**
+	 * Move operator.
+	 *
+	 * @param other the value to move from
+	 */
+	inline Value &operator=(Value &&other)
+	{
+		move(std::move(other));
+
+		return *this;
+	}
+
+	/**
+	 * Destructor.
+	 */
+	~Value();
+
+	/**
+	 * Get an iterator to the beginning.
+	 *
+	 * @pre must be an array or object
+	 * @return the iterator
+	 */
+	inline iterator begin() noexcept
+	{
+		assert(isArray() || isObject());
+
+		return m_type == Type::Object ? iterator(*this, m_object.begin()) : iterator(*this, m_array.begin());
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @pre must be an array or object
+	 * @return the iterator
+	 */
+	inline const_iterator begin() const noexcept
+	{
+		assert(isArray() || isObject());
+
+		return m_type == Type::Object ? const_iterator(*this, m_object.begin()) : const_iterator(*this, m_array.begin());
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @pre must be an array or object
+	 * @return the iterator
+	 */
+	inline const_iterator cbegin() const noexcept
+	{
+		assert(isArray() || isObject());
+
+		return m_type == Type::Object ? const_iterator(*this, m_object.cbegin()) : const_iterator(*this, m_array.cbegin());
+	}
+
+	/**
+	 * Get an iterator to the end.
+	 *
+	 * @pre must be an array or object
+	 * @return the iterator
+	 */
+	inline iterator end() noexcept
+	{
+		assert(isArray() || isObject());
+
+		return m_type == Type::Object ? iterator(*this, m_object.end()) : iterator(*this, m_array.end());
+	}
+
+	/**
+	 * Get an iterator to the end.
+	 *
+	 * @pre must be an array or object
+	 * @return the iterator
+	 */
+	inline const_iterator end() const noexcept
+	{
+		assert(isArray() || isObject());
+
+		return m_type == Type::Object ? const_iterator(*this, m_object.end()) : const_iterator(*this, m_array.end());
+	}
+
+	/**
+	 * Get an iterator to the end.
+	 *
+	 * @pre must be an array or object
+	 * @return the iterator
+	 */
+	inline const_iterator cend() const noexcept
+	{
+		assert(isArray() || isObject());
+
+		return m_type == Type::Object ? const_iterator(*this, m_object.cend()) : const_iterator(*this, m_array.cend());
+	}
+
+	/**
+	 * Get the value type.
+	 *
+	 * @return the type
+	 */
+	inline Type typeOf() const noexcept
+	{
+		return m_type;
+	}
+
+	/**
+	 * Get the value as boolean.
+	 *
+	 * @return the value or false if not a boolean
+	 */
+	bool toBool() const noexcept;
+
+	/**
+	 * Get the value as integer.
+	 *
+	 * @return the value or 0 if not a integer
+	 */
+	int toInt() const noexcept;
+
+	/**
+	 * Get the value as real.
+	 *
+	 * @return the value or 0 if not a real
+	 */
+	double toReal() const noexcept;
+
+	/**
+	 * Get the value as string.
+	 *
+	 * @return the value or empty stirng if not a string
+	 */
+	std::string toString() const noexcept;
+
+	/**
+	 * Check if the value is boolean type.
+	 *
+	 * @return true if boolean
+	 */
+	inline bool isBool() const noexcept
+	{
+		return m_type == Type::Boolean;
+	}
+
+	/**
+	 * Check if the value is integer type.
+	 *
+	 * @return true if integer
+	 */
+	inline bool isInt() const noexcept
+	{
+		return m_type == Type::Int;
+	}
+
+	/**
+	 * Check if the value is object type.
+	 *
+	 * @return true if object
+	 */
+	inline bool isObject() const noexcept
+	{
+		return m_type == Type::Object;
+	}
+
+	/**
+	 * Check if the value is array type.
+	 *
+	 * @return true if array
+	 */
+	inline bool isArray() const noexcept
+	{
+		return m_type == Type::Array;
+	}
+
+	/**
+	 * Check if the value is integer or real type.
+	 *
+	 * @return true if integer or real
+	 * @see toInt
+	 * @see toReal
+	 */
+	inline bool isNumber() const noexcept
+	{
+		return m_type == Type::Real || m_type == Type::Int;
+	}
+
+	/**
+	 * Check if the value is real type.
+	 *
+	 * @return true if real
+	 */
+	inline bool isReal() const noexcept
+	{
+		return m_type == Type::Real;
+	}
+
+	/**
+	 * Check if the value is null type.
+	 *
+	 * @return true if null
+	 */
+	inline bool isNull() const noexcept
+	{
+		return m_type == Type::Null;
+	}
+
+	/**
+	 * Check if the value is string type.
+	 *
+	 * @return true if string
+	 */
+	inline bool isString() const noexcept
+	{
+		return m_type == Type::String;
+	}
+
+	/**
+	 * Get the array or object size.
+	 *
+	 * @pre must be an array or object
+	 * @return the size
+	 */
+	inline unsigned size() const noexcept
+	{
+		assert(isArray() || isObject());
+
+		if (m_type == Type::Object) {
+			return m_object.size();
+		}
+
+		return m_array.size();
+	}
+
+	/**
+	 * Remove all the values.
+	 *
+	 * @pre must be an array or an object
+	 */
+	inline void clear() noexcept
+	{
+		assert(isArray() || isObject());
+
+		if (m_type == Type::Array) {
+			m_array.clear();
+		} else {
+			m_object.clear();
+		}
+	}
+
+	/*
+	 * Array functions
+	 * ----------------------------------------------------------
+	 */
+
+	/**
+	 * Get the value at the specified position or the defaultValue if position is out of bounds.
+	 *
+	 * @param position the position
+	 * @param defaultValue the value replacement
+	 * @return the value or defaultValue
+	 */
+	template <typename DefaultValue>
+	inline Value valueOr(unsigned position, DefaultValue &&defaultValue) const
+	{
+		if (m_type != Type::Array || position >= m_array.size()) {
+			return defaultValue;
+		}
+
+		return m_array[position];
+	}
+
+	/**
+	 * Get a value at the specified index.
+	 *
+	 * @pre must be an array
+	 * @param position the position
+	 * @return the value
+	 * @throw std::out_of_range if out of bounds
+	 */
+	inline const Value &at(unsigned position) const
+	{
+		assert(isArray());
+
+		return m_array.at(position);
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @pre must be an array
+	 * @param position the position
+	 * @return the value
+	 * @throw std::out_of_range if out of bounds
+	 */
+	inline Value &at(unsigned position)
+	{
+		assert(isArray());
+
+		return m_array.at(position);
+	}
+
+	/**
+	 * Get a value at the specified index.
+	 *
+	 * @pre must be an array
+	 * @pre position must be valid
+	 * @param position the position
+	 * @return the value
+	 */
+	inline const Value &operator[](unsigned position) const
+	{
+		assert(isArray());
+		assert(position < m_array.size());
+
+		return m_array[position];
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @pre must be an array
+	 * @pre position must be valid
+	 * @param position the position
+	 * @return the value
+	 */
+	inline Value &operator[](unsigned position)
+	{
+		assert(isArray());
+		assert(position < m_array.size());
+
+		return m_array[position];
+	}
+
+	/**
+	 * Push a value to the beginning of the array.
+	 *
+	 * @pre must be an array
+	 * @param value the value to push
+	 */
+	inline void push(const Value &value)
+	{
+		assert(isArray());
+
+		m_array.push_front(value);
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @pre must be an array
+	 * @param value the value to push
+	 */
+	inline void push(Value &&value)
+	{
+		assert(isArray());
+
+		m_array.push_front(std::move(value));
+	}
+
+	/**
+	 * Insert a value at the specified position.
+	 *
+	 * @pre must be an array
+	 * @pre position must be valid
+	 * @param position the position
+	 * @param value the value to push
+	 */
+	inline void insert(unsigned position, const Value &value)
+	{
+		assert(isArray());
+		assert(position <= m_array.size());
+
+		m_array.insert(m_array.begin() + position, value);
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @pre must be an array
+	 * @pre position must be valid
+	 * @param position the position
+	 * @param value the value to push
+	 */
+	inline void insert(unsigned position, Value &&value)
+	{
+		assert(isArray());
+		assert(position <= m_array.size());
+
+		m_array.insert(m_array.begin() + position, std::move(value));
+	}
+
+	/**
+	 * Add a new value to the end.
+	 *
+	 * @pre must be an array
+	 * @param value the value to append
+	 */
+	inline void append(const Value &value)
+	{
+		assert(isArray());
+
+		m_array.push_back(value);
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @pre must be an array
+	 * @param value the value to append
+	 */
+	inline void append(Value &&value)
+	{
+		assert(isArray());
+
+		m_array.push_back(std::move(value));
+	}
+
+	/**
+	 * Remove a value at the specified position.
+	 *
+	 * @pre must be an array
+	 * @pre position must be valid
+	 * @param position the position
+	 */
+	inline void erase(unsigned position)
+	{
+		assert(isArray());
+		assert(position < m_array.size());
+
+		m_array.erase(m_array.begin() + position);
+	}
+
+	/*
+	 * Object functions
+	 * ----------------------------------------------------------
+	 */
+
+	/**
+	 * Get the value at the specified key or the defaultValue if key is absent.
+	 *
+	 * @param name the name
+	 * @param defaultValue the value replacement
+	 * @return the value or defaultValue
+	 */
+	template <typename DefaultValue>
+	Value valueOr(const std::string &name, DefaultValue &&defaultValue) const
+	{
+		if (m_type != Type::Object) {
+			return defaultValue;
+		}
+
+		auto it = m_object.find(name);
+
+		if (it == m_object.end()) {
+			return defaultValue;
+		}
+
+		return it->second;
+	}
+
+	/**
+	 * Get a value from the object.
+	 *
+	 * @pre must be an object
+	 * @param name the value key
+	 * @return the value
+	 * @throw std::out_of_range if not found
+	 */
+	inline const Value &at(const std::string &name) const
+	{
+		assert(isObject());
+
+		return m_object.at(name);
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @pre must be an object
+	 * @param name the value key
+	 * @return the value
+	 * @throw std::out_of_range if not found
+	 */
+	inline Value &at(const std::string &name)
+	{
+		assert(isObject());
+
+		return m_object.at(name);
+	}
+
+	/**
+	 * Get a value from the object.
+	 *
+	 * @pre must be an object
+	 * @param name the value key
+	 * @return the value
+	 */
+	inline Value &operator[](const std::string &name)
+	{
+		assert(isObject());
+
+		return m_object[name];
+	}
+
+	/**
+	 * Get a value from the object.
+	 *
+	 * @pre must be an object
+	 * @param name the value key
+	 * @return the value
+	 */
+	inline const Value &operator[](const std::string &name) const
+	{
+		assert(isObject());
+
+		return m_object.at(name);
+	}
+
+	/**
+	 * Find a value by key.
+	 *
+	 * @pre must be an object
+	 * @param key the property key
+	 * @return the iterator or past the end if not found
+	 */
+	inline iterator find(const std::string &key)
+	{
+		assert(isObject());
+
+		return iterator(*this, m_object.find(key));
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @pre must be an object
+	 * @param key the property key
+	 * @return the iterator or past the end if not found
+	 */
+	inline const_iterator find(const std::string &key) const
+	{
+		assert(isObject());
+
+		return const_iterator(*this, m_object.find(key));
+	}
+
+	/**
+	 * Insert a new value.
+	 *
+	 * @pre must be an object
+	 * @param name the key
+	 * @param value the value
+	 */
+	inline void insert(std::string name, const Value &value)
+	{
+		assert(isObject());
+
+		m_object.insert({std::move(name), value});
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @pre must be an object
+	 * @param name the key
+	 * @param value the value
+	 */
+	inline void insert(std::string name, Value &&value)
+	{
+		assert(isObject());
+
+		m_object.insert({std::move(name), std::move(value)});
+	}
+
+	/**
+	 * Check if a value exists.
+	 *
+	 * @pre must be an object
+	 * @param key the key value
+	 * @return true if exists
+	 */
+	inline bool contains(const std::string &key) const noexcept
+	{
+		assert(isObject());
+
+		return m_object.find(key) != m_object.end();
+	}
+
+	/**
+	 * Remove a value of the specified key.
+	 *
+	 * @pre must be an object
+	 * @param key the value key
+	 */
+	inline void erase(const std::string &key)
+	{
+		assert(isObject());
+
+		m_object.erase(key);
+	}
+
+	/**
+	 * Return this value as JSon representation.
+	 *
+	 * @param indent, the indentation to use (0 == compact, < 0 == tabs, > 0 == number of spaces)
+	 * @param tabs, use tabs or not
+	 * @return the string
+	 */
+	inline std::string toJson(int indent = 2) const
+	{
+		return toJson(indent, 0);
+	}
+};
+
+/**
+ * Escape the input.
+ *
+ * @param input the input
+ * @return the escaped string
+ */
+std::string escape(const std::string &input);
+
+/**
+ * Convenient function for creating array from initializer list.
+ *
+ * @param values the values
+ * @return the array
+ */
+inline Value array(std::initializer_list<Value> values)
+{
+	return Value(std::deque<Value>(values.begin(), values.end()));
+}
+
+/**
+ * Convenient function for creating object from initializer list.
+ *
+ * @param values the values
+ * @return the object
+ */
+inline Value object(std::initializer_list<std::pair<std::string, Value>> values)
+{
+	return Value(std::map<std::string, Value>(values.begin(), values.end()));
+}
+
+} // !json
+
+#endif // !_JSON_H_