Merge branch 'nikitakit_master'
[synfig.git] / ETL / ETL / _value.h
1 /* ========================================================================
2 ** Extended Template and Library
3 ** Abstraction for a Generic Value Type
4 ** $Id$
5 **
6 ** Copyright (c) 2002 Adrian Bentley
7 **
8 ** This package is free software; you can redistribute it and/or
9 ** modify it under the terms of the GNU General Public License as
10 ** published by the Free Software Foundation; either version 2 of
11 ** the License, or (at your option) any later version.
12 **
13 ** This package is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 ** General Public License for more details.
17 **
18 ** === N O T E S ===========================================================
19 **
20 ** This is an internal header file, included by other ETL headers.
21 ** You should not attempt to use it directly.
22 **
23 ** ========================================================================= */
24
25 /* === S T A R T =========================================================== */
26
27 #ifndef __ETL__VALUE_H
28 #define __ETL__VALUE_H
29
30 /* === H E A D E R S ======================================================= */
31 #include <algorithm>
32 #include <typeinfo>
33 #include <cassert>
34
35 /* === M A C R O S ========================================================= */
36
37 /* === T Y P E D E F S ===================================================== */
38
39 /* === C L A S S E S & S T R U C T S ======================================= */
40
41 /*!     \note   This class may be specialized to support binary compatibility
42                         for desired objects (e.g. point3,vector3,float[3]).
43                         However it MUST be declared within scope that you are using the
44                         values....
45
46         \warning        If you specialize this class for something that isn't binary
47                                 compatible, then your values could easily report belonging to
48                                 the wrong types.
49 */
50 template < typename T >
51 class value_store_type
52 {
53 public:
54         typedef T                                               value_type;
55 };
56
57 _ETL_BEGIN_NAMESPACE
58
59 /*!     \class  value   _value.h        ETL/value
60         \brief  Abstraction of the concept of a generic value
61
62         Modified from ideas for the boost::any type.  Added binary compatibility
63         structure
64 */
65 class value
66 {
67         struct contentholder
68         {
69                 virtual ~contentholder() {}
70                 virtual contentholder *clone() const = 0;
71                 virtual const std::type_info &type() const = 0;
72         };
73
74         contentholder   *content;
75
76 public: //constructor interface
77         value()
78                 :content(0)
79         {
80         }
81
82         value(const value &v)
83                 :content( v.content ? v.content->clone() : 0 )
84         {
85         }
86
87         /* Copies the object passed to it
88         */
89         template < typename T >
90         value(const T &v)
91                 :content( new holder< typename value_store_type<T>::value_type >
92                                                 (reinterpret_cast<const typename value_store_type<T>::value_type &>(v)) )
93         {
94         }
95
96 public: //modifier interface
97
98         value & swap(value & rhs)
99         {
100                 std::swap(content, rhs.content);
101                 return *this;
102         }
103
104         template<typename ValueType>
105         value & operator=(const ValueType & rhs)
106         {
107                 value(rhs).swap(*this);
108                 return *this;
109         }
110
111         value & operator=(const value & rhs)
112         {
113                 value(rhs).swap(*this);
114                 return *this;
115         }
116
117 public: //query interface
118
119         bool empty() const
120         {
121                 return content == 0;
122         }
123
124         const std::type_info & type() const
125         {
126                 return content ? content->type() : typeid(void);
127         }
128
129 private: //implementation interface
130
131         template < typename T >
132         class holder : public contentholder
133         {
134         public: //representation
135                 T       obj;
136
137         public: //constructor interface
138
139                 holder(const T &o)
140                         :obj(o)
141                 {
142                 }
143
144                 holder(const holder<T> &h)
145                         :obj(h.obj)
146                 {
147                 }
148
149         public: //accessor interface
150                 virtual contentholder *clone() const
151                 {
152                         return new holder(*this);
153                 }
154
155                 virtual const std::type_info &type() const
156                 {
157                         return typeid(T);
158                 }
159
160         public: //allocation interface
161                 void *operator new(unsigned int size)
162                 {
163                         assert(size == sizeof(holder<T>));
164
165                         //use pool allocation at some point
166                         return malloc(size);
167                 }
168
169                 void operator delete(void *p)
170                 {
171                         assert(p);
172                         //use pool allocation at some point
173                         return free(p);
174                 }
175         };
176
177         template < typename ValueType >
178         friend ValueType *value_cast(value *v);
179 };
180
181 /*!     Is thrown for bad value_casts (when using a reference...)
182 */
183 class bad_value_cast : public std::bad_cast
184 {
185 public:
186         virtual const char * what() const throw()
187         {
188                 return "etl::bad_value_cast: " "failed conversion using boost::value_cast";
189         }
190 };
191
192 /*!     Returns a pointer to the desired value type if the value_type and the internal
193         binary format agree (mediated by using the value_store_type class), otherwise
194         it returns 0.
195
196         \see value_store_type
197 */
198 template < typename ValueType >
199 ValueType *value_cast(value *v)
200 {
201         assert(v);
202
203         return ( typeid(typename value_store_type<ValueType>::value_type) == v->type() )
204                         ? &static_cast<value::holder<ValueType> *>(v->content)->obj
205                         : 0;
206 }
207
208 /*!     Same as above except tweaked to allow const cast (possibly for purposes involving
209         type agreement... if const impacts a typeid call I do not know...)
210 */
211 template < typename ValueType >
212 const ValueType * value_cast(const value *v)
213 {
214         return value_cast<ValueType>(const_cast<value *>(v));
215 }
216
217 /*!     Extract a copy of the internal object and will throw a bad_value_cast exception
218         if the types do not agree.
219
220         \note   I'm not sure why boost::any didn't use a reference here... there must be a reason...
221
222         \see bad_value_cast
223 */
224 template < typename ValueType >
225 ValueType value_cast(const value &v)
226 {
227         const ValueType * result = value_cast<ValueType>(&v);
228         if(!result)
229                 throw bad_value_cast();
230         return *result;
231 }
232
233 _ETL_END_NAMESPACE
234
235 /* === E N D =============================================================== */
236
237 #endif