]> Creatis software - bbtk.git/blob - kernel/src/bbtkAny.h
Allow user to always forget .bbs
[bbtk.git] / kernel / src / bbtkAny.h
1 /*=========================================================================
2                                                                                 
3   Program:   bbtk
4   Module:    $RCSfile: bbtkAny.h,v $
5   Language:  C++
6   Date:      $Date: 2008/01/22 15:02:00 $
7   Version:   $Revision: 1.1 $
8                                                                                 
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.
12                                                                                 
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.
16                                                                                 
17 =========================================================================*/
18 /**
19  *\file
20  *\brief  Defines the class any which can store any type of data (adapted from boost::any).
21  */
22 #ifndef __BBTKANY_H_INCLUDED__
23 #define __BBTKANY_H_INCLUDED__
24
25 /*
26 #include <string>
27 #include <iostream>
28 #include <typeinfo>
29 #include <set>
30 #include <map>
31 #include <sstream>
32 #include <exception>
33
34 #include <cxxabi.h>
35 */
36 #include <sstream>
37 #include "bbtkRTTI.h"
38 #include "bbtkMessageManager.h"
39 #include "bbtkException.h"
40
41 #ifdef _USE_BOOST_
42 #include <boost/type_traits/is_pointer.hpp>
43 #endif 
44
45 namespace bbtk 
46 {
47
48
49
50
51
52   //=========================================================
53   /// Abstract class used by the any class to store values
54   class anyplaceholder
55   {
56   public: // structors
57     
58     virtual ~anyplaceholder() {}
59     
60   public: // queries
61     
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;
66     
67     /// returns true iff the stored value is a pointer
68     virtual bool is_pointer() const = 0;
69     
70     /// If the held value is a pointer then 
71     /// returns its value
72     virtual void* get_pointer() const = 0;
73  
74     /// 
75     virtual void* get_pointer_to( const std::type_info& ) const = 0;
76    
77     virtual anyplaceholder * clone() const = 0;
78     
79   };
80   //=========================================================
81   
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
87   {
88   public: // structors
89     
90     anyholder(const ValueType & value)
91       : held(value)
92     {}
93     
94   public: // queries
95     
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); }
102     
103     public: // representation
104     
105     ValueType held;
106     
107   };
108   //=========================================================
109   
110   //=========================================================
111   /// specialization of anyholder for pointer types
112   template<typename ValueType>
113   class anyholder<ValueType*> : public anyplaceholder
114   {
115   public: // structors
116     
117     anyholder(ValueType* const & value)
118       : held(value)
119     { }
120     
121   public: // queries
122     
123     virtual const std::type_info & type() const
124     {
125       return typeid(ValueType*);
126     }
127     
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 { 
131       return (void*)held; 
132     }
133     virtual void* get_pointer_to( const std::type_info& t) const 
134     { 
135       return run_time_up_or_down_cast(t,typeid(ValueType),held);
136     }
137
138     virtual anyplaceholder * clone() const { return new anyholder(held); }
139     
140   public: // representation
141     
142     ValueType* held;
143     
144   };
145   //=========================================================
146
147
148   /** A magic class which can store any type of data which 
149    * is allowed by the template template parameter TypeTrait.
150    *
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 
154    * 
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)
158    * Example :
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; 
163    * etc.
164    * You can use any boost type_trait, like is_pointer, is_floating_point, etc.
165    *
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.
170    **/
171   template <template <class> class TypeTraits >
172   class any
173   {
174   public:
175     typedef any< TypeTraits > self;
176     // structors
177   
178     /// Default constructor
179     any()
180       : content(0)
181     {
182     }
183   
184     /// Constructor with a value of template type
185     template<typename ValueType>
186     any(const ValueType & value)
187       : content(0)
188     {
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;
195       
196       if (accepts<ValueType>()) 
197         { 
198           content = new anyholder<ValueType>(value);
199         }
200       else 
201         {
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> >()<<"> ");
207         }
208     }
209   
210     /// Copy constructor
211     any(const any & other)
212       : content(other.content ? other.content->clone() : 0)
213     {
214       bbtkDebugMessage("Data",1,
215                        HumanTypeName<self>()
216                        <<" copy construction with new content : "
217                        <<HumanTypeName(type())
218                        <<std::endl);
219     }
220   
221     /// Destructor
222     ~any()
223     {
224       delete content;
225     }
226   
227
228     /// Swaps the content of this with another any
229     any & swap(any & rhs)
230     {
231       std::swap(content, rhs.content);
232       return *this;
233     }
234
235     /// Affectation of a value of template type
236     template<typename ValueType>
237     any & operator=(const ValueType & rhs)
238     {
239       bbtkDebugMessage("Data",1,
240                        HumanTypeName<self>()
241                        <<" operator= with data of type <"
242                        <<HumanTypeName<ValueType>()
243                        <<">"<<std::endl);
244       if (accepts<ValueType>()) 
245         {
246           any(rhs).swap(*this);
247           return *this;
248         }
249       else 
250         {
251           bbtkError(HumanTypeName<self>()
252                     <<" operator= : data of type <"
253                     <<HumanTypeName<ValueType>()
254                     <<"> are not accepted by traits <"
255                     <<HumanTypeName<TypeTraits<void> >()<<"> ");
256         }
257     
258     }
259   
260     /// Affectation of another any
261     any & operator=(const any & rhs)
262     {
263         bbtkDebugMessage("Data",1,
264                          HumanTypeName<self >()
265                          <<" operator=(const any&) with content : "
266                          <<HumanTypeName(rhs.type())<<std::endl);
267
268       any(rhs).swap(*this);
269       return *this;
270     }
271   
272
273     /// Is it empty (no value held) ?
274     bool empty() const
275     {
276       return !content;
277     }
278   
279     /// Returns the type_info of the held value
280     const std::type_info & type() const
281     {
282       return content ? content->type() : typeid(void);
283     }
284
285     /// Returns the type_info of the pointed held value
286     const std::type_info & pointed_type() const
287     {
288       return content ? content->pointed_type() : typeid(void);
289     }
290
291
292     /// Returns true iff the contained type is Type
293     template<typename Type>
294     inline bool contains()
295     {
296       return ( type() == typeid(Type) );
297     }
298
299     /// Returns true iff the contained type is a pointer
300     inline bool contains_pointer()
301     {
302       return content->is_pointer() ;
303     }
304
305     /// Returns true iff the contained type is t
306     inline bool contains(TypeInfo t)
307     {
308       return ( type() == t );
309      }
310
311     /// Returns true iff any of type ValueType can be held 
312     template<typename Type>
313     inline bool accepts()
314     {
315       return TypeTraits<Type>::value; //is_valid();
316     }
317
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
322     {
323         bbtkDebugMessage("Data",1,
324                          HumanTypeName<self >()
325                          <<" get<"<<HumanTypeName<ValueType>()
326                          <<"> with content : "
327                          <<HumanTypeName(type())<<std::endl);
328
329       if ( type() == typeid(ValueType) )
330         return static_cast< anyholder<ValueType> *>(content)->held;
331
332       bbtkError(HumanTypeName<self >()
333                 <<" get with type <"
334                 <<bbtk::HumanTypeName<ValueType>()
335                 <<"> does not match content type <"
336                 <<bbtk::HumanTypeName<>(type())<<">");
337     }
338
339     template<typename ValueType>
340     inline const ValueType* getP() const
341     {
342       if ( type() == typeid(ValueType) )
343         return &static_cast< anyholder<ValueType> *>(content)->held;
344  
345       bbtkError(HumanTypeName<self >()
346                 <<" getP with type <"
347                 <<bbtk::HumanTypeName<ValueType>()
348                 <<"> does not match content type <"
349                 <<bbtk::HumanTypeName<>(type())<<">");
350     }
351
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
358     {
359         bbtkDebugMessage("Data",1,
360                          HumanTypeName<self>()
361                          <<"::unsafe_get<"
362                          <<HumanTypeName<ValueType>()<<"> with content : "
363                          <<HumanTypeName(this->type())
364                          <<std::endl);
365
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;
369
370         if (content) 
371           return static_cast< anyholder<ValueType> * >(content)->held;
372         
373         bbtkError(HumanTypeName<self >()
374                   <<"::usafe_get<"
375                   <<bbtk::HumanTypeName<ValueType>()
376                   <<"> : void content");
377     }
378
379
380     inline void* get_pointer() const 
381     {
382       void* p = content->get_pointer();
383       bbtkDebugMessage("Data",1,
384                        HumanTypeName<self>()
385                        <<"::get_pointer() with content <"
386                        <<HumanTypeName(this->type())
387                        <<"> : result = "
388                        << p
389                        <<std::endl);
390       return p;
391     }
392     
393     inline void* get_pointer_to(const std::type_info& t) const 
394     {
395       void* p = content->get_pointer_to(t);
396       bbtkDebugMessage("Data",1,
397                        HumanTypeName<self>()
398                        <<"::get_pointer_to("<<HumanTypeName(t)
399                        <<") with content <"
400                        <<HumanTypeName(this->type())
401                        <<"> : result = "
402                        << p
403                        <<std::endl);
404       return p;
405     }
406     
407   private: 
408     /// content
409     anyplaceholder * content;
410     
411   };
412
413   
414
415   /// The TypeTraits which validates any type 
416   template <typename T> struct thing { static const bool value = true; };
417
418   BBTK_DEFINE_HUMAN_READABLE_TYPE_NAME(bbtk::any<bbtk::thing>,"anything");
419
420
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;
424
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;
428
429
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 ;
434   
435   
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;
443   
444 #define BBTK_ADD_TO_TYPE_TRAITS(NAME,TYPE)      \
445   template <> bool NAME<TYPE>::value = true;
446
447
448 }
449
450
451
452
453
454 /*
455
456 // TRY TO INCLUDE BOOST DIRECTLY : OK WORKS !
457 #include <algorithm>
458 #include <typeinfo>
459
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>
465
466
467 namespace bbtk
468 {
469
470
471   class bad_any_cast : public std::bad_cast
472   {
473   public:
474     virtual const char * what() const throw()
475     {
476       return "boost::bad_any_cast: "
477         "failed conversion using boost::any_cast";
478     }
479   };
480   
481   typedef any<thing> anything;
482
483   template<typename ValueType>
484   ValueType * any_cast(anything * operand)
485   {
486     return operand && operand->type() == typeid(ValueType)
487       ? &static_cast<anything::holder<ValueType> *>(operand->content)->held
488       : 0;
489   }
490   
491     template<typename ValueType>
492     const ValueType * any_cast(const anything * operand)
493     {
494         return any_cast<ValueType>(const_cast<anything *>(operand));
495     }
496
497     template<typename ValueType>
498     ValueType any_cast(const anything & operand)
499     {
500       typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<ValueType>::type nonref;
501
502 #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
503         // If 'nonref' is still reference type, it means the user has not
504         // specialized 'remove_reference'.
505
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);
510 #endif
511
512         const nonref * result = any_cast<nonref>(&operand);
513         if(!result)
514             boost::throw_exception(bad_any_cast());
515         return *result;
516     }
517
518     template<typename ValueType>
519     ValueType any_cast(anything & operand)
520     {
521       typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<ValueType>::type nonref;
522
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);
527 #endif
528
529         nonref * result = any_cast<nonref>(&operand);
530         if(!result)
531             boost::throw_exception(bad_any_cast());
532         return *result;
533     }
534
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)
542     {
543         return &static_cast<anything::holder<ValueType> *>(operand->content)->held;
544     }
545
546     template<typename ValueType>
547     inline const ValueType * unsafe_any_cast(const anything * operand)
548     {
549         return unsafe_any_cast<ValueType>(const_cast<anything *>(operand));
550     }
551 }
552 */ // EO TRY TO INCLUDE BOOST
553
554 #endif
555