[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

any.hxx VIGRA

1 /************************************************************************/
2 /* */
3 /* Copyright 2014-2015 by Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA2 computer vision library. */
6 /* The VIGRA2 Website is */
7 /* http://ukoethe.github.io/vigra2 */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35 
36 #pragma once
37 
38 #ifndef VIGRA_ANY_HXX
39 #define VIGRA_ANY_HXX
40 
41 #include "config.hxx"
42 #include "error.hxx"
43 #include <typeinfo>
44 #include <type_traits>
45 
46 namespace vigra {
47 
48 namespace detail {
49 
50 struct AnyHandle
51 {
52  AnyHandle() {}
53  virtual ~AnyHandle() {}
54  virtual const std::type_info & type() const = 0;
55  virtual AnyHandle * clone() const = 0;
56  virtual bool equal(AnyHandle const *) const = 0;
57 
58  private:
59  AnyHandle(AnyHandle const &);
60  AnyHandle & operator=(AnyHandle const &);
61 };
62 
63 template <class T>
64 struct TypedAnyHandle
65 : public AnyHandle
66 {
67  T value_;
68 
69  TypedAnyHandle(T const & t)
70  : value_(t)
71  {}
72 
73  const std::type_info & type() const
74  {
75  return typeid(T);
76  }
77 
78  AnyHandle * clone() const
79  {
80  return new TypedAnyHandle(value_);
81  }
82 
83  bool equal(AnyHandle const * h) const
84  {
85  TypedAnyHandle const * ptr = dynamic_cast<TypedAnyHandle const *>(h);
86  return ptr != 0 && value_ == ptr->value_;
87  }
88 };
89 
90 struct ConvertibleAnyHandle
91 : public AnyHandle
92 {
93  template <class T>
94  struct TypeTag {};
95 
96  ConvertibleAnyHandle() {}
97 
98  virtual signed char cast(TypeTag<signed char>) const = 0;
99  virtual signed short cast(TypeTag<signed short>) const = 0;
100  virtual signed int cast(TypeTag<signed int>) const = 0;
101  virtual signed long cast(TypeTag<signed long>) const = 0;
102  virtual signed long long cast(TypeTag<signed long long>) const = 0;
103 
104  virtual unsigned char cast(TypeTag<unsigned char>) const = 0;
105  virtual unsigned short cast(TypeTag<unsigned short>) const = 0;
106  virtual unsigned int cast(TypeTag<unsigned int>) const = 0;
107  virtual unsigned long cast(TypeTag<unsigned long>) const = 0;
108  virtual unsigned long long cast(TypeTag<unsigned long long>) const = 0;
109 
110  virtual float cast(TypeTag<float>) const = 0;
111  virtual double cast(TypeTag<double>) const = 0;
112  virtual long double cast(TypeTag<long double>) const = 0;
113 };
114 
115 #define VIGRA_ANY_OF_CONVERTIBLE(TYPE) \
116 template <> \
117 struct TypedAnyHandle<TYPE> \
118 : public ConvertibleAnyHandle \
119 { \
120  TYPE value_; \
121  \
122  TypedAnyHandle(TYPE const & t) \
123  : value_(t) \
124  {} \
125  \
126  const std::type_info & type() const \
127  { \
128  return typeid(value_); \
129  } \
130  \
131  AnyHandle * clone() const \
132  { \
133  return new TypedAnyHandle(value_); \
134  } \
135  \
136  bool equal(AnyHandle const * h) const \
137  { \
138  TypedAnyHandle const * ptr = dynamic_cast<TypedAnyHandle const *>(h); \
139  return ptr != 0 && value_ == ptr->value_; \
140  } \
141  \
142  virtual signed char cast(TypeTag<signed char>) const \
143  { return static_cast<signed char>(value_); } \
144  virtual signed short cast(TypeTag<signed short>) const \
145  { return static_cast<signed short>(value_); } \
146  virtual signed int cast(TypeTag<signed int>) const \
147  { return static_cast<signed int>(value_); } \
148  virtual signed long cast(TypeTag<signed long>) const \
149  { return static_cast<signed long>(value_); } \
150  virtual signed long long cast(TypeTag<signed long long>) const \
151  { return static_cast<signed long long>(value_); } \
152  \
153  virtual unsigned char cast(TypeTag<unsigned char>) const \
154  { return static_cast<unsigned char>(value_); } \
155  virtual unsigned short cast(TypeTag<unsigned short>) const \
156  { return static_cast<unsigned short>(value_); } \
157  virtual unsigned int cast(TypeTag<unsigned int>) const \
158  { return static_cast<unsigned int>(value_); } \
159  virtual unsigned long cast(TypeTag<unsigned long>) const \
160  { return static_cast<unsigned long>(value_); } \
161  virtual unsigned long long cast(TypeTag<unsigned long long>) const \
162  { return static_cast<unsigned long long>(value_); } \
163  \
164  virtual float cast(TypeTag<float>) const \
165  { return static_cast<float>(value_); } \
166  virtual double cast(TypeTag<double>) const \
167  { return static_cast<double>(value_); } \
168  virtual long double cast(TypeTag<long double>) const \
169  { return static_cast<long double>(value_); } \
170 };
171 
172 VIGRA_ANY_OF_CONVERTIBLE(signed char )
173 VIGRA_ANY_OF_CONVERTIBLE(signed short )
174 VIGRA_ANY_OF_CONVERTIBLE(signed int )
175 VIGRA_ANY_OF_CONVERTIBLE(signed long )
176 VIGRA_ANY_OF_CONVERTIBLE(signed long long)
177 
178 VIGRA_ANY_OF_CONVERTIBLE(unsigned char )
179 VIGRA_ANY_OF_CONVERTIBLE(unsigned short )
180 VIGRA_ANY_OF_CONVERTIBLE(unsigned int )
181 VIGRA_ANY_OF_CONVERTIBLE(unsigned long )
182 VIGRA_ANY_OF_CONVERTIBLE(unsigned long long)
183 
184 VIGRA_ANY_OF_CONVERTIBLE(float )
185 VIGRA_ANY_OF_CONVERTIBLE(double )
186 VIGRA_ANY_OF_CONVERTIBLE(long double)
187 
188 #undef VIGRA_ANY_OF_CONVERTIBLE
189 
190 } // namespace detail
191 
192  /** \brief Typesafe storage of arbitrary values.
193 
194  Items are always stored by value, but it is of course possible
195  to store pointers and smart pointers.
196 
197  <b>Usage:</b>
198 
199  \code
200  Any a(10); // store integer '10'
201 
202  assert(a.is_type<int>());
203  assert(a.is_convertible<int>());
204 
205  // retrieve the stored value (throws when types don't match)
206  assert(a.get<int>() == 10);
207 
208  // change the value
209  a = 20;
210  assert(a.get<int>() == 20);
211 
212  // values of arithmetic types can be converted into each other
213  // (this is currently not implemented for other types)
214  assert(a.is_convewrtible<double>());
215  assert(a.cast<double>() == 20.0);
216 
217  // delete the stored value
218  a.destroy();
219  assert(a.empty());
220  assert(a == false);
221 
222  // store a shared_ptr
223  typedef std::shared_ptr<int> Ptr;
224  Any p(Ptr(new int(5))), q = p;
225  assert(*(p.get<Ptr>()) == 5);
226  // the addresses of the elements in p and q are the same
227  assert(p.get<Ptr>().get() == p.get<Ptr>().get());
228  \endcode
229  */
230 class Any
231 {
232 
233  VIGRA_UNIQUE_PTR<detail::AnyHandle> handle_;
234 
235  public:
236 
237  /** Construct empty 'Any' object.
238  */
239  Any()
240  : handle_((detail::AnyHandle*)0)
241  {}
242 
243  /** Construct 'Any' object holding the given value.
244  */
245  template <class T>
246  Any(T const & t)
247  : handle_(new detail::TypedAnyHandle<T>(t))
248  {}
249 
250  /** Construct 'Any' object holding a copy of other's value.
251  */
252  Any(Any const & other)
253  : handle_(bool(other) ? other.handle_->clone() : (detail::AnyHandle*)0)
254  {}
255 
256  /** Assign the given value to this 'Any' object
257  (overwrites the old value, regardless of types).
258  */
259  template <class T>
260  Any & operator=(T const & t)
261  {
262  handle_.reset(new detail::TypedAnyHandle<T>(t));
263  return *this;
264  }
265 
266  /** Assign a copy of other's value to this 'Any' object
267  (overwrites the old value, regardless of types).
268  */
269  Any & operator=(Any const & other)
270  {
271  if(this != &other)
272  handle_.reset(bool(other) ? other.handle_->clone() : (detail::AnyHandle*)0);
273  return *this;
274  }
275 
276  /** Delete the contained object (make this 'Any' object empty).
277  */
278  void destroy()
279  {
280  handle_.reset((detail::AnyHandle*)0);
281  }
282 
283  /** Exchange the value of this object with other's.
284  */
285  void swap(Any & other)
286  {
287 #ifdef VIGRA_NO_UNIQUE_PTR // fallback for old compilers
288  detail::AnyHandle *t = handle_.release(),
289  *o = other.handle_.release();
290  handle_.reset(o);
291  other.handle_.reset(t);
292 #else
293  handle_.swap(other.handle_);
294 #endif
295  }
296 
297  /** Exchange the value of objects l and r.
298  */
299  friend void swap(Any & l, Any & r)
300  {
301  l.swap(r);
302  }
303 
304  /** Check if this object contains the same type and value as other.
305  Also true if both 'Any' objects are empty.
306  */
307  bool operator==(Any const & other) const
308  {
309  return (handle_.get() == 0 && other.handle_.get() == 0) ||
310  (handle_.get() != 0 && handle_->equal(other.handle_.get()));
311  }
312 
313  /** Check if this object differs from other by type or value.
314  */
315  bool operator!=(Any const & other) const
316  {
317  return !operator==(other);
318  }
319 
320  bool operator==(bool other) const
321  {
322  return bool(*this) == other;
323  }
324 
325  bool operator!=(bool other) const
326  {
327  return bool(*this) != other;
328  }
329 
330  /** Convert 'Any' to <tt>false</tt> if this object is empty, <tt>true</tt> otherwise.
331  */
332  operator bool() const
333  {
334  return handle_.get() != 0;
335  }
336 
337  /** Check if this object is empty (holds no value).
338  */
339  bool empty() const
340  {
341  return handle_.get() == 0;
342  }
343 
344  /** Check if this object holds a value of the given type.
345  */
346  template <class T>
347  bool is_type() const
348  {
349  return dynamic_cast<detail::TypedAnyHandle<T> const *>(handle_.get()) != 0;
350  }
351 
352  /** Check if this object's value is convertible to the given type.
353  At present, this only succeeds if <tt>T</tt> matches the stored
354  type exactly or is an arithmetic type convertible from the stored type.
355  */
356  template <class T>
357  bool is_readable() const
358  {
359  return (dynamic_cast<detail::TypedAnyHandle<T> const *>(handle_.get()) != 0) ||
360  (std::is_arithmetic<T>::value &&
361  dynamic_cast<detail::ConvertibleAnyHandle const *>(handle_.get()) != 0);
362  }
363 
364  /** Read-write access to the contained value. This throws an exception
365  if the types don't match.
366  */
367  template <class T>
368  T & get()
369  {
370  vigra_precondition(bool(*this), "Any::get(): object empty.");
371  auto ptr = dynamic_cast<detail::TypedAnyHandle<T> *>(handle_.get());
372  vigra_precondition(ptr != 0, "Any::get(): object is not an instance of the target type.");
373  return ptr->value_;
374  }
375 
376  /** Read-only access to the contained value. This throws an exception
377  if the types don't match.
378  */
379  template <class T>
380  T const & get() const
381  {
382  vigra_precondition(bool(*this), "Any::get(): object empty.");
383  auto ptr = dynamic_cast<detail::TypedAnyHandle<T> const *>(handle_.get());
384  vigra_precondition(ptr != 0, "Any::get(): object is not an instance of the target type.");
385  return ptr->value_;
386  }
387 
388  /** By-value access to the stored value. This throws an exception
389  if the stored type doesn't match <tt>T</tt> and <tt>T</tt> is
390  not an arithmetic type.
391  */
392  template <class T>
393  T read() const
394  {
395  vigra_precondition(bool(*this), "Any::read(): object empty.");
396  auto ptr1 = dynamic_cast<detail::TypedAnyHandle<T> const *>(handle_.get());
397  if(ptr1 != 0)
398  return ptr1->value_;
399  auto ptr2 = dynamic_cast<detail::ConvertibleAnyHandle const *>(handle_.get());
400  vigra_precondition(ptr2 != 0, "Any::read(): object is not covertible to the target type.");
401  return ptr2->cast(detail::ConvertibleAnyHandle::TypeTag<T>());
402  }
403 };
404 
405 } // namespace vigra
406 
407 #endif // VIGRA_ANY_HXX
bool operator==(Any const &other) const
Definition: any.hxx:307
Any & operator=(T const &t)
Definition: any.hxx:260
bool operator!=(Any const &other) const
Definition: any.hxx:315
bool is_type() const
Definition: any.hxx:347
Any(Any const &other)
Definition: any.hxx:252
friend void swap(Any &l, Any &r)
Definition: any.hxx:299
Any()
Definition: any.hxx:239
Any(T const &t)
Definition: any.hxx:246
T read() const
Definition: any.hxx:393
Typesafe storage of arbitrary values.
Definition: any.hxx:230
void destroy()
Definition: any.hxx:278
bool empty() const
Definition: any.hxx:339
void swap(Any &other)
Definition: any.hxx:285
Any & operator=(Any const &other)
Definition: any.hxx:269
bool is_readable() const
Definition: any.hxx:357

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.11.1 (Fri May 19 2017)