xref: /aosp_15_r20/external/private-join-and-compute/third_party/abseil-cpp-20230125.2/absl/types/any.h (revision a6aa18fbfbf9cb5cd47356a9d1b057768998488c)
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 has also released an `absl::variant` type (a C++11 compatible version
51 // of the C++17 `std::variant`), which is generally preferred for use over
52 // `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/internal/fast_type_id.h"
84 #include "absl/meta/type_traits.h"
85 #include "absl/types/bad_any_cast.h"
86 
87 namespace absl {
88 ABSL_NAMESPACE_BEGIN
89 
90 class any;
91 
92 // swap()
93 //
94 // Swaps two `absl::any` values. Equivalent to `x.swap(y) where `x` and `y` are
95 // `absl::any` types.
96 void swap(any& x, any& y) noexcept;
97 
98 // make_any()
99 //
100 // Constructs an `absl::any` of type `T` with the given arguments.
101 template <typename T, typename... Args>
102 any make_any(Args&&... args);
103 
104 // Overload of `absl::make_any()` for constructing an `absl::any` type from an
105 // initializer list.
106 template <typename T, typename U, typename... Args>
107 any make_any(std::initializer_list<U> il, Args&&... args);
108 
109 // any_cast()
110 //
111 // Statically casts the value of a `const absl::any` type to the given type.
112 // This function will throw `absl::bad_any_cast` if the stored value type of the
113 // `absl::any` does not match the cast.
114 //
115 // `any_cast()` can also be used to get a reference to the internal storage iff
116 // a reference type is passed as its `ValueType`:
117 //
118 // Example:
119 //
120 //   absl::any my_any = std::vector<int>();
121 //   absl::any_cast<std::vector<int>&>(my_any).push_back(42);
122 template <typename ValueType>
123 ValueType any_cast(const any& operand);
124 
125 // Overload of `any_cast()` to statically cast the value of a non-const
126 // `absl::any` type to the given type. This function will throw
127 // `absl::bad_any_cast` if the stored value type of the `absl::any` does not
128 // match the cast.
129 template <typename ValueType>
130 ValueType any_cast(any& operand);  // NOLINT(runtime/references)
131 
132 // Overload of `any_cast()` to statically cast the rvalue of an `absl::any`
133 // type. This function will throw `absl::bad_any_cast` if the stored value type
134 // of the `absl::any` does not match the cast.
135 template <typename ValueType>
136 ValueType any_cast(any&& operand);
137 
138 // Overload of `any_cast()` to statically cast the value of a const pointer
139 // `absl::any` type to the given pointer type, or `nullptr` if the stored value
140 // type of the `absl::any` does not match the cast.
141 template <typename ValueType>
142 const ValueType* any_cast(const any* operand) noexcept;
143 
144 // Overload of `any_cast()` to statically cast the value of a pointer
145 // `absl::any` type to the given pointer type, or `nullptr` if the stored value
146 // type of the `absl::any` does not match the cast.
147 template <typename ValueType>
148 ValueType* any_cast(any* operand) noexcept;
149 
150 // -----------------------------------------------------------------------------
151 // absl::any
152 // -----------------------------------------------------------------------------
153 //
154 // An `absl::any` object provides the facility to either store an instance of a
155 // type, known as the "contained object", or no value. An `absl::any` is used to
156 // store values of types that are unknown at compile time. The `absl::any`
157 // object, when containing a value, must contain a value type; storing a
158 // reference type is neither desired nor supported.
159 //
160 // An `absl::any` can only store a type that is copy-constructible; move-only
161 // types are not allowed within an `any` object.
162 //
163 // Example:
164 //
165 //   auto a = absl::any(65);                 // Literal, copyable
166 //   auto b = absl::any(std::vector<int>()); // Default-initialized, copyable
167 //   std::unique_ptr<Foo> my_foo;
168 //   auto c = absl::any(std::move(my_foo));  // Error, not copy-constructible
169 //
170 // Note that `absl::any` makes use of decayed types (`absl::decay_t` in this
171 // context) to remove const-volatile qualifiers (known as "cv qualifiers"),
172 // decay functions to function pointers, etc. We essentially "decay" a given
173 // type into its essential type.
174 //
175 // `absl::any` makes use of decayed types when determining the basic type `T` of
176 // the value to store in the any's contained object. In the documentation below,
177 // we explicitly denote this by using the phrase "a decayed type of `T`".
178 //
179 // Example:
180 //
181 //   const int a = 4;
182 //   absl::any foo(a);  // Decay ensures we store an "int", not a "const int&".
183 //
184 //   void my_function() {}
185 //   absl::any bar(my_function);  // Decay ensures we store a function pointer.
186 //
187 // `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
188 // and is designed to be a drop-in replacement for code compliant with C++17.
189 class any {
190  private:
191   template <typename T>
192   struct IsInPlaceType;
193 
194  public:
195   // Constructors
196 
197   // Constructs an empty `absl::any` object (`any::has_value()` will return
198   // `false`).
199   constexpr any() noexcept;
200 
201   // Copy constructs an `absl::any` object with a "contained object" of the
202   // passed type of `other` (or an empty `absl::any` if `other.has_value()` is
203   // `false`.
any(const any & other)204   any(const any& other)
205       : obj_(other.has_value() ? other.obj_->Clone()
206                                : std::unique_ptr<ObjInterface>()) {}
207 
208   // Move constructs an `absl::any` object with a "contained object" of the
209   // passed type of `other` (or an empty `absl::any` if `other.has_value()` is
210   // `false`).
211   any(any&& other) noexcept = default;
212 
213   // Constructs an `absl::any` object with a "contained object" of the decayed
214   // type of `T`, which is initialized via `std::forward<T>(value)`.
215   //
216   // This constructor will not participate in overload resolution if the
217   // decayed type of `T` is not copy-constructible.
218   template <
219       typename T, typename VT = absl::decay_t<T>,
220       absl::enable_if_t<!absl::disjunction<
221           std::is_same<any, VT>, IsInPlaceType<VT>,
222           absl::negation<std::is_copy_constructible<VT> > >::value>* = nullptr>
any(T && value)223   any(T&& value) : obj_(new Obj<VT>(in_place, std::forward<T>(value))) {}
224 
225   // Constructs an `absl::any` object with a "contained object" of the decayed
226   // type of `T`, which is initialized via `std::forward<T>(value)`.
227   template <typename T, typename... Args, typename VT = absl::decay_t<T>,
228             absl::enable_if_t<absl::conjunction<
229                 std::is_copy_constructible<VT>,
230                 std::is_constructible<VT, Args...>>::value>* = nullptr>
any(in_place_type_t<T>,Args &&...args)231   explicit any(in_place_type_t<T> /*tag*/, Args&&... args)
232       : obj_(new Obj<VT>(in_place, std::forward<Args>(args)...)) {}
233 
234   // Constructs an `absl::any` object with a "contained object" of the passed
235   // type `VT` as a decayed type of `T`. `VT` is initialized as if
236   // direct-non-list-initializing an object of type `VT` with the arguments
237   // `initializer_list, std::forward<Args>(args)...`.
238   template <
239       typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
240       absl::enable_if_t<
241           absl::conjunction<std::is_copy_constructible<VT>,
242                             std::is_constructible<VT, std::initializer_list<U>&,
243                                                   Args...>>::value>* = nullptr>
any(in_place_type_t<T>,std::initializer_list<U> ilist,Args &&...args)244   explicit any(in_place_type_t<T> /*tag*/, std::initializer_list<U> ilist,
245                Args&&... args)
246       : obj_(new Obj<VT>(in_place, ilist, std::forward<Args>(args)...)) {}
247 
248   // Assignment operators
249 
250   // Copy assigns an `absl::any` object with a "contained object" of the
251   // passed type.
252   any& operator=(const any& rhs) {
253     any(rhs).swap(*this);
254     return *this;
255   }
256 
257   // Move assigns an `absl::any` object with a "contained object" of the
258   // passed type. `rhs` is left in a valid but otherwise unspecified state.
259   any& operator=(any&& rhs) noexcept {
260     any(std::move(rhs)).swap(*this);
261     return *this;
262   }
263 
264   // Assigns an `absl::any` object with a "contained object" of the passed type.
265   template <typename T, typename VT = absl::decay_t<T>,
266             absl::enable_if_t<absl::conjunction<
267                 absl::negation<std::is_same<VT, any>>,
268                 std::is_copy_constructible<VT>>::value>* = nullptr>
269   any& operator=(T&& rhs) {
270     any tmp(in_place_type_t<VT>(), std::forward<T>(rhs));
271     tmp.swap(*this);
272     return *this;
273   }
274 
275   // Modifiers
276 
277   // any::emplace()
278   //
279   // Emplaces a value within an `absl::any` object by calling `any::reset()`,
280   // initializing the contained value as if direct-non-list-initializing an
281   // object of type `VT` with the arguments `std::forward<Args>(args)...`, and
282   // returning a reference to the new contained value.
283   //
284   // Note: If an exception is thrown during the call to `VT`'s constructor,
285   // `*this` does not contain a value, and any previously contained value has
286   // been destroyed.
287   template <
288       typename T, typename... Args, typename VT = absl::decay_t<T>,
289       absl::enable_if_t<std::is_copy_constructible<VT>::value &&
290                         std::is_constructible<VT, Args...>::value>* = nullptr>
emplace(Args &&...args)291   VT& emplace(Args&&... args) {
292     reset();  // NOTE: reset() is required here even in the world of exceptions.
293     Obj<VT>* const object_ptr =
294         new Obj<VT>(in_place, std::forward<Args>(args)...);
295     obj_ = std::unique_ptr<ObjInterface>(object_ptr);
296     return object_ptr->value;
297   }
298 
299   // Overload of `any::emplace()` to emplace a value within an `absl::any`
300   // object by calling `any::reset()`, initializing the contained value as if
301   // direct-non-list-initializing an object of type `VT` with the arguments
302   // `initializer_list, std::forward<Args>(args)...`, and returning a reference
303   // to the new contained value.
304   //
305   // Note: If an exception is thrown during the call to `VT`'s constructor,
306   // `*this` does not contain a value, and any previously contained value has
307   // been destroyed. The function shall not participate in overload resolution
308   // unless `is_copy_constructible_v<VT>` is `true` and
309   // `is_constructible_v<VT, initializer_list<U>&, Args...>` is `true`.
310   template <
311       typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
312       absl::enable_if_t<std::is_copy_constructible<VT>::value &&
313                         std::is_constructible<VT, std::initializer_list<U>&,
314                                               Args...>::value>* = nullptr>
emplace(std::initializer_list<U> ilist,Args &&...args)315   VT& emplace(std::initializer_list<U> ilist, Args&&... args) {
316     reset();  // NOTE: reset() is required here even in the world of exceptions.
317     Obj<VT>* const object_ptr =
318         new Obj<VT>(in_place, ilist, std::forward<Args>(args)...);
319     obj_ = std::unique_ptr<ObjInterface>(object_ptr);
320     return object_ptr->value;
321   }
322 
323   // any::reset()
324   //
325   // Resets the state of the `absl::any` object, destroying the contained object
326   // if present.
reset()327   void reset() noexcept { obj_ = nullptr; }
328 
329   // any::swap()
330   //
331   // Swaps the passed value and the value of this `absl::any` object.
swap(any & other)332   void swap(any& other) noexcept { obj_.swap(other.obj_); }
333 
334   // Observers
335 
336   // any::has_value()
337   //
338   // Returns `true` if the `any` object has a contained value, otherwise
339   // returns `false`.
has_value()340   bool has_value() const noexcept { return obj_ != nullptr; }
341 
342 #ifdef ABSL_INTERNAL_HAS_RTTI
343   // Returns: typeid(T) if *this has a contained object of type T, otherwise
344   // typeid(void).
type()345   const std::type_info& type() const noexcept {
346     if (has_value()) {
347       return obj_->Type();
348     }
349 
350     return typeid(void);
351   }
352 #endif  // ABSL_INTERNAL_HAS_RTTI
353 
354  private:
355   // Tagged type-erased abstraction for holding a cloneable object.
356   class ObjInterface {
357    public:
358     virtual ~ObjInterface() = default;
359     virtual std::unique_ptr<ObjInterface> Clone() const = 0;
360     virtual const void* ObjTypeId() const noexcept = 0;
361 #ifdef ABSL_INTERNAL_HAS_RTTI
362     virtual const std::type_info& Type() const noexcept = 0;
363 #endif  // ABSL_INTERNAL_HAS_RTTI
364   };
365 
366   // Hold a value of some queryable type, with an ability to Clone it.
367   template <typename T>
368   class Obj : public ObjInterface {
369    public:
370     template <typename... Args>
Obj(in_place_t,Args &&...args)371     explicit Obj(in_place_t /*tag*/, Args&&... args)
372         : value(std::forward<Args>(args)...) {}
373 
Clone()374     std::unique_ptr<ObjInterface> Clone() const final {
375       return std::unique_ptr<ObjInterface>(new Obj(in_place, value));
376     }
377 
ObjTypeId()378     const void* ObjTypeId() const noexcept final { return IdForType<T>(); }
379 
380 #ifdef ABSL_INTERNAL_HAS_RTTI
Type()381     const std::type_info& Type() const noexcept final { return typeid(T); }
382 #endif  // ABSL_INTERNAL_HAS_RTTI
383 
384     T value;
385   };
386 
CloneObj()387   std::unique_ptr<ObjInterface> CloneObj() const {
388     if (!obj_) return nullptr;
389     return obj_->Clone();
390   }
391 
392   template <typename T>
IdForType()393   constexpr static const void* IdForType() {
394     // Note: This type dance is to make the behavior consistent with typeid.
395     using NormalizedType =
396         typename std::remove_cv<typename std::remove_reference<T>::type>::type;
397 
398     return base_internal::FastTypeId<NormalizedType>();
399   }
400 
GetObjTypeId()401   const void* GetObjTypeId() const {
402     return obj_ ? obj_->ObjTypeId() : base_internal::FastTypeId<void>();
403   }
404 
405   // `absl::any` nonmember functions //
406 
407   // Description at the declaration site (top of file).
408   template <typename ValueType>
409   friend ValueType any_cast(const any& operand);
410 
411   // Description at the declaration site (top of file).
412   template <typename ValueType>
413   friend ValueType any_cast(any& operand);  // NOLINT(runtime/references)
414 
415   // Description at the declaration site (top of file).
416   template <typename T>
417   friend const T* any_cast(const any* operand) noexcept;
418 
419   // Description at the declaration site (top of file).
420   template <typename T>
421   friend T* any_cast(any* operand) noexcept;
422 
423   std::unique_ptr<ObjInterface> obj_;
424 };
425 
426 // -----------------------------------------------------------------------------
427 // Implementation Details
428 // -----------------------------------------------------------------------------
429 
430 constexpr any::any() noexcept = default;
431 
432 template <typename T>
433 struct any::IsInPlaceType : std::false_type {};
434 
435 template <typename T>
436 struct any::IsInPlaceType<in_place_type_t<T>> : std::true_type {};
437 
438 inline void swap(any& x, any& y) noexcept { x.swap(y); }
439 
440 // Description at the declaration site (top of file).
441 template <typename T, typename... Args>
442 any make_any(Args&&... args) {
443   return any(in_place_type_t<T>(), std::forward<Args>(args)...);
444 }
445 
446 // Description at the declaration site (top of file).
447 template <typename T, typename U, typename... Args>
448 any make_any(std::initializer_list<U> il, Args&&... args) {
449   return any(in_place_type_t<T>(), il, std::forward<Args>(args)...);
450 }
451 
452 // Description at the declaration site (top of file).
453 template <typename ValueType>
454 ValueType any_cast(const any& operand) {
455   using U = typename std::remove_cv<
456       typename std::remove_reference<ValueType>::type>::type;
457   static_assert(std::is_constructible<ValueType, const U&>::value,
458                 "Invalid ValueType");
459   auto* const result = (any_cast<U>)(&operand);
460   if (result == nullptr) {
461     any_internal::ThrowBadAnyCast();
462   }
463   return static_cast<ValueType>(*result);
464 }
465 
466 // Description at the declaration site (top of file).
467 template <typename ValueType>
468 ValueType any_cast(any& operand) {  // NOLINT(runtime/references)
469   using U = typename std::remove_cv<
470       typename std::remove_reference<ValueType>::type>::type;
471   static_assert(std::is_constructible<ValueType, U&>::value,
472                 "Invalid ValueType");
473   auto* result = (any_cast<U>)(&operand);
474   if (result == nullptr) {
475     any_internal::ThrowBadAnyCast();
476   }
477   return static_cast<ValueType>(*result);
478 }
479 
480 // Description at the declaration site (top of file).
481 template <typename ValueType>
482 ValueType any_cast(any&& operand) {
483   using U = typename std::remove_cv<
484       typename std::remove_reference<ValueType>::type>::type;
485   static_assert(std::is_constructible<ValueType, U>::value,
486                 "Invalid ValueType");
487   return static_cast<ValueType>(std::move((any_cast<U&>)(operand)));
488 }
489 
490 // Description at the declaration site (top of file).
491 template <typename T>
492 const T* any_cast(const any* operand) noexcept {
493   using U =
494       typename std::remove_cv<typename std::remove_reference<T>::type>::type;
495   return operand && operand->GetObjTypeId() == any::IdForType<U>()
496              ? std::addressof(
497                    static_cast<const any::Obj<U>*>(operand->obj_.get())->value)
498              : nullptr;
499 }
500 
501 // Description at the declaration site (top of file).
502 template <typename T>
503 T* any_cast(any* operand) noexcept {
504   using U =
505       typename std::remove_cv<typename std::remove_reference<T>::type>::type;
506   return operand && operand->GetObjTypeId() == any::IdForType<U>()
507              ? std::addressof(
508                    static_cast<any::Obj<U>*>(operand->obj_.get())->value)
509              : nullptr;
510 }
511 
512 ABSL_NAMESPACE_END
513 }  // namespace absl
514 
515 #endif  // ABSL_USES_STD_ANY
516 
517 #endif  // ABSL_TYPES_ANY_H_
518