Updated license header to reference Apache 2.0 License
[platform/upstream/iotivity.git] / include / OCProperties.h
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Corporation 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 #ifndef __INTEL_OCPROPERTIES_H_20140708
22  #define __INTEL_OCPROPERTIES_H_20140708
23
24 #include <list>
25 #include <array>
26 #include <deque>
27 #include <vector>
28 #include <algorithm>
29 #include <functional>
30
31 #include <sstream>
32 #include <ostream>
33 #include <iostream>
34
35 #include <iterator>
36 #include <type_traits>
37
38 #include "OCException.h"
39
40 namespace OC { namespace OCReflect {
41
42 enum class property_type : uint8_t {
43     nil                 = 1,
44     boolean,
45     integer,
46     rational,
47     string,     
48     list,
49
50         INVALID
51 };
52
53 enum class property_attribute : uint8_t {
54     r,
55     w,
56     rw
57 };
58
59 struct property_signature
60 {
61  OC::OCReflect::property_type       type;
62  OC::OCReflect::property_attribute  attribute;
63
64  public:
65  property_signature()
66   : type(OC::OCReflect::property_type::nil),
67     attribute(OC::OCReflect::property_attribute::rw)
68  {}
69
70  property_signature(const OC::OCReflect::property_type& type_)
71   : type(type_),
72     attribute(OC::OCReflect::property_attribute::rw)
73  {}
74
75  property_signature(const OC::OCReflect::property_type type_, const OC::OCReflect::property_attribute attribute_)
76   : type(type_),
77     attribute(attribute_)
78  {}
79 };
80
81 typedef std::vector<property_type>                                                      property_type_vector;
82
83 typedef std::vector<property_signature>                     property_signature_vector;
84
85 typedef std::vector<char>                                   property_data;
86
87 typedef std::tuple<std::string, property_signature>         named_property_binding;
88 typedef std::vector<named_property_binding>                                     named_property_binding_vector;
89
90 typedef std::tuple<named_property_binding, property_data>   property;
91 typedef std::tuple<property_signature, property_data>       tagged_property;         // eg. a return value
92
93 typedef std::vector<property>                               property_vector;
94
95 typedef std::function<property(property_vector)>            bound_function;
96
97 namespace detail {
98
99 // Great name, huh? Must be late in the day:
100 inline property_signature_vector typev2signaturev(const property_type_vector& ptv, const property_attribute pa = property_attribute::rw)
101 {
102  property_signature_vector psv(ptv.size());
103
104  std::transform(std::begin(ptv), std::end(ptv), std::back_inserter(psv),
105                 [&pa](const property_type& pt) -> property_signature { return property_signature(pt, pa); });
106
107  return psv;
108 }
109
110 }
111
112 namespace detail {
113
114 // Helper for constructing sequences (like vector<property>) from a parameter pack:
115 template <typename SeqT, typename T>
116 SeqT make_seq(const T& x)
117 {
118  return SeqT { x };
119 }
120
121 template <typename SeqT, typename T, typename ...TS>
122 SeqT make_seq(const T& x, const TS&... xs)
123 {
124  SeqT s { x };
125
126  auto vs = make_seq<SeqT>(xs...);
127
128  s.insert(s.end(), std::make_move_iterator(vs.begin()), std::make_move_iterator(vs.end()));
129
130  return s;
131 }
132
133 } // namespace OC::OCReflect::detail
134
135 }} // namespace OC::OCReflect
136
137 // Prettyprinters:
138 namespace OC { namespace OCReflect {
139
140 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_type& pt);
141 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_attribute& pa);
142 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_signature& ps);
143 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property& p);
144
145 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_type_vector& pv);
146 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_vector& p);
147
148 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::method_binding& mb);
149
150 }} // namespace OC::OCReflect
151
152 /* JFW: I wonder if I can do this...
153 constexpr OC::OCReflect::property_type map_property_type(bool)
154 {
155  return OC::OCReflect::property_type::boolean;
156 }
157 */
158
159 // Map concerete to property type enumerations:
160 namespace OC { namespace OCReflect {
161
162 template <typename T>
163 struct map_property_type
164 {
165  static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::INVALID);
166 };
167
168 template <>
169 struct map_property_type<bool>
170 {
171  static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::boolean);
172 };
173
174 template <>
175 struct map_property_type<int64_t>
176 {
177  static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::integer);
178 };
179
180 template <>
181 struct map_property_type<double>
182 {
183  static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::rational);
184 };
185
186 template <>
187 struct map_property_type<std::string>
188 {
189  static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::string);
190 };
191
192 template <>
193 struct map_property_type<const char *>
194 {
195  static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::string);
196 };
197
198 }} // namespace OC::OCReflect
199
200 /*
201 // Sequence containers:
202 template <>
203 struct map_property_type< template <class T, class A> >
204 {
205  static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
206 };
207
208 template <>
209 struct map_property_type<std::vector>
210 {
211  static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
212 };
213
214 template <>
215 struct map_property_type<std::list>
216 {
217  static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
218 };
219
220 template <>
221 struct map_property_type<std::forward_list>
222 {
223  static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
224 };
225
226 template <>
227 struct map_property_type<std::deque>
228 {
229  static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
230 };
231 */
232
233 namespace OC { namespace OCReflect { namespace to_property {
234
235 OC::OCReflect::tagged_property convert(const bool& in);
236 OC::OCReflect::tagged_property convert(const int& in);
237 OC::OCReflect::tagged_property convert(const int64_t& in);
238 OC::OCReflect::tagged_property convert(const double& in);
239 OC::OCReflect::tagged_property convert(const std::string& in);
240
241 }}} // namespace OC::OCReflect::to_property
242
243 typedef std::tuple<OC::OCReflect::property_data::const_iterator, OC::OCReflect::property_data::const_iterator>  pd_iter_tuple;
244
245 pd_iter_tuple consume_typecheck(const OC::OCReflect::property_type expected_pt, const OC::OCReflect::property_data& in);
246
247 namespace OC { namespace OCReflect { namespace from_property {
248
249 typedef OC::OCReflect::property_data::const_iterator pdci;
250 typedef std::tuple<pdci, pdci>  pd_iter_pair;
251
252 /* We need to use a struct to get around the fact that we can't partially specialize against a
253 free function's signature-- nothing else special happening here: */
254 struct conversion {
255
256 static void convert(const pd_iter_pair& in, bool& out)
257 {
258  out = static_cast<bool>(static_cast<int>(*(std::get<0>(in))));
259 }
260
261 static void convert(const pd_iter_pair& in, int64_t& out)
262 {
263  std::copy(std::get<0>(in), std::get<1>(in), reinterpret_cast<char *>(&out));
264 }
265
266 static void convert(const pd_iter_pair& in, double& out)
267 {
268  std::copy(std::get<0>(in), std::get<1>(in), reinterpret_cast<char *>(&out));
269 }
270
271 static void convert(const pd_iter_pair& in, std::string& out)
272 {
273  out.assign(std::get<0>(in), std::get<1>(in));
274 }
275
276 /*
277 template <template <class T, class AllocT> class SeqT>
278 static void convert(const pd_iter_pair& in, SeqT& out)
279 {
280  std::copy(std::get<0>(in), std::get<1>(in), std::back_inserter(out));
281 }
282 */
283
284 };
285
286 }}} // namespace OC::OCReflect::from_property
287
288 namespace OC { namespace OCReflect {
289
290 inline OC::OCReflect::named_property_binding make_named_property_binding(const std::string& name, const OC::OCReflect::property_type pt, const OC::OCReflect::property_attribute pa = OC::OCReflect::property_attribute::rw)
291 {
292  return OC::OCReflect::named_property_binding { name, { pt, pa } };
293 }
294
295 }} // namespace OC::OCReflect
296
297 // ...probably not-so-efficent, but we want it "working" for now:
298 namespace OC { namespace OCReflect {
299
300 // ...a class just to facilitate the usual ADL trick:
301 struct make_property {
302
303 // ...work around array->bool conversion:
304 static OC::OCReflect::property apply(const char *in, const std::string& name)
305 {
306  return apply(std::string(in), name);
307 }
308
309 template <class InT>
310 static OC::OCReflect::property apply(const InT& in, const std::string& name)
311 {
312 /* JFW:
313  static_assert(property_valid(InT, OC::OCReflect::property_type::INVALID),
314                "invalid input type for make_property()");
315 */
316
317  OC::OCReflect::tagged_property         tp { OC::OCReflect::to_property::convert(in) };
318  OC::OCReflect::named_property_binding npb { name, { std::get<0>(tp) } };
319
320  OC::OCReflect::property_data& tp_data = std::get<1>(tp);
321
322  // Encode the type, followed by the data:
323  OC::OCReflect::property_data encoded_data;
324
325  encoded_data.push_back(OC::OCReflect::map_property_type<InT>::value);
326  std::copy(std::begin(tp_data), std::end(tp_data), std::back_inserter(encoded_data));
327
328  return OC::OCReflect::property(npb, encoded_data);
329 }
330
331 /*
332 // Pretend you didn't see this, and I won't tell anyone where you hide the bodies:
333 template <class InT>
334 make_property(const InT& in, const std::string& name, OC::OCReflect::property& out)
335 {
336  out = detail::make_property::apply(in, name, out);
337 }
338 */
339
340 }; // struct make_property
341
342 }} // namespace OC::OCReflect
343
344 namespace OC { namespace OCReflect {
345
346 template <class OutT>
347 OutT concretize(const OC::OCReflect::property_data& pd)
348 {
349  OutT ret;
350
351  OC::OCReflect::from_property::conversion::convert(
352         consume_typecheck(
353                 static_cast<OC::OCReflect::property_type>(
354                         OC::OCReflect::map_property_type<OutT>::value), pd), ret);
355
356  return ret;
357 }
358
359 template <class OutT>
360 OutT concretize(const OC::OCReflect::tagged_property& tp)
361 {
362  return concretize<OutT>(std::get<1>(tp));
363 }
364
365 template <class OutT>
366 OutT concretize(const OC::OCReflect::property& p)
367 {
368  return concretize<OutT>(std::get<1>(p));
369 }
370
371 }} // namespace OC::OCReflect
372
373 namespace OC { namespace OCReflect {
374
375 // Runtime dynamic cast from entities to concrete types:
376 template <class OutT>
377 OutT narrow(const entity& e)
378 {
379  return OutT(); // placeholder
380 }
381
382 struct method_signature
383 {
384  property_signature           ret_signature;
385  property_signature_vector    param_signatures;
386
387  public:
388  method_signature(const property_type& return_type, const property_signature_vector& param_types_)
389   : ret_signature(return_type, OC::OCReflect::property_attribute::r),
390     param_signatures(param_types_)
391  {}
392
393  method_signature(const property_type& return_type, const property_type_vector& param_types_)
394   : ret_signature(return_type, OC::OCReflect::property_attribute::r),
395     param_signatures(detail::typev2signaturev(param_types_))
396  {}
397
398  template <typename ...ParameterT>
399  method_signature(const property_type& return_type, const ParameterT& ...params_)
400   : ret_signature(return_type, OC::OCReflect::property_attribute::r),
401     param_signatures { detail::make_seq<property_signature_vector>(params_...) }
402  {}
403 };
404
405 }} // namespace OC::OCReflect
406
407 namespace OC { namespace OCReflect {
408
409 struct method_binding
410 {
411  friend std::ostream& operator<<(std::ostream& os, const OC::OCReflect::method_binding& mb);
412
413  public:
414  std::string            name;
415  bound_function         f;
416  method_signature       signature;
417
418  private:
419  static unsigned long long anon;
420
421  public: 
422  method_binding() 
423   : name("__ANONYMOUS__"), 
424     signature { property_type::nil, {{ property_type::nil, property_attribute::r }} }
425  {}
426
427  method_binding(bound_function& f,
428                 method_signature& signature_)
429   : signature(signature_)
430  {}
431
432  method_binding(const std::string& name_, bound_function& f_, 
433                 const property_type& return_type_, const property_type_vector& param_types_)
434   : name(name_),
435     f(f_),
436     signature { return_type_, param_types_ } 
437  {}
438
439  method_binding(const std::string& name_, bound_function& f_,
440                 const method_signature& signature_)
441   : name(name_),
442     f(f_),
443    signature(signature_)
444  {}
445 };
446
447 struct property_binding
448 {
449  template <typename PropertyT>
450  property_binding(PropertyT& property, const named_property_binding& pb)
451  {
452  }
453 };
454
455 }} // namespace OC::OCReflect
456
457 #endif