1 #pragma once
2 /*
3  * (C) Copyright Christopher Diggins 2005-2011
4  * (C) Copyright Pablo Aguilar 2005
5  * (C) Copyright Kevlin Henney 2001
6  *
7  * Distributed under the Boost Software License, Version 1.0. (See
8  * accompanying file LICENSE_1_0.txt or copy at
9  * http://www.boost.org/LICENSE_1_0.txt
10  */
11 
12 #include  <stdint.h>
13 #include <stdexcept>
14 #include <cstring>
15 
16 namespace static_any
17 {
18 namespace anyimpl
19 {
20     struct empty_any
21     {
22     };
23 
24     struct base_any_policy
25     {
26         virtual void static_delete(void** x) = 0;
27         virtual void copy_from_value(void const* src, void** dest) = 0;
28         virtual void clone(void* const* src, void** dest) = 0;
29         virtual void move(void* const* src, void** dest) = 0;
30         virtual void* get_value(void** src) = 0;
31         virtual size_t get_size() = 0;
32     protected:
33         ~base_any_policy() = default;
34     };
35 
36     //inline base_any_policy::~base_any_policy() throw () {}
37 
38     template<typename T>
39     struct typed_base_any_policy : base_any_policy
40     {
get_sizestatic_any::anyimpl::typed_base_any_policy41         virtual size_t get_size()
42         {
43             return sizeof(T);
44         }
45     protected:
46         ~typed_base_any_policy() = default;
47     };
48 
49     template<typename T>
50     struct small_any_policy : typed_base_any_policy<T>
51     {
52         virtual ~small_any_policy() = default;
static_deletestatic_any::anyimpl::small_any_policy53         virtual void static_delete(void** x)
54         {
55             *x = 0;
56         }
copy_from_valuestatic_any::anyimpl::small_any_policy57         virtual void copy_from_value(void const* src, void** dest)
58         {
59             new(dest) T(*reinterpret_cast<T const*>(src));
60         }
clonestatic_any::anyimpl::small_any_policy61         virtual void clone(void* const* src, void** dest)
62         {
63             *dest = *src;
64         }
movestatic_any::anyimpl::small_any_policy65         virtual void move(void* const* src, void** dest)
66         {
67             *dest = *src;
68         }
get_valuestatic_any::anyimpl::small_any_policy69         virtual void* get_value(void** src)
70         {
71             return reinterpret_cast<void*>(src);
72         }
73     };
74 
75     template<typename T>
76     struct big_any_policy : typed_base_any_policy<T>
77     {
78         virtual ~big_any_policy() = default;
static_deletestatic_any::anyimpl::big_any_policy79         virtual void static_delete(void** x)
80         {
81             if (*x)
82                 delete(*reinterpret_cast<T**>(x));
83             *x = NULL;
84         }
copy_from_valuestatic_any::anyimpl::big_any_policy85         virtual void copy_from_value(void const* src, void** dest)
86         {
87             *dest = new T(*reinterpret_cast<T const*>(src));
88         }
clonestatic_any::anyimpl::big_any_policy89         virtual void clone(void* const* src, void** dest)
90         {
91             *dest = new T(**reinterpret_cast<T* const*>(src));
92         }
movestatic_any::anyimpl::big_any_policy93         virtual void move(void* const* src, void** dest)
94         {
95             (*reinterpret_cast<T**>(dest))->~T();
96             **reinterpret_cast<T**>(dest) = **reinterpret_cast<T* const*>(src);
97         }
get_valuestatic_any::anyimpl::big_any_policy98         virtual void* get_value(void** src)
99         {
100             return *src;
101         }
102     };
103 
104     template<typename T>
105     struct choose_policy
106     {
107         typedef big_any_policy<T> type;
108     };
109 
110     template<typename T>
111     struct choose_policy<T*>
112     {
113         typedef small_any_policy<T*> type;
114     };
115 
116     struct any;
117 
118     /// Choosing the policy for an any type is illegal, but should never happen.
119     /// This is designed to throw a compiler error.
120     template<>
121     struct choose_policy<any>
122     {
123         typedef void type;
124     };
125 
126     /// Specializations for small types.
127 #define SMALL_POLICY(TYPE) template<> struct \
128    choose_policy<TYPE> { typedef small_any_policy<TYPE> type; };
129 
130     SMALL_POLICY(char);
131     SMALL_POLICY(signed char);
132     SMALL_POLICY(unsigned char);
133     SMALL_POLICY(signed short);
134     SMALL_POLICY(unsigned short);
135     SMALL_POLICY(signed int);
136     SMALL_POLICY(unsigned int);
137     SMALL_POLICY(signed long);
138     SMALL_POLICY(unsigned long);
139     SMALL_POLICY(signed long long);
140     SMALL_POLICY(unsigned long long);
141     SMALL_POLICY(float);
142     SMALL_POLICY(double);
143     SMALL_POLICY(bool);
144 
145 #undef SMALL_POLICY
146 
147     /// This function will return a different policy for each type.
148     template<typename T>
get_policy()149     base_any_policy* get_policy()
150     {
151         static typename choose_policy<T>::type policy;
152         return &policy;
153     };
154 }
155 
156 class any
157 {
158 private:
159     // fields
160     anyimpl::base_any_policy* policy;
161     void* object;
162 
163 public:
164     /// Initializing constructor.
165     template <typename T>
any(const T & x)166     any(const T& x)
167     : policy(anyimpl::get_policy<anyimpl::empty_any>()), object(NULL)
168     {
169         assign(x);
170     }
171 
172     /// Empty constructor.
any()173     any()
174     : policy(anyimpl::get_policy<anyimpl::empty_any>()), object(NULL)
175     {
176     }
177 
178     /// Special initializing constructor for string literals.
any(const char * x)179     any(const char* x)
180     : policy(anyimpl::get_policy<anyimpl::empty_any>()), object(NULL)
181     {
182         assign(x);
183     }
184 
185     /// Copy constructor.
any(const any & x)186     any(const any& x)
187     : policy(anyimpl::get_policy<anyimpl::empty_any>()), object(NULL)
188     {
189         assign(x);
190     }
191 
192     /// Destructor.
~any()193     ~any()
194     {
195         policy->static_delete(&object);
196     }
197 
198     /// Assignment function from another any.
assign(const any & x)199     any& assign(const any& x)
200     {
201         reset();
202         policy = x.policy;
203         policy->clone(&x.object, &object);
204         return *this;
205     }
206 
207     /// Assignment function.
208     template <typename T>
assign(const T & x)209     any& assign(const T& x)
210     {
211         reset();
212         policy = anyimpl::get_policy<T>();
213         policy->copy_from_value(&x, &object);
214         return *this;
215     }
216 
217     /// Assignment operator.
218     template<typename T>
operator =(const T & x)219     any& operator=(const T& x) {
220         return assign(x);
221     }
222 
223     /// Assignment operator, specialed for literal strings.
224     /// They have types like const char [6] which don't work as expected.
operator =(const char * x)225     any& operator=(const char* x) {
226         return assign(x);
227     }
228 
229     /// Less than operator for sorting
operator <(const any & x) const230     bool operator<(const any& x) const
231     {
232         if (policy == x.policy)
233         {
234             void* p1 = const_cast<void*>(object);
235             void* p2 = const_cast<void*>(x.object);
236             return memcmp(policy->get_value(&p1),
237                           x.policy->get_value(&p2),
238                           policy->get_size()) < 0 ? 1 : 0;
239         }
240         return 0;
241     }
242 
243     /// equal operator
operator ==(const any & x) const244     bool operator==(const any& x) const
245     {
246         if (policy == x.policy)
247         {
248             void* p1 = const_cast<void*>(object);
249             void* p2 = const_cast<void*>(x.object);
250             return memcmp(policy->get_value(&p1),
251                           x.policy->get_value(&p2),
252                           policy->get_size()) == 0 ? 1 : 0;
253         }
254         return 0;
255     }
256 
257     /// Utility functions
getHash() const258     uint8_t getHash() const
259     {
260         void* p1 = const_cast<void*>(object);
261         return *(uint64_t*)policy->get_value(&p1) % 4048;
262     }
swap(any & x)263     any& swap(any& x)
264     {
265         std::swap(policy, x.policy);
266         std::swap(object, x.object);
267         return *this;
268     }
269 
270     /// Cast operator. You can only cast to the original type.
271     template<typename T>
cast()272     T& cast()
273     {
274         if (policy != anyimpl::get_policy<T>())
275             throw std::runtime_error("static_any: type mismatch in cast");
276         T* r = reinterpret_cast<T*>(policy->get_value(&object));
277         return *r;
278     }
279 
280     /// Returns true if the any contains no value.
empty() const281     bool empty() const
282     {
283         return policy == anyimpl::get_policy<anyimpl::empty_any>();
284     }
285 
286     /// Frees any allocated memory, and sets the value to NULL.
reset()287     void reset()
288     {
289         policy->static_delete(&object);
290         policy = anyimpl::get_policy<anyimpl::empty_any>();
291     }
292 
293     /// Returns true if the two types are the same.
compatible(const any & x) const294     bool compatible(const any& x) const
295     {
296         return policy == x.policy;
297     }
298 };
299 
300 }
301