Refine toString method of RCSResourceAttributes
[platform/upstream/iotivity.git] / service / resource-encapsulation / src / common / primitiveResource / src / RCSResourceAttributes.cpp
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include "RCSResourceAttributes.h"
22
23 #include <sstream>
24
25 #include "ResourceAttributesUtils.h"
26 #include "ResourceAttributesConverter.h"
27
28 #include "boost/lexical_cast.hpp"
29 #include "boost/mpl/advance.hpp"
30 #include "boost/mpl/size.hpp"
31 #include "boost/mpl/deref.hpp"
32
33 namespace
34 {
35
36     using namespace OIC::Service;
37
38     class ToStringVisitor: public boost::static_visitor<>
39     {
40     public:
41         ToStringVisitor() = default;
42         ToStringVisitor(const ToStringVisitor&) = delete;
43         ToStringVisitor(ToStringVisitor&&) = delete;
44
45         ToStringVisitor& operator=(const ToStringVisitor&) = delete;
46         ToStringVisitor& operator=(ToStringVisitor&&) = delete;
47
48         template< typename T >
49         void operator()(const T& value)
50         {
51             m_stream << boost::lexical_cast< std::string >(value);
52         }
53
54         template< typename T >
55         void operator()(const std::vector< T >& v)
56         {
57             m_stream << "[";
58             for (auto it = v.begin(); it != v.end(); ++it)
59             {
60                 if (it != v.begin()) m_stream << ", ";
61                 (*this)(*it);
62             }
63             m_stream << "]";
64         }
65
66         void operator()(std::nullptr_t)
67         {
68             m_stream << "";
69         }
70
71         void operator()(bool value)
72         {
73             m_stream << (value ? "true" : "false");
74         }
75
76         void operator()(const std::string& value)
77         {
78             m_stream << "\"" + value + "\"";
79         }
80
81         void operator()(const RCSResourceAttributes& attrs)
82         {
83             m_stream << "{";
84             for (auto it = attrs.begin(); it != attrs.end(); ++it)
85             {
86                 if (it != attrs.begin()) m_stream << ", ";
87                 m_stream << "\"" << it->key() << "\" : " << it->value().toString();
88             }
89             m_stream << "}";
90         }
91
92         std::string get() const {
93             return m_stream.str();
94         }
95
96     private:
97         std::ostringstream m_stream;
98     };
99
100     class TypeVisitor: public boost::static_visitor< RCSResourceAttributes::Type >
101     {
102     public:
103         TypeVisitor() = default;
104         TypeVisitor(const TypeVisitor&) = delete;
105         TypeVisitor(TypeVisitor&&) = delete;
106
107         TypeVisitor& operator=(const TypeVisitor&) = delete;
108         TypeVisitor& operator=(TypeVisitor&&) = delete;
109
110         template< typename T >
111         RCSResourceAttributes::Type operator()(const T& value) const
112         {
113             return RCSResourceAttributes::Type::typeOf(value);
114         }
115
116     };
117
118     template< int >
119     struct Int2Type {};
120
121     template< typename T >
122     struct TypeInfoConverter;
123
124     template< >
125     struct TypeInfoConverter< int >
126     {
127         static constexpr RCSResourceAttributes::TypeId typeId = RCSResourceAttributes::TypeId::INT;
128     };
129
130     template< >
131     struct TypeInfoConverter< std::nullptr_t >
132     {
133         static constexpr RCSResourceAttributes::TypeId typeId =
134                 RCSResourceAttributes::TypeId::NULL_T;
135     };
136
137     template< >
138     struct TypeInfoConverter< double >
139     {
140         static constexpr RCSResourceAttributes::TypeId typeId =
141                 RCSResourceAttributes::TypeId::DOUBLE;
142     };
143
144     template< >
145     struct TypeInfoConverter< bool >
146     {
147         static constexpr RCSResourceAttributes::TypeId typeId = RCSResourceAttributes::TypeId::BOOL;
148     };
149
150     template< >
151     struct TypeInfoConverter< std::string >
152     {
153         static constexpr RCSResourceAttributes::TypeId typeId =
154                 RCSResourceAttributes::TypeId::STRING;
155     };
156
157     template< >
158     struct TypeInfoConverter< RCSResourceAttributes >
159     {
160         static constexpr RCSResourceAttributes::TypeId typeId =
161                 RCSResourceAttributes::TypeId::ATTRIBUTES;
162     };
163
164     template< typename T >
165     struct TypeInfoConverter< std::vector< T > >
166     {
167         static constexpr RCSResourceAttributes::TypeId typeId =
168                 RCSResourceAttributes::TypeId::VECTOR;
169     };
170
171     template< typename T >
172     struct SequenceTraits
173     {
174         static constexpr size_t depth = 0;
175         typedef T base_type;
176     };
177
178     template< typename T >
179     struct SequenceTraits< std::vector< T > >
180     {
181         static constexpr size_t depth = SequenceTraits< T >::depth + 1;
182         typedef typename SequenceTraits< T >::base_type base_type;
183     };
184
185     struct TypeInfo
186     {
187         RCSResourceAttributes::TypeId m_typeId;
188         RCSResourceAttributes::Type m_baseType;
189         size_t m_depth;
190
191         template< typename T, typename ST = SequenceTraits < T > >
192         constexpr static TypeInfo get()
193         {
194             return { TypeInfoConverter< T >::typeId ,
195                     RCSResourceAttributes::Type::typeOf< typename ST::base_type >(), ST::depth };
196         }
197
198         template< typename VARIANT, int POS >
199         constexpr static TypeInfo get()
200         {
201             typedef typename boost::mpl::begin< typename VARIANT::types >::type mpl_begin;
202             typedef typename boost::mpl::advance< mpl_begin, boost::mpl::int_< POS > >::type iter;
203
204             return get< typename boost::mpl::deref< iter >::type >();
205         }
206     };
207
208     template< typename VARIANT, int POS >
209     constexpr inline std::vector< TypeInfo > getTypeInfo(Int2Type< POS >) noexcept
210     {
211         auto vec = getTypeInfo< VARIANT >(Int2Type< POS - 1 >{ });
212         vec.push_back(TypeInfo::get< VARIANT, POS >());
213         return vec;
214     }
215
216     template< typename VARIANT >
217     constexpr inline std::vector< TypeInfo > getTypeInfo(Int2Type< 0 >) noexcept
218     {
219         return { TypeInfo::get< VARIANT, 0 >() };
220     }
221
222     template< typename VARIANT >
223     inline TypeInfo getTypeInfo(int which) noexcept
224     {
225         static constexpr size_t variantSize = boost::mpl::size< typename VARIANT::types >::value;
226         static constexpr size_t variantEnd = variantSize - 1;
227         static const std::vector< TypeInfo > typeInfos = getTypeInfo< VARIANT >(
228                 Int2Type< variantEnd >{ });
229
230         static_assert(variantSize > 0, "Variant has no type!");
231
232         return typeInfos[which];
233     }
234
235 } // unnamed namespace
236
237
238 namespace OIC
239 {
240     namespace Service
241     {
242
243         RCSResourceAttributes::Value::ComparisonHelper::ComparisonHelper(const Value& v) :
244                 m_valueRef(v)
245         {
246         }
247
248         bool RCSResourceAttributes::Value::ComparisonHelper::operator==
249                 (const Value::ComparisonHelper& rhs) const
250         {
251             return *m_valueRef.m_data == *rhs.m_valueRef.m_data;
252         }
253
254         bool operator==(const RCSResourceAttributes::Type& lhs,
255                 const RCSResourceAttributes::Type& rhs) noexcept
256         {
257             return lhs.m_which == rhs.m_which;
258         }
259
260         bool operator!=(const RCSResourceAttributes::Type& lhs,
261                 const RCSResourceAttributes::Type& rhs) noexcept
262         {
263             return !(lhs == rhs);
264         }
265
266         bool operator==(const RCSResourceAttributes::Value::ComparisonHelper& lhs,
267                 const RCSResourceAttributes::Value::ComparisonHelper& rhs)
268         {
269             return lhs.operator==(rhs);
270         }
271
272         bool operator!=(const RCSResourceAttributes::Value::ComparisonHelper& lhs,
273                 const RCSResourceAttributes::Value::ComparisonHelper& rhs)
274         {
275             return !lhs.operator==(rhs);
276         }
277
278         bool operator==(const RCSResourceAttributes& lhs, const RCSResourceAttributes& rhs)
279         {
280             return lhs.m_values == rhs.m_values;
281         }
282
283         bool operator!=(const RCSResourceAttributes& lhs, const RCSResourceAttributes& rhs)
284         {
285             return !(lhs == rhs);
286         }
287
288         auto RCSResourceAttributes::Type::getId() const noexcept -> TypeId
289         {
290             return ::getTypeInfo< ValueVariant >(m_which).m_typeId;
291         }
292
293         auto RCSResourceAttributes::Type::getBaseTypeId(const Type& t) noexcept -> TypeId
294         {
295             return ::getTypeInfo< ValueVariant >(t.m_which).m_baseType.getId();
296         }
297
298         size_t RCSResourceAttributes::Type::getDepth(const Type& t) noexcept
299         {
300             return ::getTypeInfo< ValueVariant >(t.m_which).m_depth;
301         }
302
303
304         RCSResourceAttributes::Value::Value() :
305                 m_data{ new ValueVariant{} }
306         {
307         }
308
309         RCSResourceAttributes::Value::Value(const Value& from) :
310                 m_data{ new ValueVariant{ *from.m_data } }
311         {
312         }
313
314         RCSResourceAttributes::Value::Value(Value&& from) noexcept :
315                 m_data{ new ValueVariant{} }
316         {
317             m_data.swap(from.m_data);
318         }
319
320         RCSResourceAttributes::Value::Value(const char* value) :
321                 m_data{ new ValueVariant{ std::string{ value } } }
322         {
323         }
324
325         auto RCSResourceAttributes::Value::operator=(const Value& rhs) -> Value&
326         {
327             *m_data = *rhs.m_data;
328             return *this;
329         }
330
331         auto RCSResourceAttributes::Value::operator=(Value&& rhs) -> Value&
332         {
333             *m_data = ValueVariant{};
334             m_data->swap(*rhs.m_data);
335             return *this;
336         }
337
338         auto RCSResourceAttributes::Value::operator=(const char* rhs) -> Value&
339         {
340             *m_data = std::string{ rhs };
341             return *this;
342         }
343
344         auto RCSResourceAttributes::Value::operator=(std::nullptr_t) -> Value&
345         {
346             *m_data = nullptr;
347             return *this;
348         }
349
350         auto RCSResourceAttributes::Value::getType() const -> Type
351         {
352             return boost::apply_visitor(TypeVisitor(), *m_data);
353         }
354
355         std::string RCSResourceAttributes::Value::toString() const
356         {
357             ToStringVisitor visitor;
358             boost::apply_visitor(visitor, *m_data);
359             return visitor.get();
360         }
361
362         void RCSResourceAttributes::Value::swap(Value& rhs) noexcept
363         {
364             m_data.swap(rhs.m_data);
365         }
366
367         auto RCSResourceAttributes::KeyValuePair::KeyVisitor::operator()(
368                 iterator* iter) const noexcept -> result_type
369         {
370             return iter->m_cur->first;
371         }
372
373         auto RCSResourceAttributes::KeyValuePair::KeyVisitor::operator()(
374                 const_iterator* iter) const noexcept -> result_type
375         {
376             return iter->m_cur->first;
377         }
378
379         auto RCSResourceAttributes::KeyValuePair::ValueVisitor::operator() (iterator* iter) noexcept
380                 -> result_type
381         {
382             return iter->m_cur->second;
383         }
384
385         auto RCSResourceAttributes::KeyValuePair::ValueVisitor::operator() (const_iterator*)
386                 -> result_type
387         {
388             // should not reach here.
389             throw RCSBadGetException("");
390         }
391
392         auto RCSResourceAttributes::KeyValuePair::ConstValueVisitor::operator()(
393                 iterator*iter) const noexcept -> result_type
394         {
395             return iter->m_cur->second;
396         }
397
398         auto RCSResourceAttributes::KeyValuePair::ConstValueVisitor::operator()(
399                 const_iterator* iter) const noexcept -> result_type
400         {
401             return iter->m_cur->second;
402         }
403
404         auto RCSResourceAttributes::KeyValuePair::key() const noexcept -> const std::string&
405         {
406             return boost::apply_visitor(m_keyVisitor, m_iterRef);
407         }
408
409         auto RCSResourceAttributes::KeyValuePair::value() const noexcept -> const Value&
410         {
411             return boost::apply_visitor(m_constValueVisitor, m_iterRef);
412         }
413
414         auto RCSResourceAttributes::KeyValuePair::value() -> Value&
415         {
416             return boost::apply_visitor(m_valueVisitor, m_iterRef);
417         }
418
419         RCSResourceAttributes::KeyValuePair::KeyValuePair(boost::variant<iterator*,
420                 const_iterator*>&& ref) noexcept :
421                 m_iterRef{ ref }
422         {
423         }
424
425
426         RCSResourceAttributes::iterator::iterator() :
427                 m_cur{ base_iterator{ } },
428                 m_keyValuePair{ this }
429         {
430         }
431
432         RCSResourceAttributes::iterator::iterator(base_iterator&& iter) :
433                 m_cur{ std::move(iter) },
434                 m_keyValuePair{ this }
435         {
436         }
437
438         auto RCSResourceAttributes::iterator::operator*() -> KeyValuePair&
439         {
440             return m_keyValuePair;
441         }
442
443         auto RCSResourceAttributes::iterator::iterator::operator->() -> KeyValuePair*
444         {
445             return &m_keyValuePair;
446         }
447
448         auto RCSResourceAttributes::iterator::operator++() -> iterator&
449         {
450             ++m_cur;
451             return *this;
452         }
453
454         auto RCSResourceAttributes::iterator::operator++(int) -> iterator
455         {
456             iterator iter(*this);
457             ++(*this);
458             return iter;
459         }
460
461         bool RCSResourceAttributes::iterator::operator==(const iterator& rhs) const
462         {
463             return m_cur == rhs.m_cur;
464         }
465
466         bool RCSResourceAttributes::iterator::operator!=(const iterator& rhs) const
467         {
468             return !(*this == rhs);
469         }
470
471
472         RCSResourceAttributes::const_iterator::const_iterator() :
473                 m_cur{ base_iterator{} }, m_keyValuePair{ this }
474         {
475         }
476
477         RCSResourceAttributes::const_iterator::const_iterator(base_iterator&& iter) :
478                 m_cur{ iter }, m_keyValuePair{ this }
479         {
480         }
481
482         RCSResourceAttributes::const_iterator::const_iterator(
483                 const RCSResourceAttributes::iterator& iter) :
484                 m_cur{ iter.m_cur }, m_keyValuePair{ this }
485         {
486         }
487
488         auto RCSResourceAttributes::const_iterator::operator=(
489                 const RCSResourceAttributes::iterator& iter) -> const_iterator&
490         {
491             m_cur = iter.m_cur;
492             return *this;
493         }
494
495         auto RCSResourceAttributes::const_iterator::operator*() const -> reference
496         {
497             return m_keyValuePair;
498         }
499
500         auto RCSResourceAttributes::const_iterator::operator->() const -> pointer
501         {
502             return &m_keyValuePair;
503         }
504
505         auto RCSResourceAttributes::const_iterator::operator++() -> const_iterator&
506         {
507             ++m_cur;
508             return *this;
509         }
510
511         auto RCSResourceAttributes::const_iterator::operator++(int) -> const_iterator
512         {
513             const_iterator iter(*this);
514             ++(*this);
515             return iter;
516         }
517
518         bool RCSResourceAttributes::const_iterator::operator==(const const_iterator& rhs) const
519         {
520             return m_cur == rhs.m_cur;
521         }
522
523         bool RCSResourceAttributes::const_iterator::operator!=(const const_iterator& rhs) const
524         {
525             return !(*this == rhs);
526         }
527
528
529         auto RCSResourceAttributes::begin() noexcept -> iterator
530         {
531             return iterator{ m_values.begin() };
532         }
533
534         auto RCSResourceAttributes::end() noexcept -> iterator
535         {
536             return iterator{ m_values.end() };
537         }
538
539         auto RCSResourceAttributes::begin() const noexcept -> const_iterator
540         {
541             return const_iterator{ m_values.begin() };
542         }
543
544         auto RCSResourceAttributes::end() const noexcept -> const_iterator
545         {
546             return const_iterator{ m_values.end() };
547         }
548
549         auto RCSResourceAttributes::cbegin() const noexcept -> const_iterator
550         {
551             return const_iterator{ m_values.begin() };
552         }
553
554         auto RCSResourceAttributes::cend() const noexcept -> const_iterator
555         {
556             return const_iterator{ m_values.end() };
557         }
558
559         auto RCSResourceAttributes::operator[](const std::string& key) -> Value&
560         {
561             return m_values[key];
562         }
563
564         auto RCSResourceAttributes::operator[](std::string&& key) -> Value&
565         {
566             return m_values[std::move(key)];
567         }
568
569         auto RCSResourceAttributes::at(const std::string& key) -> Value&
570         {
571             try
572             {
573                 return m_values.at(key);
574             }
575             catch (const std::out_of_range&)
576             {
577                 throw RCSInvalidKeyException{ "No attribute named '" + key + "'" };
578             }
579         }
580
581         auto RCSResourceAttributes::at(const std::string& key) const -> const Value&
582         {
583             try
584             {
585                 return m_values.at(key);
586             }
587             catch (const std::out_of_range&)
588             {
589                 throw RCSInvalidKeyException{ "No attribute named '" + key + "'" };
590             }
591         }
592
593         void RCSResourceAttributes::clear() noexcept
594         {
595             return m_values.clear();
596         }
597
598         bool RCSResourceAttributes::erase(const std::string& key)
599         {
600             return m_values.erase(key) == 1U;
601         }
602
603         bool RCSResourceAttributes::contains(const std::string& key) const
604         {
605             return m_values.find(key) != m_values.end();
606         }
607
608         bool RCSResourceAttributes::empty() const noexcept
609         {
610             return m_values.empty();
611         }
612
613         size_t RCSResourceAttributes::size() const noexcept
614         {
615             return m_values.size();
616         }
617
618
619         bool acceptableAttributeValue(const RCSResourceAttributes::Value& dest,
620                 const RCSResourceAttributes::Value& value)
621         {
622             if (dest.getType() != value.getType())
623             {
624                 return false;
625             }
626
627             static_assert(RCSResourceAttributes::is_supported_type< RCSResourceAttributes >::value,
628                     "RCSResourceAttributes doesn't have RCSResourceAttributes recursively.");
629             if (dest.getType().getId() == RCSResourceAttributes::TypeId::ATTRIBUTES
630                     && !acceptableAttributes(dest.get< RCSResourceAttributes >(),
631                             value.get< RCSResourceAttributes >()))
632             {
633                 return false;
634             }
635
636             return true;
637         }
638
639         bool acceptableAttributes(const RCSResourceAttributes& dest, const RCSResourceAttributes& attr)
640         {
641             for (const auto& kv : attr)
642             {
643                 if (!dest.contains(kv.key()))
644                 {
645                     return false;
646                 }
647
648                 if (!acceptableAttributeValue(dest.at(kv.key()), kv.value()))
649                 {
650                     return false;
651                 }
652             }
653
654             return true;
655         }
656
657         AttrKeyValuePairs replaceAttributes(RCSResourceAttributes& dest,
658                 const RCSResourceAttributes& newAttrs)
659         {
660             AttrKeyValuePairs replacedList;
661
662             for (const auto& kv : newAttrs)
663             {
664                 if (dest[kv.key()] != kv.value())
665                 {
666                     RCSResourceAttributes::Value replacedValue;
667                     replacedValue.swap(dest[kv.key()]);
668                     dest[kv.key()] = kv.value();
669
670                     replacedList.push_back(AttrKeyValuePair{ kv.key(), std::move(replacedValue) });
671                 }
672             }
673
674             return replacedList;
675         }
676
677     }
678 }