1 #ifndef DALI_SCENE_LOADER_JSON_READER_H_
2 #define DALI_SCENE_LOADER_JSON_READER_H_
4 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 #include "dali-scene-loader/third-party/json.h"
24 #include "dali/public-api/common/vector-wrapper.h"
27 #include <string_view>
36 * @brief Helper for freeing the memory allocated by json_parse()
38 struct json_value_deleter
40 void operator()(json_value_s* p) const
45 typedef std::unique_ptr<json_value_s, json_value_deleter> unique_ptr;
48 * @brief Case sensitive comparison of json_string_s and c-string.
49 * @return difference in first different character, or 0 if the strings are identical.
51 int StrCmp(const json_string_s& js, const char* s);
54 * @brief Case sensitive comparison of json_string_s and std::string.
55 * @return difference in first different character, or 0 if the strings are identical.
57 int StrCmp(const json_string_s& js, const std::string& s);
60 * @brief Convenience function to compare json_string_s and other supported string type,
63 template <typename String>
65 int StrCmp(String& s, const json_string_s& js)
67 return -StrCmp(js, s);
71 * @brief Checks @a jv to be the given @a type, otherwise a std::runtime_error is thrown.
73 void Validate(const json_value_s& jv, json_type_e type);
78 * @brief Compile-time type-enum mapping.
84 #define TYPE2ENUM(x) template<> struct Type2Enum<json_## x ##_s>\
86 enum { VALUE = json_type_## x };\
97 * @brief Casts the payload of a json_value_s to the given type.
99 template <typename Out>
101 const Out& Cast(const json_value_s& j)
103 Validate(j, static_cast<json_type_e>(detail::Type2Enum<typename std::decay<Out>::type>::VALUE));
104 return *static_cast<const Out*>(j.payload);
108 * @brief Casts the payload of a json_value_s to the given type.
109 * @note std::runtime_error is thrown if the value is not the given type.
111 template <typename Out>
113 Out& Cast(json_value_s& j)
115 Validate(j, static_cast<json_type_e>(detail::Type2Enum<typename std::decay<Out>::type>::VALUE));
116 return *static_cast<Out*>(j.payload);
120 * @brief Helper function to find a child element of @a obj mapped to @a key.
121 * @return Pointer to the element, or nullptr if it could not be found.
123 json_value_s* FindObjectChild(const std::string& key, json_object_s& obj);
126 * @brief Helper functions for reading various value types.
130 static bool Boolean(const json_value_s& j)
132 if (j.type == json_type_true)
136 else if (j.type == json_type_false)
140 else // try to interpret a numeric value.
142 return Number<int>(j) != 0;
146 template <typename T>
147 static T Number(const json_value_s& j)
149 auto& jn = Cast<const json_number_s>(j);
150 std::stringstream ss;
151 for (auto i0 = jn.number, i1 = i0 + jn.number_size; i0 != i1; ++i0)
161 throw std::runtime_error("Failed to convert value to number");
164 template <typename E>
165 static E Enum(const json_value_s& j)
167 size_t number = Number<size_t>(j);
168 return static_cast<E>(number);
171 static std::string_view StringView(const json_value_s& j)
173 auto& js = Cast<json_string_s>(j);
174 return std::string_view(js.string, js.string_size);
177 static std::string String(const json_value_s& j)
179 auto& js = Cast<const json_string_s>(j);
180 return std::string(js.string, js.string_size);
183 template <typename T, T(*readElement)(const json_value_s&)>
184 static std::vector<T> Array(const json_value_s& j)
186 auto& ja = Cast<const json_array_s>(j);
187 std::vector<T> result;
188 result.reserve(ja.length);
192 result.push_back(std::move(readElement(*i->value)));
200 * @brief Core class for object properties.
205 explicit PropertyCore(const std::string& key)
209 const std::string& GetKey() const { return mKey; }
216 * @brief Base class for the properties of a type T.
218 template <typename T>
219 struct PropertyBase : PropertyCore
221 using PropertyCore::GetKey;
223 explicit PropertyBase(const std::string& key)
227 virtual ~PropertyBase()
230 virtual void Read(const json_value_s& j, T& obj) = 0;
234 * @brief Concrete property of an object to read into from JSON with a given function.
236 template <class T, typename U>
237 struct Property : PropertyBase<T>
239 using ReadFn = U(*)(const json_value_s&);
240 using MemberPtr = U T::*;
241 using SetterArgType = typename std::conditional<sizeof(U) <= sizeof(uintptr_t), U, const U&>::type;
242 using Setter = void (T::*)(SetterArgType);
244 Property(const std::string& key, ReadFn read, MemberPtr ptr)
245 : PropertyBase<T>(key),
247 mAccessor(new DirectAccessor(ptr))
250 Property(const std::string& key, ReadFn read, Setter setter)
251 : PropertyBase<T>(key),
253 mAccessor(new SetterAccessor(setter))
259 void Read(const json_value_s& j, T& obj) override
261 mAccessor->Set(mRead(j), obj);
267 virtual ~AccessorBase()
270 virtual void Set(U value, T& obj) const = 0;
273 struct DirectAccessor : AccessorBase
275 DirectAccessor(MemberPtr ptr)
279 void Set(U value, T& obj) const override
281 obj.*mPointer = std::move(value);
287 struct SetterAccessor : AccessorBase
289 SetterAccessor(Setter setter)
293 void Set(U value, T& obj) const override
295 (obj.*mSetter)(value);
302 std::unique_ptr<AccessorBase> mAccessor;
306 * @brief Helper function to make a Property for a member of type U, of object of type T.
308 template <class T, typename U>
309 Property<T, U>* MakeProperty(const std::string& key, typename Property<T, U>::ReadFn readFn,
312 return new Property<T, U>(key, readFn, ptr);
316 * @brief Core class for an object Reader.
321 std::vector<void*> mProperties;
323 ReaderCore() = default;
325 ReaderCore(const ReaderCore& other) = delete;
326 ReaderCore& operator=(const ReaderCore& other) = delete;
328 ReaderCore(ReaderCore&& other) = default;
329 ReaderCore& operator=(ReaderCore&& other) = default;
333 * @brief Object Reader template for reading into an object of a given type,
334 * with properties registered for the various members.
336 template <typename T>
337 class Reader : protected ReaderCore
342 Reader(const Reader<T>& other) = delete;
343 Reader<T>& operator=(const Reader<T>& other) = delete;
345 Reader(Reader<T>&& other) = default;
346 Reader<T>& operator=(Reader&& other) = default;
350 for (auto& p : mProperties)
356 Reader<T>& Register(PropertyBase<T>& prop)
358 auto iInsert = std::lower_bound(mProperties.begin(), mProperties.end(), &prop,
360 if (iInsert == mProperties.end() || Cast(*iInsert)->GetKey() != prop.GetKey())
362 mProperties.insert(iInsert, &prop);
366 delete Cast(*iInsert);
372 void Read(const json_object_s& jo, T& obj) const
377 auto iFind = std::lower_bound(mProperties.begin(), mProperties.end(),
378 *i->name, FindPredicate);
379 if (iFind != mProperties.end())
381 auto prop = Cast(*iFind);
382 if (0 == StrCmp(*i->name, prop->GetKey()))
384 prop->Read(*i->value, obj);
392 static inline PropertyBase<T>* Cast(void* p)
394 return static_cast<PropertyBase<T>*>(p);
397 static bool SortPredicate(void* p, PropertyBase<T>* prop)
399 const auto prop0 = Cast(p);
400 return prop0->GetKey().compare(prop->GetKey()) < 0;
403 static bool FindPredicate(void* p, const json_string_s& key)
405 const auto prop = Cast(p);
406 return StrCmp(prop->GetKey(), key) < 0;
411 * @brief Wraps a Reader<T> in a function usable as a Property<T>::ReadFn, i.e. to facilitate
412 * deserializing structures of nested objects.
414 template <typename T>
417 static const Reader<T>* sReader;
419 static T Read(const json_value_s& j)
422 auto& jo = Cast<json_object_s>(j);
423 sReader->Read(jo, result);
428 template <typename T>
429 const Reader<T>* ObjectReader<T>::sReader = nullptr;
431 template <typename T>
432 void SetObjectReader(const Reader<T>& r)
434 ObjectReader<T>::sReader = &r;
439 #endif //DALI_SCENE_LOADER_JSON_READER_H_