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