changeset 480:453f22449b33

Merge
author David Demelier <markand@malikania.fr>
date Tue, 10 Nov 2015 14:12:48 +0100
parents 65b567c8de54 (current diff) c7d83d2b462b (diff)
children b75b857aae11
files
diffstat 3 files changed, 757 insertions(+), 635 deletions(-) [+]
line wrap: on
line diff
--- a/C++/modules/Json/Json.cpp	Tue Nov 10 13:32:51 2015 +0100
+++ b/C++/modules/Json/Json.cpp	Tue Nov 10 14:12:48 2015 +0100
@@ -45,14 +45,14 @@
 		return Value{json_boolean_value(v)};
 	}
 	if (json_is_object(v)) {
-		Object object;
+		Value object{Type::Object};
 
 		readObject(object, v);
 
 		return object;
 	}
 	if (json_is_array(v)) {
-		Array array;
+		Value array{Type::Array};
 
 		readArray(array, v);
 
@@ -68,7 +68,7 @@
 	json_t *value;
 
 	json_object_foreach(object, key, value) {
-		static_cast<Object &>(parent).insert(key, readValue(value));
+		parent.insert(key, readValue(value));
 	}
 }
 
@@ -78,7 +78,7 @@
 	json_t *value;
 
 	json_array_foreach(array, index, value) {
-		static_cast<Array &>(parent).append(readValue(value));
+		parent.append(readValue(value));
 	}
 }
 
@@ -95,10 +95,10 @@
 	Value value;
 
 	if (json_is_object(json)) {
-		value = Object{};
+		value = Value{Type::Object};
 		readObject(value, json);
 	} else {
-		value = Array{};
+		value = Value{Type::Array};
 		readArray(value, json);
 	}
 
@@ -109,6 +109,106 @@
 
 } // !namespace
 
+void Value::copy(const Value &other)
+{
+	switch (other.m_type) {
+	case Type::Array:
+		new (&m_array) std::deque<Value>(other.m_array);
+		break;
+	case Type::Boolean:
+		m_boolean = other.m_boolean;
+		break;
+	case Type::Int:
+		m_integer = other.m_integer;
+		break;
+	case Type::Object:
+		new (&m_object) std::map<std::string, Value>(other.m_object);
+		break;
+	case Type::Real:
+		m_number = other.m_number;
+		break;
+	case Type::String:
+		new (&m_string) std::string(other.m_string);
+		break;
+	default:
+		break;
+	}
+
+	m_type = other.m_type;
+}
+
+void Value::move(Value &&other)
+{
+	switch (other.m_type) {
+	case Type::Array:
+		new (&m_array) std::deque<Value>(std::move(other.m_array));
+		break;
+	case Type::Boolean:
+		m_boolean = other.m_boolean;
+		break;
+	case Type::Int:
+		m_integer = other.m_integer;
+		break;
+	case Type::Object:
+		new (&m_object) std::map<std::string, Value>(std::move(other.m_object));
+		break;
+	case Type::Real:
+		m_number = other.m_number;
+		break;
+	case Type::String:
+		new (&m_string) std::string(std::move(other.m_string));
+		break;
+	default:
+		break;
+	}
+
+	m_type = other.m_type;
+}
+
+Value::Value(Type type)
+	: m_type{type}
+{
+	switch (m_type) {
+	case Type::Array:
+		new (&m_array) std::deque<Value>();
+		break;
+	case Type::Boolean:
+		m_boolean = false;
+		break;
+	case Type::Int:
+		m_integer = 0;
+		break;
+	case Type::Object:
+		new (&m_object) std::map<std::string, Value>();
+		break;
+	case Type::Real:
+		m_number = 0;
+		break;
+	case Type::String:
+		new (&m_string) std::string();
+		break;
+	default:
+		break;
+	}
+}
+
+Value::~Value()
+{
+	switch (m_type) {
+	case Type::Array:
+		m_array.~deque<Value>();
+		break;
+	case Type::Object:
+		m_object.~map<std::string, Value>();
+		break;
+	case Type::String:
+		m_string.~basic_string();
+		break;
+	default:
+		break;
+	}
+}
+
 bool Value::toBool() const noexcept
 {
 	if (m_type != Type::Boolean) {
@@ -145,32 +245,14 @@
 	return m_string;
 }
 
-Object Value::toObject() const noexcept
+Value::Value(const Buffer &buffer)
 {
-	if (m_type != Type::Object) {
-		return Object{};
-	}
-
-	return Object(*this);
+	*this = convert(json_loads, buffer.text.c_str(), 0);
 }
 
-Array Value::toArray() const noexcept
+Value::Value(const File &file)
 {
-	if (m_type != Type::Array) {
-		return Array{};
-	}
-
-	return Array(*this);
-}
-
-Document::Document(Buffer buffer)
-{
-	m_value = convert(json_loads, buffer.text.c_str(), 0);
-}
-
-Document::Document(File file)
-{
-	m_value = convert(json_load_file, file.path.c_str(), 0);
+	*this = convert(json_load_file, file.path.c_str(), 0);
 }
 
 std::string escape(const std::string &value)
--- a/C++/modules/Json/Json.h	Tue Nov 10 13:32:51 2015 +0100
+++ b/C++/modules/Json/Json.h	Tue Nov 10 14:12:48 2015 +0100
@@ -28,6 +28,7 @@
  * 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>
@@ -146,42 +147,232 @@
 	}
 };
 
-class Array;
-class Object;
+/**
+ * @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 {
-protected:
-	/**
-	 * Type of value.
-	 */
-	Type m_type;
+private:
+	Type m_type{Type::Null};
 
-	/**
-	 * Union of values.
-	 */
 	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_map;
+		std::map<std::string, Value> m_object;
 	};
 
+	void copy(const Value &);
+	void move(Value &&);
+
+	/**
+	 * @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);
+		}
+	};
+
+	/**
+	 * 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>;
+
 public:
 	/**
 	 * Construct a null value.
 	 */
-	inline Value() noexcept
-		: m_type{Type::Null}
+	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
@@ -219,7 +410,7 @@
 	inline Value(const char *value)
 		: m_type{Type::String}
 	{
-		new (&m_string) std::string{value};
+		new (&m_string) std::string{value ? value : ""};
 	}
 
 	/**
@@ -245,39 +436,57 @@
 	}
 
 	/**
+	 * 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)
 	{
-		m_type = other.m_type;
-
-		switch (m_type) {
-		case Type::String:
-			new (&m_string) std::string();
-			m_string = std::move(other.m_string);
-			break;
-		case Type::Real:
-			m_number = other.m_number;
-			break;
-		case Type::Int:
-			m_integer = other.m_integer;
-			break;
-		case Type::Boolean:
-			m_boolean = other.m_boolean;
-			break;
-		case Type::Object:
-			new (&m_map) std::map<std::string, Value>();
-			m_map = std::move(other.m_map);
-			break;
-		case Type::Array:
-			new (&m_array) std::deque<Value>();
-			m_array = std::move(other.m_array);
-			break;
-		default:
-			break;
-		}
+		move(std::move(other));
 	}
 
 	/**
@@ -287,33 +496,7 @@
 	 */
 	inline Value(const Value &other)
 	{
-		m_type = other.m_type;
-
-		switch (m_type) {
-		case Type::String:
-			new (&m_string) std::string();
-			m_string = other.m_string;
-			break;
-		case Type::Real:
-			m_number = other.m_number;
-			break;
-		case Type::Int:
-			m_integer = other.m_integer;
-			break;
-		case Type::Boolean:
-			m_boolean = other.m_boolean;
-			break;
-		case Type::Object:
-			new (&m_map) std::map<std::string, Value>();
-			m_map = other.m_map;
-			break;
-		case Type::Array:
-			new (&m_array) std::deque<Value>();
-			m_array = other.m_array;
-			break;
-		default:
-			break;
-		}
+		copy(other);
 	}
 
 	/**
@@ -324,33 +507,7 @@
 	 */
 	inline Value &operator=(const Value &other)
 	{
-		m_type = other.m_type;
-
-		switch (m_type) {
-		case Type::String:
-			new (&m_string) std::string();
-			m_string = other.m_string;
-			break;
-		case Type::Real:
-			m_number = other.m_number;
-			break;
-		case Type::Int:
-			m_integer = other.m_integer;
-			break;
-		case Type::Boolean:
-			m_boolean = other.m_boolean;
-			break;
-		case Type::Object:
-			new (&m_map) std::map<std::string, Value>();
-			m_map = other.m_map;
-			break;
-		case Type::Array:
-			new (&m_array) std::deque<Value>();
-			m_array = other.m_array;
-			break;
-		default:
-			break;
-		}
+		copy(other);
 
 		return *this;
 	}
@@ -362,33 +519,7 @@
 	 */
 	inline Value &operator=(Value &&other)
 	{
-		m_type = other.m_type;
-
-		switch (m_type) {
-		case Type::String:
-			new (&m_string) std::string();
-			m_string = std::move(other.m_string);
-			break;
-		case Type::Real:
-			m_number = other.m_number;
-			break;
-		case Type::Int:
-			m_integer = other.m_integer;
-			break;
-		case Type::Boolean:
-			m_boolean = other.m_boolean;
-			break;
-		case Type::Object:
-			new (&m_map) std::map<std::string, Value>();
-			m_map = std::move(other.m_map);
-			break;
-		case Type::Array:
-			new (&m_array) std::deque<Value>();
-			m_array = std::move(other.m_array);
-			break;
-		default:
-			break;
-		}
+		move(std::move(other));
 
 		return *this;
 	}
@@ -396,21 +527,84 @@
 	/**
 	 * Destructor.
 	 */
-	inline ~Value()
+	~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
 	{
-		switch (m_type) {
-		case Type::String:
-			m_string.~basic_string();
-			break;
-		case Type::Object:
-			m_map.~map<std::string, Value>();
-			break;
-		case Type::Array:
-			m_array.~deque<Value>();
-			break;
-		default:
-			break;
-		}
+		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());
 	}
 
 	/**
@@ -452,22 +646,6 @@
 	std::string toString() const noexcept;
 
 	/**
-	 * Convert the value to object.
-	 *
-	 * @return an object or empty if not an object
-	 * @note the returned object is a copy, modifying it won't modify this value
-	 */
-	Object toObject() const noexcept;
-
-	/**
-	 * Convert the value to array.
-	 *
-	 * @return an array or empty if not an array
-	 * @note the returned array is a copy, modifying it won't modify this value
-	 */
-	Array toArray() const noexcept;
-
-	/**
 	 * Check if the value is boolean type.
 	 *
 	 * @return true if boolean
@@ -548,113 +726,44 @@
 	{
 		return m_type == Type::String;
 	}
-};
-
-/**
- * @class Array
- * @brief Array definition.
- */
-class Array : public Value {
-public:
-	/**
-	 * Construct an empty array.
-	 */
-	inline Array()
-	{
-		m_type = Type::Array;
-		new (&m_array) std::deque<Value>();
-	}
 
 	/**
-	 * Copy constructor from value for safe casts.
+	 * Get the array or object size.
 	 *
-	 * @param v the value to copy from
-	 */
-	inline Array(const Value &v)
-		: Value{v}
-	{
-	}
-
-	/**
-	 * Move constructor from value for safe casts.
-	 *
-	 * @param v the value to move from
+	 * @pre must be an array or object
+	 * @return the size
 	 */
-	inline Array(Value &&v)
-		: Value{std::move(v)}
+	inline unsigned size() const noexcept
 	{
-	}
+		assert(isArray() || isObject());
 
-	/**
-	 * Construct an array from a std::initializer_list.
-	 *
-	 * @param values the list of values
-	 */
-	inline Array(std::initializer_list<Value> values)
-	{
-		m_type = Type::Array;
-		new (&m_array) std::deque<Value>(values.begin(), values.end());
+		if (m_type == Type::Object) {
+			return m_object.size();
+		}
+
+		return m_array.size();
 	}
 
 	/**
-	 * Get non-const iterator to the beginning.
+	 * Remove all the values.
 	 *
-	 * @return the iterator
-	 */
-	inline auto begin() noexcept
-	{
-		return m_array.begin();
-	}
-
-	/**
-	 * Get a const iterator to the beginning.
-	 *
-	 * @return the iterator
+	 * @pre must be an array or an object
 	 */
-	inline auto begin() const noexcept
+	inline void clear() noexcept
 	{
-		return m_array.begin();
-	}
+		assert(isArray() || isObject());
 
-	/**
-	 * Get a const iterator to the beginning.
-	 *
-	 * @return the iterator
-	 */
-	inline auto cbegin() const noexcept
-	{
-		return m_array.cbegin();
+		if (m_type == Type::Array) {
+			m_array.clear();
+		} else {
+			m_object.clear();
+		}
 	}
 
-	/**
-	 * Get a non-const iterator to the end.
-	 *
-	 * @return the iterator
-	 */
-	inline auto end() noexcept
-	{
-		return m_array.end();
-	}
-
-	/**
-	 * Get a const iterator to the end.
-	 *
-	 * @return the iterator
+	/*
+	 * Array functions
+	 * ----------------------------------------------------------
 	 */
-	inline auto end() const noexcept
-	{
-		return m_array.end();
-	}
-
-	/**
-	 * Get a const iterator to the end.
-	 *
-	 * @return the iterator
-	 */
-	inline auto cend() const noexcept
-	{
-		return m_array.cend();
-	}
 
 	/**
 	 * Get the value at the specified position or the defaultValue if position is out of bounds.
@@ -663,10 +772,10 @@
 	 * @param defaultValue the value replacement
 	 * @return the value or defaultValue
 	 */
-	template <typename V>
-	inline Value valueOr(unsigned position, V &&defaultValue) const
+	template <typename DefaultValue>
+	inline Value valueOr(unsigned position, DefaultValue &&defaultValue) const
 	{
-		if (position >= m_array.size()) {
+		if (m_type != Type::Array || position >= m_array.size()) {
 			return defaultValue;
 		}
 
@@ -676,217 +785,168 @@
 	/**
 	 * 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);
 	}
 
 	/**
-	 * Get a value at the specified index.
+	 * 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
 	 */
-	template <typename T>
-	inline void push(T &&value)
+	inline void push(const Value &value)
 	{
-		m_array.push_front(std::forward<T>(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
 	 */
-	template <typename T>
-	inline void insert(unsigned position, T &&value)
+	inline void insert(unsigned position, const Value &value)
 	{
-		m_array.insert(m_array.begin() + position, std::forward<T>(value));
+		assert(isArray());
+		assert(position <= m_array.size());
+
+		m_array.insert(m_array.begin() + position, value);
 	}
 
 	/**
-	 * Add a new value.
+	 * Overloaded function.
 	 *
-	 * @param value the value to append
+	 * @pre must be an array
+	 * @pre position must be valid
+	 * @param position the position
+	 * @param value the value to push
 	 */
-	template <typename T>
-	inline void append(T &&value)
+	inline void insert(unsigned position, Value &&value)
 	{
-		m_array.push_back(std::forward<T>(value));
+		assert(isArray());
+		assert(position <= m_array.size());
+
+		m_array.insert(m_array.begin() + position, std::move(value));
 	}
 
 	/**
-	 * Get the array size.
+	 * Add a new value to the end.
 	 *
-	 * @return the size
+	 * @pre must be an array
+	 * @param value the value to append
 	 */
-	inline unsigned size() const noexcept
+	inline void append(const Value &value)
 	{
-		return m_array.size();
+		assert(isArray());
+
+		m_array.push_back(value);
 	}
 
 	/**
-	 * Remove all the values.
+	 * Overloaded function.
+	 *
+	 * @pre must be an array
+	 * @param value the value to append
 	 */
-	inline void clear()
+	inline void append(Value &&value)
 	{
-		m_array.clear();
+		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)
 	{
-		m_array.erase(m_array.begin() + position);
-	}
-};
-
-/**
- * @class Object
- * @brief Object definition.
- */
-class Object : public Value {
-public:
-	/**
-	 * Construct an empty object.
-	 */
-	Object()
-	{
-		m_type = Type::Object;
-		new (&m_map) std::map<std::string, Value>();
-	}
+		assert(isArray());
+		assert(position < m_array.size());
 
-	/**
-	 * Copy constructor from value for safe casts.
-	 *
-	 * @param v the value to copy from
-	 */
-	Object(const Value &v)
-		: Value{v}
-	{
-	}
-
-	/**
-	 * Move constructor from value for safe casts.
-	 *
-	 * @param v the value to move from
-	 */
-	Object(Value &&v)
-		: Value{std::move(v)}
-	{
-	}
-
-	/**
-	 * Create an object from the initializer_list of key-value pairs.
-	 *
-	 * @param values the values
-	 */
-	Object(std::initializer_list<std::pair<std::string, Value>> values)
-	{
-		m_type = Type::Object;
-		new (&m_map) std::map<std::string, Value>(values.begin(), values.end());
+		m_array.erase(m_array.begin() + position);
 	}
 
-	/**
-	 * Get non-const iterator to the beginning.
-	 *
-	 * @return the iterator
-	 */
-	inline auto begin() noexcept
-	{
-		return m_map.begin();
-	}
-
-	/**
-	 * Get a const iterator to the beginning.
-	 *
-	 * @return the iterator
-	 */
-	inline auto begin() const noexcept
-	{
-		return m_map.begin();
-	}
-
-	/**
-	 * Get a const iterator to the beginning.
-	 *
-	 * @return the iterator
+	/*
+	 * Object functions
+	 * ----------------------------------------------------------
 	 */
-	inline auto cbegin() const noexcept
-	{
-		return m_map.cbegin();
-	}
-
-	/**
-	 * Get a non-const iterator to the end.
-	 *
-	 * @return the iterator
-	 */
-	inline auto end() noexcept
-	{
-		return m_map.end();
-	}
-
-	/**
-	 * Get a const iterator to the end.
-	 *
-	 * @return the iterator
-	 */
-	inline auto end() const noexcept
-	{
-		return m_map.end();
-	}
-
-	/**
-	 * Get a const iterator to the end.
-	 *
-	 * @return the iterator
-	 */
-	inline auto cend() const noexcept
-	{
-		return m_map.cend();
-	}
 
 	/**
 	 * Get the value at the specified key or the defaultValue if key is absent.
@@ -895,12 +955,16 @@
 	 * @param defaultValue the value replacement
 	 * @return the value or defaultValue
 	 */
-	template <typename V>
-	inline Value valueOr(const std::string &name, V &&defaultValue) const
+	template <typename DefaultValue>
+	Value valueOr(const std::string &name, DefaultValue &&defaultValue) const
 	{
-		auto it = m_map.find(name);
+		if (m_type != Type::Object) {
+			return defaultValue;
+		}
 
-		if (it == m_map.end()) {
+		auto it = m_object.find(name);
+
+		if (it == m_object.end()) {
 			return defaultValue;
 		}
 
@@ -910,180 +974,142 @@
 	/**
 	 * 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
 	{
-		return m_map.at(name);
+		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)
 	{
-		return m_map.at(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 Value &operator[](const std::string &name)
+	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)
 	{
-		return m_map.at(name);
+		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, Value value)
+	inline void insert(std::string name, const Value &value)
 	{
-		m_map.insert({std::move(name), std::move(value)});
+		assert(isObject());
+
+		m_object.insert({std::move(name), value});
 	}
 
 	/**
-	 * Remove all the values from the object.
+	 * Overloaded function.
+	 *
+	 * @pre must be an object
+	 * @param name the key
+	 * @param value the value
 	 */
-	inline void clear()
+	inline void insert(std::string name, Value &&value)
 	{
-		m_map.clear();
-	}
+		assert(isObject());
 
-	/**
-	 * Get the number of entries in the object.
-	 *
-	 * @return the size
-	 */
-	inline unsigned size() const noexcept
-	{
-		return m_map.size();
+		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
 	{
-		return m_map.find(key) != m_map.end();
+		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)
 	{
-		m_map.erase(key);
-	}
-};
-
-/**
- * @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 Document
- * @brief Construct a JSON document from a source
- * @see Buffer
- * @see File
- */
-class Document {
-private:
-	Value m_value;
-
-public:
-	/**
-	 * Construct a document from a buffer.
-	 *
-	 * @param buffer the text
-	 * @throw Error on errors
-	 */
-	Document(Buffer buffer);
+		assert(isObject());
 
-	/**
-	 * Construct a document from a file.
-	 *
-	 * @param file the file
-	 * @throw Error on errors
-	 */
-	Document(File file);
-
-	/**
-	 * Check if the opened document is an object.
-	 *
-	 * @return true if object
-	 */
-	inline bool isObject() const noexcept
-	{
-		return m_value.typeOf() == Type::Object;
-	}
-
-	/**
-	 * Check if the opened document is an array.
-	 *
-	 * @return true if array
-	 */
-	inline bool isArray() const noexcept
-	{
-		return m_value.typeOf() == Type::Array;
-	}
-
-	/**
-	 * Get the object.
-	 *
-	 * @return the object or empty object if not an object
-	 */
-	inline Object toObject() const noexcept
-	{
-		if (m_value.typeOf() != Type::Object) {
-			return Object{};
-		}
-
-		return Object(m_value);
-	}
-
-	/**
-	 * Get the array.
-	 *
-	 * @return the array or empty object if not an array
-	 */
-	inline Array toArray() const noexcept
-	{
-		if (m_value.typeOf() != Type::Array) {
-			return Array{};
-		}
-
-		return Array(m_value);
+		m_object.erase(key);
 	}
 };
 
@@ -1095,6 +1121,28 @@
  */
 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_
--- a/C++/tests/Json/main.cpp	Tue Nov 10 13:32:51 2015 +0100
+++ b/C++/tests/Json/main.cpp	Tue Nov 10 14:12:48 2015 +0100
@@ -23,18 +23,19 @@
 
 #include "Json.h"
 
-/* --------------------------------------------------------
+/*
  * Miscellaneous
- * -------------------------------------------------------- */
+ * ------------------------------------------------------------------
+ */
 
 TEST(Misc, copy)
 {
-	json::Object object;
+	json::Value object{json::Type::Object};
 
 	object.insert("integer", 123);
 	object.insert("true", true);
 
-	json::Object object2{object};
+	json::Value object2{object};
 
 	ASSERT_TRUE(object2.isObject());
 	ASSERT_EQ(123, object2["integer"].toInt());
@@ -43,10 +44,10 @@
 
 TEST(Misc, copyAssign)
 {
-	json::Object object;
+	json::Value object{json::Type::Object};
 
 	{
-		json::Object tmp;
+		json::Value tmp{json::Type::Object};
 
 		tmp.insert("integer", 123);
 		tmp.insert("true", true);
@@ -61,8 +62,8 @@
 
 TEST(Misc, move)
 {
-	json::Object object(123);
-	json::Object object2(std::move(object));
+	json::Value object(123);
+	json::Value object2(std::move(object));
 
 	ASSERT_TRUE(object2.isInt());
 	ASSERT_EQ(123, object2.toInt());
@@ -70,8 +71,8 @@
 
 TEST(Misc, moveAssign)
 {
-	json::Object object(123);
-	json::Object object2;
+	json::Value object(123);
+	json::Value object2;
 
 	object2 = std::move(object);
 
@@ -87,9 +88,10 @@
 	ASSERT_EQ(expected, json::escape(input));
 }
 
-/* --------------------------------------------------------
+/*
  * json::Value constructors
- * -------------------------------------------------------- */
+ * ------------------------------------------------------------------
+ */
 
 TEST(Constructors, null)
 {
@@ -154,14 +156,15 @@
 	}
 }
 
-/* --------------------------------------------------------
+/*
  * Object
- * -------------------------------------------------------- */
+ * ------------------------------------------------------------------
+ */
 
 TEST(Object, set)
 {
 	try {
-		json::Object object;
+		json::Value object{json::Type::Object};
 
 		object.insert("integer", 123);
 		object.insert("string", "hello");
@@ -178,7 +181,7 @@
 TEST(Object, clear)
 {
 	try {
-		json::Object object;
+		json::Value object{json::Type::Object};
 
 		object.insert("integer", 123);
 		object.insert("string", "hello");
@@ -198,7 +201,7 @@
 TEST(Object, erase)
 {
 	try {
-		json::Object object;
+		json::Value object{json::Type::Object};
 
 		object.insert("integer", 123);
 		object.insert("string", "hello");
@@ -218,10 +221,10 @@
 TEST(Object, valueOr)
 {
 	try {
-		json::Object object{
+		json::Value object = json::object({
 			{ "x", 10 },
 			{ "y", 20 }
-		};
+		});
 
 		ASSERT_EQ(10, object.valueOr("x", -9999).toInt());
 		ASSERT_EQ(20, object.valueOr("y", -9999).toInt());
@@ -234,10 +237,10 @@
 TEST(ObjectInitializer, simple)
 {
 	try {
-		json::Object object{
+		json::Value object = json::object({
 			{ "username", "jean"	},
 			{ "age", 99		}
-		};
+		});
 
 		ASSERT_EQ(2, static_cast<int>(object.size()));
 		ASSERT_EQ("jean", object["username"].toString());
@@ -250,15 +253,15 @@
 TEST(ObjectInitializer, deep)
 {
 	try {
-		json::Object object{
+		json::Value object = json::object({
 			{ "username", "jean"		},
 			{ "age", 99			},
-			{ "network", json::Object{
+			{ "network", json::object({
 					{ "port", 9999 		},
 					{ "host", "localhost"	}
-				}
+				})
 			}
-		};
+		});
 
 		// First
 		ASSERT_EQ(3, static_cast<int>(object.size()));
@@ -266,7 +269,7 @@
 		ASSERT_EQ(99, object["age"].toInt());
 
 		// Second
-		json::Object network = object["network"].toObject();
+		const json::Value &network = object["network"];
 		ASSERT_TRUE(network.isObject());
 		ASSERT_EQ(2, static_cast<int>(network.size()));
 		ASSERT_EQ(9999, network["port"].toInt());
@@ -276,14 +279,15 @@
 	}
 }
 
-/* --------------------------------------------------------
+/*
  * Array
- * -------------------------------------------------------- */
+ * ------------------------------------------------------------------
+ */
 
 TEST(Array, push)
 {
 	try {
-		json::Array array;
+		json::Value array{json::Type::Array};
 
 		ASSERT_TRUE(array.isArray());
 
@@ -303,7 +307,7 @@
 TEST(Array, append)
 {
 	try {
-		json::Array array;
+		json::Value array{json::Type::Array};
 
 		ASSERT_TRUE(array.isArray());
 
@@ -323,7 +327,7 @@
 TEST(Array, insert)
 {
 	try {
-		json::Array array;
+		json::Value array{json::Type::Array};
 
 		ASSERT_TRUE(array.isArray());
 
@@ -343,7 +347,7 @@
 TEST(Array, clear)
 {
 	try {
-		json::Array array;
+		json::Value array{json::Type::Array};
 
 		array.append(1);
 		array.append("hello");
@@ -360,7 +364,7 @@
 TEST(Array, erase)
 {
 	try {
-		json::Array array;
+		json::Value array{json::Type::Array};
 
 		array.append(1);
 		array.append("hello");
@@ -379,7 +383,7 @@
 TEST(Array, valueOr)
 {
 	try {
-		json::Array array{-10, -20};
+		json::Value array = json::array({-10, -20});
 
 		ASSERT_EQ(-10, array.valueOr(0, -9999).toInt());
 		ASSERT_EQ(-20, array.valueOr(1, -9999).toInt());
@@ -392,7 +396,7 @@
 TEST(ArrayInitializer, simple)
 {
 	try {
-		json::Array array{123, true, "hello"};
+		json::Value array = json::array({123, true, "hello"});
 
 		ASSERT_EQ(3, static_cast<int>(array.size()));
 		ASSERT_EQ(123, array[0].toInt());
@@ -406,16 +410,16 @@
 TEST(ArrayInitializer, deep)
 {
 	try {
-		json::Array array{
+		json::Value array = json::array({
 			123,
 			true,
 			"hello",
-			json::Array{
+			json::array({
 				321,
 				false,
 				"olleh"
-			}
-		};
+			})
+		});
 
 		// First
 		ASSERT_EQ(4, static_cast<int>(array.size()));
@@ -424,7 +428,7 @@
 		ASSERT_EQ("hello", array[2].toString());
 
 		// Second
-		json::Array array2 = array[3].toArray();
+		const json::Value &array2 = array[3];
 		ASSERT_TRUE(array.isArray());
 		ASSERT_EQ(3, static_cast<int>(array2.size()));
 		ASSERT_EQ(321, array2[0].toInt());
@@ -435,14 +439,15 @@
 	}
 }
 
-/* --------------------------------------------------------
+/*
  * I/O
- * -------------------------------------------------------- */
+ * ------------------------------------------------------------------
+ */
 
 TEST(FileRead, simple)
 {
 	try {
-		json::Document doc(json::File{"Json/simple.json"});
+		json::Value doc(json::File{"Json/simple.json"});
 
 		ASSERT_TRUE(doc.isObject());
 		ASSERT_FALSE(doc.isArray());
@@ -454,7 +459,7 @@
 TEST(FileRead, fail)
 {
 	try {
-		json::Document(json::File{"Json/notexist.json"});
+		json::Value(json::File{"Json/notexist.json"});
 
 		FAIL() << "Exception expected";
 	} catch (const json::Error &) {
@@ -464,7 +469,7 @@
 TEST(StringRead, simple)
 {
 	try {
-		json::Document doc(json::Buffer{"{ \"license\": \"ISC\" }"});
+		json::Value doc(json::Buffer{"{ \"license\": \"ISC\" }"});
 
 		ASSERT_TRUE(doc.isObject());
 		ASSERT_FALSE(doc.isArray());
@@ -476,27 +481,28 @@
 TEST(StringRead, fail)
 {
 	try {
-		json::Document(json::Buffer{"{ \"license\": ISC }"});
+		json::Value(json::Buffer{"{ \"license\": ISC }"});
 
 		FAIL() << "Exception expected";
 	} catch (const json::Error &ex) {
 	}
 }
 
-/* --------------------------------------------------------
+/*
  * Object read
- * -------------------------------------------------------- */
+ * ------------------------------------------------------------------
+ */
 
 class ObjectRead : public testing::Test {
 protected:
-	json::Object m_object;
-	json::Object m_objectAll;
+	json::Value m_object;
+	json::Value m_objectAll;
 
 public:
 	ObjectRead()
+		: m_object(json::File{"Json/object.json"})
+		, m_objectAll(json::File{"Json/object-all.json"})
 	{
-		m_object = json::Document(json::File{"Json/object.json"}).toObject();
-		m_objectAll = json::Document(json::File{"Json/object-all.json"}).toObject();
 	}
 };
 
@@ -546,20 +552,21 @@
 	}
 }
 
-/* --------------------------------------------------------
+/*
  * Array read
- * -------------------------------------------------------- */
+ * ------------------------------------------------------------------
+ */
 
 class ArrayRead : public testing::Test {
 protected:
-	json::Array m_array;
-	json::Array m_arrayAll;
+	json::Value m_array;
+	json::Value m_arrayAll;
 
 public:
 	ArrayRead()
+		: m_array(json::File{"Json/array.json"})
+		, m_arrayAll(json::File{"Json/array-all.json"})
 	{
-		m_array = json::Document(json::File{"Json/array.json"}).toArray();
-		m_arrayAll = json::Document(json::File{"Json/array-all.json"}).toArray();
 	}
 };
 
@@ -603,13 +610,14 @@
 	}
 }
 
-/* --------------------------------------------------------
+/*
  * Object iterators
- * -------------------------------------------------------- */
+ * ------------------------------------------------------------------
+ */
 
 class ObjectIteratorsTest : public testing::Test {
 protected:
-	json::Object m_object;
+	json::Value m_object{json::Type::Object};
 
 public:
 	ObjectIteratorsTest()
@@ -631,8 +639,9 @@
 		auto end = m_object.end();
 
 		while (it != end) {
-			values.insert({it->first, it->second});
-			result.insert((*it++).first);
+			values.insert({it.key(), *it});
+			result.insert(it.key());
+			it++;
 		}
 
 		ASSERT_EQ(expected, result);
@@ -650,8 +659,9 @@
 		auto end = m_object.cend();
 
 		while (it != end) {
-			values.insert({it->first, it->second});
-			result.insert((*it++).first);
+			values.insert({it.key(), *it});
+			result.insert(it.key());
+			it++;
 		}
 
 		ASSERT_EQ(expected, result);
@@ -666,23 +676,39 @@
 	// Assign (non const)
 	{
 		auto it = m_object.begin();
-		auto key = it->first;
+		auto key = it.key();
 
-		it->second = json::Value("CHANGED");
+		*it = json::Value("CHANGED");
 
 		ASSERT_EQ("CHANGED", m_object[key].toString());
-		ASSERT_EQ("CHANGED", it->second.toString());
+		ASSERT_EQ("CHANGED", it->toString());
 		ASSERT_EQ(3, static_cast<int>(m_object.size()));
 	}
 }
 
-/* --------------------------------------------------------
+TEST_F(ObjectIteratorsTest, find)
+{
+	auto it = m_object.find("integer");
+
+	ASSERT_TRUE(it != m_object.end());
+	ASSERT_EQ(1, it->toInt());
+}
+
+TEST_F(ObjectIteratorsTest, find2)
+{
+	auto it = m_object.find("not exists");
+
+	ASSERT_TRUE(it == m_object.end());
+}
+
+/*
  * Array iterators
- * -------------------------------------------------------- */
+ * ------------------------------------------------------------------
+ */
 
 class ArrayIteratorsTest : public testing::Test {
 protected:
-	json::Array m_array;
+	json::Value m_array{json::Type::Array};
 
 public:
 	ArrayIteratorsTest()
@@ -699,68 +725,34 @@
 	{
 		auto it = m_array.begin();
 
+		// 1
 		ASSERT_EQ(1, (*it).toInt());
 		ASSERT_EQ(1, it->toInt());
-		ASSERT_EQ("hello", it[1].toString());
-		ASSERT_TRUE(it[2].toBool());
-
-		auto it2 = it + 1;
-		ASSERT_EQ(1, it2[-1].toInt());
-		ASSERT_EQ("hello", it2->toString());
-		ASSERT_TRUE(it2[1].toBool());
-
-		auto it3 = it;
-		ASSERT_TRUE(it2 != it);
-		ASSERT_FALSE(it3 != it);
 
-		ASSERT_FALSE(it2 == it);
-		ASSERT_TRUE(it3 == it);
-
-		ASSERT_TRUE(it3 >= it);
-		ASSERT_TRUE(it2 >= it);
+		// "hello"
+		it++;
+		ASSERT_EQ("hello", it->toString());
 
-		ASSERT_TRUE(it2 > it);
-		ASSERT_FALSE(it3 > it);
-
-		ASSERT_FALSE(it2 <= it);
-		ASSERT_TRUE(it3 <= it);
-
-		ASSERT_FALSE(it2 < it);
-		ASSERT_FALSE(it3 < it);
+		// true
+		it++;
+		ASSERT_TRUE(it->toBool());
 	}
 
 	// Read only (const)
 	{
 		auto it = m_array.cbegin();
 
+		// 1
 		ASSERT_EQ(1, (*it).toInt());
 		ASSERT_EQ(1, it->toInt());
-		ASSERT_EQ("hello", it[1].toString());
-		ASSERT_TRUE(it[2].toBool());
-
-		auto it2 = it + 1;
-		ASSERT_EQ(1, it2[-1].toInt());
-		ASSERT_EQ("hello", it2->toString());
-		ASSERT_TRUE(it2[1].toBool());
-
-		auto it3 = it;
-		ASSERT_TRUE(it2 != it);
-		ASSERT_FALSE(it3 != it);
 
-		ASSERT_FALSE(it2 == it);
-		ASSERT_TRUE(it3 == it);
-
-		ASSERT_TRUE(it3 >= it);
-		ASSERT_TRUE(it2 >= it);
+		// "hello"
+		it++;
+		ASSERT_EQ("hello", it->toString());
 
-		ASSERT_TRUE(it2 > it);
-		ASSERT_FALSE(it3 > it);
-
-		ASSERT_FALSE(it2 <= it);
-		ASSERT_TRUE(it3 <= it);
-
-		ASSERT_FALSE(it2 < it);
-		ASSERT_FALSE(it3 < it);
+		// true
+		it++;
+		ASSERT_TRUE(it->toBool());
 	}
 }
 
@@ -780,7 +772,7 @@
 
 TEST_F(ArrayIteratorsTest, castToRef)
 {
-	json::Array array{1, 2, 3};
+	json::Value array = json::array({1, 2, 3});
 	int i = 1;
 
 	for (const json::Value &v : array) {