diff C++/Json.cpp @ 311:ed3cc10761e4

Json: * Split Json class into several classes * Add unit tests * Json is considered usable
author David Demelier <markand@malikania.fr>
date Fri, 13 Feb 2015 13:42:21 +0100
parents 777bc3cb665a
children ea1a73a7d468
line wrap: on
line diff
--- a/C++/Json.cpp	Wed Feb 11 19:52:13 2015 +0100
+++ b/C++/Json.cpp	Fri Feb 13 13:42:21 2015 +0100
@@ -18,258 +18,245 @@
 
 #include "Json.h"
 
-Json Json::fromString(const std::string &data, int flags)
-{
-	return from(json_loads, data.c_str(), flags);
-}
+/* --------------------------------------------------------
+ * JsonValue implementation
+ * -------------------------------------------------------- */
 
-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)
+JsonValue::JsonValue(const JsonValue &value)
+	: m_handle(json_deep_copy(value.m_handle.get()), json_decref)
 {
 }
 
-Json::Json(bool value)
+JsonValue &JsonValue::operator=(const JsonValue &value)
+{
+	m_handle = Handle(json_deep_copy(value.m_handle.get()), json_decref);
+}
+
+JsonValue::JsonValue(json_t *json)
+	: m_handle(json, json_decref)
+{
+}
+
+JsonValue::JsonValue()
+	: m_handle(json_null(), json_decref)
+{
+}
+
+JsonValue::JsonValue(bool value)
 	: m_handle(json_boolean(value), json_decref)
 {
 }
 
-Json::Json(int value)
+JsonValue::JsonValue(int value)
 	: m_handle(json_integer(value), json_decref)
 {
 }
 
-Json::Json(double value)
+JsonValue::JsonValue(double value)
 	: m_handle(json_real(value), json_decref)
 {
 }
 
-Json::Json(const std::string &value)
+JsonValue::JsonValue(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))
+JsonValue::JsonValue(const char *value)
+	: m_handle(json_string(value), json_decref)
 {
 }
 
-Json::Json(std::initializer_list<Json> list)
-	: m_handle(json_array(), json_decref)
+JsonType JsonValue::typeOf() const
 {
-	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());
-	}
+	return static_cast<JsonType>(json_typeof(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
+bool JsonValue::isObject() const
 {
 	return json_is_object(m_handle.get()) != 0;
 }
 
-bool Json::isArray() const
+bool JsonValue::isArray() const
 {
 	return json_is_array(m_handle.get()) != 0;
 }
 
-bool Json::isString() const
+bool JsonValue::isString() const
 {
 	return json_is_string(m_handle.get()) != 0;
 }
 
-bool Json::isReal() const
+bool JsonValue::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
+bool JsonValue::isTrue() const
 {
 	return json_is_true(m_handle.get()) != 0;
 }
 
-bool Json::isNull() const
+bool JsonValue::isFalse() const
+{
+	return json_is_false(m_handle.get()) != 0;
+}
+
+bool JsonValue::isNull() const
 {
 	return json_is_null(m_handle.get()) != 0;
 }
 
-bool Json::isNumber() const
+bool JsonValue::isNumber() const
 {
 	return json_is_number(m_handle.get()) != 0;
 }
 
-bool Json::isInteger() const
+bool JsonValue::isInteger() const
 {
 	return json_is_integer(m_handle.get()) != 0;
 }
 
-bool Json::isBoolean() const
+bool JsonValue::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
+std::string JsonValue::toString() const
 {
 	auto value = json_string_value(m_handle.get());
 
 	return (value == nullptr) ? "" : value;
 }
 
-int Json::toInteger() const noexcept
+int JsonValue::toInteger() const noexcept
 {
 	return json_integer_value(m_handle.get());
 }
 
-double Json::toReal() const noexcept
+double JsonValue::toReal() const noexcept
 {
 	return json_real_value(m_handle.get());
 }
 
-std::string Json::dump(int flags)
+JsonObject JsonValue::toObject() const
 {
-	auto v = json_dumps(m_handle.get(), flags);
+	json_incref(m_handle.get());
+
+	return JsonObject(m_handle.get());
+}
+
+JsonArray JsonValue::toArray() const
+{
+	json_incref(m_handle.get());
 
-	if (v == nullptr)
-		throw std::runtime_error("failed to dump");
+	return JsonArray(m_handle.get());
+}
+
+/* --------------------------------------------------------
+ * JsonArray
+ * -------------------------------------------------------- */
 
-	return std::string(v);
+JsonArray::JsonArray()
+	: JsonValue(json_array())
+{
+}
+
+unsigned JsonArray::size() const noexcept
+{
+	return json_array_size(m_handle.get());
 }
 
-void Json::dump(const std::string &path, int flags)
+void JsonArray::push(const JsonValue &value)
 {
-	if (json_dump_file(m_handle.get(), path.c_str(), flags) < 0)
-		throw std::runtime_error("failed to dump");
+	json_array_insert(m_handle.get(), 0, value.m_handle.get());
+}
+
+void JsonArray::append(const JsonValue &value)
+{
+	json_array_append(m_handle.get(), value.m_handle.get());
 }
 
-Json &Json::operator[](int index)
+void JsonArray::insert(const JsonValue &value, int index)
 {
-	if (!isArray())
-		throw std::invalid_argument("not an array");
+	json_array_insert(m_handle.get(), index, value.m_handle.get());
+}
 
-	if (index >= m_list.size())
-		throw std::out_of_range("invalid index");
+JsonValue JsonArray::operator[](int index) const
+{
+	if (typeOf() != JsonType::Array)
+		throw JsonError("not an array");
+
+	auto value = json_array_get(m_handle.get(), index);
 
-	return m_list[index];
+	if (value == nullptr)
+		throw JsonError("index out of bounds");
+
+	json_incref(value);
+
+	return JsonValue(value);
 }
 
-const Json &Json::operator[](int index) const
+/* --------------------------------------------------------
+ * JsonObject
+ * -------------------------------------------------------- */
+
+JsonObject::JsonObject()
+	: JsonValue(json_object())
 {
-	if (!isArray())
-		throw std::invalid_argument("not an array");
+}
+
+JsonValue JsonObject::operator[](const std::string &name) const
+{
+	if (typeOf() != JsonType::Object)
+		throw JsonError("not an object");
 
-	if (index >= m_list.size())
-		throw std::out_of_range("invalid index");
+	auto value = json_object_get(m_handle.get(), name.c_str());
+
+	if (value == nullptr)
+		throw JsonError("key " + name + +" not found");
+
+	json_incref(value);
 
-	return m_list[index];
+	return JsonValue(value);
+}
+
+void JsonObject::set(const std::string &key, const JsonValue &value)
+{
+	json_object_set(m_handle.get(), key.c_str(), value.m_handle.get());
 }
 
-Json &Json::operator[](const std::string &name)
-{
-	if (!isObject())
-		throw std::invalid_argument("not an object");
+/* --------------------------------------------------------
+ * JsonReaderFile
+ * -------------------------------------------------------- */
 
-	if (m_map.count(name) == 0)
-		throw std::out_of_range("invalid key");
-
-	return m_map[name];
+JsonReaderFile::JsonReaderFile(std::string path)
+	: m_path(std::move(path))
+{
 }
 
-const Json &Json::operator[](const std::string &name) const
+JsonValue JsonReaderFile::read()
 {
-	if (!isObject())
-		throw std::invalid_argument("not an object");
+	json_error_t error;
+	json_t *handle = json_load_file(m_path.c_str(), 0, &error);
 
-	if (m_map.count(name) == 0)
-		throw std::out_of_range("invalid key");
+	if (handle == nullptr)
+		throw JsonError{error};
 
-	return m_map.at(name);
+	return JsonValue(handle);
 }
 
-bool operator==(const Json &j1, const Json &j2)
+/* --------------------------------------------------------
+ * JsonWriterFile
+ * -------------------------------------------------------- */
+
+JsonWriterFile::JsonWriterFile(std::string path)
+	: m_path(std::move(path))
 {
-	return json_equal(j1.m_handle.get(), j2.m_handle.get()) != 0;
 }
+
+void JsonWriterFile::write(const JsonValue &value)
+{
+	if (json_dump_file(value, m_path.c_str(), 0) < 0)
+		throw JsonError("Failed to write file: " + m_path);
+}