1 #ifndef DALI_SCENE3D_LOADER_JSON_READER_H_
2 #define DALI_SCENE3D_LOADER_JSON_READER_H_
4 * Copyright (c) 2023 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/public-api/common/vector-wrapper.h>
27 #include <string_view>
30 #include <dali-scene3d/third-party/json.h> // TODO : Since license issue, We shoud replace this thing as <dali-toolkit/devel-api/builder/json-parser.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_string_s& js)
175 return std::string_view(js.string, js.string_size);
178 static std::string_view StringView(const json_value_s& j)
180 auto& js = Cast<json_string_s>(j);
181 return StringView(js);
184 static std::string String(const json_value_s& j)
186 auto& js = Cast<const json_string_s>(j);
187 return std::string(js.string, js.string_size);
190 template<typename T, T (*readElement)(const json_value_s&)>
191 static std::vector<T> Array(const json_value_s& j)
193 auto& ja = Cast<const json_array_s>(j);
194 std::vector<T> result;
195 result.reserve(ja.length);
199 result.push_back(std::move(readElement(*i->value)));
207 * @brief Core class for object properties.
212 explicit PropertyCore(const std::string& key)
217 const std::string& GetKey() const
227 * @brief Base class for the properties of a type T.
230 struct PropertyBase : PropertyCore
232 using PropertyCore::GetKey;
234 explicit PropertyBase(const std::string& key)
239 virtual ~PropertyBase()
243 virtual void Read(const json_value_s& j, T& obj) = 0;
247 * @brief Concrete property of an object to read into from JSON with a given function.
249 template<class T, typename U>
250 struct Property : PropertyBase<T>
252 using ReadFn = U (*)(const json_value_s&);
253 using MemberPtr = U T::*;
254 using SetterArgType = typename std::conditional<sizeof(U) <= sizeof(uintptr_t), U, const U&>::type;
255 using Setter = void (T::*)(SetterArgType);
257 Property(const std::string& key, ReadFn read, MemberPtr ptr)
258 : PropertyBase<T>(key),
260 mAccessor(new DirectAccessor(ptr))
264 Property(const std::string& key, ReadFn read, Setter setter)
265 : PropertyBase<T>(key),
267 mAccessor(new SetterAccessor(setter))
275 void Read(const json_value_s& j, T& obj) override
277 mAccessor->Set(mRead(j), obj);
283 virtual ~AccessorBase()
287 virtual void Set(U value, T& obj) const = 0;
290 struct DirectAccessor : AccessorBase
292 DirectAccessor(MemberPtr ptr)
297 void Set(U value, T& obj) const override
299 obj.*mPointer = std::move(value);
305 struct SetterAccessor : AccessorBase
307 SetterAccessor(Setter setter)
312 void Set(U value, T& obj) const override
314 (obj.*mSetter)(value);
321 std::unique_ptr<AccessorBase> mAccessor;
325 * @brief Helper function to make a Property for a member of type U, of object of type T.
327 template<class T, typename U>
328 Property<T, U>* MakeProperty(const std::string& key, typename Property<T, U>::ReadFn readFn, U T::*ptr)
330 return new Property<T, U>(key, readFn, ptr);
334 * @brief Core class for an object Reader.
339 std::vector<void*> mProperties;
341 ReaderCore() = default;
343 ReaderCore(const ReaderCore& other) = delete;
344 ReaderCore& operator=(const ReaderCore& other) = delete;
346 ReaderCore(ReaderCore&& other) = default;
347 ReaderCore& operator=(ReaderCore&& other) = default;
351 * @brief Object Reader template for reading into an object of a given type,
352 * with properties registered for the various members.
355 class Reader : protected ReaderCore
360 Reader(const Reader<T>& other) = delete;
361 Reader<T>& operator=(const Reader<T>& other) = delete;
363 Reader(Reader<T>&& other) = default;
364 Reader<T>& operator=(Reader&& other) = default;
368 for(auto& p : mProperties)
374 Reader<T>& Register(PropertyBase<T>& prop)
376 auto iInsert = std::lower_bound(mProperties.begin(), mProperties.end(), &prop, SortPredicate);
377 if(iInsert == mProperties.end() || Cast(*iInsert)->GetKey() != prop.GetKey())
379 mProperties.insert(iInsert, &prop);
383 delete Cast(*iInsert);
389 void Read(const json_object_s& jo, T& obj) const
394 auto iFind = std::lower_bound(mProperties.begin(), mProperties.end(), *i->name, FindPredicate);
395 if(iFind != mProperties.end())
397 auto prop = Cast(*iFind);
398 if(0 == StrCmp(*i->name, prop->GetKey()))
400 prop->Read(*i->value, obj);
408 static inline PropertyBase<T>* Cast(void* p)
410 return static_cast<PropertyBase<T>*>(p);
413 static bool SortPredicate(void* p, PropertyBase<T>* prop)
415 const auto prop0 = Cast(p);
416 return prop0->GetKey().compare(prop->GetKey()) < 0;
419 static bool FindPredicate(void* p, const json_string_s& key)
421 const auto prop = Cast(p);
422 return StrCmp(prop->GetKey(), key) < 0;
427 * @brief Wraps a Reader<T> in a function usable as a Property<T>::ReadFn, i.e. to facilitate
428 * deserializing structures of nested objects.
433 static const Reader<T>* sReader;
435 static T Read(const json_value_s& j)
438 auto& jo = Cast<json_object_s>(j);
439 sReader->Read(jo, result);
445 const Reader<T>* ObjectReader<T>::sReader = nullptr;
448 void SetObjectReader(const Reader<T>& r)
450 ObjectReader<T>::sReader = &r;
455 #endif //DALI_SCENE3D_LOADER_JSON_READER_H_