1 /*=========================================================================
4 Module: $RCSfile: bbtkAny.h,v $
6 Date: $Date: 2008/01/22 15:02:00 $
7 Version: $Revision: 1.1 $
9 Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10 l'Image). All rights reserved. See doc/license.txt or
11 http://www.creatis.insa-lyon.fr/Public/bbtk/License.html for details.
13 This software is distributed WITHOUT ANY WARRANTY; without even
14 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 PURPOSE. See the above copyright notices for more information.
17 =========================================================================*/
20 *\brief Defines the class any which can store any type of data (adapted from boost::any).
22 #ifndef __BBTKANY_H_INCLUDED__
23 #define __BBTKANY_H_INCLUDED__
38 #include "bbtkMessageManager.h"
39 #include "bbtkException.h"
42 #include <boost/type_traits/is_pointer.hpp>
52 //=========================================================
53 /// Abstract class used by the any class to store values
58 virtual ~anyplaceholder() {}
62 /// returns the type of the held value
63 virtual const std::type_info & type() const = 0;
64 /// returns the type of the pointed held value
65 virtual const std::type_info & pointed_type() const = 0;
67 /// returns true iff the stored value is a pointer
68 virtual bool is_pointer() const = 0;
70 /// If the held value is a pointer then
72 virtual void* get_pointer() const = 0;
75 virtual void* get_pointer_to( const std::type_info& ) const = 0;
77 virtual anyplaceholder * clone() const = 0;
80 //=========================================================
82 //=========================================================
83 /// Concrete template class used by the any class to store values
84 /// which stores a value of type ValueType
85 template<typename ValueType>
86 class anyholder : public anyplaceholder
90 anyholder(const ValueType & value)
96 virtual const std::type_info & type() const { return typeid(ValueType);}
97 virtual bool is_pointer() const { return false; }
98 virtual const std::type_info & pointed_type() const { return typeid(void); }
99 virtual void* get_pointer() const { return 0; }
100 virtual void* get_pointer_to( const std::type_info& ) const { return 0; }
101 virtual anyplaceholder * clone() const { return new anyholder(held); }
103 public: // representation
108 //=========================================================
110 //=========================================================
111 /// specialization of anyholder for pointer types
112 template<typename ValueType>
113 class anyholder<ValueType*> : public anyplaceholder
117 anyholder(ValueType* const & value)
123 virtual const std::type_info & type() const
125 return typeid(ValueType*);
128 virtual bool is_pointer() const { return true; }
129 virtual const std::type_info & pointed_type() const { return typeid(ValueType); }
130 virtual void* get_pointer() const {
133 virtual void* get_pointer_to( const std::type_info& t) const
135 return run_time_up_or_down_cast(t,typeid(ValueType),held);
138 virtual anyplaceholder * clone() const { return new anyholder(held); }
140 public: // representation
145 //=========================================================
148 /** A magic class which can store any type of data which
149 * is allowed by the template template parameter TypeTrait.
151 * The only requirement on TypeTrait<T> is to have the member :
152 * static const bool value;
153 * which is true iff the type T is an allowed type
155 * TypeTraits compliant objects are usually template structs
156 * for which the initialisation of value is set to false by default
157 * and set to true for the allowed types (template specialisation)
159 * template <typename T> struct mytypes { static const bool value; };
160 * template <typename T> const bool mytypes<T>::value = false;
161 * template <> const bool mytypes<int>::value = true;
162 * template <> const bool mytypes<float>::value = true;
164 * You can use any boost type_trait, like is_pointer, is_floating_point, etc.
166 * The class any is a generalisation of the boost::any class
167 * (see http://www.boost.org/doc/html/any.html).
168 * The boost::any class itself is reproduced by any<thing>,
169 * where thing is a TypeTrait whose value is true for all types.
171 template <template <class> class TypeTraits >
175 typedef any< TypeTraits > self;
178 /// Default constructor
184 /// Constructor with a value of template type
185 template<typename ValueType>
186 any(const ValueType & value)
189 bbtkDebugMessage("Data",1,
190 bbtk::HumanTypeName<self>()<<" construction with <"
191 <<bbtk::HumanTypeName<ValueType>()<<">"<<std::endl);
192 // ValueType v = value;
193 // int** i = (int**)(&v);
194 // std::cout << "v="<<*i<<std::endl;
196 if (accepts<ValueType>())
198 content = new anyholder<ValueType>(value);
202 bbtkError(bbtk::HumanTypeName<self>()
203 <<" constructor : data of type <"
204 <<bbtk::HumanTypeName<ValueType>()
205 <<"> are not accepted by traits <"
206 <<bbtk::HumanTypeName<TypeTraits<void> >()<<"> ");
211 any(const any & other)
212 : content(other.content ? other.content->clone() : 0)
214 bbtkDebugMessage("Data",1,
215 HumanTypeName<self>()
216 <<" copy construction with new content : "
217 <<HumanTypeName(type())
228 /// Swaps the content of this with another any
229 any & swap(any & rhs)
231 std::swap(content, rhs.content);
235 /// Affectation of a value of template type
236 template<typename ValueType>
237 any & operator=(const ValueType & rhs)
239 bbtkDebugMessage("Data",1,
240 HumanTypeName<self>()
241 <<" operator= with data of type <"
242 <<HumanTypeName<ValueType>()
244 if (accepts<ValueType>())
246 any(rhs).swap(*this);
251 bbtkError(HumanTypeName<self>()
252 <<" operator= : data of type <"
253 <<HumanTypeName<ValueType>()
254 <<"> are not accepted by traits <"
255 <<HumanTypeName<TypeTraits<void> >()<<"> ");
260 /// Affectation of another any
261 any & operator=(const any & rhs)
263 bbtkDebugMessage("Data",1,
264 HumanTypeName<self >()
265 <<" operator=(const any&) with content : "
266 <<HumanTypeName(rhs.type())<<std::endl);
268 any(rhs).swap(*this);
273 /// Is it empty (no value held) ?
279 /// Returns the type_info of the held value
280 const std::type_info & type() const
282 return content ? content->type() : typeid(void);
285 /// Returns the type_info of the pointed held value
286 const std::type_info & pointed_type() const
288 return content ? content->pointed_type() : typeid(void);
292 /// Returns true iff the contained type is Type
293 template<typename Type>
294 inline bool contains()
296 return ( type() == typeid(Type) );
299 /// Returns true iff the contained type is a pointer
300 inline bool contains_pointer()
302 return content->is_pointer() ;
305 /// Returns true iff the contained type is t
306 inline bool contains(TypeInfo t)
308 return ( type() == t );
311 /// Returns true iff any of type ValueType can be held
312 template<typename Type>
313 inline bool accepts()
315 return TypeTraits<Type>::value; //is_valid();
318 /// Returns a const reference on the held value iff its type matches
319 /// the template parameter
320 template<typename ValueType>
321 inline const ValueType& get() const
323 bbtkDebugMessage("Data",1,
324 HumanTypeName<self >()
325 <<" get<"<<HumanTypeName<ValueType>()
326 <<"> with content : "
327 <<HumanTypeName(type())<<std::endl);
329 if ( type() == typeid(ValueType) )
330 return static_cast< anyholder<ValueType> *>(content)->held;
332 bbtkError(HumanTypeName<self >()
334 <<bbtk::HumanTypeName<ValueType>()
335 <<"> does not match content type <"
336 <<bbtk::HumanTypeName<>(type())<<">");
339 template<typename ValueType>
340 inline const ValueType* getP() const
342 if ( type() == typeid(ValueType) )
343 return &static_cast< anyholder<ValueType> *>(content)->held;
345 bbtkError(HumanTypeName<self >()
346 <<" getP with type <"
347 <<bbtk::HumanTypeName<ValueType>()
348 <<"> does not match content type <"
349 <<bbtk::HumanTypeName<>(type())<<">");
352 /// Returns a const reference on the held value
353 /// ** EVEN IF ITS TYPE DOES NOT MATCH THE TEMPLATE PARAMETER **
354 /// Hence must be used when one knows that the type is good
355 /// Otherwise can lead to unpredictible results
356 template<typename ValueType>
357 inline const ValueType& unsafe_get() const
359 bbtkDebugMessage("Data",1,
360 HumanTypeName<self>()
362 <<HumanTypeName<ValueType>()<<"> with content : "
363 <<HumanTypeName(this->type())
366 // PrintValueIfIsPointer<ValueType>(static_cast< anyholder<ValueType> * >(content)->held);
367 // int** i = (int**)(&static_cast< anyholder<ValueType> * >(content)->held);
368 // std::cout << "v="<<*i<<std::endl;
371 return static_cast< anyholder<ValueType> * >(content)->held;
373 bbtkError(HumanTypeName<self >()
375 <<bbtk::HumanTypeName<ValueType>()
376 <<"> : void content");
380 inline void* get_pointer() const
382 void* p = content->get_pointer();
383 bbtkDebugMessage("Data",1,
384 HumanTypeName<self>()
385 <<"::get_pointer() with content <"
386 <<HumanTypeName(this->type())
393 inline void* get_pointer_to(const std::type_info& t) const
395 void* p = content->get_pointer_to(t);
396 bbtkDebugMessage("Data",1,
397 HumanTypeName<self>()
398 <<"::get_pointer_to("<<HumanTypeName(t)
400 <<HumanTypeName(this->type())
409 anyplaceholder * content;
415 /// The TypeTraits which validates any type
416 template <typename T> struct thing { static const bool value = true; };
418 BBTK_DEFINE_HUMAN_READABLE_TYPE_NAME(bbtk::any<bbtk::thing>,"anything");
421 /// The TypeTraits which validates all integer types
422 template <typename T> struct integer { static const bool value; };
423 template <class T> const bool integer<T>::value = false;
425 /// The TypeTraits which validates all floating point number types
426 template <typename T> struct floating_point { static const bool value; };
427 template <class T> const bool floating_point<T>::value = false;
430 /// The TypeTraits which validates all numerical types
431 template <typename T> struct number { static const bool value; };
432 template <class T> const bool number<T>::value =
433 integer<T>::value || floating_point<T>::value ;
436 /// Macro to begin the enumeration of types included into a
437 /// any_type_collection previously declared with
438 /// DECLARE_any_type_collection.
439 /// Must be placed in the implementation part of the code.
440 #define BBTK_DECLARE_TYPE_TRAITS(NAME) \
441 template <typename T> struct NAME { static const bool value; }; \
442 template <class T> const bool NAME<T>::value = false;
444 #define BBTK_ADD_TO_TYPE_TRAITS(NAME,TYPE) \
445 template <> bool NAME<TYPE>::value = true;
456 // TRY TO INCLUDE BOOST DIRECTLY : OK WORKS !
460 #include "boost/config.hpp"
461 #include <boost/type_traits/remove_reference.hpp>
462 #include <boost/type_traits/is_reference.hpp>
463 #include <boost/throw_exception.hpp>
464 #include <boost/static_assert.hpp>
471 class bad_any_cast : public std::bad_cast
474 virtual const char * what() const throw()
476 return "boost::bad_any_cast: "
477 "failed conversion using boost::any_cast";
481 typedef any<thing> anything;
483 template<typename ValueType>
484 ValueType * any_cast(anything * operand)
486 return operand && operand->type() == typeid(ValueType)
487 ? &static_cast<anything::holder<ValueType> *>(operand->content)->held
491 template<typename ValueType>
492 const ValueType * any_cast(const anything * operand)
494 return any_cast<ValueType>(const_cast<anything *>(operand));
497 template<typename ValueType>
498 ValueType any_cast(const anything & operand)
500 typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<ValueType>::type nonref;
502 #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
503 // If 'nonref' is still reference type, it means the user has not
504 // specialized 'remove_reference'.
506 // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro
507 // to generate specialization of remove_reference for your class
508 // See type traits library documentation for details
509 BOOST_STATIC_ASSERT(!boost::is_reference<nonref>::value);
512 const nonref * result = any_cast<nonref>(&operand);
514 boost::throw_exception(bad_any_cast());
518 template<typename ValueType>
519 ValueType any_cast(anything & operand)
521 typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<ValueType>::type nonref;
523 #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
524 // The comment in the above version of 'any_cast' explains when this
525 // assert is fired and what to do.
526 BOOST_STATIC_ASSERT(!is_reference<nonref>::value);
529 nonref * result = any_cast<nonref>(&operand);
531 boost::throw_exception(bad_any_cast());
535 // Note: The "unsafe" versions of any_cast are not part of the
536 // public interface and may be removed at any time. They are
537 // required where we know what type is stored in the any and can't
538 // use typeid() comparison, e.g., when our types may travel across
539 // different shared libraries.
540 template<typename ValueType>
541 inline ValueType * unsafe_any_cast(anything * operand)
543 return &static_cast<anything::holder<ValueType> *>(operand->content)->held;
546 template<typename ValueType>
547 inline const ValueType * unsafe_any_cast(const anything * operand)
549 return unsafe_any_cast<ValueType>(const_cast<anything *>(operand));
552 */ // EO TRY TO INCLUDE BOOST