]> git.donarmstrong.com Git - bamtools.git/blob - bamtools_variant.h
json output
[bamtools.git] / 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: 2 June 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 <stdexcept>
22 #include <typeinfo>
23 #include <string>
24
25 namespace BamTools {
26
27 class 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) data->Release();
40         }
41
42         // NOTE: This code takes care of self-assignment.
43         // DO NOT CHANGE THE ORDER of the statements.
44         Variant& operator=(const Variant& rhs) {
45             if(rhs.data != NULL) 
46                 rhs.data->AddRef();
47             if(data != NULL) 
48                 data->Release();
49             data = rhs.data;
50             return * this;
51         }
52
53         // This member template constructor allows you to
54         // instance a variant_t object with a value of any type.
55         template<typename T>
56         Variant(T v)
57             : data(new Impl<T>(v))
58         { 
59             data->AddRef(); 
60         }
61
62         // This generic conversion operator let you retrieve
63         // the value held. To avoid template specialization conflicts,
64         // it returns an instance of type T, which will be a COPY
65         // of the value contained.
66         template<typename T> 
67         operator T() const { 
68             return CastFromBase<T>(data)->data;
69         }
70
71         // This forms returns a REFERENCE and not a COPY, which
72         // will be significant in some cases.
73         template<typename T> 
74         const T& get(void) const { 
75             return CastFromBase<T>(data)->data; 
76         }
77
78         template<typename T> 
79         bool is_type(void) const { 
80             return typeid(*data)==typeid(Impl<T>); 
81         }
82
83         template<typename T> 
84         bool is_type(T v) const { 
85             return typeid(*data)==typeid(v); 
86         }
87
88     private:
89         struct ImplBase {
90                 
91             ImplBase() : refs(0) {}
92             virtual ~ImplBase() {}
93                 
94             void AddRef(void) { refs ++; }
95             void Release(void) { 
96                 --refs;
97                 if(refs == 0) delete this;
98             }
99                 
100             size_t refs;
101         };
102
103         template<typename T>
104         struct Impl : ImplBase {
105             Impl(T v) : data (v) { }
106             ~Impl(void) { }
107             T data;
108         };
109
110         // The following method is static because it doesn't
111         // operate on variant_t instances.
112         template<typename T> 
113         static Impl<T>* CastFromBase(ImplBase* v) {
114             // This upcast will fail if T is other than the T used
115             // with the constructor of variant_t.
116             Impl<T>* p = dynamic_cast<Impl<T>*> (v);
117             if (p == NULL) 
118                 throw std::invalid_argument(typeid(T).name()+std::string(" is not a valid type"));
119             return p;
120         }
121
122         ImplBase* data;
123 };
124
125 } // namespace BamTools
126
127 #endif // BAMTOOLS_VARIANT_H