1 //******************************************************************
3 // Copyright 2014 Intel Corporation All Rights Reserved.
4 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 #ifndef __INTEL_OCPROPERTIES_H_20140708
7 #define __INTEL_OCPROPERTIES_H_20140708
21 #include <type_traits>
23 #include "OCException.h"
25 namespace OC { namespace OCReflect {
27 enum class property_type : uint8_t {
38 enum class property_attribute : uint8_t {
44 struct property_signature
46 OC::OCReflect::property_type type;
47 OC::OCReflect::property_attribute attribute;
51 : type(OC::OCReflect::property_type::nil),
52 attribute(OC::OCReflect::property_attribute::rw)
55 property_signature(const OC::OCReflect::property_type& type_)
57 attribute(OC::OCReflect::property_attribute::rw)
60 property_signature(const OC::OCReflect::property_type type_, const OC::OCReflect::property_attribute attribute_)
66 typedef std::vector<property_type> property_type_vector;
68 typedef std::vector<property_signature> property_signature_vector;
70 typedef std::vector<char> property_data;
72 typedef std::tuple<std::string, property_signature> named_property_binding;
73 typedef std::vector<named_property_binding> named_property_binding_vector;
75 typedef std::tuple<named_property_binding, property_data> property;
76 typedef std::tuple<property_signature, property_data> tagged_property; // eg. a return value
78 typedef std::vector<property> property_vector;
80 typedef std::function<property(property_vector)> bound_function;
84 // Great name, huh? Must be late in the day:
85 inline property_signature_vector typev2signaturev(const property_type_vector& ptv, const property_attribute pa = property_attribute::rw)
87 property_signature_vector psv(ptv.size());
89 std::transform(std::begin(ptv), std::end(ptv), std::back_inserter(psv),
90 [&pa](const property_type& pt) -> property_signature { return property_signature(pt, pa); });
99 // Helper for constructing sequences (like vector<property>) from a parameter pack:
100 template <typename SeqT, typename T>
101 SeqT make_seq(const T& x)
106 template <typename SeqT, typename T, typename ...TS>
107 SeqT make_seq(const T& x, const TS&... xs)
111 auto vs = make_seq<SeqT>(xs...);
113 s.insert(s.end(), std::make_move_iterator(vs.begin()), std::make_move_iterator(vs.end()));
118 } // namespace OC::OCReflect::detail
120 }} // namespace OC::OCReflect
123 namespace OC { namespace OCReflect {
125 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_type& pt);
126 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_attribute& pa);
127 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_signature& ps);
128 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property& p);
130 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_type_vector& pv);
131 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::property_vector& p);
133 std::ostream& operator<<(std::ostream& os, const OC::OCReflect::method_binding& mb);
135 }} // namespace OC::OCReflect
137 /* JFW: I wonder if I can do this...
138 constexpr OC::OCReflect::property_type map_property_type(bool)
140 return OC::OCReflect::property_type::boolean;
144 // Map concerete to property type enumerations:
145 namespace OC { namespace OCReflect {
147 template <typename T>
148 struct map_property_type
150 static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::INVALID);
154 struct map_property_type<bool>
156 static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::boolean);
160 struct map_property_type<int64_t>
162 static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::integer);
166 struct map_property_type<double>
168 static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::rational);
172 struct map_property_type<std::string>
174 static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::string);
178 struct map_property_type<const char *>
180 static const uint8_t value = static_cast<const uint8_t>(OC::OCReflect::property_type::string);
183 }} // namespace OC::OCReflect
186 // Sequence containers:
188 struct map_property_type< template <class T, class A> >
190 static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
194 struct map_property_type<std::vector>
196 static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
200 struct map_property_type<std::list>
202 static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
206 struct map_property_type<std::forward_list>
208 static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
212 struct map_property_type<std::deque>
214 static const uint8_t value = static_const<const uint8_t>(OC::OCReflect::property_type::list);
218 namespace OC { namespace OCReflect { namespace to_property {
220 OC::OCReflect::tagged_property convert(const bool& in);
221 OC::OCReflect::tagged_property convert(const int& in);
222 OC::OCReflect::tagged_property convert(const int64_t& in);
223 OC::OCReflect::tagged_property convert(const double& in);
224 OC::OCReflect::tagged_property convert(const std::string& in);
226 }}} // namespace OC::OCReflect::to_property
228 typedef std::tuple<OC::OCReflect::property_data::const_iterator, OC::OCReflect::property_data::const_iterator> pd_iter_tuple;
230 pd_iter_tuple consume_typecheck(const OC::OCReflect::property_type expected_pt, const OC::OCReflect::property_data& in);
232 namespace OC { namespace OCReflect { namespace from_property {
234 typedef OC::OCReflect::property_data::const_iterator pdci;
235 typedef std::tuple<pdci, pdci> pd_iter_pair;
237 /* We need to use a struct to get around the fact that we can't partially specialize against a
238 free function's signature-- nothing else special happening here: */
241 static void convert(const pd_iter_pair& in, bool& out)
243 out = static_cast<bool>(static_cast<int>(*(std::get<0>(in))));
246 static void convert(const pd_iter_pair& in, int64_t& out)
248 std::copy(std::get<0>(in), std::get<1>(in), reinterpret_cast<char *>(&out));
251 static void convert(const pd_iter_pair& in, double& out)
253 std::copy(std::get<0>(in), std::get<1>(in), reinterpret_cast<char *>(&out));
256 static void convert(const pd_iter_pair& in, std::string& out)
258 out.assign(std::get<0>(in), std::get<1>(in));
262 template <template <class T, class AllocT> class SeqT>
263 static void convert(const pd_iter_pair& in, SeqT& out)
265 std::copy(std::get<0>(in), std::get<1>(in), std::back_inserter(out));
271 }}} // namespace OC::OCReflect::from_property
273 namespace OC { namespace OCReflect {
275 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)
277 return OC::OCReflect::named_property_binding { name, { pt, pa } };
280 }} // namespace OC::OCReflect
282 // ...probably not-so-efficent, but we want it "working" for now:
283 namespace OC { namespace OCReflect {
285 // ...a class just to facilitate the usual ADL trick:
286 struct make_property {
288 // ...work around array->bool conversion:
289 static OC::OCReflect::property apply(const char *in, const std::string& name)
291 return apply(std::string(in), name);
295 static OC::OCReflect::property apply(const InT& in, const std::string& name)
298 static_assert(property_valid(InT, OC::OCReflect::property_type::INVALID),
299 "invalid input type for make_property()");
302 OC::OCReflect::tagged_property tp { OC::OCReflect::to_property::convert(in) };
303 OC::OCReflect::named_property_binding npb { name, { std::get<0>(tp) } };
305 OC::OCReflect::property_data& tp_data = std::get<1>(tp);
307 // Encode the type, followed by the data:
308 OC::OCReflect::property_data encoded_data;
310 encoded_data.push_back(OC::OCReflect::map_property_type<InT>::value);
311 std::copy(std::begin(tp_data), std::end(tp_data), std::back_inserter(encoded_data));
313 return OC::OCReflect::property(npb, encoded_data);
317 // Pretend you didn't see this, and I won't tell anyone where you hide the bodies:
319 make_property(const InT& in, const std::string& name, OC::OCReflect::property& out)
321 out = detail::make_property::apply(in, name, out);
325 }; // struct make_property
327 }} // namespace OC::OCReflect
329 namespace OC { namespace OCReflect {
331 template <class OutT>
332 OutT concretize(const OC::OCReflect::property_data& pd)
336 OC::OCReflect::from_property::conversion::convert(
338 static_cast<OC::OCReflect::property_type>(
339 OC::OCReflect::map_property_type<OutT>::value), pd), ret);
344 template <class OutT>
345 OutT concretize(const OC::OCReflect::tagged_property& tp)
347 return concretize<OutT>(std::get<1>(tp));
350 template <class OutT>
351 OutT concretize(const OC::OCReflect::property& p)
353 return concretize<OutT>(std::get<1>(p));
356 }} // namespace OC::OCReflect
358 namespace OC { namespace OCReflect {
360 // Runtime dynamic cast from entities to concrete types:
361 template <class OutT>
362 OutT narrow(const entity& e)
364 return OutT(); // placeholder
367 struct method_signature
369 property_signature ret_signature;
370 property_signature_vector param_signatures;
373 method_signature(const property_type& return_type, const property_signature_vector& param_types_)
374 : ret_signature(return_type, OC::OCReflect::property_attribute::r),
375 param_signatures(param_types_)
378 method_signature(const property_type& return_type, const property_type_vector& param_types_)
379 : ret_signature(return_type, OC::OCReflect::property_attribute::r),
380 param_signatures(detail::typev2signaturev(param_types_))
383 template <typename ...ParameterT>
384 method_signature(const property_type& return_type, const ParameterT& ...params_)
385 : ret_signature(return_type, OC::OCReflect::property_attribute::r),
386 param_signatures { detail::make_seq<property_signature_vector>(params_...) }
390 }} // namespace OC::OCReflect
392 namespace OC { namespace OCReflect {
394 struct method_binding
396 friend std::ostream& operator<<(std::ostream& os, const OC::OCReflect::method_binding& mb);
401 method_signature signature;
404 static unsigned long long anon;
408 : name("__ANONYMOUS__"),
409 signature { property_type::nil, {{ property_type::nil, property_attribute::r }} }
412 method_binding(bound_function& f,
413 method_signature& signature_)
414 : signature(signature_)
417 method_binding(const std::string& name_, bound_function& f_,
418 const property_type& return_type_, const property_type_vector& param_types_)
421 signature { return_type_, param_types_ }
424 method_binding(const std::string& name_, bound_function& f_,
425 const method_signature& signature_)
428 signature(signature_)
432 struct property_binding
434 template <typename PropertyT>
435 property_binding(PropertyT& property, const named_property_binding& pb)
440 }} // namespace OC::OCReflect