diff C++/modules/Json/Json.cpp @ 405:f81478065901

Json: - Complete rewrite, - Convert jansson tree to own C++ tree, - Conversion from Value to Object/Array makes copies
author David Demelier <markand@malikania.fr>
date Mon, 05 Oct 2015 17:04:40 +0200
parents 9ab878fb9fa2
children d485d36a8de1
line wrap: on
line diff
--- a/C++/modules/Json/Json.cpp	Mon Oct 05 14:39:57 2015 +0200
+++ b/C++/modules/Json/Json.cpp	Mon Oct 05 17:04:40 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Json.cpp -- jansson C++11 wrapper
+ * Json.cpp -- C++14 JSON manipulation using jansson parser
  *
  * Copyright (c) 2013-2015 David Demelier <markand@malikania.fr>
  *
@@ -16,147 +16,147 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <stdexcept>
+#include "Json.h"
 
-#include "Json.h"
+#include <jansson.h>
 
 namespace json {
 
-/* --------------------------------------------------------
- * Object
- * -------------------------------------------------------- */
+namespace {
+
+void readObject(Value &parent, json_t *object);
+void readArray(Value &parent, json_t *array);
+
+Value readValue(json_t *v)
+{
+	if (json_is_null(v)) {
+		return Value{nullptr};
+	}
+	if (json_is_string(v)) {
+		return Value{json_string_value(v)};
+	}
+	if (json_is_number(v)) {
+		return Value{json_number_value(v)};
+	}
+	if (json_is_boolean(v)) {
+		return Value{json_boolean_value(v)};
+	}
+	if (json_is_object(v)) {
+		Object object;
+
+		readObject(object, v);
+
+		return object;
+	}
+	if (json_is_array(v)) {
+		Array array;
+
+		readArray(array, v);
+
+		return array;
+	}
+
+	return Value{};
+}
+
+void readObject(Value &parent, json_t *object)
+{
+	const char *key;
+	json_t *value;
+
+	json_object_foreach(object, key, value) {
+		static_cast<Object &>(parent).insert(key, readValue(value));
+	}
+}
+
+void readArray(Value &parent, json_t *array)
+{
+	size_t index;
+	json_t *value;
+
+	json_array_foreach(array, index, value) {
+		static_cast<Array &>(parent).append(readValue(value));
+	}
+}
+
+template <typename Func, typename... Args>
+Value convert(Func fn, Args&&... args)
+{
+	json_error_t error;
+	json_t *json = fn(std::forward<Args>(args)..., &error);
+
+	if (json == nullptr) {
+		throw Error{error.text, error.source, error.line, error.column, error.position};
+	}
+
+	Value value;
+
+	if (json_is_object(json)) {
+		value = Object{};
+		readObject(value, json);
+	} else {
+		value = Array{};
+		readArray(value, json);
+	}
+
+	json_decref(json);
+
+	return value;
+}
+
+} // !namespace
+
+bool Value::toBool() const noexcept
+{
+	if (m_type != Type::Boolean)
+		return false;
+
+	return m_boolean;
+}
+
+double Value::toNumber() const noexcept
+{
+	if (m_type != Type::Number)
+		return 0;
+
+	return m_number;
+}
+
+std::string Value::toString() const noexcept
+{
+	if (m_type != Type::String) {
+		return "";
+	}
+
+	return m_string;
+}
 
 Object Value::toObject() const noexcept
 {
-	json_incref(m_handle.get());
+	if (m_type != Type::Object) {
+		return Object{};
+	}
 
-	return Object(m_handle.get());
+	return Object(*this);
 }
 
 Array Value::toArray() const noexcept
 {
-	json_incref(m_handle.get());
-
-	return Array(m_handle.get());
-}
-
-/* --------------------------------------------------------
- * Array
- * -------------------------------------------------------- */
-
-Value Array::at(int index) const
-{
-	auto value = json_array_get(m_handle.get(), index);
-
-	if (value == nullptr)
-		throw Error("index out of bounds");
-
-	json_incref(value);
-
-	return Value{value};
-}
-
-Value Array::operator[](int index) const noexcept
-{
-	auto value = json_array_get(m_handle.get(), index);
-
-	if (value == nullptr)
-		return Value();
-
-	json_incref(value);
+	if (m_type != Type::Array) {
+		return Array{};
+	}
 
-	return Value(value);
-}
-
-Array::Ref Array::operator[](int index) noexcept
-{
-	auto value = json_array_get(m_handle.get(), index);
-
-	if (value == nullptr)
-		value = json_null();
-	else
-		json_incref(value);
-
-	return Ref(value, *this, index);
-}
-
-/* --------------------------------------------------------
- * Object
- * -------------------------------------------------------- */
-
-Object::Ref Object::operator[](const std::string &name)
-{
-	if (typeOf() != Type::Object)
-		return Ref(Value(), *this, name);
-
-	auto value = json_object_get(m_handle.get(), name.c_str());
-
-	json_incref(value);
-
-	return Ref(value, *this, name);
+	return Array(*this);
 }
 
-Value Object::operator[](const std::string &name) const
+Document::Document(Buffer buffer)
 {
-	if (typeOf() != Type::Object)
-		return Value();
-
-	auto value = json_object_get(m_handle.get(), name.c_str());
-
-	if (value == nullptr)
-		return Value();
-
-	json_incref(value);
-
-	return Value(value);
-}
-
-/* --------------------------------------------------------
- * Document
- * -------------------------------------------------------- */
-
-Value Document::read(std::string content, int flags) const
-{
-	json_error_t error;
-	json_t *json = json_loads(content.c_str(), flags, &error);
-
-	if (json == nullptr)
-		throw Error(error);
-
-	return Value(json);
+	m_value = convert(json_loads, buffer.text.c_str(), 0);
 }
 
-Value Document::read(std::ifstream &stream, int flags) const
+Document::Document(File file)
 {
-	if (!stream.is_open())
-		throw Error("File not opened");
-
-	stream.seekg(0, stream.end);
-	auto length = stream.tellg();
-	stream.seekg(0, stream.beg);
-
-	std::string buffer;
-	buffer.resize(length, ' ');
-
-	stream.read(&buffer[0], length);
-	stream.close();
-
-	return read(std::move(buffer), flags);
-}
-
-Document::Document(std::ifstream &stream, int flags)
-{
-	m_value = read(stream, flags);
-}
-
-Document::Document(std::ifstream &&stream, int flags)
-{
-	m_value = read(stream, flags);
-}
-
-Document::Document(std::string content, int flags)
-{
-	m_value = read(std::move(content), flags);
+	m_value = convert(json_load_file, file.path.c_str(), 0);
 }
 
 } // !json
\ No newline at end of file