]> git.donarmstrong.com Git - bamtools.git/blob - src/utils/bamtools_variant.h
020b3363baa1a316d4bea7a6fa75e1901c7a953f
[bamtools.git] / src / utils / bamtools_variant.h
1 // ***************************************************************************
2 // bamtools_variant.h (c) 2010 Derek Barnett, Erik Garrison
3 // Marth Lab, Department of Biology, Boston College
4 // ---------------------------------------------------------------------------
5 // Last modified: 19 November 2010
6 // ---------------------------------------------------------------------------
7 // Provides a template-based variant type
8 // ---------------------------------------------------------------------------
9 // Modified from:
10 // variant_t - An Improved Variant Type Based on Member Templates
11 // (c) 2000 Fernando Cacciola
12 // Dr. Dobb's (http://www.ddj.com/cpp/184401293)
13 //
14 // * Modified to be in BamTools namespace, otherwise code is same. (DB)
15 // ***************************************************************************
16
17 #ifndef BAMTOOLS_VARIANT_H
18 #define BAMTOOLS_VARIANT_H
19
20 #include <utils/utils_global.h>
21 #include <stdexcept>
22 #include <string>
23 #include <typeinfo>
24
25 namespace BamTools {
26
27 class UTILS_EXPORT Variant {
28   
29     public:
30         Variant(void) : data(NULL) { }
31         
32         Variant(const Variant& other) { 
33             if ( other.data != NULL ) 
34                 other.data->AddRef();
35             data = other.data;
36         }
37
38         ~Variant(void) { 
39             if ( data != NULL ) 
40                 data->Release();
41         }
42
43         // NOTE: This code takes care of self-assignment.
44         // DO NOT CHANGE THE ORDER of the statements.
45         Variant& operator= (const Variant& rhs) {
46             if ( rhs.data != NULL ) 
47                 rhs.data->AddRef();
48             if ( data != NULL ) 
49                 data->Release();
50             data = rhs.data;
51             return *this;
52         }
53
54         // This member template constructor allows you to
55         // instance a variant_t object with a value of any type.
56         template<typename T>
57         Variant(T v) 
58             : data(new Impl<T>(v)) 
59         { 
60             data->AddRef(); 
61         }
62
63         // This generic conversion operator let you retrieve
64         // the value held. To avoid template specialization conflicts,
65         // it returns an instance of type T, which will be a COPY
66         // of the value contained.
67         template<typename T> 
68         operator T() const { 
69             return CastFromBase<T>(data)->data;
70         }
71
72         // This forms returns a REFERENCE and not a COPY, which
73         // will be significant in some cases.
74         template<typename T> 
75         const T& get(void) const { 
76             return CastFromBase<T>(data)->data; 
77         }
78
79         template<typename T> 
80         bool is_type(void) const { 
81             return typeid(*data)==typeid(Impl<T>); 
82         }
83
84         template<typename T> 
85         bool is_type(T v) const { 
86             return typeid(*data)==typeid(v); 
87         }
88
89     private:
90         struct ImplBase {
91                 
92             ImplBase() : refs(0) { }
93             virtual ~ImplBase(void) { }
94                 
95             void AddRef(void) { ++refs; }
96             void Release(void) { 
97                 --refs;
98                 if ( refs == 0 ) delete this;
99             }
100                 
101             size_t refs;
102         };
103
104         template<typename T>
105         struct Impl : ImplBase {
106             Impl(T v) : data(v) { }
107             ~Impl(void) { }
108             T data;
109         };
110
111         // The following method is static because it doesn't
112         // operate on variant_t instances.
113         template<typename T> 
114         static Impl<T>* CastFromBase(ImplBase* v) {
115             // This upcast will fail if T is other than the T used
116             // with the constructor of variant_t.
117             Impl<T>* p = dynamic_cast< Impl<T>* > (v);
118             if ( p == NULL ) 
119                 throw std::invalid_argument( typeid(T).name() + std::string(" is not a valid type") );
120             return p;
121         }
122
123         ImplBase* data;
124 };
125
126 } // namespace BamTools
127
128 #endif // BAMTOOLS_VARIANT_H