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