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