4fb6f7a7f299943dadf89e940b20731b8f54a9a4
[platform/core/uifw/dali-toolkit.git] / dali-scene-loader / internal / json-reader.h
1 #ifndef DALI_SCENE_LOADER_JSON_READER_H_
2 #define DALI_SCENE_LOADER_JSON_READER_H_
3 /*
4  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  */
19
20 // INTERNAL INCLUDES
21 #include "dali-scene-loader/third-party/json.h"
22
23 // EXTERNAL INCLUDES
24 #include <algorithm>
25 #include <cstring>
26 #include <map>
27 #include <memory>
28 #include <sstream>
29 #include <string_view>
30 #include "dali/public-api/common/vector-wrapper.h"
31
32 namespace json
33 {
34 /**
35  * @brief Helper for freeing the memory allocated by json_parse()
36  */
37 struct json_value_deleter
38 {
39   void operator()(json_value_s* p) const
40   {
41     free(p);
42   }
43 };
44 typedef std::unique_ptr<json_value_s, json_value_deleter> unique_ptr;
45
46 /**
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.
49  */
50 int StrCmp(const json_string_s& js, const char* s);
51
52 /**
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.
55  */
56 int StrCmp(const json_string_s& js, const std::string& s);
57
58 /**
59  * @brief Convenience function to compare json_string_s and other supported string type,
60  *  in swapped order.
61  */
62 template<typename String>
63 inline int StrCmp(String& s, const json_string_s& js)
64 {
65   return -StrCmp(js, s);
66 }
67
68 /**
69  * @brief Checks @a jv to be the given @a type, otherwise a std::runtime_error is thrown.
70  */
71 void Validate(const json_value_s& jv, json_type_e type);
72
73 namespace detail
74 {
75 /**
76  * @brief Compile-time type-enum mapping.
77  */
78 template<typename T>
79 struct Type2Enum
80 {
81 };
82
83 #define TYPE2ENUM(x)             \
84   template<>                     \
85   struct Type2Enum<json_##x##_s> \
86   {                              \
87     enum                         \
88     {                            \
89       VALUE = json_type_##x      \
90     };                           \
91   };
92
93 TYPE2ENUM(object)
94 TYPE2ENUM(array)
95 TYPE2ENUM(string)
96 TYPE2ENUM(number)
97 #undef TYPE2ENUM
98 } // namespace detail
99
100 /**
101  * @brief Casts the payload of a json_value_s to the given type.
102  */
103 template<typename Out>
104 inline const Out& Cast(const json_value_s& j)
105 {
106   Validate(j, static_cast<json_type_e>(detail::Type2Enum<typename std::decay<Out>::type>::VALUE));
107   return *static_cast<const Out*>(j.payload);
108 }
109
110 /**
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.
113  */
114 template<typename Out>
115 inline Out& Cast(json_value_s& j)
116 {
117   Validate(j, static_cast<json_type_e>(detail::Type2Enum<typename std::decay<Out>::type>::VALUE));
118   return *static_cast<Out*>(j.payload);
119 }
120
121 /**
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.
124  */
125 json_value_s* FindObjectChild(const std::string& key, json_object_s& obj);
126
127 /**
128  * @brief Helper functions for reading various value types.
129  */
130 struct Read
131 {
132   static bool Boolean(const json_value_s& j)
133   {
134     if(j.type == json_type_true)
135     {
136       return true;
137     }
138     else if(j.type == json_type_false)
139     {
140       return false;
141     }
142     else // try to interpret a numeric value.
143     {
144       return Number<int>(j) != 0;
145     }
146   }
147
148   template<typename T>
149   static T Number(const json_value_s& j)
150   {
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)
154     {
155       ss.put(*i0);
156     }
157
158     T result;
159     if(ss >> result)
160     {
161       return result;
162     }
163     throw std::runtime_error("Failed to convert value to number");
164   }
165
166   template<typename E>
167   static E Enum(const json_value_s& j)
168   {
169     size_t number = Number<size_t>(j);
170     return static_cast<E>(number);
171   }
172
173   static std::string_view StringView(const json_value_s& j)
174   {
175     auto& js = Cast<json_string_s>(j);
176     return std::string_view(js.string, js.string_size);
177   }
178
179   static std::string String(const json_value_s& j)
180   {
181     auto& js = Cast<const json_string_s>(j);
182     return std::string(js.string, js.string_size);
183   }
184
185   template<typename T, T (*readElement)(const json_value_s&)>
186   static std::vector<T> Array(const json_value_s& j)
187   {
188     auto&          ja = Cast<const json_array_s>(j);
189     std::vector<T> result;
190     result.reserve(ja.length);
191     auto i = ja.start;
192     while(i)
193     {
194       result.push_back(std::move(readElement(*i->value)));
195       i = i->next;
196     }
197     return result;
198   }
199 };
200
201 /**
202  * @brief Core class for object properties.
203  */
204 struct PropertyCore
205 {
206 protected:
207   explicit PropertyCore(const std::string& key)
208   : mKey(key)
209   {
210   }
211
212   const std::string& GetKey() const
213   {
214     return mKey;
215   }
216
217 private:
218   std::string mKey;
219 };
220
221 /**
222  * @brief Base class for the properties of a type T.
223  */
224 template<typename T>
225 struct PropertyBase : PropertyCore
226 {
227   using PropertyCore::GetKey;
228
229   explicit PropertyBase(const std::string& key)
230   : PropertyCore(key)
231   {
232   }
233
234   virtual ~PropertyBase()
235   {
236   }
237
238   virtual void Read(const json_value_s& j, T& obj) = 0;
239 };
240
241 /**
242  * @brief Concrete property of an object to read into from JSON with a given function.
243  */
244 template<class T, typename U>
245 struct Property : PropertyBase<T>
246 {
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);
251
252   Property(const std::string& key, ReadFn read, MemberPtr ptr)
253   : PropertyBase<T>(key),
254     mRead(read),
255     mAccessor(new DirectAccessor(ptr))
256   {
257   }
258
259   Property(const std::string& key, ReadFn read, Setter setter)
260   : PropertyBase<T>(key),
261     mRead(read),
262     mAccessor(new SetterAccessor(setter))
263   {
264   }
265
266   ~Property()
267   {
268   }
269
270   void Read(const json_value_s& j, T& obj) override
271   {
272     mAccessor->Set(mRead(j), obj);
273   }
274
275 private:
276   struct AccessorBase
277   {
278     virtual ~AccessorBase()
279     {
280     }
281
282     virtual void Set(U value, T& obj) const = 0;
283   };
284
285   struct DirectAccessor : AccessorBase
286   {
287     DirectAccessor(MemberPtr ptr)
288     : mPointer(ptr)
289     {
290     }
291
292     void Set(U value, T& obj) const override
293     {
294       obj.*mPointer = std::move(value);
295     }
296
297     MemberPtr mPointer;
298   };
299
300   struct SetterAccessor : AccessorBase
301   {
302     SetterAccessor(Setter setter)
303     : mSetter(setter)
304     {
305     }
306
307     void Set(U value, T& obj) const override
308     {
309       (obj.*mSetter)(value);
310     }
311
312     Setter mSetter;
313   };
314
315   ReadFn                        mRead;
316   std::unique_ptr<AccessorBase> mAccessor;
317 };
318
319 /**
320  * @brief Helper function to make a Property for a member of type U, of object of type T.
321  */
322 template<class T, typename U>
323 Property<T, U>* MakeProperty(const std::string& key, typename Property<T, U>::ReadFn readFn, U T::*ptr)
324 {
325   return new Property<T, U>(key, readFn, ptr);
326 }
327
328 /**
329  * @brief Core class for an object Reader.
330  */
331 struct ReaderCore
332 {
333 protected:
334   std::vector<void*> mProperties;
335
336   ReaderCore() = default;
337
338   ReaderCore(const ReaderCore& other) = delete;
339   ReaderCore& operator=(const ReaderCore& other) = delete;
340
341   ReaderCore(ReaderCore&& other) = default;
342   ReaderCore& operator=(ReaderCore&& other) = default;
343 };
344
345 /**
346  * @brief Object Reader template for reading into an object of a given type,
347  *  with properties registered for the various members.
348  */
349 template<typename T>
350 class Reader : protected ReaderCore
351 {
352 public:
353   Reader() = default;
354
355   Reader(const Reader<T>& other) = delete;
356   Reader<T>& operator=(const Reader<T>& other) = delete;
357
358   Reader(Reader<T>&& other) = default;
359   Reader<T>& operator=(Reader&& other) = default;
360
361   ~Reader()
362   {
363     for(auto& p : mProperties)
364     {
365       delete Cast(p);
366     }
367   }
368
369   Reader<T>& Register(PropertyBase<T>& prop)
370   {
371     auto iInsert = std::lower_bound(mProperties.begin(), mProperties.end(), &prop, SortPredicate);
372     if(iInsert == mProperties.end() || Cast(*iInsert)->GetKey() != prop.GetKey())
373     {
374       mProperties.insert(iInsert, &prop);
375     }
376     else
377     {
378       delete Cast(*iInsert);
379       *iInsert = &prop;
380     }
381     return *this;
382   }
383
384   void Read(const json_object_s& jo, T& obj) const
385   {
386     auto i = jo.start;
387     while(i)
388     {
389       auto iFind = std::lower_bound(mProperties.begin(), mProperties.end(), *i->name, FindPredicate);
390       if(iFind != mProperties.end())
391       {
392         auto prop = Cast(*iFind);
393         if(0 == StrCmp(*i->name, prop->GetKey()))
394         {
395           prop->Read(*i->value, obj);
396         }
397       }
398       i = i->next;
399     }
400   }
401
402 private:
403   static inline PropertyBase<T>* Cast(void* p)
404   {
405     return static_cast<PropertyBase<T>*>(p);
406   }
407
408   static bool SortPredicate(void* p, PropertyBase<T>* prop)
409   {
410     const auto prop0 = Cast(p);
411     return prop0->GetKey().compare(prop->GetKey()) < 0;
412   }
413
414   static bool FindPredicate(void* p, const json_string_s& key)
415   {
416     const auto prop = Cast(p);
417     return StrCmp(prop->GetKey(), key) < 0;
418   }
419 };
420
421 /**
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.
424  */
425 template<typename T>
426 struct ObjectReader
427 {
428   static const Reader<T>* sReader;
429
430   static T Read(const json_value_s& j)
431   {
432     T     result;
433     auto& jo = Cast<json_object_s>(j);
434     sReader->Read(jo, result);
435     return result;
436   }
437 };
438
439 template<typename T>
440 const Reader<T>* ObjectReader<T>::sReader = nullptr;
441
442 template<typename T>
443 void SetObjectReader(const Reader<T>& r)
444 {
445   ObjectReader<T>::sReader = &r;
446 }
447
448 } // namespace json
449
450 #endif //DALI_SCENE_LOADER_JSON_READER_H_