Worked Around GCC 4.6.3's Bool issue
[platform/upstream/iotivity.git] / resource / src / OCRepresentation.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH 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 /**
22  * @file
23  *
24  * This file contains the implementation of classes and its members related
25  * to OCRepresentation.
26  */
27
28
29 #include <OCRepresentation.h>
30
31 #include <boost/lexical_cast.hpp>
32 #include <algorithm>
33 #include "ocpayload.h"
34 #include "ocrandom.h"
35 #include "oic_malloc.h"
36 #include "oic_string.h"
37
38 namespace OC
39 {
40
41     void MessageContainer::setPayload(const OCPayload* rep)
42     {
43         switch(rep->type)
44         {
45             case PAYLOAD_TYPE_REPRESENTATION:
46                 setPayload(reinterpret_cast<const OCRepPayload*>(rep));
47                 break;
48             case PAYLOAD_TYPE_DEVICE:
49                 setPayload(reinterpret_cast<const OCDevicePayload*>(rep));
50                 break;
51             case PAYLOAD_TYPE_PLATFORM:
52                 setPayload(reinterpret_cast<const OCPlatformPayload*>(rep));
53                 break;
54             default:
55                 throw OC::OCException("Invalid Payload type in setPayload");
56                 break;
57         }
58     }
59
60     void MessageContainer::setPayload(const OCDevicePayload* payload)
61     {
62         OCRepresentation rep;
63         rep.setUri(payload->uri);
64         char uuidString[UUID_STRING_SIZE];
65         if(payload->sid && RAND_UUID_OK == OCConvertUuidToString(payload->sid, uuidString))
66         {
67             rep[OC_RSRVD_DEVICE_ID] = std::string(uuidString);
68         }
69         else
70         {
71             rep[OC_RSRVD_DEVICE_ID] = std::string();
72         }
73         rep[OC_RSRVD_DEVICE_NAME] = payload->deviceName ?
74             std::string(payload->deviceName) :
75             std::string();
76         rep[OC_RSRVD_SPEC_VERSION] = payload->specVersion ?
77             std::string(payload->specVersion) :
78             std::string();
79         rep[OC_RSRVD_DATA_MODEL_VERSION] = payload->dataModelVersion ?
80             std::string(payload->dataModelVersion) :
81             std::string();
82         m_reps.push_back(std::move(rep));
83     }
84
85     void MessageContainer::setPayload(const OCPlatformPayload* payload)
86     {
87         OCRepresentation rep;
88         rep.setUri(payload->uri);
89
90         rep[OC_RSRVD_PLATFORM_ID] = payload->info.platformID ?
91             std::string(payload->info.platformID) :
92             std::string();
93         rep[OC_RSRVD_MFG_NAME] = payload->info.manufacturerName ?
94             std::string(payload->info.manufacturerName) :
95             std::string();
96         rep[OC_RSRVD_MFG_URL] = payload->info.manufacturerUrl ?
97             std::string(payload->info.manufacturerUrl) :
98             std::string();
99         rep[OC_RSRVD_MODEL_NUM] = payload->info.modelNumber ?
100             std::string(payload->info.modelNumber) :
101             std::string();
102         rep[OC_RSRVD_MFG_DATE] = payload->info.dateOfManufacture ?
103             std::string(payload->info.dateOfManufacture) :
104             std::string();
105         rep[OC_RSRVD_PLATFORM_VERSION] = payload->info.platformVersion ?
106             std::string(payload->info.platformVersion) :
107             std::string();
108         rep[OC_RSRVD_OS_VERSION] = payload->info.operatingSystemVersion ?
109             std::string(payload->info.operatingSystemVersion) :
110             std::string();
111         rep[OC_RSRVD_HARDWARE_VERSION] = payload->info.hardwareVersion ?
112             std::string(payload->info.hardwareVersion) :
113             std::string();
114         rep[OC_RSRVD_FIRMWARE_VERSION] = payload->info.firmwareVersion ?
115             std::string(payload->info.firmwareVersion) :
116             std::string();
117         rep[OC_RSRVD_SUPPORT_URL] = payload->info.supportUrl ?
118             std::string(payload->info.supportUrl) :
119             std::string();
120         rep[OC_RSRVD_SYSTEM_TIME] = payload->info.systemTime ?
121             std::string(payload->info.systemTime) :
122             std::string();
123
124         m_reps.push_back(std::move(rep));
125     }
126
127     void MessageContainer::setPayload(const OCRepPayload* payload)
128     {
129         const OCRepPayload* pl = payload;
130         while(pl)
131         {
132             OCRepresentation cur;
133             cur.setPayload(pl);
134
135             pl = pl->next;
136             this->addRepresentation(cur);
137         }
138     }
139
140     OCRepPayload* MessageContainer::getPayload() const
141     {
142         OCRepPayload* root = nullptr;
143         for(const auto& r : representations())
144         {
145             if(!root)
146             {
147                 root = r.getPayload();
148             }
149             else
150             {
151                 OCRepPayloadAppend(root, r.getPayload());
152             }
153         }
154
155         return root;
156     }
157
158     const std::vector<OCRepresentation>& MessageContainer::representations() const
159     {
160         return m_reps;
161     }
162
163     void MessageContainer::addRepresentation(const OCRepresentation& rep)
164     {
165         m_reps.push_back(rep);
166     }
167 }
168
169 namespace OC
170 {
171     struct get_payload_array: boost::static_visitor<>
172     {
173         template<typename T>
174         void operator()(T& /*arr*/)
175         {
176             throw std::logic_error("Invalid calc_dimensions_visitor type");
177         }
178
179         template<typename T>
180         void operator()(std::vector<T>& arr)
181         {
182             root_size_calc<T>();
183             dimensions[0] = arr.size();
184             dimTotal = calcDimTotal(dimensions);
185
186             array = (void*)OICMalloc(dimTotal * root_size);
187
188             for(size_t i = 0; i < dimensions[0]; ++i)
189             {
190                 copy_to_array(arr[i], array, i);
191             }
192
193         }
194         template<typename T>
195         void operator()(std::vector<std::vector<T>>& arr)
196         {
197             root_size_calc<T>();
198             dimensions[0] = arr.size();
199             for(size_t i = 0; i < arr.size(); ++i)
200             {
201                 dimensions[1] = std::max(dimensions[1], arr[i].size());
202             }
203             dimTotal = calcDimTotal(dimensions);
204             array = (void*)OICCalloc(1, dimTotal * root_size);
205
206             for(size_t i = 0; i < dimensions[0]; ++i)
207             {
208                 for(size_t j = 0; j < dimensions[1] && j < arr[i].size(); ++j)
209                 {
210                     copy_to_array(arr[i][j], array, i*dimensions[1] + j);
211                 }
212             }
213         }
214         template<typename T>
215         void operator()(std::vector<std::vector<std::vector<T>>>& arr)
216         {
217             root_size_calc<T>();
218             dimensions[0] = arr.size();
219             for(size_t i = 0; i < arr.size(); ++i)
220             {
221                 dimensions[1] = std::max(dimensions[1], arr[i].size());
222
223                 for(size_t j = 0; j < arr[i].size(); ++j)
224                 {
225                     dimensions[2] = std::max(dimensions[2], arr[i][j].size());
226                 }
227             }
228
229             dimTotal = calcDimTotal(dimensions);
230             array = (void*)OICCalloc(1, dimTotal * root_size);
231
232             for(size_t i = 0; i < dimensions[0]; ++i)
233             {
234                 for(size_t j = 0; j < dimensions[1] && j < arr[i].size(); ++j)
235                 {
236                     for(size_t k = 0; k < dimensions[2] && k < arr[i][j].size(); ++k)
237                     {
238                         copy_to_array(arr[i][j][k], array,
239                                 dimensions[2] * j +
240                                 dimensions[2] * dimensions[1] * i +
241                                 k);
242                     }
243                 }
244             }
245         }
246
247         template<typename T>
248         void root_size_calc()
249         {
250             root_size = sizeof(T);
251         }
252
253         template<typename T>
254         void copy_to_array(T item, void* array, size_t pos)
255         {
256             ((T*)array)[pos] = item;
257         }
258
259         size_t dimensions[MAX_REP_ARRAY_DEPTH];
260         size_t root_size;
261         size_t dimTotal;
262         void* array;
263     };
264
265     template<>
266     void get_payload_array::root_size_calc<int>()
267     {
268         root_size = sizeof(int64_t);
269     }
270
271     template<>
272     void get_payload_array::root_size_calc<std::string>()
273     {
274         root_size = sizeof(char*);
275     }
276
277     template<>
278     void get_payload_array::root_size_calc<OC::OCRepresentation>()
279     {
280         root_size = sizeof(OCRepPayload*);
281     }
282
283     template<>
284     void get_payload_array::copy_to_array(int item, void* array, size_t pos)
285     {
286         ((int64_t*)array)[pos] = item;
287     }
288
289     template<>
290     void get_payload_array::copy_to_array(std::_Bit_reference br, void* array, size_t pos)
291     {
292         ((bool*)array)[pos] = static_cast<bool>(br);
293     }
294
295     template<>
296     void get_payload_array::copy_to_array(const std::string& item, void* array, size_t pos)
297     {
298         ((char**)array)[pos] = OICStrdup(item.c_str());
299     }
300
301     template<>
302     void get_payload_array::copy_to_array(OC::OCRepresentation item, void* array, size_t pos)
303     {
304         ((OCRepPayload**)array)[pos] = item.getPayload();
305     }
306
307     void OCRepresentation::getPayloadArray(OCRepPayload* payload,
308                     const OCRepresentation::AttributeItem& item) const
309     {
310         get_payload_array vis{};
311         boost::apply_visitor(vis, m_values[item.attrname()]);
312
313
314         switch(item.base_type())
315         {
316             case AttributeType::Integer:
317                 OCRepPayloadSetIntArrayAsOwner(payload, item.attrname().c_str(),
318                         (int64_t*)vis.array,
319                         vis.dimensions);
320                 break;
321             case AttributeType::Double:
322                 OCRepPayloadSetDoubleArrayAsOwner(payload, item.attrname().c_str(),
323                         (double*)vis.array,
324                         vis.dimensions);
325                 break;
326             case AttributeType::Boolean:
327                 OCRepPayloadSetBoolArrayAsOwner(payload, item.attrname().c_str(),
328                         (bool*)vis.array,
329                         vis.dimensions);
330                 break;
331             case AttributeType::String:
332                 OCRepPayloadSetStringArrayAsOwner(payload, item.attrname().c_str(),
333                         (char**)vis.array,
334                         vis.dimensions);
335                 break;
336             case AttributeType::OCRepresentation:
337                 OCRepPayloadSetPropObjectArrayAsOwner(payload, item.attrname().c_str(),
338                         (OCRepPayload**)vis.array, vis.dimensions);
339                 break;
340             default:
341                 throw std::logic_error(std::string("GetPayloadArray: Not Implemented") +
342                         std::to_string((int)item.base_type()));
343         }
344     }
345
346     OCRepPayload* OCRepresentation::getPayload() const
347     {
348         OCRepPayload* root = OCRepPayloadCreate();
349         if(!root)
350         {
351             throw std::bad_alloc();
352         }
353
354         OCRepPayloadSetUri(root, getUri().c_str());
355
356         for(const std::string& type : getResourceTypes())
357         {
358             OCRepPayloadAddResourceType(root, type.c_str());
359         }
360
361         for(const std::string& iface : getResourceInterfaces())
362         {
363             OCRepPayloadAddInterface(root, iface.c_str());
364         }
365
366         for(auto& val : *this)
367         {
368             switch(val.type())
369             {
370                 case AttributeType::Null:
371                     OCRepPayloadSetNull(root, val.attrname().c_str());
372                     break;
373                 case AttributeType::Integer:
374                     OCRepPayloadSetPropInt(root, val.attrname().c_str(), static_cast<int>(val));
375                     break;
376                 case AttributeType::Double:
377                     OCRepPayloadSetPropDouble(root, val.attrname().c_str(),
378                             val.getValue<double>());
379                     break;
380                 case AttributeType::Boolean:
381                     OCRepPayloadSetPropBool(root, val.attrname().c_str(), val.getValue<bool>());
382                     break;
383                 case AttributeType::String:
384                     OCRepPayloadSetPropString(root, val.attrname().c_str(),
385                             static_cast<std::string>(val).c_str());
386                     break;
387                 case AttributeType::OCRepresentation:
388                     OCRepPayloadSetPropObjectAsOwner(root, val.attrname().c_str(),
389                             static_cast<OCRepresentation>(val).getPayload());
390                     break;
391                 case AttributeType::Vector:
392                     getPayloadArray(root, val);
393                     break;
394                 default:
395                     throw std::logic_error(std::string("Getpayload: Not Implemented") +
396                             std::to_string((int)val.type()));
397                     break;
398             }
399         }
400
401         OCRepPayload* cur = root;
402         for(auto& child : this->getChildren())
403         {
404             cur->next = child.getPayload();
405             cur = cur->next;
406         }
407
408         return root;
409     }
410
411     size_t calcArrayDepth(const size_t dimensions[MAX_REP_ARRAY_DEPTH])
412     {
413         if(dimensions[0] == 0)
414         {
415             throw std::logic_error("invalid calcArrayDepth");
416         }
417         else if(dimensions[1] == 0)
418         {
419             return 1;
420         }
421         else if (dimensions[2] == 0)
422         {
423             return 2;
424         }
425         else
426         {
427             return 3;
428         }
429     }
430
431     template<typename T>
432     T OCRepresentation::payload_array_helper_copy(size_t index, const OCRepPayloadValue* pl)
433     {
434         throw std::logic_error("payload_array_helper_copy: unsupported type");
435     }
436     template<>
437     int OCRepresentation::payload_array_helper_copy<int>(size_t index, const OCRepPayloadValue* pl)
438     {
439         return pl->arr.iArray[index];
440     }
441     template<>
442     double OCRepresentation::payload_array_helper_copy<double>(size_t index, const OCRepPayloadValue* pl)
443     {
444         return pl->arr.dArray[index];
445     }
446     template<>
447     bool OCRepresentation::payload_array_helper_copy<bool>(size_t index, const OCRepPayloadValue* pl)
448     {
449         return pl->arr.bArray[index];
450     }
451     template<>
452     std::string OCRepresentation::payload_array_helper_copy<std::string>(
453             size_t index, const OCRepPayloadValue* pl)
454     {
455         return std::string(pl->arr.strArray[index]);
456     }
457     template<>
458     OCRepresentation OCRepresentation::payload_array_helper_copy<OCRepresentation>(
459             size_t index, const OCRepPayloadValue* pl)
460     {
461         OCRepresentation r;
462         r.setPayload(pl->arr.objArray[index]);
463         return r;
464     }
465
466     template<typename T>
467     void OCRepresentation::payload_array_helper(const OCRepPayloadValue* pl, size_t depth)
468     {
469         if(depth == 1)
470         {
471             std::vector<T> val(pl->arr.dimensions[0]);
472
473             for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
474             {
475                 val[i] = payload_array_helper_copy<T>(i, pl);
476             }
477             this->setValue(std::string(pl->name), val);
478         }
479         else if (depth == 2)
480         {
481             std::vector<std::vector<T>> val(pl->arr.dimensions[0]);
482             for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
483             {
484                 val[i].reserve(pl->arr.dimensions[1]);
485                 for(size_t j = 0; j < pl->arr.dimensions[1]; ++j)
486                 {
487                     val[i][j] = payload_array_helper_copy<T>(
488                             i * pl->arr.dimensions[1] + j, pl);
489                 }
490             }
491             this->setValue(std::string(pl->name), val);
492         }
493         else if (depth == 3)
494         {
495             std::vector<std::vector<std::vector<T>>> val;
496             for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
497             {
498                 val[i].reserve(pl->arr.dimensions[1]);
499                 for(size_t j = 0; j < pl->arr.dimensions[1]; ++j)
500                 {
501                     val[i][j].reserve(pl->arr.dimensions[2]);
502                     for(size_t k = 0; k < pl->arr.dimensions[2]; ++k)
503                     {
504                         val[i][j][k] = payload_array_helper_copy<T>(
505                                 pl->arr.dimensions[2] * j +
506                                 pl->arr.dimensions[2] * pl->arr.dimensions[1] * i +
507                                 k,
508                                 pl);
509                     }
510                 }
511             }
512             this->setValue(std::string(pl->name), val);
513         }
514         else
515         {
516             throw std::logic_error("Invalid depth in payload_array_helper");
517         }
518     }
519
520     void OCRepresentation::setPayloadArray(const OCRepPayloadValue* pl)
521     {
522
523         switch(pl->arr.type)
524         {
525             case OCREP_PROP_INT:
526                 payload_array_helper<int>(pl, calcArrayDepth(pl->arr.dimensions));
527                 break;
528             case OCREP_PROP_DOUBLE:
529                 payload_array_helper<double>(pl, calcArrayDepth(pl->arr.dimensions));
530                 break;
531             case OCREP_PROP_BOOL:
532                 payload_array_helper<bool>(pl, calcArrayDepth(pl->arr.dimensions));
533                 break;
534             case OCREP_PROP_STRING:
535                 payload_array_helper<std::string>(pl, calcArrayDepth(pl->arr.dimensions));
536                 break;
537             case OCREP_PROP_OBJECT:
538                 payload_array_helper<OCRepresentation>(pl, calcArrayDepth(pl->arr.dimensions));
539                 break;
540             default:
541                 throw std::logic_error("setPayload array invalid type");
542                 break;
543         }
544     }
545
546     void OCRepresentation::setPayload(const OCRepPayload* pl)
547     {
548         setUri(pl->uri);
549
550         OCStringLL* ll = pl->types;
551         while(ll)
552         {
553             addResourceType(ll->value);
554             ll = ll->next;
555         }
556
557         ll = pl->interfaces;
558         while(ll)
559         {
560             addResourceInterface(ll->value);
561             ll = ll->next;
562         }
563
564         OCRepPayloadValue* val = pl->values;
565
566         while(val)
567         {
568             switch(val->type)
569             {
570                 case OCREP_PROP_NULL:
571                     setNULL(val->name);
572                     break;
573                 case OCREP_PROP_INT:
574                     setValue<int>(val->name, val->i);
575                     break;
576                 case OCREP_PROP_DOUBLE:
577                     setValue<double>(val->name, val->d);
578                     break;
579                 case OCREP_PROP_BOOL:
580                     setValue<bool>(val->name, val->b);
581                     break;
582                 case OCREP_PROP_STRING:
583                     setValue<std::string>(val->name, val->str);
584                     break;
585                 case OCREP_PROP_OBJECT:
586                     {
587                         OCRepresentation cur;
588                         cur.setPayload(val->obj);
589                         setValue<OCRepresentation>(val->name, cur);
590                     }
591                     break;
592                 case OCREP_PROP_ARRAY:
593                     setPayloadArray(val);
594                     break;
595                 default:
596                     throw std::logic_error(std::string("Not Implemented!") +
597                             std::to_string((int)val->type));
598                     break;
599             }
600             val = val->next;
601         }
602     }
603
604     void OCRepresentation::addChild(const OCRepresentation& rep)
605     {
606         m_children.push_back(rep);
607     }
608
609     void OCRepresentation::clearChildren()
610     {
611         m_children.clear();
612     }
613
614     const std::vector<OCRepresentation>& OCRepresentation::getChildren() const
615     {
616         return m_children;
617     }
618
619     void OCRepresentation::setChildren(const std::vector<OCRepresentation>& children)
620     {
621         m_children = children;
622     }
623     void OCRepresentation::setUri(const char* uri)
624     {
625         m_uri = uri ? uri : "";
626     }
627
628     void OCRepresentation::setUri(const std::string& uri)
629     {
630         m_uri = uri;
631     }
632
633     std::string OCRepresentation::getUri() const
634     {
635         return m_uri;
636     }
637
638     const std::vector<std::string>& OCRepresentation::getResourceTypes() const
639     {
640         return m_resourceTypes;
641     }
642
643     void OCRepresentation::setResourceTypes(const std::vector<std::string>& resourceTypes)
644     {
645         m_resourceTypes = resourceTypes;
646     }
647
648     void OCRepresentation::addResourceType(const std::string& str)
649     {
650         m_resourceTypes.push_back(str);
651     }
652
653     const std::vector<std::string>& OCRepresentation::getResourceInterfaces() const
654     {
655         return m_interfaces;
656     }
657
658     void OCRepresentation::addResourceInterface(const std::string& str)
659     {
660         m_interfaces.push_back(str);
661     }
662
663     void OCRepresentation::setResourceInterfaces(const std::vector<std::string>& resourceInterfaces)
664     {
665         m_interfaces = resourceInterfaces;
666     }
667
668     bool OCRepresentation::hasAttribute(const std::string& str) const
669     {
670         return m_values.find(str) != m_values.end();
671     }
672
673     bool OCRepresentation::emptyData() const
674     {
675         // This logic is meant to determine whether based on the JSON serialization rules
676         // if this object will result in empty JSON.  URI is only serialized if there is valid
677         // data, ResourceType and Interfaces are only serialized if we are a nothing, a
678         // child of a default or link item.
679         // Our values array is only printed in the if we are the child of a Batch resource,
680         // the parent in a 'default' situation, or not in a child/parent relationship.
681         if(!m_uri.empty())
682         {
683             return false;
684         }
685         else if ((m_interfaceType == InterfaceType::None
686                         || m_interfaceType==InterfaceType::DefaultChild
687                         || m_interfaceType==InterfaceType::LinkChild)
688                     && (m_resourceTypes.size()>0 || m_interfaces.size()>0))
689         {
690             return false;
691         }
692         else if((m_interfaceType == InterfaceType::None
693                         || m_interfaceType == InterfaceType::BatchChild
694                         || m_interfaceType == InterfaceType::DefaultParent)
695                     && m_values.size()>0)
696         {
697             return false;
698         }
699
700         if(m_children.size() > 0)
701         {
702             return false;
703         }
704
705         return true;
706     }
707
708     int OCRepresentation::numberOfAttributes() const
709     {
710         return m_values.size();
711     }
712
713     bool OCRepresentation::erase(const std::string& str)
714     {
715         return m_values.erase(str);
716     }
717
718     void OCRepresentation::setNULL(const std::string& str)
719     {
720         m_values[str] = OC::NullType();
721     }
722
723     bool OCRepresentation::isNULL(const std::string& str) const
724     {
725         auto x = m_values.find(str);
726
727         if(m_values.end() != x)
728         {
729             return x->second.which() == AttributeValueNullIndex;
730         }
731         else
732         {
733             throw OCException(OC::Exception::INVALID_ATTRIBUTE+ str);
734         }
735     }
736 }
737
738 namespace OC
739 {
740     std::ostream& operator <<(std::ostream& os, const AttributeType at)
741     {
742         switch(at)
743         {
744             case AttributeType::Null:
745                 os << "Null";
746                 break;
747             case AttributeType::Integer:
748                 os << "Integer";
749                 break;
750             case AttributeType::Double:
751                 os << "Double";
752                 break;
753             case AttributeType::Boolean:
754                 os << "Boolean";
755                 break;
756             case AttributeType::String:
757                 os << "String";
758                 break;
759             case AttributeType::OCRepresentation:
760                 os << "OCRepresentation";
761                 break;
762             case AttributeType::Vector:
763                 os << "Vector";
764                 break;
765         }
766         return os;
767     }
768 }
769
770 // STL Container For OCRepresentation
771 namespace OC
772 {
773     OCRepresentation::AttributeItem::AttributeItem(const std::string& name,
774             std::map<std::string, AttributeValue>& vals):
775             m_attrName(name), m_values(vals){}
776
777     OCRepresentation::AttributeItem OCRepresentation::operator[](const std::string& key)
778     {
779         OCRepresentation::AttributeItem attr{key, m_values};
780         return std::move(attr);
781     }
782
783     const OCRepresentation::AttributeItem OCRepresentation::operator[](const std::string& key) const
784     {
785         OCRepresentation::AttributeItem attr{key, m_values};
786         return std::move(attr);
787     }
788
789     const std::string& OCRepresentation::AttributeItem::attrname() const
790     {
791         return m_attrName;
792     }
793
794     template<typename T, typename = void>
795     struct type_info
796     {
797         // contains the actual type
798         typedef T type;
799         // contains the inner most vector-type
800         typedef T base_type;
801         // contains the AttributeType for this item
802         constexpr static AttributeType enum_type =
803             AttributeTypeConvert<T>::type;
804         // contains the AttributeType for this base-type
805         constexpr static AttributeType enum_base_type =
806             AttributeTypeConvert<T>::type;
807         // depth of the vector
808         constexpr static size_t depth = 0;
809     };
810
811     template<typename T>
812     struct type_info<T, typename std::enable_if<is_vector<T>::value>::type>
813     {
814         typedef T type;
815         typedef typename type_info<typename T::value_type>::base_type base_type;
816         constexpr static AttributeType enum_type = AttributeType::Vector;
817         constexpr static AttributeType enum_base_type =
818             type_info<typename T::value_type>::enum_base_type;
819         constexpr static size_t depth = 1 +
820             type_info<typename T::value_type>::depth;
821     };
822
823     struct type_introspection_visitor : boost::static_visitor<>
824     {
825         AttributeType type;
826         AttributeType base_type;
827         size_t depth;
828
829         type_introspection_visitor() : boost::static_visitor<>(),
830             type(AttributeType::Null), base_type(AttributeType::Null), depth(0){}
831
832         template <typename T>
833         void operator()(T const& /*item*/)
834         {
835             type = type_info<T>::enum_type;
836             base_type = type_info<T>::enum_base_type;
837             depth = type_info<T>::depth;
838         }
839     };
840
841     AttributeType OCRepresentation::AttributeItem::type() const
842     {
843         type_introspection_visitor vis;
844         boost::apply_visitor(vis, m_values[m_attrName]);
845         return vis.type;
846     }
847
848     AttributeType OCRepresentation::AttributeItem::base_type() const
849     {
850         type_introspection_visitor vis;
851         boost::apply_visitor(vis, m_values[m_attrName]);
852         return vis.base_type;
853     }
854
855     size_t OCRepresentation::AttributeItem::depth() const
856     {
857         type_introspection_visitor vis;
858         boost::apply_visitor(vis, m_values[m_attrName]);
859         return vis.depth;
860     }
861
862     OCRepresentation::iterator OCRepresentation::begin()
863     {
864         return OCRepresentation::iterator(m_values.begin(), m_values);
865     }
866
867     OCRepresentation::const_iterator OCRepresentation::begin() const
868     {
869          return OCRepresentation::const_iterator(m_values.begin(), m_values);
870     }
871
872     OCRepresentation::const_iterator OCRepresentation::cbegin() const
873     {
874         return OCRepresentation::const_iterator(m_values.cbegin(), m_values);
875     }
876
877     OCRepresentation::iterator OCRepresentation::end()
878     {
879         return OCRepresentation::iterator(m_values.end(), m_values);
880     }
881
882     OCRepresentation::const_iterator OCRepresentation::end() const
883     {
884         return OCRepresentation::const_iterator(m_values.end(), m_values);
885     }
886
887     OCRepresentation::const_iterator OCRepresentation::cend() const
888     {
889         return OCRepresentation::const_iterator(m_values.cend(), m_values);
890     }
891
892     size_t OCRepresentation::size() const
893     {
894         return m_values.size();
895     }
896
897     bool OCRepresentation::empty() const
898     {
899         return m_values.empty();
900     }
901
902     bool OCRepresentation::iterator::operator==(const OCRepresentation::iterator& rhs) const
903     {
904         return m_iterator == rhs.m_iterator;
905     }
906
907     bool OCRepresentation::iterator::operator!=(const OCRepresentation::iterator& rhs) const
908     {
909         return m_iterator != rhs.m_iterator;
910     }
911
912     bool OCRepresentation::const_iterator::operator==(
913             const OCRepresentation::const_iterator& rhs) const
914     {
915         return m_iterator == rhs.m_iterator;
916     }
917
918     bool OCRepresentation::const_iterator::operator!=(
919             const OCRepresentation::const_iterator& rhs) const
920     {
921         return m_iterator != rhs.m_iterator;
922     }
923
924     OCRepresentation::iterator::reference OCRepresentation::iterator::operator*()
925     {
926         return m_item;
927     }
928
929     OCRepresentation::const_iterator::const_reference
930         OCRepresentation::const_iterator::operator*() const
931     {
932         return m_item;
933     }
934
935     OCRepresentation::iterator::pointer OCRepresentation::iterator::operator->()
936     {
937         return &m_item;
938     }
939
940     OCRepresentation::const_iterator::const_pointer
941         OCRepresentation::const_iterator::operator->() const
942     {
943         return &m_item;
944     }
945
946     OCRepresentation::iterator& OCRepresentation::iterator::operator++()
947     {
948         m_iterator++;
949         if(m_iterator != m_item.m_values.end())
950         {
951             m_item.m_attrName = m_iterator->first;
952         }
953         else
954         {
955             m_item.m_attrName = "";
956         }
957         return *this;
958     }
959
960     OCRepresentation::const_iterator& OCRepresentation::const_iterator::operator++()
961     {
962         m_iterator++;
963         if(m_iterator != m_item.m_values.end())
964         {
965             m_item.m_attrName = m_iterator->first;
966         }
967         else
968         {
969             m_item.m_attrName = "";
970         }
971         return *this;
972     }
973
974     OCRepresentation::iterator OCRepresentation::iterator::operator++(int)
975     {
976         OCRepresentation::iterator itr(*this);
977         ++(*this);
978         return itr;
979     }
980
981     OCRepresentation::const_iterator OCRepresentation::const_iterator::operator++(int)
982     {
983         OCRepresentation::const_iterator itr(*this);
984         ++(*this);
985         return itr;
986     }
987
988     struct to_string_visitor : boost::static_visitor<>
989     {
990         std::string str;
991         template <typename T>
992         void operator()(T const& item)
993         {
994             str = boost::lexical_cast<std::string>(item);
995         }
996
997         template <typename T>
998         void operator()(std::vector<T> const& item)
999         {
1000             to_string_visitor vis;
1001             std::ostringstream stream;
1002             stream << "[";
1003
1004             for(const auto& i : item)
1005             {
1006                 vis(i);
1007                 stream << vis.str  << " ";
1008             }
1009             stream << "]";
1010             str = stream.str();
1011         }
1012     };
1013
1014     template<>
1015     void to_string_visitor::operator()(bool const& item)
1016     {
1017         str = item ? "true" : "false";
1018     }
1019
1020     template<>
1021     void to_string_visitor::operator()(std::string const& item)
1022     {
1023         str = item;
1024     }
1025
1026     template<>
1027     void to_string_visitor::operator()(NullType const& /*item*/)
1028     {
1029         str = "(null)";
1030     }
1031
1032     template<>
1033     void to_string_visitor::operator()(OCRepresentation const& /*item*/)
1034     {
1035         str = "OC::OCRepresentation";
1036     }
1037
1038     std::string OCRepresentation::getValueToString(const std::string& key) const
1039     {
1040         auto x = m_values.find(key);
1041         if(x != m_values.end())
1042         {
1043             to_string_visitor vis;
1044             boost::apply_visitor(vis, x->second);
1045             return std::move(vis.str);
1046         }
1047
1048         return "";
1049     }
1050
1051     std::string OCRepresentation::AttributeItem::getValueToString() const
1052     {
1053         to_string_visitor vis;
1054         boost::apply_visitor(vis, m_values[m_attrName]);
1055         return std::move(vis.str);
1056     }
1057
1058     std::ostream& operator<<(std::ostream& os, const OCRepresentation::AttributeItem& ai)
1059     {
1060         os << ai.getValueToString();
1061         return os;
1062     }
1063 }
1064