Explorar el Código

Use FixedString to represent keys in JSON objects

Daniele Bartolini hace 10 años
padre
commit
8bbb764655

+ 26 - 9
src/core/json/json.cpp

@@ -59,17 +59,17 @@ namespace json
 		return json;
 	}
 
-	JSONValueType::Enum type(const char* json)
+	JsonValueType::Enum type(const char* json)
 	{
 		CE_ASSERT_NOT_NULL(json);
 
 		switch (*json)
 		{
-			case '"': return JSONValueType::STRING;
-			case '{': return JSONValueType::OBJECT;
-			case '[': return JSONValueType::ARRAY;
-			case '-': return JSONValueType::NUMBER;
-			default: return (isdigit(*json)) ? JSONValueType::NUMBER : (*json == 'n' ? JSONValueType::NIL : JSONValueType::BOOL);
+			case '"': return JsonValueType::STRING;
+			case '{': return JsonValueType::OBJECT;
+			case '[': return JsonValueType::ARRAY;
+			case '-': return JsonValueType::NUMBER;
+			default: return (isdigit(*json)) ? JsonValueType::NUMBER : (*json == 'n' ? JsonValueType::NIL : JsonValueType::BOOL);
 		}
 	}
 
@@ -208,7 +208,7 @@ namespace json
 		return (float) parse_number(json);
 	}
 
-	void parse_array(const char* json, Array<const char*>& array)
+	void parse_array(const char* json, JsonArray& array)
 	{
 		CE_ASSERT_NOT_NULL(json);
 
@@ -244,7 +244,7 @@ namespace json
 		CE_FATAL("Bad array");
 	}
 
-	void parse_object(const char* json, Map<DynamicString, const char*>& object)
+	void parse_object(const char* json, JsonObject& object)
 	{
 		CE_ASSERT_NOT_NULL(json);
 
@@ -262,16 +262,20 @@ namespace json
 
 			while (*json)
 			{
+				const char* key_begin = *json == '"' ? (json + 1) : json;
+
 				TempAllocator256 ta;
 				DynamicString key(ta);
 				parse_string(json, key);
 
+				FixedString fs_key(key_begin, key.length());
+
 				json = skip_string(json);
 				json = skip_spaces(json);
 				json = next(json, ':');
 				json = skip_spaces(json);
 
-				map::set(object, key, json);
+				map::set(object, fs_key, json);
 
 				json = skip_value(json);
 				json = skip_spaces(json);
@@ -289,5 +293,18 @@ namespace json
 
 		CE_FATAL("Bad object");
 	}
+
+	void parse(const char* json, JsonObject& object)
+	{
+		CE_ASSERT_NOT_NULL(json);
+		parse_object(json, object);
+	}
+
+	void parse(Buffer& json, JsonObject& object)
+	{
+		array::push_back(json, '\0');
+		array::pop_back(json);
+		parse(array::begin(json), object);
+	}
 } // namespace json
 } // namespace crown

+ 10 - 22
src/core/json/json.h

@@ -5,37 +5,19 @@
 
 #pragma once
 
+#include "json_types.h"
 #include "dynamic_string.h"
-#include "container_types.h"
 
 namespace crown
 {
 
-/// @defgroup JSON
-
-/// Enumerates JSON value types.
-///
-/// @ingroup JSON
-struct JSONValueType
-{
-	enum Enum
-	{
-		NIL,
-		BOOL,
-		NUMBER,
-		STRING,
-		ARRAY,
-		OBJECT
-	};
-};
-
 /// Functions to parse JSON-encoded strings.
 ///
 /// @ingroup JSON
 namespace json
 {
 	/// Returns the data type of the JSON string @a json.
-	JSONValueType::Enum type(const char* json);
+	JsonValueType::Enum type(const char* json);
 
 	/// Parses the JSON string @a json ad puts it into @a string.
 	void parse_string(const char* json, DynamicString& string);
@@ -54,10 +36,16 @@ namespace json
 
 	/// Parses the JSON array @a json and puts it into @a array as pointers to
 	/// the corresponding items into the original @a json string.
-	void parse_array(const char* json, Array<const char*>& array);
+	void parse_array(const char* json, JsonArray& array);
 
 	/// Parses the JSON object @a json and puts it into @a object as map from
 	/// key to pointer to the corresponding value into the original string @a json.
-	void parse_object(const char* json, Map<DynamicString, const char*>& object);
+	void parse_object(const char* json, JsonObject& object);
+
+	/// Parses the NJSON-encoded @a json.
+	void parse(const char* json, JsonObject& object);
+
+	/// Parses the NJSON-encoded @a json.
+	void parse(Buffer& json, JsonObject& object);
 } // namespace json
 } // namespace crown

+ 12 - 12
src/core/json/json_parser.cpp

@@ -332,7 +332,7 @@ bool JSONElement::is_nil() const
 {
 	if (_at != NULL)
 	{
-		return njson::type(_at) == NJSONValueType::NIL;
+		return njson::type(_at) == JsonValueType::NIL;
 	}
 
 	return true;
@@ -342,7 +342,7 @@ bool JSONElement::is_bool() const
 {
 	if (_at != NULL)
 	{
-		return njson::type(_at) == NJSONValueType::BOOL;
+		return njson::type(_at) == JsonValueType::BOOL;
 	}
 
 	return false;
@@ -352,7 +352,7 @@ bool JSONElement::is_number() const
 {
 	if (_at != NULL)
 	{
-		return njson::type(_at) == NJSONValueType::NUMBER;
+		return njson::type(_at) == JsonValueType::NUMBER;
 	}
 
 	return false;
@@ -362,7 +362,7 @@ bool JSONElement::is_string() const
 {
 	if (_at != NULL)
 	{
-		return njson::type(_at) == NJSONValueType::STRING;
+		return njson::type(_at) == JsonValueType::STRING;
 	}
 
 	return false;
@@ -372,7 +372,7 @@ bool JSONElement::is_array() const
 {
 	if (_at != NULL)
 	{
-		return njson::type(_at) == NJSONValueType::ARRAY;
+		return njson::type(_at) == JsonValueType::ARRAY;
 	}
 
 	return false;
@@ -382,7 +382,7 @@ bool JSONElement::is_object() const
 {
 	if (_at != NULL)
 	{
-		return njson::type(_at) == NJSONValueType::OBJECT;
+		return njson::type(_at) == JsonValueType::OBJECT;
 	}
 
 	return false;
@@ -397,34 +397,34 @@ uint32_t JSONElement::size() const
 
 	switch(njson::type(_at))
 	{
-		case NJSONValueType::NIL:
+		case JsonValueType::NIL:
 		{
 			return 1;
 		}
-		case NJSONValueType::OBJECT:
+		case JsonValueType::OBJECT:
 		{
 			Map<DynamicString, const char*> object(default_allocator());
 			njson::parse(_at, object);
 			return map::size(object);
 		}
-		case NJSONValueType::ARRAY:
+		case JsonValueType::ARRAY:
 		{
 			Array<const char*> array(default_allocator());
 			njson::parse_array(_at, array);
 			return array::size(array);
 		}
-		case NJSONValueType::STRING:
+		case JsonValueType::STRING:
 		{
 			TempAllocator256 ta;
 			DynamicString string(ta);
 			njson::parse_string(_at, string);
 			return string.length();
 		}
-		case NJSONValueType::NUMBER:
+		case JsonValueType::NUMBER:
 		{
 			return 1;
 		}
-		case NJSONValueType::BOOL:
+		case JsonValueType::BOOL:
 		{
 			return 1;
 		}

+ 35 - 0
src/core/json/json_types.h

@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012-2015 Daniele Bartolini and individual contributors.
+ * License: https://github.com/taylor001/crown/blob/master/LICENSE
+ */
+
+#pragma once
+
+#include "container_types.h"
+#include "fixed_string.h"
+
+namespace crown
+{
+
+/// @defgroup JSON
+
+/// Enumerates JSON value types.
+///
+/// @ingroup JSON
+struct JsonValueType
+{
+	enum Enum
+	{
+		NIL,
+		BOOL,
+		NUMBER,
+		STRING,
+		ARRAY,
+		OBJECT
+	};
+};
+
+typedef Array<const char*> JsonArray;
+typedef Map<FixedString, const char*> JsonObject;
+
+} // namespace crown

+ 203 - 6
src/core/json/njson.cpp

@@ -7,6 +7,7 @@
 #include "string_utils.h"
 #include "temp_allocator.h"
 #include "map.h"
+#include "quaternion.h"
 
 namespace crown
 {
@@ -101,17 +102,17 @@ namespace njson
 		return json;
 	}
 
-	NJSONValueType::Enum type(const char* json)
+	JsonValueType::Enum type(const char* json)
 	{
 		CE_ASSERT_NOT_NULL(json);
 
 		switch (*json)
 		{
-			case '"': return NJSONValueType::STRING;
-			case '{': return NJSONValueType::OBJECT;
-			case '[': return NJSONValueType::ARRAY;
-			case '-': return NJSONValueType::NUMBER;
-			default: return (isdigit(*json)) ? NJSONValueType::NUMBER : (*json == 'n' ? NJSONValueType::NIL : NJSONValueType::BOOL);
+			case '"': return JsonValueType::STRING;
+			case '{': return JsonValueType::OBJECT;
+			case '[': return JsonValueType::ARRAY;
+			case '-': return JsonValueType::NUMBER;
+			default: return (isdigit(*json)) ? JsonValueType::NUMBER : (*json == 'n' ? JsonValueType::NIL : JsonValueType::BOOL);
 		}
 	}
 
@@ -385,5 +386,201 @@ namespace njson
 		else
 			parse_root_object(json, object);
 	}
+
+	void parse_root_object(const char* json, JsonObject& object)
+	{
+		CE_ASSERT_NOT_NULL(json);
+
+		while (*json)
+		{
+			const char* key_begin = *json == '"' ? (json + 1) : json;
+
+			TempAllocator256 ta;
+			DynamicString key(ta);
+			json = parse_key(json, key);
+
+			FixedString fs_key(key_begin, key.length());
+
+			json = skip_spaces(json);
+			json = next(json, '=');
+			json = skip_spaces(json);
+
+			map::set(object, fs_key, json);
+
+			json = skip_value(json);
+			json = skip_spaces(json);
+		}
+	}
+
+	void parse_object(const char* json, JsonObject& object)
+	{
+		CE_ASSERT_NOT_NULL(json);
+
+		if (*json == '{')
+		{
+			json = next(json, '{');
+
+			json = skip_spaces(json);
+
+			if (*json == '}')
+			{
+				next(json, '}');
+				return;
+			}
+
+			while (*json)
+			{
+				const char* key_begin = *json == '"' ? (json + 1) : json;
+
+				TempAllocator256 ta;
+				DynamicString key(ta);
+				json = parse_key(json, key);
+
+				FixedString fs_key(key_begin, key.length());
+
+				json = skip_spaces(json);
+				json = next(json, '=');
+				json = skip_spaces(json);
+
+				map::set(object, fs_key, json);
+
+				json = skip_value(json);
+				json = skip_spaces(json);
+
+				if (*json == '}')
+				{
+					next(json, '}');
+					return;
+				}
+
+				json = skip_spaces(json);
+			}
+		}
+
+		CE_FATAL("Bad object");
+	}
+
+	void parse(const char* json, JsonObject& object)
+	{
+		CE_ASSERT_NOT_NULL(json);
+
+		json = skip_spaces(json);
+
+		if (*json == '{')
+			parse_object(json, object);
+		else
+			parse_root_object(json, object);
+	}
+
+	void parse(Buffer& json, JsonObject& object)
+	{
+		array::push_back(json, '\0');
+		array::pop_back(json);
+		parse(array::begin(json), object);
+	}
 } // namespace njson
+
+namespace njson
+{
+	Vector2 parse_vector2(const char* json)
+	{
+		TempAllocator64 ta;
+		JsonArray array(ta);
+		njson::parse_array(json, array);
+
+		Vector2 v;
+		v.x = njson::parse_float(array[0]);
+		v.y = njson::parse_float(array[1]);
+		return v;
+	}
+
+	Vector3 parse_vector3(const char* json)
+	{
+		TempAllocator64 ta;
+		JsonArray array(ta);
+		njson::parse_array(json, array);
+
+		Vector3 v;
+		v.x = njson::parse_float(array[0]);
+		v.y = njson::parse_float(array[1]);
+		v.z = njson::parse_float(array[2]);
+		return v;
+	}
+
+	Vector4 parse_vector4(const char* json)
+	{
+		TempAllocator64 ta;
+		JsonArray array(ta);
+		njson::parse_array(json, array);
+
+		Vector4 v;
+		v.x = njson::parse_float(array[0]);
+		v.y = njson::parse_float(array[1]);
+		v.z = njson::parse_float(array[2]);
+		v.w = njson::parse_float(array[3]);
+		return v;
+	}
+
+	Quaternion parse_quaternion(const char* json)
+	{
+		TempAllocator64 ta;
+		JsonArray array(ta);
+		njson::parse_array(json, array);
+
+		Vector3 axis;
+		axis.x = njson::parse_float(array[0]);
+		axis.y = njson::parse_float(array[1]);
+		axis.z = njson::parse_float(array[2]);
+
+		float angle = njson::parse_float(array[3]);
+
+		return quaternion(axis, angle);
+	}
+
+	Matrix4x4 parse_matrix4x4(const char* json)
+	{
+		TempAllocator128 ta;
+		JsonArray array(ta);
+		njson::parse_array(json, array);
+
+		Matrix4x4 m;
+		m.x.x = njson::parse_float(array[ 0]);
+		m.x.y = njson::parse_float(array[ 1]);
+		m.x.z = njson::parse_float(array[ 2]);
+		m.x.w = njson::parse_float(array[ 3]);
+
+		m.y.x = njson::parse_float(array[ 4]);
+		m.y.y = njson::parse_float(array[ 5]);
+		m.y.z = njson::parse_float(array[ 6]);
+		m.y.w = njson::parse_float(array[ 7]);
+
+		m.z.x = njson::parse_float(array[ 8]);
+		m.z.y = njson::parse_float(array[ 9]);
+		m.z.z = njson::parse_float(array[10]);
+		m.z.w = njson::parse_float(array[11]);
+
+		m.t.x = njson::parse_float(array[12]);
+		m.t.y = njson::parse_float(array[13]);
+		m.t.z = njson::parse_float(array[14]);
+		m.t.w = njson::parse_float(array[15]);
+		return m;
+	}
+
+	StringId32 parse_string_id(const char* json)
+	{
+		TempAllocator1024 ta;
+		DynamicString str(ta);
+		njson::parse_string(json, str);
+		return str.to_string_id();
+	}
+
+	ResourceId parse_resource_id(const char* json)
+	{
+		TempAllocator1024 ta;
+		DynamicString str(ta);
+		njson::parse_string(json, str);
+		return ResourceId(str.c_str());
+	}
+} // namespace json
+
 } // namespace crown

+ 44 - 21
src/core/json/njson.h

@@ -5,37 +5,20 @@
 
 #pragma once
 
+#include "json_types.h"
+#include "math_types.h"
 #include "dynamic_string.h"
-#include "container_types.h"
 
 namespace crown
 {
 
-/// @defgroup JSON
-
-/// Enumerates JSON value types.
-///
-/// @ingroup JSON
-struct NJSONValueType
-{
-	enum Enum
-	{
-		NIL,
-		BOOL,
-		NUMBER,
-		STRING,
-		ARRAY,
-		OBJECT
-	};
-};
-
 /// Functions to parse NJSON-encoded strings.
 ///
 /// @ingroup JSON
 namespace njson
 {
 	/// Returns the data type of the NJSON string @a json.
-	NJSONValueType::Enum type(const char* json);
+	JsonValueType::Enum type(const char* json);
 
 	/// Parses the NJSON string @a json ad puts it into @a string.
 	void parse_string(const char* json, DynamicString& string);
@@ -54,7 +37,7 @@ namespace njson
 
 	/// Parses the NJSON array @a json and puts it into @a array as pointers to
 	/// the corresponding items into the original @a json string.
-	void parse_array(const char* json, Array<const char*>& array);
+	void parse_array(const char* json, JsonArray& array);
 
 	/// Parses the NJSON object @a json and puts it into @a object as map from
 	/// key to pointer to the corresponding value into the original string @a json.
@@ -62,5 +45,45 @@ namespace njson
 
 	/// Parses the NJSON-encoded @a json.
 	void parse(const char* json, Map<DynamicString, const char*>& object);
+
+	/// Parses the NJSON object @a json and puts it into @a object as map from
+	/// key to pointer to the corresponding value into the original string @a json.
+	void parse_object(const char* json, JsonObject& object);
+
+	/// Parses the NJSON-encoded @a json.
+	void parse(const char* json, JsonObject& object);
+
+	/// Parses the NJSON-encoded @a json.
+	void parse(Buffer& json, JsonObject& object);
 } // namespace njson
+
+namespace njson
+{
+	/// Returns the array @a json as Vector2.
+	/// @note Vector2 = [x, y]
+	Vector2 parse_vector2(const char* json);
+
+	/// Returns the array @a json as Vector3.
+	/// @note Vector3 = [x, y, z]
+	Vector3 parse_vector3(const char* json);
+
+	/// Returns the array @a json as Vector4.
+	/// @note Vector4 = [x, y, z, w]
+	Vector4 parse_vector4(const char* json);
+
+	/// Returns the array @a json as Quaternion.
+	/// @note Quaternion = [x, y, z, w]
+	Quaternion parse_quaternion(const char* json);
+
+	/// Returns the array @a json as Matrix4x4.
+	/// @note Matrix4x4 = [x, x, x, x, y, y, y, y, z, z, z, z, t, t, t, t]
+	Matrix4x4 parse_matrix4x4(const char* json);
+
+	/// Returns the string @a json as StringId32.
+	StringId32 parse_string_id(const char* json);
+
+	/// Returns the string @a json as ResourceId.
+	ResourceId parse_resource_id(const char* json);
+}
+
 } // namespace crown

+ 72 - 0
src/core/strings/fixed_string.h

@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012-2015 Daniele Bartolini and individual contributors.
+ * License: https://github.com/taylor001/crown/blob/master/LICENSE
+ */
+
+#pragma once
+
+#include "string_utils.h"
+#include <algorithm>
+
+namespace crown
+{
+
+class FixedString
+{
+public:
+
+	FixedString()
+		: _length(0)
+		, _data(NULL)
+	{
+	}
+
+	FixedString(const char* str)
+		: _length(strlen(str))
+		, _data(str)
+	{
+	}
+
+	FixedString(const char* str, uint32_t len)
+		: _length(len)
+		, _data(str)
+	{
+	}
+
+	FixedString(const FixedString& b)
+		: _length(b._length)
+		, _data(b._data)
+	{
+	}
+
+	FixedString& operator=(const char* str)
+	{
+		_length = strlen(str);
+		_data = str;
+		return *this;
+	}
+
+	bool operator==(const char* str) const
+	{
+		const uint32_t len = strlen(str);
+		return _length == len && !strncmp(_data, str, len);
+	}
+
+	bool operator==(const FixedString& b) const
+	{
+		return (_length == b._length) && !strncmp(_data, b._data, _length);
+	}
+
+	bool operator<(const FixedString& b) const
+	{
+		const uint32_t len = std::max(_length, b._length);
+		return strncmp(_data, b._data, len) < 0;
+	}
+
+private:
+
+	uint32_t _length;
+	const char* _data;
+};
+
+} // namespace crown