// <any> -*- C++ -*-
-// Copyright (C) 2014-2016 Free Software Foundation, Inc.
+// Copyright (C) 2014-2022 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
#pragma GCC system_header
-#if __cplusplus <= 201402L
-# include <bits/c++17_warning.h>
-#else
+#if __cplusplus >= 201703L
+#include <initializer_list>
#include <typeinfo>
#include <new>
-#include <utility>
#include <type_traits>
+#include <bits/utility.h> // in_place_type_t
namespace std _GLIBCXX_VISIBILITY(default)
{
#endif
}
+#define __cpp_lib_any 201606L
+
/**
* @brief A type-safe container of any type.
- *
- * An @c any object's state is either empty or it stores a contained object
+ *
+ * An `any` object's state is either empty or it stores a contained object
* of CopyConstructible type.
+ *
+ * @since C++17
*/
class any
{
// Holds either pointer to a heap object or the contained object itself.
union _Storage
{
- // This constructor intentionally doesn't initialize anything.
- _Storage() = default;
+ constexpr _Storage() : _M_ptr{nullptr} {}
// Prevent trivial copies of this type, buffer might hold a non-POD.
_Storage(const _Storage&) = delete;
struct _Manager_external; // creates contained object on the heap
template<typename _Tp>
- using _Manager = conditional_t<_Internal<_Tp>::value,
- _Manager_internal<_Tp>,
- _Manager_external<_Tp>>;
+ using _Manager = __conditional_t<_Internal<_Tp>::value,
+ _Manager_internal<_Tp>,
+ _Manager_external<_Tp>>;
+
+ template<typename _Tp, typename _VTp = decay_t<_Tp>>
+ using _Decay_if_not_any = enable_if_t<!is_same_v<_VTp, any>, _VTp>;
+
+ /// Emplace with an object created from @p __args as the contained object.
+ template <typename _Tp, typename... _Args,
+ typename _Mgr = _Manager<_Tp>>
+ void __do_emplace(_Args&&... __args)
+ {
+ reset();
+ _Mgr::_S_create(_M_storage, std::forward<_Args>(__args)...);
+ _M_manager = &_Mgr::_S_manage;
+ }
+
+ /// Emplace with an object created from @p __il and @p __args as
+ /// the contained object.
+ template <typename _Tp, typename _Up, typename... _Args,
+ typename _Mgr = _Manager<_Tp>>
+ void __do_emplace(initializer_list<_Up> __il, _Args&&... __args)
+ {
+ reset();
+ _Mgr::_S_create(_M_storage, __il, std::forward<_Args>(__args)...);
+ _M_manager = &_Mgr::_S_manage;
+ }
+
+ template <typename _Res, typename _Tp, typename... _Args>
+ using __any_constructible
+ = enable_if<__and_<is_copy_constructible<_Tp>,
+ is_constructible<_Tp, _Args...>>::value,
+ _Res>;
- template<typename _Tp, typename _Decayed = decay_t<_Tp>>
- using _Decay = enable_if_t<!is_same<_Decayed, any>::value, _Decayed>;
+ template <typename _Tp, typename... _Args>
+ using __any_constructible_t
+ = typename __any_constructible<bool, _Tp, _Args...>::type;
+
+ template<typename _VTp, typename... _Args>
+ using __emplace_t
+ = typename __any_constructible<_VTp&, _VTp, _Args...>::type;
public:
// construct/destruct
/// Default constructor, creates an empty object.
- any() noexcept : _M_manager(nullptr) { }
+ constexpr any() noexcept : _M_manager(nullptr) { }
/// Copy constructor, copies the state of @p __other
any(const any& __other)
{
- if (__other.empty())
+ if (!__other.has_value())
_M_manager = nullptr;
else
{
/**
* @brief Move constructor, transfer the state from @p __other
*
- * @post @c __other.empty() (this postcondition is a GNU extension)
+ * @post @c !__other.has_value() (this postcondition is a GNU extension)
*/
any(any&& __other) noexcept
{
- if (__other.empty())
+ if (!__other.has_value())
_M_manager = nullptr;
else
{
}
/// Construct with a copy of @p __value as the contained object.
- template <typename _ValueType, typename _Tp = _Decay<_ValueType>,
- typename _Mgr = _Manager<_Tp>,
- typename enable_if<is_constructible<_Tp, _ValueType&&>::value,
- bool>::type = true>
- any(_ValueType&& __value)
+ template <typename _Tp, typename _VTp = _Decay_if_not_any<_Tp>,
+ typename _Mgr = _Manager<_VTp>,
+ typename = _Require<__not_<__is_in_place_type<_VTp>>,
+ is_copy_constructible<_VTp>>>
+ any(_Tp&& __value)
: _M_manager(&_Mgr::_S_manage)
{
- _Mgr::_S_create(_M_storage, std::forward<_ValueType>(__value));
- static_assert(is_copy_constructible<_Tp>::value,
- "The contained object must be CopyConstructible");
+ _Mgr::_S_create(_M_storage, std::forward<_Tp>(__value));
}
- /// Construct with a copy of @p __value as the contained object.
- template <typename _ValueType, typename _Tp = _Decay<_ValueType>,
- typename _Mgr = _Manager<_Tp>,
- typename enable_if<!is_constructible<_Tp, _ValueType&&>::value,
- bool>::type = false>
- any(_ValueType&& __value)
+ /// Construct with an object created from @p __args as the contained object.
+ template <typename _Tp, typename... _Args, typename _VTp = decay_t<_Tp>,
+ typename _Mgr = _Manager<_VTp>,
+ __any_constructible_t<_VTp, _Args&&...> = false>
+ explicit
+ any(in_place_type_t<_Tp>, _Args&&... __args)
+ : _M_manager(&_Mgr::_S_manage)
+ {
+ _Mgr::_S_create(_M_storage, std::forward<_Args>(__args)...);
+ }
+
+ /// Construct with an object created from @p __il and @p __args as
+ /// the contained object.
+ template <typename _Tp, typename _Up, typename... _Args,
+ typename _VTp = decay_t<_Tp>, typename _Mgr = _Manager<_VTp>,
+ __any_constructible_t<_VTp, initializer_list<_Up>&,
+ _Args&&...> = false>
+ explicit
+ any(in_place_type_t<_Tp>, initializer_list<_Up> __il, _Args&&... __args)
: _M_manager(&_Mgr::_S_manage)
{
- _Mgr::_S_create(_M_storage, __value);
- static_assert(is_copy_constructible<_Tp>::value,
- "The contained object must be CopyConstructible");
+ _Mgr::_S_create(_M_storage, __il, std::forward<_Args>(__args)...);
}
- /// Destructor, calls @c clear()
- ~any() { clear(); }
+ /// Destructor, calls @c reset()
+ ~any() { reset(); }
// assignments
/// Copy the state of another object.
- any& operator=(const any& __rhs)
+ any&
+ operator=(const any& __rhs)
{
- if (__rhs.empty())
- clear();
- else if (this != &__rhs)
- {
- if (!empty())
- _M_manager(_Op_destroy, this, nullptr);
- _Arg __arg;
- __arg._M_any = this;
- __rhs._M_manager(_Op_clone, &__rhs, &__arg);
- }
+ *this = any(__rhs);
return *this;
}
/**
* @brief Move assignment operator
*
- * @post @c __rhs.empty() (not guaranteed for other implementations)
+ * @post @c !__rhs.has_value() (not guaranteed for other implementations)
*/
- any& operator=(any&& __rhs) noexcept
+ any&
+ operator=(any&& __rhs) noexcept
{
- if (__rhs.empty())
- clear();
+ if (!__rhs.has_value())
+ reset();
else if (this != &__rhs)
{
- if (!empty())
- _M_manager(_Op_destroy, this, nullptr);
+ reset();
_Arg __arg;
__arg._M_any = this;
__rhs._M_manager(_Op_xfer, &__rhs, &__arg);
}
/// Store a copy of @p __rhs as the contained object.
- template<typename _ValueType>
- enable_if_t<!is_same<any, decay_t<_ValueType>>::value, any&>
- operator=(_ValueType&& __rhs)
+ template<typename _Tp>
+ enable_if_t<is_copy_constructible<_Decay_if_not_any<_Tp>>::value, any&>
+ operator=(_Tp&& __rhs)
{
- *this = any(std::forward<_ValueType>(__rhs));
+ *this = any(std::forward<_Tp>(__rhs));
return *this;
}
+ /// Emplace with an object created from @p __args as the contained object.
+ template <typename _Tp, typename... _Args>
+ __emplace_t<decay_t<_Tp>, _Args...>
+ emplace(_Args&&... __args)
+ {
+ using _VTp = decay_t<_Tp>;
+ __do_emplace<_VTp>(std::forward<_Args>(__args)...);
+ return *any::_Manager<_VTp>::_S_access(_M_storage);
+ }
+
+ /// Emplace with an object created from @p __il and @p __args as
+ /// the contained object.
+ template <typename _Tp, typename _Up, typename... _Args>
+ __emplace_t<decay_t<_Tp>, initializer_list<_Up>&, _Args&&...>
+ emplace(initializer_list<_Up> __il, _Args&&... __args)
+ {
+ using _VTp = decay_t<_Tp>;
+ __do_emplace<_VTp, _Up>(__il, std::forward<_Args>(__args)...);
+ return *any::_Manager<_VTp>::_S_access(_M_storage);
+ }
+
// modifiers
/// If not empty, destroy the contained object.
- void clear() noexcept
+ void reset() noexcept
{
- if (!empty())
+ if (has_value())
{
_M_manager(_Op_destroy, this, nullptr);
_M_manager = nullptr;
/// Exchange state with another object.
void swap(any& __rhs) noexcept
{
- if (empty() && __rhs.empty())
+ if (!has_value() && !__rhs.has_value())
return;
- if (!empty() && !__rhs.empty())
+ if (has_value() && __rhs.has_value())
{
if (this == &__rhs)
return;
}
else
{
- any* __empty = empty() ? this : &__rhs;
- any* __full = empty() ? &__rhs : this;
+ any* __empty = !has_value() ? this : &__rhs;
+ any* __full = !has_value() ? &__rhs : this;
_Arg __arg;
__arg._M_any = __empty;
__full->_M_manager(_Op_xfer, __full, &__arg);
// observers
/// Reports whether there is a contained object or not.
- bool empty() const noexcept { return _M_manager == nullptr; }
+ bool has_value() const noexcept { return _M_manager != nullptr; }
#if __cpp_rtti
/// The @c typeid of the contained object, or @c typeid(void) if empty.
const type_info& type() const noexcept
{
- if (empty())
+ if (!has_value())
return typeid(void);
_Arg __arg;
_M_manager(_Op_get_type_info, this, &__arg);
}
#endif
+ /// @cond undocumented
template<typename _Tp>
static constexpr bool __is_valid_cast()
{ return __or_<is_reference<_Tp>, is_copy_constructible<_Tp>>::value; }
+ /// @endcond
private:
enum _Op {
void (*_M_manager)(_Op, const any*, _Arg*);
_Storage _M_storage;
+ /// @cond undocumented
template<typename _Tp>
friend void* __any_caster(const any* __any);
+ /// @endcond
// Manage in-place contained object.
template<typename _Tp>
void* __addr = &__storage._M_buffer;
::new (__addr) _Tp(std::forward<_Up>(__value));
}
+
+ template<typename... _Args>
+ static void
+ _S_create(_Storage& __storage, _Args&&... __args)
+ {
+ void* __addr = &__storage._M_buffer;
+ ::new (__addr) _Tp(std::forward<_Args>(__args)...);
+ }
+
+ static _Tp*
+ _S_access(const _Storage& __storage)
+ {
+ // The contained object is in __storage._M_buffer
+ const void* __addr = &__storage._M_buffer;
+ return static_cast<_Tp*>(const_cast<void*>(__addr));
+ }
};
// Manage external contained object.
{
__storage._M_ptr = new _Tp(std::forward<_Up>(__value));
}
+ template<typename... _Args>
+ static void
+ _S_create(_Storage& __storage, _Args&&... __args)
+ {
+ __storage._M_ptr = new _Tp(std::forward<_Args>(__args)...);
+ }
+ static _Tp*
+ _S_access(const _Storage& __storage)
+ {
+ // The contained object is in *__storage._M_ptr
+ return static_cast<_Tp*>(__storage._M_ptr);
+ }
};
};
/// Exchange the states of two @c any objects.
inline void swap(any& __x, any& __y) noexcept { __x.swap(__y); }
+ /// Create an `any` holding a `_Tp` constructed from `__args...`.
+ template <typename _Tp, typename... _Args>
+ inline
+ enable_if_t<is_constructible_v<any, in_place_type_t<_Tp>, _Args...>, any>
+ make_any(_Args&&... __args)
+ {
+ return any(in_place_type<_Tp>, std::forward<_Args>(__args)...);
+ }
+
+ /// Create an `any` holding a `_Tp` constructed from `__il` and `__args...`.
+ template <typename _Tp, typename _Up, typename... _Args>
+ inline
+ enable_if_t<is_constructible_v<any, in_place_type_t<_Tp>,
+ initializer_list<_Up>&, _Args...>, any>
+ make_any(initializer_list<_Up> __il, _Args&&... __args)
+ {
+ return any(in_place_type<_Tp>, __il, std::forward<_Args>(__args)...);
+ }
+
/**
* @brief Access the contained object.
*
template<typename _ValueType>
inline _ValueType any_cast(const any& __any)
{
+ using _Up = __remove_cvref_t<_ValueType>;
static_assert(any::__is_valid_cast<_ValueType>(),
"Template argument must be a reference or CopyConstructible type");
- auto __p = any_cast<add_const_t<remove_reference_t<_ValueType>>>(&__any);
+ static_assert(is_constructible_v<_ValueType, const _Up&>,
+ "Template argument must be constructible from a const value.");
+ auto __p = any_cast<_Up>(&__any);
if (__p)
- return *__p;
+ return static_cast<_ValueType>(*__p);
__throw_bad_any_cast();
}
template<typename _ValueType>
inline _ValueType any_cast(any& __any)
{
+ using _Up = __remove_cvref_t<_ValueType>;
static_assert(any::__is_valid_cast<_ValueType>(),
"Template argument must be a reference or CopyConstructible type");
- auto __p = any_cast<remove_reference_t<_ValueType>>(&__any);
- if (__p)
- return *__p;
- __throw_bad_any_cast();
- }
-
- template<typename _ValueType,
- typename enable_if<!is_move_constructible<_ValueType>::value
- || is_lvalue_reference<_ValueType>::value,
- bool>::type = true>
- inline _ValueType any_cast(any&& __any)
- {
- static_assert(any::__is_valid_cast<_ValueType>(),
- "Template argument must be a reference or CopyConstructible type");
- auto __p = any_cast<remove_reference_t<_ValueType>>(&__any);
+ static_assert(is_constructible_v<_ValueType, _Up&>,
+ "Template argument must be constructible from an lvalue.");
+ auto __p = any_cast<_Up>(&__any);
if (__p)
- return *__p;
+ return static_cast<_ValueType>(*__p);
__throw_bad_any_cast();
}
- template<typename _ValueType,
- typename enable_if<is_move_constructible<_ValueType>::value
- && !is_lvalue_reference<_ValueType>::value,
- bool>::type = false>
+ template<typename _ValueType>
inline _ValueType any_cast(any&& __any)
{
+ using _Up = __remove_cvref_t<_ValueType>;
static_assert(any::__is_valid_cast<_ValueType>(),
"Template argument must be a reference or CopyConstructible type");
- auto __p = any_cast<remove_reference_t<_ValueType>>(&__any);
+ static_assert(is_constructible_v<_ValueType, _Up>,
+ "Template argument must be constructible from an rvalue.");
+ auto __p = any_cast<_Up>(&__any);
if (__p)
- return std::move(*__p);
+ return static_cast<_ValueType>(std::move(*__p));
__throw_bad_any_cast();
}
- // @}
+ /// @}
+ /// @cond undocumented
template<typename _Tp>
void* __any_caster(const any* __any)
{
- if (__any->_M_manager != &any::_Manager<decay_t<_Tp>>::_S_manage)
+ // any_cast<T> returns non-null if __any->type() == typeid(T) and
+ // typeid(T) ignores cv-qualifiers so remove them:
+ using _Up = remove_cv_t<_Tp>;
+ // The contained value has a decayed type, so if decay_t<U> is not U,
+ // then it's not possible to have a contained value of type U:
+ if constexpr (!is_same_v<decay_t<_Up>, _Up>)
return nullptr;
- any::_Arg __arg;
- __any->_M_manager(any::_Op_access, __any, &__arg);
- return __arg._M_obj;
+ // Only copy constructible types can be used for contained values:
+ else if constexpr (!is_copy_constructible_v<_Up>)
+ return nullptr;
+ // First try comparing function addresses, which works without RTTI
+ else if (__any->_M_manager == &any::_Manager<_Up>::_S_manage
+#if __cpp_rtti
+ || __any->type() == typeid(_Tp)
+#endif
+ )
+ {
+ return any::_Manager<_Up>::_S_access(__any->_M_storage);
+ }
+ return nullptr;
}
+ /// @endcond
/**
* @brief Access the contained object.
template<typename _ValueType>
inline const _ValueType* any_cast(const any* __any) noexcept
{
- if (__any)
- return static_cast<_ValueType*>(__any_caster<_ValueType>(__any));
+ if constexpr (is_object_v<_ValueType>)
+ if (__any)
+ return static_cast<_ValueType*>(__any_caster<_ValueType>(__any));
return nullptr;
}
template<typename _ValueType>
inline _ValueType* any_cast(any* __any) noexcept
{
- if (__any)
- return static_cast<_ValueType*>(__any_caster<_ValueType>(__any));
+ if constexpr (is_object_v<_ValueType>)
+ if (__any)
+ return static_cast<_ValueType*>(__any_caster<_ValueType>(__any));
return nullptr;
}
- // @}
+ /// @}
template<typename _Tp>
void
__ptr->~_Tp();
break;
case _Op_xfer:
- ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr);
+ ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp
+ (std::move(*const_cast<_Tp*>(__ptr)));
__ptr->~_Tp();
__arg->_M_any->_M_manager = __any->_M_manager;
const_cast<any*>(__any)->_M_manager = nullptr;
}
/// @}
-
+
+ namespace __detail::__variant
+ {
+ template<typename> struct _Never_valueless_alt; // see <variant>
+
+ // Provide the strong exception-safety guarantee when emplacing an
+ // any into a variant.
+ template<>
+ struct _Never_valueless_alt<std::any>
+ : std::true_type
+ { };
+ } // namespace __detail::__variant
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
-#endif // C++14
-
+#endif // C++17
#endif // _GLIBCXX_ANY