1 #ifndef DALI_SCENE_LOADER_JSON_READER_H_
2 #define DALI_SCENE_LOADER_JSON_READER_H_
4 * Copyright (c) 2021 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"
29 #include <string_view>
30 #include "dali/public-api/common/vector-wrapper.h"
35 * @brief Helper for freeing the memory allocated by json_parse()
37 struct json_value_deleter
39 void operator()(json_value_s* p) const
44 typedef std::unique_ptr<json_value_s, json_value_deleter> unique_ptr;
47 * @brief Case sensitive comparison of json_string_s and c-string.
48 * @return difference in first different character, or 0 if the strings are identical.
50 int StrCmp(const json_string_s& js, const char* s);
53 * @brief Case sensitive comparison of json_string_s and std::string.
54 * @return difference in first different character, or 0 if the strings are identical.
56 int StrCmp(const json_string_s& js, const std::string& s);
59 * @brief Convenience function to compare json_string_s and other supported string type,
62 template<typename String>
63 inline int StrCmp(String& s, const json_string_s& js)
65 return -StrCmp(js, s);
69 * @brief Checks @a jv to be the given @a type, otherwise a std::runtime_error is thrown.
71 void Validate(const json_value_s& jv, json_type_e type);
76 * @brief Compile-time type-enum mapping.
83 #define TYPE2ENUM(x) \
85 struct Type2Enum<json_##x##_s> \
89 VALUE = json_type_##x \
101 * @brief Casts the payload of a json_value_s to the given type.
103 template<typename Out>
104 inline const Out& Cast(const json_value_s& j)
106 Validate(j, static_cast<json_type_e>(detail::Type2Enum<typename std::decay<Out>::type>::VALUE));
107 return *static_cast<const Out*>(j.payload);
111 * @brief Casts the payload of a json_value_s to the given type.
112 * @note std::runtime_error is thrown if the value is not the given type.
114 template<typename Out>
115 inline Out& Cast(json_value_s& j)
117 Validate(j, static_cast<json_type_e>(detail::Type2Enum<typename std::decay<Out>::type>::VALUE));
118 return *static_cast<Out*>(j.payload);
122 * @brief Helper function to find a child element of @a obj mapped to @a key.
123 * @return Pointer to the element, or nullptr if it could not be found.
125 json_value_s* FindObjectChild(const std::string& key, json_object_s& obj);
128 * @brief Helper functions for reading various value types.
132 static bool Boolean(const json_value_s& j)
134 if(j.type == json_type_true)
138 else if(j.type == json_type_false)
142 else // try to interpret a numeric value.
144 return Number<int>(j) != 0;
149 static T Number(const json_value_s& j)
151 auto& jn = Cast<const json_number_s>(j);
152 std::stringstream ss;
153 for(auto i0 = jn.number, i1 = i0 + jn.number_size; i0 != i1; ++i0)
163 throw std::runtime_error("Failed to convert value to number");
167 static E Enum(const json_value_s& j)
169 size_t number = Number<size_t>(j);
170 return static_cast<E>(number);
173 static std::string_view StringView(const json_value_s& j)
175 auto& js = Cast<json_string_s>(j);
176 return std::string_view(js.string, js.string_size);
179 static std::string String(const json_value_s& j)
181 auto& js = Cast<const json_string_s>(j);
182 return std::string(js.string, js.string_size);
185 template<typename T, T (*readElement)(const json_value_s&)>
186 static std::vector<T> Array(const json_value_s& j)
188 auto& ja = Cast<const json_array_s>(j);
189 std::vector<T> result;
190 result.reserve(ja.length);
194 result.push_back(std::move(readElement(*i->value)));
202 * @brief Core class for object properties.
207 explicit PropertyCore(const std::string& key)
212 const std::string& GetKey() const
222 * @brief Base class for the properties of a type T.
225 struct PropertyBase : PropertyCore
227 using PropertyCore::GetKey;
229 explicit PropertyBase(const std::string& key)
234 virtual ~PropertyBase()
238 virtual void Read(const json_value_s& j, T& obj) = 0;
242 * @brief Concrete property of an object to read into from JSON with a given function.
244 template<class T, typename U>
245 struct Property : PropertyBase<T>
247 using ReadFn = U (*)(const json_value_s&);
248 using MemberPtr = U T::*;
249 using SetterArgType = typename std::conditional<sizeof(U) <= sizeof(uintptr_t), U, const U&>::type;
250 using Setter = void (T::*)(SetterArgType);
252 Property(const std::string& key, ReadFn read, MemberPtr ptr)
253 : PropertyBase<T>(key),
255 mAccessor(new DirectAccessor(ptr))
259 Property(const std::string& key, ReadFn read, Setter setter)
260 : PropertyBase<T>(key),
262 mAccessor(new SetterAccessor(setter))
270 void Read(const json_value_s& j, T& obj) override
272 mAccessor->Set(mRead(j), obj);
278 virtual ~AccessorBase()
282 virtual void Set(U value, T& obj) const = 0;
285 struct DirectAccessor : AccessorBase
287 DirectAccessor(MemberPtr ptr)
292 void Set(U value, T& obj) const override
294 obj.*mPointer = std::move(value);
300 struct SetterAccessor : AccessorBase
302 SetterAccessor(Setter setter)
307 void Set(U value, T& obj) const override
309 (obj.*mSetter)(value);
316 std::unique_ptr<AccessorBase> mAccessor;
320 * @brief Helper function to make a Property for a member of type U, of object of type T.
322 template<class T, typename U>
323 Property<T, U>* MakeProperty(const std::string& key, typename Property<T, U>::ReadFn readFn, U T::*ptr)
325 return new Property<T, U>(key, readFn, ptr);
329 * @brief Core class for an object Reader.
334 std::vector<void*> mProperties;
336 ReaderCore() = default;
338 ReaderCore(const ReaderCore& other) = delete;
339 ReaderCore& operator=(const ReaderCore& other) = delete;
341 ReaderCore(ReaderCore&& other) = default;
342 ReaderCore& operator=(ReaderCore&& other) = default;
346 * @brief Object Reader template for reading into an object of a given type,
347 * with properties registered for the various members.
350 class Reader : protected ReaderCore
355 Reader(const Reader<T>& other) = delete;
356 Reader<T>& operator=(const Reader<T>& other) = delete;
358 Reader(Reader<T>&& other) = default;
359 Reader<T>& operator=(Reader&& other) = default;
363 for(auto& p : mProperties)
369 Reader<T>& Register(PropertyBase<T>& prop)
371 auto iInsert = std::lower_bound(mProperties.begin(), mProperties.end(), &prop, SortPredicate);
372 if(iInsert == mProperties.end() || Cast(*iInsert)->GetKey() != prop.GetKey())
374 mProperties.insert(iInsert, &prop);
378 delete Cast(*iInsert);
384 void Read(const json_object_s& jo, T& obj) const
389 auto iFind = std::lower_bound(mProperties.begin(), mProperties.end(), *i->name, FindPredicate);
390 if(iFind != mProperties.end())
392 auto prop = Cast(*iFind);
393 if(0 == StrCmp(*i->name, prop->GetKey()))
395 prop->Read(*i->value, obj);
403 static inline PropertyBase<T>* Cast(void* p)
405 return static_cast<PropertyBase<T>*>(p);
408 static bool SortPredicate(void* p, PropertyBase<T>* prop)
410 const auto prop0 = Cast(p);
411 return prop0->GetKey().compare(prop->GetKey()) < 0;
414 static bool FindPredicate(void* p, const json_string_s& key)
416 const auto prop = Cast(p);
417 return StrCmp(prop->GetKey(), key) < 0;
422 * @brief Wraps a Reader<T> in a function usable as a Property<T>::ReadFn, i.e. to facilitate
423 * deserializing structures of nested objects.
428 static const Reader<T>* sReader;
430 static T Read(const json_value_s& j)
433 auto& jo = Cast<json_object_s>(j);
434 sReader->Read(jo, result);
440 const Reader<T>* ObjectReader<T>::sReader = nullptr;
443 void SetObjectReader(const Reader<T>& r)
445 ObjectReader<T>::sReader = &r;
450 #endif //DALI_SCENE_LOADER_JSON_READER_H_