1 //
2 // Copyright 2017 The Abseil Authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // https://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 // -----------------------------------------------------------------------------
17 // any.h
18 // -----------------------------------------------------------------------------
19 //
20 // This header file define the `absl::any` type for holding a type-safe value
21 // of any type. The 'absl::any` type is useful for providing a way to hold
22 // something that is, as yet, unspecified. Such unspecified types
23 // traditionally are passed between API boundaries until they are later cast to
24 // their "destination" types. To cast to such a destination type, use
25 // `absl::any_cast()`. Note that when casting an `absl::any`, you must cast it
26 // to an explicit type; implicit conversions will throw.
27 //
28 // Example:
29 //
30 // auto a = absl::any(65);
31 // absl::any_cast<int>(a); // 65
32 // absl::any_cast<char>(a); // throws absl::bad_any_cast
33 // absl::any_cast<std::string>(a); // throws absl::bad_any_cast
34 //
35 // `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
36 // and is designed to be a drop-in replacement for code compliant with C++17.
37 //
38 // Traditionally, the behavior of casting to a temporary unspecified type has
39 // been accomplished with the `void *` paradigm, where the pointer was to some
40 // other unspecified type. `absl::any` provides an "owning" version of `void *`
41 // that avoids issues of pointer management.
42 //
43 // Note: just as in the case of `void *`, use of `absl::any` (and its C++17
44 // version `std::any`) is a code smell indicating that your API might not be
45 // constructed correctly. We have seen that most uses of `any` are unwarranted,
46 // and `absl::any`, like `std::any`, is difficult to use properly. Before using
47 // this abstraction, make sure that you should not instead be rewriting your
48 // code to be more specific.
49 //
50 // Abseil expects to release an `absl::variant` type shortly (a C++11 compatible
51 // version of the C++17 `std::variant), which is generally preferred for use
52 // over `absl::any`.
53 #ifndef ABSL_TYPES_ANY_H_
54 #define ABSL_TYPES_ANY_H_
55
56 #include "absl/base/config.h"
57 #include "absl/utility/utility.h"
58
59 #ifdef ABSL_USES_STD_ANY
60
61 #include <any> // IWYU pragma: export
62
63 namespace absl {
64 ABSL_NAMESPACE_BEGIN
65 using std::any;
66 using std::any_cast;
67 using std::bad_any_cast;
68 using std::make_any;
69 ABSL_NAMESPACE_END
70 } // namespace absl
71
72 #else // ABSL_USES_STD_ANY
73
74 #include <algorithm>
75 #include <cstddef>
76 #include <initializer_list>
77 #include <memory>
78 #include <stdexcept>
79 #include <type_traits>
80 #include <typeinfo>
81 #include <utility>
82
83 #include "absl/base/macros.h"
84 #include "absl/meta/type_traits.h"
85 #include "absl/types/bad_any_cast.h"
86
87 // NOTE: This macro is an implementation detail that is undefined at the bottom
88 // of the file. It is not intended for expansion directly from user code.
89 #ifdef ABSL_ANY_DETAIL_HAS_RTTI
90 #error ABSL_ANY_DETAIL_HAS_RTTI cannot be directly set
91 #elif !defined(__GNUC__) || defined(__GXX_RTTI)
92 #define ABSL_ANY_DETAIL_HAS_RTTI 1
93 #endif // !defined(__GNUC__) || defined(__GXX_RTTI)
94
95 namespace absl {
96 ABSL_NAMESPACE_BEGIN
97
98 namespace any_internal {
99
100 template <typename Type>
101 struct TypeTag {
102 constexpr static char dummy_var = 0;
103 };
104
105 template <typename Type>
106 constexpr char TypeTag<Type>::dummy_var;
107
108 // FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the
109 // passed in type. These are meant to be good match for keys into maps or
110 // straight up comparisons.
111 template<typename Type>
FastTypeId()112 constexpr inline const void* FastTypeId() {
113 return &TypeTag<Type>::dummy_var;
114 }
115
116 } // namespace any_internal
117
118 class any;
119
120 // swap()
121 //
122 // Swaps two `absl::any` values. Equivalent to `x.swap(y) where `x` and `y` are
123 // `absl::any` types.
124 void swap(any& x, any& y) noexcept;
125
126 // make_any()
127 //
128 // Constructs an `absl::any` of type `T` with the given arguments.
129 template <typename T, typename... Args>
130 any make_any(Args&&... args);
131
132 // Overload of `absl::make_any()` for constructing an `absl::any` type from an
133 // initializer list.
134 template <typename T, typename U, typename... Args>
135 any make_any(std::initializer_list<U> il, Args&&... args);
136
137 // any_cast()
138 //
139 // Statically casts the value of a `const absl::any` type to the given type.
140 // This function will throw `absl::bad_any_cast` if the stored value type of the
141 // `absl::any` does not match the cast.
142 //
143 // `any_cast()` can also be used to get a reference to the internal storage iff
144 // a reference type is passed as its `ValueType`:
145 //
146 // Example:
147 //
148 // absl::any my_any = std::vector<int>();
149 // absl::any_cast<std::vector<int>&>(my_any).push_back(42);
150 template <typename ValueType>
151 ValueType any_cast(const any& operand);
152
153 // Overload of `any_cast()` to statically cast the value of a non-const
154 // `absl::any` type to the given type. This function will throw
155 // `absl::bad_any_cast` if the stored value type of the `absl::any` does not
156 // match the cast.
157 template <typename ValueType>
158 ValueType any_cast(any& operand); // NOLINT(runtime/references)
159
160 // Overload of `any_cast()` to statically cast the rvalue of an `absl::any`
161 // type. This function will throw `absl::bad_any_cast` if the stored value type
162 // of the `absl::any` does not match the cast.
163 template <typename ValueType>
164 ValueType any_cast(any&& operand);
165
166 // Overload of `any_cast()` to statically cast the value of a const pointer
167 // `absl::any` type to the given pointer type, or `nullptr` if the stored value
168 // type of the `absl::any` does not match the cast.
169 template <typename ValueType>
170 const ValueType* any_cast(const any* operand) noexcept;
171
172 // Overload of `any_cast()` to statically cast the value of a pointer
173 // `absl::any` type to the given pointer type, or `nullptr` if the stored value
174 // type of the `absl::any` does not match the cast.
175 template <typename ValueType>
176 ValueType* any_cast(any* operand) noexcept;
177
178 // -----------------------------------------------------------------------------
179 // absl::any
180 // -----------------------------------------------------------------------------
181 //
182 // An `absl::any` object provides the facility to either store an instance of a
183 // type, known as the "contained object", or no value. An `absl::any` is used to
184 // store values of types that are unknown at compile time. The `absl::any`
185 // object, when containing a value, must contain a value type; storing a
186 // reference type is neither desired nor supported.
187 //
188 // An `absl::any` can only store a type that is copy-constructible; move-only
189 // types are not allowed within an `any` object.
190 //
191 // Example:
192 //
193 // auto a = absl::any(65); // Literal, copyable
194 // auto b = absl::any(std::vector<int>()); // Default-initialized, copyable
195 // std::unique_ptr<Foo> my_foo;
196 // auto c = absl::any(std::move(my_foo)); // Error, not copy-constructible
197 //
198 // Note that `absl::any` makes use of decayed types (`absl::decay_t` in this
199 // context) to remove const-volatile qualifiers (known as "cv qualifiers"),
200 // decay functions to function pointers, etc. We essentially "decay" a given
201 // type into its essential type.
202 //
203 // `absl::any` makes use of decayed types when determining the basic type `T` of
204 // the value to store in the any's contained object. In the documentation below,
205 // we explicitly denote this by using the phrase "a decayed type of `T`".
206 //
207 // Example:
208 //
209 // const int a = 4;
210 // absl::any foo(a); // Decay ensures we store an "int", not a "const int&".
211 //
212 // void my_function() {}
213 // absl::any bar(my_function); // Decay ensures we store a function pointer.
214 //
215 // `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
216 // and is designed to be a drop-in replacement for code compliant with C++17.
217 class any {
218 private:
219 template <typename T>
220 struct IsInPlaceType;
221
222 public:
223 // Constructors
224
225 // Constructs an empty `absl::any` object (`any::has_value()` will return
226 // `false`).
227 constexpr any() noexcept;
228
229 // Copy constructs an `absl::any` object with a "contained object" of the
230 // passed type of `other` (or an empty `absl::any` if `other.has_value()` is
231 // `false`.
any(const any & other)232 any(const any& other)
233 : obj_(other.has_value() ? other.obj_->Clone()
234 : std::unique_ptr<ObjInterface>()) {}
235
236 // Move constructs an `absl::any` object with a "contained object" of the
237 // passed type of `other` (or an empty `absl::any` if `other.has_value()` is
238 // `false`).
239 any(any&& other) noexcept = default;
240
241 // Constructs an `absl::any` object with a "contained object" of the decayed
242 // type of `T`, which is initialized via `std::forward<T>(value)`.
243 //
244 // This constructor will not participate in overload resolution if the
245 // decayed type of `T` is not copy-constructible.
246 template <
247 typename T, typename VT = absl::decay_t<T>,
248 absl::enable_if_t<!absl::disjunction<
249 std::is_same<any, VT>, IsInPlaceType<VT>,
250 absl::negation<std::is_copy_constructible<VT> > >::value>* = nullptr>
any(T && value)251 any(T&& value) : obj_(new Obj<VT>(in_place, std::forward<T>(value))) {}
252
253 // Constructs an `absl::any` object with a "contained object" of the decayed
254 // type of `T`, which is initialized via `std::forward<T>(value)`.
255 template <typename T, typename... Args, typename VT = absl::decay_t<T>,
256 absl::enable_if_t<absl::conjunction<
257 std::is_copy_constructible<VT>,
258 std::is_constructible<VT, Args...>>::value>* = nullptr>
any(in_place_type_t<T>,Args &&...args)259 explicit any(in_place_type_t<T> /*tag*/, Args&&... args)
260 : obj_(new Obj<VT>(in_place, std::forward<Args>(args)...)) {}
261
262 // Constructs an `absl::any` object with a "contained object" of the passed
263 // type `VT` as a decayed type of `T`. `VT` is initialized as if
264 // direct-non-list-initializing an object of type `VT` with the arguments
265 // `initializer_list, std::forward<Args>(args)...`.
266 template <
267 typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
268 absl::enable_if_t<
269 absl::conjunction<std::is_copy_constructible<VT>,
270 std::is_constructible<VT, std::initializer_list<U>&,
271 Args...>>::value>* = nullptr>
any(in_place_type_t<T>,std::initializer_list<U> ilist,Args &&...args)272 explicit any(in_place_type_t<T> /*tag*/, std::initializer_list<U> ilist,
273 Args&&... args)
274 : obj_(new Obj<VT>(in_place, ilist, std::forward<Args>(args)...)) {}
275
276 // Assignment operators
277
278 // Copy assigns an `absl::any` object with a "contained object" of the
279 // passed type.
280 any& operator=(const any& rhs) {
281 any(rhs).swap(*this);
282 return *this;
283 }
284
285 // Move assigns an `absl::any` object with a "contained object" of the
286 // passed type. `rhs` is left in a valid but otherwise unspecified state.
287 any& operator=(any&& rhs) noexcept {
288 any(std::move(rhs)).swap(*this);
289 return *this;
290 }
291
292 // Assigns an `absl::any` object with a "contained object" of the passed type.
293 template <typename T, typename VT = absl::decay_t<T>,
294 absl::enable_if_t<absl::conjunction<
295 absl::negation<std::is_same<VT, any>>,
296 std::is_copy_constructible<VT>>::value>* = nullptr>
297 any& operator=(T&& rhs) {
298 any tmp(in_place_type_t<VT>(), std::forward<T>(rhs));
299 tmp.swap(*this);
300 return *this;
301 }
302
303 // Modifiers
304
305 // any::emplace()
306 //
307 // Emplaces a value within an `absl::any` object by calling `any::reset()`,
308 // initializing the contained value as if direct-non-list-initializing an
309 // object of type `VT` with the arguments `std::forward<Args>(args)...`, and
310 // returning a reference to the new contained value.
311 //
312 // Note: If an exception is thrown during the call to `VT`'s constructor,
313 // `*this` does not contain a value, and any previously contained value has
314 // been destroyed.
315 template <
316 typename T, typename... Args, typename VT = absl::decay_t<T>,
317 absl::enable_if_t<std::is_copy_constructible<VT>::value &&
318 std::is_constructible<VT, Args...>::value>* = nullptr>
emplace(Args &&...args)319 VT& emplace(Args&&... args) {
320 reset(); // NOTE: reset() is required here even in the world of exceptions.
321 Obj<VT>* const object_ptr =
322 new Obj<VT>(in_place, std::forward<Args>(args)...);
323 obj_ = std::unique_ptr<ObjInterface>(object_ptr);
324 return object_ptr->value;
325 }
326
327 // Overload of `any::emplace()` to emplace a value within an `absl::any`
328 // object by calling `any::reset()`, initializing the contained value as if
329 // direct-non-list-initializing an object of type `VT` with the arguments
330 // `initializer_list, std::forward<Args>(args)...`, and returning a reference
331 // to the new contained value.
332 //
333 // Note: If an exception is thrown during the call to `VT`'s constructor,
334 // `*this` does not contain a value, and any previously contained value has
335 // been destroyed. The function shall not participate in overload resolution
336 // unless `is_copy_constructible_v<VT>` is `true` and
337 // `is_constructible_v<VT, initializer_list<U>&, Args...>` is `true`.
338 template <
339 typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
340 absl::enable_if_t<std::is_copy_constructible<VT>::value &&
341 std::is_constructible<VT, std::initializer_list<U>&,
342 Args...>::value>* = nullptr>
emplace(std::initializer_list<U> ilist,Args &&...args)343 VT& emplace(std::initializer_list<U> ilist, Args&&... args) {
344 reset(); // NOTE: reset() is required here even in the world of exceptions.
345 Obj<VT>* const object_ptr =
346 new Obj<VT>(in_place, ilist, std::forward<Args>(args)...);
347 obj_ = std::unique_ptr<ObjInterface>(object_ptr);
348 return object_ptr->value;
349 }
350
351 // any::reset()
352 //
353 // Resets the state of the `absl::any` object, destroying the contained object
354 // if present.
reset()355 void reset() noexcept { obj_ = nullptr; }
356
357 // any::swap()
358 //
359 // Swaps the passed value and the value of this `absl::any` object.
swap(any & other)360 void swap(any& other) noexcept { obj_.swap(other.obj_); }
361
362 // Observers
363
364 // any::has_value()
365 //
366 // Returns `true` if the `any` object has a contained value, otherwise
367 // returns `false`.
has_value()368 bool has_value() const noexcept { return obj_ != nullptr; }
369
370 #if ABSL_ANY_DETAIL_HAS_RTTI
371 // Returns: typeid(T) if *this has a contained object of type T, otherwise
372 // typeid(void).
type()373 const std::type_info& type() const noexcept {
374 if (has_value()) {
375 return obj_->Type();
376 }
377
378 return typeid(void);
379 }
380 #endif // ABSL_ANY_DETAIL_HAS_RTTI
381
382 private:
383 // Tagged type-erased abstraction for holding a cloneable object.
384 class ObjInterface {
385 public:
386 virtual ~ObjInterface() = default;
387 virtual std::unique_ptr<ObjInterface> Clone() const = 0;
388 virtual const void* ObjTypeId() const noexcept = 0;
389 #if ABSL_ANY_DETAIL_HAS_RTTI
390 virtual const std::type_info& Type() const noexcept = 0;
391 #endif // ABSL_ANY_DETAIL_HAS_RTTI
392 };
393
394 // Hold a value of some queryable type, with an ability to Clone it.
395 template <typename T>
396 class Obj : public ObjInterface {
397 public:
398 template <typename... Args>
Obj(in_place_t,Args &&...args)399 explicit Obj(in_place_t /*tag*/, Args&&... args)
400 : value(std::forward<Args>(args)...) {}
401
Clone()402 std::unique_ptr<ObjInterface> Clone() const final {
403 return std::unique_ptr<ObjInterface>(new Obj(in_place, value));
404 }
405
ObjTypeId()406 const void* ObjTypeId() const noexcept final { return IdForType<T>(); }
407
408 #if ABSL_ANY_DETAIL_HAS_RTTI
Type()409 const std::type_info& Type() const noexcept final { return typeid(T); }
410 #endif // ABSL_ANY_DETAIL_HAS_RTTI
411
412 T value;
413 };
414
CloneObj()415 std::unique_ptr<ObjInterface> CloneObj() const {
416 if (!obj_) return nullptr;
417 return obj_->Clone();
418 }
419
420 template <typename T>
IdForType()421 constexpr static const void* IdForType() {
422 // Note: This type dance is to make the behavior consistent with typeid.
423 using NormalizedType =
424 typename std::remove_cv<typename std::remove_reference<T>::type>::type;
425
426 return any_internal::FastTypeId<NormalizedType>();
427 }
428
GetObjTypeId()429 const void* GetObjTypeId() const {
430 return obj_ ? obj_->ObjTypeId() : any_internal::FastTypeId<void>();
431 }
432
433 // `absl::any` nonmember functions //
434
435 // Description at the declaration site (top of file).
436 template <typename ValueType>
437 friend ValueType any_cast(const any& operand);
438
439 // Description at the declaration site (top of file).
440 template <typename ValueType>
441 friend ValueType any_cast(any& operand); // NOLINT(runtime/references)
442
443 // Description at the declaration site (top of file).
444 template <typename T>
445 friend const T* any_cast(const any* operand) noexcept;
446
447 // Description at the declaration site (top of file).
448 template <typename T>
449 friend T* any_cast(any* operand) noexcept;
450
451 std::unique_ptr<ObjInterface> obj_;
452 };
453
454 // -----------------------------------------------------------------------------
455 // Implementation Details
456 // -----------------------------------------------------------------------------
457
458 constexpr any::any() noexcept = default;
459
460 template <typename T>
461 struct any::IsInPlaceType : std::false_type {};
462
463 template <typename T>
464 struct any::IsInPlaceType<in_place_type_t<T>> : std::true_type {};
465
466 inline void swap(any& x, any& y) noexcept { x.swap(y); }
467
468 // Description at the declaration site (top of file).
469 template <typename T, typename... Args>
470 any make_any(Args&&... args) {
471 return any(in_place_type_t<T>(), std::forward<Args>(args)...);
472 }
473
474 // Description at the declaration site (top of file).
475 template <typename T, typename U, typename... Args>
476 any make_any(std::initializer_list<U> il, Args&&... args) {
477 return any(in_place_type_t<T>(), il, std::forward<Args>(args)...);
478 }
479
480 // Description at the declaration site (top of file).
481 template <typename ValueType>
482 ValueType any_cast(const any& operand) {
483 using U = typename std::remove_cv<
484 typename std::remove_reference<ValueType>::type>::type;
485 static_assert(std::is_constructible<ValueType, const U&>::value,
486 "Invalid ValueType");
487 auto* const result = (any_cast<U>)(&operand);
488 if (result == nullptr) {
489 any_internal::ThrowBadAnyCast();
490 }
491 return static_cast<ValueType>(*result);
492 }
493
494 // Description at the declaration site (top of file).
495 template <typename ValueType>
496 ValueType any_cast(any& operand) { // NOLINT(runtime/references)
497 using U = typename std::remove_cv<
498 typename std::remove_reference<ValueType>::type>::type;
499 static_assert(std::is_constructible<ValueType, U&>::value,
500 "Invalid ValueType");
501 auto* result = (any_cast<U>)(&operand);
502 if (result == nullptr) {
503 any_internal::ThrowBadAnyCast();
504 }
505 return static_cast<ValueType>(*result);
506 }
507
508 // Description at the declaration site (top of file).
509 template <typename ValueType>
510 ValueType any_cast(any&& operand) {
511 using U = typename std::remove_cv<
512 typename std::remove_reference<ValueType>::type>::type;
513 static_assert(std::is_constructible<ValueType, U>::value,
514 "Invalid ValueType");
515 return static_cast<ValueType>(std::move((any_cast<U&>)(operand)));
516 }
517
518 // Description at the declaration site (top of file).
519 template <typename T>
520 const T* any_cast(const any* operand) noexcept {
521 using U =
522 typename std::remove_cv<typename std::remove_reference<T>::type>::type;
523 return operand && operand->GetObjTypeId() == any::IdForType<U>()
524 ? std::addressof(
525 static_cast<const any::Obj<U>*>(operand->obj_.get())->value)
526 : nullptr;
527 }
528
529 // Description at the declaration site (top of file).
530 template <typename T>
531 T* any_cast(any* operand) noexcept {
532 using U =
533 typename std::remove_cv<typename std::remove_reference<T>::type>::type;
534 return operand && operand->GetObjTypeId() == any::IdForType<U>()
535 ? std::addressof(
536 static_cast<any::Obj<U>*>(operand->obj_.get())->value)
537 : nullptr;
538 }
539
540 ABSL_NAMESPACE_END
541 } // namespace absl
542
543 #undef ABSL_ANY_DETAIL_HAS_RTTI
544
545 #endif // ABSL_USES_STD_ANY
546
547 #endif // ABSL_TYPES_ANY_H_
548