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

any.hxx
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
46namespace vigra {
47
48namespace detail {
49
50struct 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
63template <class T>
64struct 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
90struct 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) \
116template <> \
117struct 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
172VIGRA_ANY_OF_CONVERTIBLE(signed char )
173VIGRA_ANY_OF_CONVERTIBLE(signed short )
174VIGRA_ANY_OF_CONVERTIBLE(signed int )
175VIGRA_ANY_OF_CONVERTIBLE(signed long )
176VIGRA_ANY_OF_CONVERTIBLE(signed long long)
177
178VIGRA_ANY_OF_CONVERTIBLE(unsigned char )
179VIGRA_ANY_OF_CONVERTIBLE(unsigned short )
180VIGRA_ANY_OF_CONVERTIBLE(unsigned int )
181VIGRA_ANY_OF_CONVERTIBLE(unsigned long )
182VIGRA_ANY_OF_CONVERTIBLE(unsigned long long)
183
184VIGRA_ANY_OF_CONVERTIBLE(float )
185VIGRA_ANY_OF_CONVERTIBLE(double )
186VIGRA_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 */
230class Any
231{
232
234
235 public:
236
237 /** Construct empty 'Any' object.
238 */
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
Typesafe storage of arbitrary values.
Definition any.hxx:231
Any(Any const &other)
Definition any.hxx:252
Any()
Definition any.hxx:239
Any & operator=(Any const &other)
Definition any.hxx:269
T & get()
Definition any.hxx:368
void destroy()
Definition any.hxx:278
bool is_readable() const
Definition any.hxx:357
bool empty() const
Definition any.hxx:339
T read() const
Definition any.hxx:393
T const & get() const
Definition any.hxx:380
friend void swap(Any &l, Any &r)
Definition any.hxx:299
Any & operator=(T const &t)
Definition any.hxx:260
void swap(Any &other)
Definition any.hxx:285
Any(T const &t)
Definition any.hxx:246
bool is_type() const
Definition any.hxx:347
bool operator!=(Any const &other) const
Definition any.hxx:315
bool operator==(Any const &other) const
Definition any.hxx:307
Class for a single RGB value.
Definition rgbvalue.hxx:128

© 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.2