Pothos  0.4.1-gb758ed46
The Pothos dataflow programming software suite
ObjectImpl.hpp
Go to the documentation of this file.
1 
11 #pragma once
12 #include <Pothos/Config.hpp>
13 #include <Pothos/Object/Object.hpp>
14 #include <type_traits> //std::conditional, std::decay
15 #include <functional> //std::reference_wrapper
16 #include <cstdlib> //size_t
17 #include <utility> //std::forward
18 #include <atomic>
19 #include <iosfwd>
20 
21 namespace Pothos {
22 namespace Detail {
23 
24 /***********************************************************************
25  * meta-template foo to implement remove_reference_wrapper
26  * http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error
27  **********************************************************************/
28 template <typename T, bool C> struct extract_type_helper;
29 template <typename T> struct extract_type_helper<T, true>
30 {
31  typedef typename T::type type;
32 };
33 
34 template <typename T> struct extract_type_helper<T, false>
35 {
36  typedef T type;
37 };
38 
39 template <typename T>
40 class remove_reference_wrapper
41 {
42 private:
43  // Types "yes" and "no" are guaranteed to have different sizes
44  typedef char yes[1];
45  typedef char no[2];
46 
47  template <typename C>
48  static yes& test(typename C::type*);
49 
50  template <typename C>
51  static no& test(C *);
52 
53  static const bool has_type_field = sizeof(test<T>(nullptr)) == sizeof(yes);
54  typedef typename extract_type_helper<T, has_type_field>::type extracted_type;
55  typedef std::is_same<std::reference_wrapper<extracted_type>, T> is_reference_wrapper;
56 
57 public:
58  typedef typename std::conditional<is_reference_wrapper::value, extracted_type, T>::type type;
59 };
60 
61 /***********************************************************************
62  * ObjectContainer interface
63  **********************************************************************/
64 struct POTHOS_API ObjectContainer
65 {
66  ObjectContainer(void);
67 
68  virtual ~ObjectContainer(void);
69 
70  virtual const std::type_info &type(void) const = 0;
71  virtual const std::type_info &rawType(void) const = 0;
72 
73  std::atomic<int> counter;
74 
75  static void throwExtract(const Object &obj, const std::type_info &type);
76 
77  template <typename ValueType>
78  static ValueType &extract(const Object &obj);
79 
80  virtual void *get(void) const = 0; //opaque pointer to internal value
81 };
82 
83 /***********************************************************************
84  * ObjectContainer templated subclass
85  **********************************************************************/
86 template <typename ValueType>
87 struct ObjectContainerType
88 {
89  typedef typename std::conditional<
90  //is_copy_constructible doesnt seem to be standard,
91  //since we just use this for iostream anyway,
92  //use this conditional as a cheap replacement.
93  std::is_base_of<std::ios_base, ValueType>::value,
94  std::reference_wrapper<ValueType>, ValueType
95  >::type type;
96 };
97 
98 template <typename ValueType>
99 struct ObjectContainerT : ObjectContainer
100 {
101 
102  ObjectContainerT(void)
103  {
104  return;
105  }
106 
107  template <typename T>
108  ObjectContainerT(T &&value):
109  value(std::forward<T>(value))
110  {
111  return;
112  }
113 
114  ~ObjectContainerT(void)
115  {
116  return;
117  }
118 
123  const std::type_info &type(void) const
124  {
125  return typeid(typename remove_reference_wrapper<ValueType>::type);
126  }
127 
132  const std::type_info &rawType(void) const
133  {
134  return typeid(ValueType);
135  }
136 
137  typename ObjectContainerType<ValueType>::type value;
138 
139  void *get(void) const
140  {
141  return (void *)std::addressof(this->value);
142  }
143 };
144 
145 /***********************************************************************
146  * extract implementation with support for reference wrapper
147  **********************************************************************/
148 template <typename ValueType>
149 ValueType &ObjectContainer::extract(const Object &obj)
150 {
151  typedef typename std::decay<ValueType>::type DecayValueType;
152 
153  //Support for the special NullObject case when the _impl is nullptr:
154  if (obj._impl == nullptr and obj.type() == typeid(ValueType))
155  {
156  return *(reinterpret_cast<typename ObjectContainerType<DecayValueType>::type *>(0));
157  }
158 
159  //First check if the container is a reference wrapper of the ValueType.
160  //Handle this special case so we can treat reference wrappers like normal.
161  typedef std::reference_wrapper<DecayValueType> refWrapperType;
162  if (obj._impl != nullptr and obj._impl->rawType() == typeid(refWrapperType))
163  {
164  return *(reinterpret_cast<typename ObjectContainerType<refWrapperType>::type *>(obj._impl->get()));
165  }
166 
167  //Otherwise, check the type for a match and then extract the internal value
168  if (obj._impl != nullptr and obj.type() == typeid(ValueType))
169  {
170  return *(reinterpret_cast<typename ObjectContainerType<DecayValueType>::type *>(obj._impl->get()));
171  }
172 
173  Detail::ObjectContainer::throwExtract(obj, typeid(ValueType)); throw;
174 }
175 
176 /***********************************************************************
177  * template specialized factory for object containers
178  **********************************************************************/
179 template <typename ValueType>
180 ObjectContainer *makeObjectContainer(ValueType &&value)
181 {
182  return new ObjectContainerT<typename std::decay<ValueType>::type>(std::forward<ValueType>(value));
183 }
184 
190 inline ObjectContainer *makeObjectContainer(NullObject &&)
191 {
192  return nullptr;
193 }
194 
201 POTHOS_API ObjectContainer *makeObjectContainer(const char *s);
202 
203 } //namespace Detail
204 
205 template <typename ValueType>
206 Object Object::make(ValueType &&value)
207 {
208  Object o;
209  o._impl = Detail::makeObjectContainer(std::forward<ValueType>(value));
210  return o;
211 }
212 
213 template <typename ValueType>
214 Object::Object(ValueType &&value):
215  _impl(nullptr)
216 {
217  _impl = Detail::makeObjectContainer(std::forward<ValueType>(value));
218 }
219 
220 template <typename ValueType>
221 const ValueType &Object::extract(void) const
222 {
223  return Detail::ObjectContainer::extract<ValueType>(*this);
224 }
225 
226 template <typename ValueType>
227 ValueType Object::convert(void) const
228 {
229  Object newObj = this->convert(typeid(ValueType));
230  return newObj.extract<ValueType>();
231 }
232 
233 } //namespace Pothos
#define POTHOS_API
Definition: Config.hpp:41
static Object make(ValueType &&value)
Definition: ObjectImpl.hpp:206
Definition: Testing.hpp:134
const ValueType & extract(void) const
Definition: ObjectImpl.hpp:221
Detail::ObjectContainer * _impl
Private implementation details.
Definition: Object.hpp:258
Definition: Object.hpp:55
ValueType convert(void) const
Definition: ObjectImpl.hpp:227