changeset 244:777bc3cb665a

Add Json, a jansson wrapper
author David Demelier <markand@malikania.fr>
date Sat, 13 Sep 2014 19:42:15 +0200
parents 73e5381d7baf
children 3c12f0e8bbb9
files C++/Json.cpp C++/Json.h
diffstat 2 files changed, 701 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/Json.cpp	Sat Sep 13 19:42:15 2014 +0200
@@ -0,0 +1,275 @@
+/*
+ * Json.cpp -- jansson C++11 wrapper
+ *
+ * Copyright (c) 2013, 2014 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.
+ */
+
+#include "Json.h"
+
+Json Json::fromString(const std::string &data, int flags)
+{
+	return from(json_loads, data.c_str(), flags);
+}
+
+Json Json::fromFile(const std::string &path, int flags)
+{
+	return from(json_load_file, path.c_str(), flags);
+}
+
+Json::Json()
+	: m_handle(json_object(), json_decref)
+{
+}
+
+Json::Json(bool value)
+	: m_handle(json_boolean(value), json_decref)
+{
+}
+
+Json::Json(int value)
+	: m_handle(json_integer(value), json_decref)
+{
+}
+
+Json::Json(double value)
+	: m_handle(json_real(value), json_decref)
+{
+}
+
+Json::Json(const std::string &value)
+	: m_handle(json_string(value.c_str()), json_decref)
+{
+}
+
+Json::Json(const Json &json)
+	: m_handle(json_deep_copy(json.m_handle.get()), json_decref)
+	, m_list(json.m_list)
+	, m_map(json.m_map)
+{
+}
+
+Json::Json(Json &&value)
+	: m_handle(value.m_handle.release(), json_decref)
+	, m_list(std::move(value.m_list))
+	, m_map(std::move(value.m_map))
+{
+}
+
+Json::Json(std::initializer_list<Json> list)
+	: m_handle(json_array(), json_decref)
+{
+	m_list.reserve(list.size());
+
+	for (const auto &v : list) {
+		m_list.push_back(v);
+		json_array_append(m_handle.get(), m_list.back().m_handle.get());
+	}
+}
+
+Json &Json::operator=(const Json &json)
+{
+	m_handle = Handle(json.m_handle.get(), json_decref);
+	m_list = json.m_list;
+	m_map = json.m_map;
+
+	return *this;
+}
+
+Json &Json::operator=(Json &&value)
+{
+	m_handle = Handle(value.m_handle.release(), json_decref);
+	m_list = std::move(value.m_list);
+	m_map = std::move(value.m_map);
+
+	return *this;
+}
+
+int Json::typeOf() const
+{
+	return json_typeof(m_handle.get());
+}
+
+bool Json::isObject() const
+{
+	return json_is_object(m_handle.get()) != 0;
+}
+
+bool Json::isArray() const
+{
+	return json_is_array(m_handle.get()) != 0;
+}
+
+bool Json::isString() const
+{
+	return json_is_string(m_handle.get()) != 0;
+}
+
+bool Json::isReal() const
+{
+	return json_is_real(m_handle.get()) != 0;
+}
+
+bool Json::isTrue() const
+{
+	return json_is_true(m_handle.get()) != 0;
+}
+
+bool Json::isFalse() const
+{
+	return json_is_true(m_handle.get()) != 0;
+}
+
+bool Json::isNull() const
+{
+	return json_is_null(m_handle.get()) != 0;
+}
+
+bool Json::isNumber() const
+{
+	return json_is_number(m_handle.get()) != 0;
+}
+
+bool Json::isInteger() const
+{
+	return json_is_integer(m_handle.get()) != 0;
+}
+
+bool Json::isBoolean() const
+{
+	return json_is_boolean(m_handle.get()) != 0;
+}
+
+unsigned Json::size() const noexcept
+{
+	return m_list.size();
+}
+
+void Json::append(const Json &value)
+{
+	m_list.push_back(value);
+	json_array_append(m_handle.get(), m_list.back().m_handle.get());
+}
+
+void Json::append(Json &&value)
+{
+	m_list.push_back(std::move(value));
+	json_array_append(m_handle.get(), m_list.back().m_handle.get());
+}
+
+void Json::insert(const Json &value, int index)
+{
+	m_list.insert(m_list.begin() + index, value);
+	json_array_insert(m_handle.get(), index, m_list[index].m_handle.get());
+}
+
+void Json::insert(Json &&value, int index)
+{
+	m_list.insert(m_list.begin() + index, std::move(value));
+	json_array_insert(m_handle.get(), index, m_list[index].m_handle.get());
+}
+
+void Json::set(const Json &value, const std::string &name)
+{
+	m_map[name] = value;
+	json_object_set(m_handle.get(), name.c_str(), m_map[name].m_handle.get());
+}
+
+void Json::set(Json &&value, const std::string &name)
+{
+	m_map[name] = std::move(value);
+	json_object_set(m_handle.get(), name.c_str(), m_map[name].m_handle.get());
+}
+
+std::string Json::toString() const
+{
+	auto value = json_string_value(m_handle.get());
+
+	return (value == nullptr) ? "" : value;
+}
+
+int Json::toInteger() const noexcept
+{
+	return json_integer_value(m_handle.get());
+}
+
+double Json::toReal() const noexcept
+{
+	return json_real_value(m_handle.get());
+}
+
+std::string Json::dump(int flags)
+{
+	auto v = json_dumps(m_handle.get(), flags);
+
+	if (v == nullptr)
+		throw std::runtime_error("failed to dump");
+
+	return std::string(v);
+}
+
+void Json::dump(const std::string &path, int flags)
+{
+	if (json_dump_file(m_handle.get(), path.c_str(), flags) < 0)
+		throw std::runtime_error("failed to dump");
+}
+
+Json &Json::operator[](int index)
+{
+	if (!isArray())
+		throw std::invalid_argument("not an array");
+
+	if (index >= m_list.size())
+		throw std::out_of_range("invalid index");
+
+	return m_list[index];
+}
+
+const Json &Json::operator[](int index) const
+{
+	if (!isArray())
+		throw std::invalid_argument("not an array");
+
+	if (index >= m_list.size())
+		throw std::out_of_range("invalid index");
+
+	return m_list[index];
+}
+
+Json &Json::operator[](const std::string &name)
+{
+	if (!isObject())
+		throw std::invalid_argument("not an object");
+
+	if (m_map.count(name) == 0)
+		throw std::out_of_range("invalid key");
+
+	return m_map[name];
+}
+
+const Json &Json::operator[](const std::string &name) const
+{
+	if (!isObject())
+		throw std::invalid_argument("not an object");
+
+	if (m_map.count(name) == 0)
+		throw std::out_of_range("invalid key");
+
+	return m_map.at(name);
+}
+
+bool operator==(const Json &j1, const Json &j2)
+{
+	return json_equal(j1.m_handle.get(), j2.m_handle.get()) != 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/Json.h	Sat Sep 13 19:42:15 2014 +0200
@@ -0,0 +1,426 @@
+/*
+ * Json.h -- jansson C++11 wrapper
+ *
+ * Copyright (c) 2013, 2014 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_
+
+#include <initializer_list>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+#include <vector>
+#include <unordered_map>
+
+#include <jansson.h>
+
+/**
+ * @file Json.h
+ * @brief A jansson C++ modern wrapper
+ */
+
+/**
+ * @class Json
+ * @brief Json value
+ *
+ * This class contains one or more json values.
+ */
+class Json final {
+public:
+	using Handle	= std::unique_ptr<json_t, void (*)(json_t *)>;
+	using Array	= std::vector<Json>;
+	using Map	= std::unordered_map<std::string, Json>;
+
+	/**
+	 * @class Error
+	 * @brief Json error
+	 */
+	class Error : public std::exception {
+	private:
+		friend class Json;
+
+		std::string	m_text;
+		std::string	m_source;
+		int		m_line;
+		int		m_column;
+		unsigned	m_position;
+
+		Error(const json_error_t error)
+			: m_text(error.text)
+			, m_source(error.source)
+			, m_line(error.line)
+			, m_column(error.column)
+			, m_position(error.position)
+		{
+		}
+
+	public:
+		const char *what() const noexcept override
+		{
+			return m_text.c_str();
+		}
+	};
+
+private:
+	Handle		m_handle;
+	Array		m_list;
+	Map		m_map;
+
+	Json(Handle &&handle)
+		: m_handle(std::move(handle))
+	{
+	}
+
+	template <typename Func, typename... Args>
+	static Json from(Func func, Args&&... args)
+	{
+		json_error_t error;
+		json_t *value = func(std::forward<Args>(args)..., &error);
+
+		if (!value)
+			throw Error(error);
+
+		return Json(Handle(value, json_decref));
+	}
+
+public:
+	/**
+	 * Load data from a string.
+	 *
+	 * @param data the data
+	 * @param flags the optional flags
+	 * @return the json value
+	 * @throw Error on failures
+	 */
+	static Json fromString(const std::string &data, int flags = 0);
+
+	/**
+	 * Load data from a file.
+	 *
+	 * @param path the path
+	 * @param flags the optional flags
+	 * @return the json value
+	 * @throw Error on failures
+	 */
+	static Json fromFile(const std::string &path, int flags = 0);
+
+	/**
+	 * Create a json value of type JSON_OBJECT.
+	 */
+	explicit Json();
+
+	/**
+	 * Create a JSON_NULL object.
+	 *
+	 * @param n the null value (nullptr)
+	 */
+	explicit Json(std::nullptr_t n);
+
+	/**
+	 * Create a boolean object.
+	 *
+	 * @param value the boolean value
+	 */
+	explicit Json(bool value);
+
+	/**
+	 * Create a JSON_INTEGER object.
+	 *
+	 * @param value the value
+	 */
+	explicit Json(int value);
+
+	/**
+	 * Create a JSON_REAL object.
+	 *
+	 * @param value the value
+	 */
+	explicit Json(double value);
+
+	/**
+	 * Create a JSON_STRING object.
+	 *
+	 * @param value the value
+	 */
+	explicit Json(const std::string &value);
+
+	/**
+	 * Create a JSON_ARRAY object.
+	 *
+	 * @param list the list of children
+	 */
+	explicit Json(std::initializer_list<Json> list);
+
+	/**
+	 * Create a JSON_STRING object.
+	 *
+	 * @param str the string
+	 */
+	template <size_t N>
+	explicit Json(const char str[N])
+		: m_handle(json_string(str), json_decref)
+	{
+	}
+
+	/**
+	 * Copy the object, this does a deep copy.
+	 *
+	 * @param json the other value
+	 */
+	Json(const Json &json);
+
+	/**
+	 * Copy the object, this does a deep copy.
+	 *
+	 * @param json the other value
+	 * @return *this
+	 */
+	Json &operator=(const Json &json);
+
+	/**
+	 * Move the object.
+	 *
+	 * @param json the other value
+	 */
+	Json(Json &&);
+
+	/**
+	 * Move the object.
+	 *
+	 * @param json the other value
+	 * @return *this
+	 */
+	Json &operator=(Json &&);
+
+	/**
+	 * Get the type of value.
+	 *
+	 * @return the type
+	 */
+	int typeOf() const;
+
+	/**
+	 * Tells if the json value is an JSON_OBJECT.
+	 *
+	 * @return true or false
+	 */
+	bool isObject() const;
+
+	/**
+	 * Tells if the json value is an JSON_ARRAY.
+	 *
+	 * @return true or false
+	 */
+	bool isArray() const;
+
+	/**
+	 * Tells if the json value is an JSON_STRING.
+	 *
+	 * @return true or false
+	 */
+	bool isString() const;
+
+	/**
+	 * Tells if the json value is an JSON_REAL.
+	 *
+	 * @return true or false
+	 */
+	bool isReal() const;
+
+	/**
+	 * Tells if the json value is an JSON_TRUE.
+	 *
+	 * @return true or false
+	 */
+	bool isTrue() const;
+
+	/**
+	 * Tells if the json value is an JSON_FALSE.
+	 *
+	 * @return true or false
+	 */
+	bool isFalse() const;
+
+	/**
+	 * Tells if the json value is an JSON_NULL.
+	 *
+	 * @return true or false
+	 */
+	bool isNull() const;
+
+	/**
+	 * Tells if the json value is an JSON_INTEGER or JSON_REAL.
+	 *
+	 * @return true or false
+	 */
+	bool isNumber() const;
+
+	/**
+	 * Tells if the json value is an JSON_INTEGER.
+	 *
+	 * @return true or false
+	 */
+	bool isInteger() const;
+
+	/**
+	 * Tells if the json value is an JSON_TRUE or JSON_FALSE.
+	 *
+	 * @return true or false
+	 */
+	bool isBoolean() const;
+
+	/**
+	 * Get the number of values in the array
+	 *
+	 * @return the number or 0
+	 */
+	unsigned size() const noexcept;
+
+	/**
+	 * Insert a copy of the value at the end.
+	 *
+	 * @param value the value to insert
+	 */
+	void append(const Json &value);
+
+	/**
+	 * Move the value at the end.
+	 *
+	 * @param value the value to insert
+	 */
+	void append(Json &&value);
+
+	/**
+	 * Insert a copy of the value at the specified index.
+	 *
+	 * @param value the value to insert
+	 * @param index the position
+	 */
+	void insert(const Json &value, int index);
+
+	/**
+	 * Move the value at the specified index.
+	 *
+	 * @param value the value to insert
+	 * @param index the position
+	 */
+	void insert(Json &&value, int index);
+
+	/**
+	 * Set a copy of value to the key 'name'.
+	 *
+	 * @param value the value
+	 * @param name the key name.
+	 */
+	void set(const Json &value, const std::string &name);
+
+	/**
+	 * Move value to the key 'name'.
+	 *
+	 * @param value the value
+	 * @param name the key name.
+	 */
+	void set(Json &&value, const std::string &name);
+
+	/**
+	 * Get the string value.
+	 *
+	 * @return the string
+	 */
+	std::string toString() const;
+
+	/**
+	 * Get the integer value.
+	 *
+	 * @return the value or 0
+	 */
+	int toInteger() const noexcept;
+
+	/**
+	 * Get the real value.
+	 *
+	 * @return the value or 0
+	 */
+	double toReal() const noexcept;
+
+	/**
+	 * Dump the value as a string.
+	 *
+	 * @param flags the optional flags
+	 * @return the string
+	 */
+	std::string dump(int flags = 0);
+
+	/**
+	 * Dump the value to a path.
+	 *
+	 * @param path the path
+	 * @param flags the optional flags
+	 */
+	void dump(const std::string &path, int flags = 0);
+
+	/**
+	 * Get the value at the specified index.
+	 *
+	 * @param index the position
+	 * @return the reference to the value
+	 * @throw std::invalid_argument on error
+	 * @throw std::out_of_range on bad arguments
+	 */
+	Json &operator[](int index);
+
+	/**
+	 * Get the value at the specified index.
+	 *
+	 * @param index the position
+	 * @return the reference to the value
+	 * @throw std::invalid_argument on error
+	 * @throw std::out_of_range on bad arguments
+	 */
+	const Json &operator[](int index) const;
+
+	/**
+	 * Get the value at the specified key.
+	 *
+	 * @param name the key
+	 * @return the reference to the value
+	 * @throw std::invalid_argument on error
+	 * @throw std::out_of_range on bad arguments
+	 */
+	Json &operator[](const std::string &name);
+
+	/**
+	 * Get the value at the specified key.
+	 *
+	 * @param name the key
+	 * @return the reference to the value
+	 * @throw std::invalid_argument on error
+	 * @throw std::out_of_range on bad arguments
+	 */
+	const Json &operator[](const std::string &name) const;
+
+	/**
+	 * Compare the values.
+	 *
+	 * @param j1 the first value
+	 * @param j2 the second value
+	 */
+	friend bool operator==(const Json &j1, const Json &j2);
+};
+
+#endif // !_JSON_H_