1 #pragma once
2 
3 #include <typeinfo>
4 #include <type_traits>
5 #include <stdexcept>
6 namespace mbgl {
7 namespace util {
8 
9 class bad_any_cast : public std::bad_cast {
10 public:
what() const11     const char* what() const noexcept override {
12         return "bad any_cast<>()";
13     }
14 };
15 /**
16  * A variant of `std::any` for non-copyable types.
17  *
18  * Use `unique_any` for non-copyable types (e.g. `std::unique_ptr<T>`)
19  * or to ensure that no copies are made of copyable types that are
20  * moved in.
21  *
22  * `uniqe_any` differs from `std::any` in that it does not support copy construction
23  * or copy assignment. It also does not require the contained type to be copy
24  * constructible.
25  *
26  * The `any_cast<T>()` methods work similar to `std::any_cast<T>()` except that
27  * non-copyable types may only be cast to references.
28  *
29  * Example usage:
30  *  unique_any u1(3);
31  *  auto u2 = unique_any(std::move(u1)); // u1 is moved from
32  *  int i = any_cast<int>(u2);
33  *
34  *  unique_any u2;
35  *  u2 = std::unique_ptr<int>(new int);
36  *  std::unique_ptr<int> iPtr = any_cast<std::unique_ptr<int>>(std::move(u2));
37  *
38  * Inspired by linb::any (https://github.com/thelink2012/any) and the
39  * libc++ implementation (https://github.com/llvm-mirror/libcxx).
40  */
41 class unique_any final
42 {
43 public:
44     unique_any() = default;
45 
46     //Copy constructor (deleted)
47     unique_any(const unique_any& rhs) = delete;
48 
unique_any(unique_any && rhs)49     unique_any(unique_any&& rhs)  : vtable(rhs.vtable) {
50         if (vtable) {
51             vtable->move(std::move(rhs.storage), storage);
52         }
53         rhs.vtable = nullptr;
54     }
55 
56     // Constructs with a direct-initilizated object of type ValueType
57     template <typename ValueType,
58         typename _Vt = std::decay_t<ValueType>,
59         typename = std::enable_if_t<!std::is_same<_Vt, unique_any>::value> >
unique_any(ValueType && value)60     unique_any(ValueType&& value) {
61         create(std::forward<ValueType>(value));
62     }
63 
~unique_any()64     ~unique_any() {
65         reset();
66     }
67 
operator =(unique_any && rhs)68     unique_any& operator=(unique_any&& rhs)  {
69         unique_any(std::move(rhs)).swap(*this);
70         return *this;
71     }
72 
73     template <class ValueType,
74         typename = std::enable_if_t<!std::is_same<std::decay_t<ValueType>, unique_any>::value> >
operator =(ValueType && rhs)75     unique_any& operator=(ValueType&& rhs) {
76         unique_any(std::forward<ValueType>(rhs)).swap(*this);
77         return *this;
78     }
79 
reset()80     void reset()  {
81         if (vtable) {
82             vtable->destroy(storage);
83             vtable = nullptr;
84         }
85     }
86 
swap(unique_any & rhs)87     void swap(unique_any& rhs)  {
88         if (this == &rhs) {
89             return;
90         } else {
91             unique_any tmp(std::move(rhs));
92             rhs.vtable = vtable;
93             if (rhs.vtable) {
94                 rhs.vtable->move(std::move(storage), rhs.storage);
95             }
96             vtable = tmp.vtable;
97             if (vtable) {
98                 vtable->move(std::move(tmp.storage), storage);
99             }
100         }
101     }
102 
type() const103     const std::type_info& type() const  {
104       return !has_value()? typeid(void) : vtable->type();
105     }
106 
has_value() const107     bool has_value() const  {
108         return vtable != nullptr;
109     }
110 
111 private:
112 
113     union Storage {
114         using StackStorage = std::aligned_storage_t<3*sizeof(void*), std::alignment_of<void*>::value>;
115         Storage() = default;
116 
117         void * dynamic { nullptr };
118         StackStorage stack;
119     };
120 
121     template<typename T>
122     struct AllocateOnStack : std::integral_constant<bool,
123         sizeof(T) <= sizeof(Storage::stack)
124         && std::alignment_of<T>::value <= std::alignment_of<Storage::StackStorage>::value
125         && std::is_nothrow_move_constructible<T>::value> {
126     };
127 
128     struct VTable {
129         virtual ~VTable() = default;
130         virtual void move(Storage&& src, Storage& dest) = 0;
131         virtual void destroy(Storage&) = 0;
132         virtual const std::type_info& type() = 0;
133     };
134 
135     template <typename ValueType>
136     struct VTableHeap : public VTable {
movembgl::util::unique_any::VTableHeap137         void move(Storage&& src, Storage& dest) override {
138             dest.dynamic = src.dynamic;
139             src.dynamic = nullptr;
140         }
141 
destroymbgl::util::unique_any::VTableHeap142         void destroy(Storage& s) override {
143             delete reinterpret_cast<ValueType*>(s.dynamic);
144         }
145 
typembgl::util::unique_any::VTableHeap146         const std::type_info& type() override {
147             return typeid(ValueType);
148         }
149     };
150 
151     template <typename ValueType>
152     struct VTableStack : public VTable {
movembgl::util::unique_any::VTableStack153         void move(Storage&& src, Storage& dest) override {
154             new (&dest.stack) ValueType(std::move(reinterpret_cast<ValueType&>(src.stack)));
155             destroy(src);
156         }
157 
destroymbgl::util::unique_any::VTableStack158         void destroy(Storage& s) override {
159             reinterpret_cast<ValueType&>(s.stack).~ValueType();
160         }
161 
typembgl::util::unique_any::VTableStack162         const std::type_info& type() override {
163             return typeid(ValueType);
164         }
165     };
166 
167     template <typename ValueType>
vtableForType()168     static VTable* vtableForType() {
169         using VTableType = std::conditional_t<AllocateOnStack<ValueType>::value, VTableStack<ValueType>, VTableHeap<ValueType> >;
170         static VTableType vtable;
171         return &vtable;
172     }
173 
174     template <typename ValueType, typename _Vt>
175     std::enable_if_t<AllocateOnStack<_Vt>::value>
createStorage(ValueType && value)176     createStorage(ValueType&& value) {
177         new (&storage.stack) _Vt(std::forward<ValueType>(value));
178     }
179 
180     template <typename ValueType, typename _Vt>
181     std::enable_if_t<!AllocateOnStack<_Vt>::value>
createStorage(ValueType && value)182     createStorage(ValueType&& value) {
183         storage.dynamic = new _Vt(std::forward<ValueType>(value));
184     }
185 
186     template <typename ValueType>
create(ValueType && value)187     void create(ValueType&& value) {
188         using _Vt = std::decay_t<ValueType>;
189         vtable = vtableForType<_Vt>();
190         createStorage<ValueType, _Vt>(std::forward<ValueType>(value));
191     }
192 
193     VTable* vtable { nullptr };
194     Storage storage;
195 
196 protected:
197     template<class ValueType>
198     friend const ValueType* any_cast(const unique_any* operand) ;
199 
200     template<class ValueType>
201     friend ValueType* any_cast(unique_any* operand) ;
202 
203     template<typename ValueType, typename _Vt = std::decay_t<ValueType> >
cast()204     ValueType* cast()
205     {
206         return reinterpret_cast<ValueType *>(
207             AllocateOnStack<_Vt>::value ? &storage.stack : storage.dynamic);
208     }
209 };
210 
211 template<typename ValueType>
any_cast(const unique_any * any)212 inline const ValueType* any_cast(const unique_any* any)
213 {
214     return any_cast<ValueType>(const_cast<unique_any *>(any));
215 }
216 
217 template<typename ValueType>
any_cast(unique_any * any)218 inline ValueType* any_cast(unique_any* any)
219 {
220     if(any == nullptr || any->type() != typeid(ValueType))
221         return nullptr;
222     else
223         return any->cast<ValueType>();
224 }
225 
226 template<typename ValueType, typename _Vt = std::decay_t<ValueType> >
any_cast(const unique_any & any)227 inline ValueType any_cast(const unique_any& any)
228 {
229     static_assert(std::is_constructible<ValueType, const _Vt&>::value,
230         "any_cast type can't construct copy of contained object");
231     auto temp = any_cast<_Vt>(&any);
232     if (temp == nullptr) {
233         throw bad_any_cast();
234     }
235     return static_cast<ValueType>(*temp);
236 }
237 
238 template<typename ValueType, typename _Vt = std::decay_t<ValueType> >
any_cast(unique_any & any)239 inline ValueType any_cast(unique_any& any)
240 {
241     static_assert(std::is_constructible<ValueType, const _Vt&>::value,
242         "any_cast type can't construct copy of contained object");
243     auto temp = any_cast<_Vt>(&any);
244     if (temp == nullptr) {
245         throw bad_any_cast();
246     }
247     return static_cast<ValueType>(*temp);
248 }
249 
250 template<typename ValueType, typename _Vt = std::remove_cv_t<ValueType> >
any_cast(unique_any && any)251 inline ValueType any_cast(unique_any&& any)
252 {
253     auto temp = any_cast<_Vt>(&any);
254     if (temp == nullptr) {
255         throw bad_any_cast();
256     }
257     auto retValue = static_cast<ValueType>(std::move(*temp));
258     any.reset();
259     return std::move(retValue);
260 }
261 
262 } // namespace util
263 } // namespace mbgl
264 
265 namespace std {
266 
swap(mbgl::util::unique_any & lhs,mbgl::util::unique_any & rhs)267 inline void swap(mbgl::util::unique_any& lhs, mbgl::util::unique_any& rhs)  {
268     lhs.swap(rhs);
269 }
270 
271 } // namespace std
272