Pothos  0.1.1
The Pothos dataflow programming software suite
 All Classes Namespaces Files Functions Variables Typedefs Friends Macros
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  void *operator new(const size_t size);
71 
72  void operator delete(void *memory, const size_t size);
73 
74  virtual const std::type_info &type(void) const = 0;
75  virtual const std::type_info &rawType(void) const = 0;
76 
77  std::atomic<int> counter;
78 
79  static void throwExtract(const Object &obj, const std::type_info &type);
80 
81  template <typename ValueType>
82  static ValueType &extract(const Object &obj);
83 
84  virtual void *get(void) const = 0; //opaque pointer to internal value
85 };
86 
87 /***********************************************************************
88  * ObjectContainer templated subclass
89  **********************************************************************/
90 template <typename ValueType>
91 struct ObjectContainerType
92 {
93  typedef typename std::conditional<
94  //is_copy_constructible doesnt seem to be standard,
95  //since we just use this for iostream anyway,
96  //use this conditional as a cheap replacement.
97  std::is_base_of<std::ios_base, ValueType>::value,
98  std::reference_wrapper<ValueType>, ValueType
99  >::type type;
100 };
101 
102 template <typename ValueType>
103 struct ObjectContainerT : ObjectContainer
104 {
105 
106  ObjectContainerT(void)
107  {
108  return;
109  }
110 
111  template <typename T>
112  ObjectContainerT(T &&value):
113  value(std::forward<T>(value))
114  {
115  return;
116  }
117 
118  ~ObjectContainerT(void)
119  {
120  return;
121  }
122 
127  const std::type_info &type(void) const
128  {
129  return typeid(typename remove_reference_wrapper<ValueType>::type);
130  }
131 
136  const std::type_info &rawType(void) const
137  {
138  return typeid(ValueType);
139  }
140 
141  typename ObjectContainerType<ValueType>::type value;
142 
143  void *get(void) const
144  {
145  return (void *)std::addressof(this->value);
146  }
147 };
148 
149 /***********************************************************************
150  * extract implementation with support for reference wrapper
151  **********************************************************************/
152 template <typename ValueType>
153 ValueType &ObjectContainer::extract(const Object &obj)
154 {
155  typedef typename std::decay<ValueType>::type DecayValueType;
156 
157  //Support for the special NullObject case when the _impl is nullptr:
158  if (obj._impl == nullptr and obj.type() == typeid(ValueType))
159  {
160  return *(reinterpret_cast<typename ObjectContainerType<DecayValueType>::type *>(0));
161  }
162 
163  //First check if the container is a reference wrapper of the ValueType.
164  //Handle this special case so we can treat reference wrappers like normal.
165  typedef std::reference_wrapper<DecayValueType> refWrapperType;
166  if (obj._impl != nullptr and obj._impl->rawType() == typeid(refWrapperType))
167  {
168  return *(reinterpret_cast<typename ObjectContainerType<refWrapperType>::type *>(obj._impl->get()));
169  }
170 
171  //Otherwise, check the type for a match and then extract the internal value
172  if (obj._impl != nullptr and obj.type() == typeid(ValueType))
173  {
174  return *(reinterpret_cast<typename ObjectContainerType<DecayValueType>::type *>(obj._impl->get()));
175  }
176 
177  Detail::ObjectContainer::throwExtract(obj, typeid(ValueType)); throw;
178 }
179 
180 /***********************************************************************
181  * template specialized factory for object containers
182  **********************************************************************/
183 template <typename ValueType>
184 ObjectContainer *makeObjectContainer(ValueType &&value)
185 {
186  return new ObjectContainerT<typename std::decay<ValueType>::type>(std::forward<ValueType>(value));
187 }
188 
194 inline ObjectContainer *makeObjectContainer(NullObject &&)
195 {
196  return nullptr;
197 }
198 
205 POTHOS_API ObjectContainer *makeObjectContainer(const char *s);
206 
207 } //namespace Detail
208 
209 template <typename ValueType>
210 Object Object::make(ValueType &&value)
211 {
212  Object o;
213  o._impl = Detail::makeObjectContainer(std::forward<ValueType>(value));
214  return o;
215 }
216 
217 template <typename ValueType>
218 Object::Object(ValueType &&value):
219  _impl(nullptr)
220 {
221  _impl = Detail::makeObjectContainer(std::forward<ValueType>(value));
222 }
223 
224 template <typename ValueType>
225 const ValueType &Object::extract(void) const
226 {
227  return Detail::ObjectContainer::extract<ValueType>(*this);
228 }
229 
230 template <typename ValueType>
231 ValueType Object::convert(void) const
232 {
233  Object newObj = this->convert(typeid(ValueType));
234  return newObj.extract<ValueType>();
235 }
236 
237 } //namespace Pothos
#define POTHOS_API
Definition: Config.hpp:41
static Object make(ValueType &&value)
Definition: ObjectImpl.hpp:210
const ValueType & extract(void) const
Definition: ObjectImpl.hpp:225
Detail::ObjectContainer * _impl
Private implementation details.
Definition: Object.hpp:258
Definition: Object.hpp:55
ValueType convert(void) const
Definition: ObjectImpl.hpp:231