about summary refs log tree commit diff
path: root/absl/types/any.h
diff options
context:
space:
mode:
Diffstat (limited to 'absl/types/any.h')
-rw-r--r--absl/types/any.h539
1 files changed, 539 insertions, 0 deletions
diff --git a/absl/types/any.h b/absl/types/any.h
new file mode 100644
index 000000000000..a51dea110d0f
--- /dev/null
+++ b/absl/types/any.h
@@ -0,0 +1,539 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// any.h
+// -----------------------------------------------------------------------------
+//
+// This header file define the `absl::any` type for holding a type-safe value
+// of any type. The 'absl::any` type is useful for providing a way to hold
+// something that is, as yet, unspecified. Such unspecified types
+// traditionally are passed between API boundaries until they are later cast to
+// their "destination" types. To cast to such a destination type, use
+// `absl::any_cast()`. Note that when casting an `absl::any`, you must cast it
+// to an explicit type; implicit conversions will throw.
+//
+// Example:
+//
+//   auto a = absl::any(65);
+//   absl::any_cast<int>(a);         // 65
+//   absl::any_cast<char>(a);        // throws absl::bad_any_cast
+//   absl::any_cast<std::string>(a); // throws absl::bad_any_cast
+//
+// `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
+// and is designed to be a drop-in replacement for code compliant with C++17.
+//
+// Traditionally, the behavior of casting to a temporary unspecified type has
+// been accomplished with the `void *` paradigm, where the pointer was to some
+// other unspecified type. `absl::any` provides an "owning" version of `void *`
+// that avoids issues of pointer management.
+//
+// Note: just as in the case of `void *`, use of `absl::any` (and its C++17
+// version `std::any`) is a code smell indicating that your API might not be
+// constructed correctly. We have seen that most uses of `any` are unwarranted,
+// and `absl::any`, like `std::any`, is difficult to use properly. Before using
+// this abstraction, make sure that you should not instead be rewriting your
+// code to be more specific.
+//
+// Abseil expects to release an `absl::variant` type shortly (a C++11 compatible
+// version of the C++17 `std::variant), which is generally preferred for use
+// over `absl::any`.
+#ifndef ABSL_TYPES_ANY_H_
+#define ABSL_TYPES_ANY_H_
+
+#include "absl/base/config.h"
+#include "absl/utility/utility.h"
+
+#ifdef ABSL_HAVE_STD_ANY
+
+#include <any>
+
+namespace absl {
+using std::any;
+using std::any_cast;
+using std::bad_any_cast;
+using std::make_any;
+}  // namespace absl
+
+#else  // ABSL_HAVE_STD_ANY
+
+#include <algorithm>
+#include <cstddef>
+#include <initializer_list>
+#include <memory>
+#include <stdexcept>
+#include <type_traits>
+#include <typeinfo>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/bad_any_cast.h"
+
+// NOTE: This macro is an implementation detail that is undefined at the bottom
+// of the file. It is not intended for expansion directly from user code.
+#ifdef ABSL_ANY_DETAIL_HAS_RTTI
+#error ABSL_ANY_DETAIL_HAS_RTTI cannot be directly set
+#elif !defined(__GNUC__) || defined(__GXX_RTTI)
+#define ABSL_ANY_DETAIL_HAS_RTTI 1
+#endif  // !defined(__GNUC__) || defined(__GXX_RTTI)
+
+namespace absl {
+
+namespace any_internal {
+
+// FastTypeId<Type>() evaluates at compile/link-time to a unique integer for the
+// passed in type. Their values are neither contiguous nor small, making them
+// unfit for using as an index into a vector, but a good match for keys into
+// maps or straight up comparisons.
+// Note that on 64-bit (unix) systems size_t is 64-bit while int is 32-bit and
+// the compiler will happily and quietly assign such a 64-bit value to a
+// 32-bit integer. While a client should never do that it SHOULD still be safe,
+// assuming the BSS segment doesn't span more than 4GiB.
+template<typename Type>
+inline size_t FastTypeId() {
+  static_assert(sizeof(char*) <= sizeof(size_t),
+                "ptr size too large for size_t");
+
+  // This static variable isn't actually used, only its address, so there are
+  // no concurrency issues.
+  static char dummy_var;
+  return reinterpret_cast<size_t>(&dummy_var);
+}
+
+}  // namespace any_internal
+
+class any;
+
+// swap()
+//
+// Swaps two `absl::any` values. Equivalent to `x.swap(y) where `x` and `y` are
+// `absl::any` types.
+void swap(any& x, any& y) noexcept;
+
+// make_any()
+//
+// Constructs an `absl::any` of type `T` with the given arguments.
+template <typename T, typename... Args>
+any make_any(Args&&... args);
+
+// Overload of `absl::make_any()` for constructing an `absl::any` type from an
+// initializer list.
+template <typename T, typename U, typename... Args>
+any make_any(std::initializer_list<U> il, Args&&... args);
+
+// any_cast()
+//
+// Statically casts the value of a `const absl::any` type to the given type.
+// This function will throw `absl::bad_any_cast` if the stored value type of the
+// `absl::any` does not match the cast.
+//
+// `any_cast()` can also be used to get a reference to the internal storage iff
+// a reference type is passed as its `ValueType`:
+//
+// Example:
+//
+//   absl::any my_any = std::vector<int>();
+//   absl::any_cast<std::vector<int>&>(my_any).push_back(42);
+template <typename ValueType>
+ValueType any_cast(const any& operand);
+
+// Overload of `any_cast()` to statically cast the value of a non-const
+// `absl::any` type to the given type. This function will throw
+// `absl::bad_any_cast` if the stored value type of the `absl::any` does not
+// match the cast.
+template <typename ValueType>
+ValueType any_cast(any& operand);  // NOLINT(runtime/references)
+
+// Overload of `any_cast()` to statically cast the rvalue of an `absl::any`
+// type. This function will throw `absl::bad_any_cast` if the stored value type
+// of the `absl::any` does not match the cast.
+template <typename ValueType>
+ValueType any_cast(any&& operand);
+
+// Overload of `any_cast()` to statically cast the value of a const pointer
+// `absl::any` type to the given pointer type, or `nullptr` if the stored value
+// type of the `absl::any` does not match the cast.
+template <typename ValueType>
+const ValueType* any_cast(const any* operand) noexcept;
+
+// Overload of `any_cast()` to statically cast the value of a pointer
+// `absl::any` type to the given pointer type, or `nullptr` if the stored value
+// type of the `absl::any` does not match the cast.
+template <typename ValueType>
+ValueType* any_cast(any* operand) noexcept;
+
+// any
+//
+// An `absl::any` object provides the facility to either store an instance of a
+// type, known as the "contained object", or no value. An `absl::any` is used to
+// store values of types that are unknown at compile time. The `absl::any`
+// object, when containing a value, must contain a value type; storing a
+// reference type is neither desired nor supported.
+//
+// An `absl::any` can only store a type that is copy-constructable; move-only
+// types are not allowed within an `any` object.
+//
+// Example:
+//
+//   auto a = absl::any(65);                 // Literal, copyable
+//   auto b = absl::any(std::vector<int>()); // Default-initialized, copyable
+//   std::unique_ptr<Foo> my_foo;
+//   auto c = absl::any(std::move(my_foo));  // Error, not copy-constructable
+//
+// Note that `absl::any` makes use of decayed types (`absl::decay_t` in this
+// context) to remove const-volative qualifiers (known as "cv qualifiers"),
+// decay functions to function pointers, etc. We essentially "decay" a given
+// type into its essential type.
+//
+// `absl::any` makes use of decayed types when determing the basic type `T` of
+// the value to store in the any's contained object. In the documentation below,
+// we explcitly denote this by using the phrase "a decayed type of `T`".
+//
+// Example:
+//
+//   const int a = 4;
+//   absl::any foo(a);  // Decay ensures we store an "int", not a "const int&".
+//
+//   void my_function() {}
+//   absl::any bar(my_function);  // Decay ensures we store a function pointer.
+//
+// `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
+// and is designed to be a drop-in replacement for code compliant with C++17.
+class any {
+ private:
+  template <typename T>
+  struct IsInPlaceType;
+
+ public:
+  // Constructors
+
+  // Constructs an empty `absl::any` object (`any::has_value()` will return
+  // `false`).
+  constexpr any() noexcept;
+
+  // Copy constructs an `absl::any` object with a "contained object" of the
+  // passed type of `other` (or an empty `absl::any` if `other.has_value()` is
+  // `false`.
+  any(const any& other)
+      : obj_(other.has_value() ? other.obj_->Clone()
+                               : std::unique_ptr<ObjInterface>()) {}
+
+  // Move constructs an `absl::any` object with a "contained object" of the
+  // passed type of `other` (or an empty `absl::any` if `other.has_value()` is
+  // `false`).
+  any(any&& other) noexcept = default;
+
+  // Constructs an `absl::any` object with a "contained object" of the decayed
+  // type of `T`, which is initialized via `std::forward<T>(value)`.
+  //
+  // This constructor will not participate in overload resolution if the
+  // decayed type of `T` is not copy-constructible.
+  template <
+      typename T, typename VT = absl::decay_t<T>,
+      absl::enable_if_t<!absl::disjunction<
+          std::is_same<any, VT>, IsInPlaceType<VT>,
+          absl::negation<std::is_copy_constructible<VT> > >::value>* = nullptr>
+  any(T&& value) : obj_(new Obj<VT>(in_place, std::forward<T>(value))) {}
+
+  // Constructs an `absl::any` object with a "contained object" of the decayed
+  // type of `T`, which is initialized via `std::forward<T>(value)`.
+  template <typename T, typename... Args, typename VT = absl::decay_t<T>,
+            absl::enable_if_t<absl::conjunction<
+                std::is_copy_constructible<VT>,
+                std::is_constructible<VT, Args...>>::value>* = nullptr>
+  explicit any(in_place_type_t<T> /*tag*/, Args&&... args)
+      : obj_(new Obj<VT>(in_place, std::forward<Args>(args)...)) {}
+
+  // Constructs an `absl::any` object with a "contained object" of the passed
+  // type `VT` as a decayed type of `T`. `VT` is initialized as if
+  // direct-non-list-initializing an object of type `VT` with the arguments
+  // `initializer_list, std::forward<Args>(args)...`.
+  template <
+      typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
+      absl::enable_if_t<
+          absl::conjunction<std::is_copy_constructible<VT>,
+                            std::is_constructible<VT, std::initializer_list<U>&,
+                                                  Args...>>::value>* = nullptr>
+  explicit any(in_place_type_t<T> /*tag*/, std::initializer_list<U> ilist,
+               Args&&... args)
+      : obj_(new Obj<VT>(in_place, ilist, std::forward<Args>(args)...)) {}
+
+  // Assignment operators
+
+  // Copy assigns an `absl::any` object with a "contained object" of the
+  // passed type.
+  any& operator=(const any& rhs) {
+    any(rhs).swap(*this);
+    return *this;
+  }
+
+  // Move assigns an `absl::any` object with a "contained object" of the
+  // passed type. `rhs` is left in a valid but otherwise unspecified state.
+  any& operator=(any&& rhs) noexcept {
+    any(std::move(rhs)).swap(*this);
+    return *this;
+  }
+
+  // Assigns an `absl::any` object with a "contained object" of the passed type.
+  template <typename T, typename VT = absl::decay_t<T>,
+            absl::enable_if_t<absl::conjunction<
+                absl::negation<std::is_same<VT, any>>,
+                std::is_copy_constructible<VT>>::value>* = nullptr>
+  any& operator=(T&& rhs) {
+    any tmp(in_place_type_t<VT>(), std::forward<T>(rhs));
+    tmp.swap(*this);
+    return *this;
+  }
+
+  // Modifiers
+
+  // any::emplace()
+  //
+  // Emplaces a value within an `absl::any` object by calling `any::reset()`,
+  // initializing the contained value as if direct-non-list-initializing an
+  // object of type `VT` with the arguments `std::forward<Args>(args)...`, and
+  // returning a reference to the new contained value.
+  //
+  // Note: If an exception is thrown during the call to `VT`’s constructor,
+  // `*this` does not contain a value, and any previously contained value has
+  // been destroyed.
+  template <
+      typename T, typename... Args, typename VT = absl::decay_t<T>,
+      absl::enable_if_t<std::is_copy_constructible<VT>::value &&
+                        std::is_constructible<VT, Args...>::value>* = nullptr>
+  VT& emplace(Args&&... args) {
+    reset();  // NOTE: reset() is required here even in the world of exceptions.
+    Obj<VT>* const object_ptr =
+        new Obj<VT>(in_place, std::forward<Args>(args)...);
+    obj_ = std::unique_ptr<ObjInterface>(object_ptr);
+    return object_ptr->value;
+  }
+
+  // Overload of `any::emplace()` to emplace a value within an `absl::any`
+  // object by calling `any::reset()`, initializing the contained value as if
+  // direct-non-list-initializing an object of type `VT` with the arguments
+  // `initilizer_list, std::forward<Args>(args)...`, and returning a reference
+  // to the new contained value.
+  //
+  // Note: If an exception is thrown during the call to `VT`’s constructor,
+  // `*this` does not contain a value, and any previously contained value has
+  // been destroyed. The function shall not participate in overload resolution
+  // unless `is_copy_constructible_v<VT>` is `true` and
+  // `is_constructible_v<VT, initializer_list<U>&, Args...>` is `true`.
+  template <
+      typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
+      absl::enable_if_t<std::is_copy_constructible<VT>::value &&
+                        std::is_constructible<VT, std::initializer_list<U>&,
+                                              Args...>::value>* = nullptr>
+  VT& emplace(std::initializer_list<U> ilist, Args&&... args) {
+    reset();  // NOTE: reset() is required here even in the world of exceptions.
+    Obj<VT>* const object_ptr =
+        new Obj<VT>(in_place, ilist, std::forward<Args>(args)...);
+    obj_ = std::unique_ptr<ObjInterface>(object_ptr);
+    return object_ptr->value;
+  }
+
+  // any::reset()
+  //
+  // Resets the state of the `absl::any` object, destroying the contained object
+  // if present.
+  void reset() noexcept { obj_ = nullptr; }
+
+  // any::swap()
+  //
+  // Swaps the passed value and the value of this `absl::any` object.
+  void swap(any& other) noexcept { obj_.swap(other.obj_); }
+
+  // Observors
+
+  // any::has_value()
+  //
+  // Returns `true` if the `any` object has a contained value, otherwise
+  // returns `false`.
+  bool has_value() const noexcept { return obj_ != nullptr; }
+
+#if ABSL_ANY_DETAIL_HAS_RTTI
+  // Returns: typeid(T) if *this has a contained object of type T, otherwise
+  // typeid(void).
+  const std::type_info& type() const noexcept {
+    if (has_value()) {
+      return obj_->Type();
+    }
+
+    return typeid(void);
+  }
+#endif  // ABSL_ANY_DETAIL_HAS_RTTI
+ private:
+  // Tagged type-erased abstraction for holding a cloneable object.
+  class ObjInterface {
+   public:
+    virtual ~ObjInterface() = default;
+    virtual std::unique_ptr<ObjInterface> Clone() const = 0;
+    virtual size_t type_id() const noexcept = 0;
+#if ABSL_ANY_DETAIL_HAS_RTTI
+    virtual const std::type_info& Type() const noexcept = 0;
+#endif  // ABSL_ANY_DETAIL_HAS_RTTI
+  };
+
+  // Hold a value of some queryable type, with an ability to Clone it.
+  template <typename T>
+  class Obj : public ObjInterface {
+   public:
+    template <typename... Args>
+    explicit Obj(in_place_t /*tag*/, Args&&... args)
+        : value(std::forward<Args>(args)...) {}
+
+    std::unique_ptr<ObjInterface> Clone() const final {
+      return std::unique_ptr<ObjInterface>(new Obj(in_place, value));
+    }
+
+    size_t type_id() const noexcept final { return IdForType<T>(); }
+
+#if ABSL_ANY_DETAIL_HAS_RTTI
+    const std::type_info& Type() const noexcept final { return typeid(T); }
+#endif  // ABSL_ANY_DETAIL_HAS_RTTI
+
+    T value;
+  };
+
+  std::unique_ptr<ObjInterface> CloneObj() const {
+    if (!obj_) return nullptr;
+    return obj_->Clone();
+  }
+
+  template <typename T>
+  static size_t IdForType() {
+    // Note: This type dance is to make the behavior consistent with typeid.
+    using NormalizedType =
+        typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+
+    return any_internal::FastTypeId<NormalizedType>();
+  }
+
+  size_t GetObjTypeId() const {
+    return obj_ == nullptr ? any_internal::FastTypeId<void>() : obj_->type_id();
+  }
+
+  // `absl::any` nonmember functions //
+
+  // Description at the declaration site (top of file).
+  template <typename ValueType>
+  friend ValueType any_cast(const any& operand);
+
+  // Description at the declaration site (top of file).
+  template <typename ValueType>
+  friend ValueType any_cast(any& operand);  // NOLINT(runtime/references)
+
+  // Description at the declaration site (top of file).
+  template <typename T>
+  friend const T* any_cast(const any* operand) noexcept;
+
+  // Description at the declaration site (top of file).
+  template <typename T>
+  friend T* any_cast(any* operand) noexcept;
+
+  std::unique_ptr<ObjInterface> obj_;
+};
+
+// -----------------------------------------------------------------------------
+// Implementation Details
+// -----------------------------------------------------------------------------
+
+constexpr any::any() noexcept = default;
+
+template <typename T>
+struct any::IsInPlaceType : std::false_type {};
+
+template <typename T>
+struct any::IsInPlaceType<in_place_type_t<T>> : std::true_type {};
+
+inline void swap(any& x, any& y) noexcept { x.swap(y); }
+
+// Description at the declaration site (top of file).
+template <typename T, typename... Args>
+any make_any(Args&&... args) {
+  return any(in_place_type_t<T>(), std::forward<Args>(args)...);
+}
+
+// Description at the declaration site (top of file).
+template <typename T, typename U, typename... Args>
+any make_any(std::initializer_list<U> il, Args&&... args) {
+  return any(in_place_type_t<T>(), il, std::forward<Args>(args)...);
+}
+
+// Description at the declaration site (top of file).
+template <typename ValueType>
+ValueType any_cast(const any& operand) {
+  using U = typename std::remove_cv<
+      typename std::remove_reference<ValueType>::type>::type;
+  static_assert(std::is_constructible<ValueType, const U&>::value,
+                "Invalid ValueType");
+  auto* const result = (any_cast<U>)(&operand);
+  if (result == nullptr) {
+    any_internal::ThrowBadAnyCast();
+  }
+  return static_cast<ValueType>(*result);
+}
+
+// Description at the declaration site (top of file).
+template <typename ValueType>
+ValueType any_cast(any& operand) {  // NOLINT(runtime/references)
+  using U = typename std::remove_cv<
+      typename std::remove_reference<ValueType>::type>::type;
+  static_assert(std::is_constructible<ValueType, U&>::value,
+                "Invalid ValueType");
+  auto* result = (any_cast<U>)(&operand);
+  if (result == nullptr) {
+    any_internal::ThrowBadAnyCast();
+  }
+  return static_cast<ValueType>(*result);
+}
+
+// Description at the declaration site (top of file).
+template <typename ValueType>
+ValueType any_cast(any&& operand) {
+  using U = typename std::remove_cv<
+      typename std::remove_reference<ValueType>::type>::type;
+  static_assert(std::is_constructible<ValueType, U>::value,
+                "Invalid ValueType");
+  return static_cast<ValueType>(std::move((any_cast<U&>)(operand)));
+}
+
+// Description at the declaration site (top of file).
+template <typename T>
+const T* any_cast(const any* operand) noexcept {
+  return operand && operand->GetObjTypeId() == any::IdForType<T>()
+             ? std::addressof(
+                   static_cast<const any::Obj<T>*>(operand->obj_.get())->value)
+             : nullptr;
+}
+
+// Description at the declaration site (top of file).
+template <typename T>
+T* any_cast(any* operand) noexcept {
+  return operand && operand->GetObjTypeId() == any::IdForType<T>()
+             ? std::addressof(
+                   static_cast<any::Obj<T>*>(operand->obj_.get())->value)
+             : nullptr;
+}
+
+}  // namespace absl
+
+#undef ABSL_ANY_DETAIL_HAS_RTTI
+
+#endif  // ABSL_HAVE_STD_ANY
+
+#endif  // ABSL_TYPES_ANY_H_