forked from OSchip/llvm-project
[libcxx] Add std::any
Summary: This patch adds std::any by moving/adapting <experimental/any>. This patch also implements the std::any parts of p0032r3 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0032r3.pdf) and LWG 2509 (http://cplusplus.github.io/LWG/lwg-defects.html#2509). I plan to push it in a day or two if there are no comments. Reviewers: mclow.lists, EricWF Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D22733 llvm-svn: 278310
This commit is contained in:
parent
25fb5bda0f
commit
324506b9f3
|
@ -0,0 +1,658 @@
|
|||
// -*- C++ -*-
|
||||
//===------------------------------ any -----------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP_ANY
|
||||
#define _LIBCPP_ANY
|
||||
|
||||
/*
|
||||
any synopsis
|
||||
|
||||
namespace std {
|
||||
|
||||
class bad_any_cast : public bad_cast
|
||||
{
|
||||
public:
|
||||
virtual const char* what() const noexcept;
|
||||
};
|
||||
|
||||
class any
|
||||
{
|
||||
public:
|
||||
|
||||
// 6.3.1 any construct/destruct
|
||||
any() noexcept;
|
||||
|
||||
any(const any& other);
|
||||
any(any&& other) noexcept;
|
||||
|
||||
template <class ValueType>
|
||||
any(ValueType&& value);
|
||||
|
||||
~any();
|
||||
|
||||
// 6.3.2 any assignments
|
||||
any& operator=(const any& rhs);
|
||||
any& operator=(any&& rhs) noexcept;
|
||||
|
||||
template <class ValueType>
|
||||
any& operator=(ValueType&& rhs);
|
||||
|
||||
// 6.3.3 any modifiers
|
||||
void reset() noexcept;
|
||||
void swap(any& rhs) noexcept;
|
||||
|
||||
// 6.3.4 any observers
|
||||
bool has_value() const noexcept;
|
||||
const type_info& type() const noexcept;
|
||||
};
|
||||
|
||||
// 6.4 Non-member functions
|
||||
void swap(any& x, any& y) noexcept;
|
||||
|
||||
template <class T, class ...Args>
|
||||
any make_any(Args&& ...args);
|
||||
template <class T, class U, class ...Args>
|
||||
any make_any(initializer_list<U>, Args&& ...args);
|
||||
|
||||
template<class ValueType>
|
||||
ValueType any_cast(const any& operand);
|
||||
template<class ValueType>
|
||||
ValueType any_cast(any& operand);
|
||||
template<class ValueType>
|
||||
ValueType any_cast(any&& operand);
|
||||
|
||||
template<class ValueType>
|
||||
const ValueType* any_cast(const any* operand) noexcept;
|
||||
template<class ValueType>
|
||||
ValueType* any_cast(any* operand) noexcept;
|
||||
|
||||
} // namespace fundamentals_v1
|
||||
} // namespace experimental
|
||||
} // namespace std
|
||||
|
||||
*/
|
||||
|
||||
#include <experimental/__config>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
namespace std {
|
||||
class _LIBCPP_EXCEPTION_ABI bad_any_cast : public bad_cast
|
||||
{
|
||||
public:
|
||||
virtual const char* what() const _NOEXCEPT;
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER > 14
|
||||
|
||||
// Forward declarations
|
||||
class _LIBCPP_TYPE_VIS_ONLY any;
|
||||
|
||||
template <class _ValueType>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
add_pointer_t<add_const_t<_ValueType>>
|
||||
any_cast(any const *) _NOEXCEPT;
|
||||
|
||||
template <class _ValueType>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
add_pointer_t<_ValueType> any_cast(any *) _NOEXCEPT;
|
||||
|
||||
namespace __any_imp
|
||||
{
|
||||
using _Buffer = aligned_storage_t<3*sizeof(void*), alignment_of<void*>::value>;
|
||||
|
||||
template <class _Tp>
|
||||
using _IsSmallObject = integral_constant<bool
|
||||
, sizeof(_Tp) <= sizeof(_Buffer)
|
||||
&& alignment_of<_Buffer>::value
|
||||
% alignment_of<_Tp>::value == 0
|
||||
&& is_nothrow_move_constructible<_Tp>::value
|
||||
>;
|
||||
|
||||
enum class _Action {
|
||||
_Destroy,
|
||||
_Copy,
|
||||
_Move,
|
||||
_Get,
|
||||
_TypeInfo
|
||||
};
|
||||
|
||||
template <class _Tp> struct _SmallHandler;
|
||||
template <class _Tp> struct _LargeHandler;
|
||||
|
||||
template <class _Tp>
|
||||
struct _LIBCPP_TYPE_VIS_ONLY __unique_typeinfo { static constexpr int __id = 0; };
|
||||
template <class _Tp> constexpr int __unique_typeinfo<_Tp>::__id;
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
constexpr const void* __get_fallback_typeid() {
|
||||
return &__unique_typeinfo<decay_t<_Tp>>::__id;
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
bool __compare_typeid(type_info const* __id, const void* __fallback_id)
|
||||
{
|
||||
#if !defined(_LIBCPP_NO_RTTI)
|
||||
if (__id && *__id == typeid(_Tp))
|
||||
return true;
|
||||
#endif
|
||||
if (!__id && __fallback_id == __any_imp::__get_fallback_typeid<_Tp>())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
using _Handler = conditional_t<
|
||||
_IsSmallObject<_Tp>::value, _SmallHandler<_Tp>, _LargeHandler<_Tp>>;
|
||||
|
||||
} // namespace __any_imp
|
||||
|
||||
class _LIBCPP_TYPE_VIS_ONLY any
|
||||
{
|
||||
public:
|
||||
// construct/destruct
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
constexpr any() _NOEXCEPT : __h(nullptr) {}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
any(any const & __other) : __h(nullptr)
|
||||
{
|
||||
if (__other.__h) __other.__call(_Action::_Copy, this);
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
any(any && __other) _NOEXCEPT : __h(nullptr)
|
||||
{
|
||||
if (__other.__h) __other.__call(_Action::_Move, this);
|
||||
}
|
||||
|
||||
template <
|
||||
class _ValueType
|
||||
, class = enable_if_t<
|
||||
!is_same<decay_t<_ValueType>, any>::value &&
|
||||
!__is_inplace_type<_ValueType>::value &&
|
||||
is_copy_constructible<_ValueType>::value>
|
||||
>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
any(_ValueType && __value);
|
||||
|
||||
template <class _Tp, class ..._Args,
|
||||
class = enable_if_t<
|
||||
is_constructible<_Tp, _Args...>::value &&
|
||||
is_copy_constructible<_Tp>::value
|
||||
>
|
||||
>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
explicit any(in_place_type_t<_Tp>, _Args&&... __args);
|
||||
|
||||
template <class _Tp, class _Up, class ..._Args,
|
||||
class = enable_if_t<
|
||||
is_constructible<_Tp, initializer_list<_Up>&, _Args...>::value &&
|
||||
is_copy_constructible<_Tp>::value>
|
||||
>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
explicit any(in_place_type_t<_Tp>, initializer_list<_Up>, _Args&&... __args);
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
~any() { this->reset(); }
|
||||
|
||||
// assignments
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
any & operator=(any const & __rhs) {
|
||||
any(__rhs).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
any & operator=(any && __rhs) _NOEXCEPT {
|
||||
any(_VSTD::move(__rhs)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// TODO: Should this be constrained to disallow in_place types like the
|
||||
// ValueType constructor?
|
||||
template <
|
||||
class _ValueType
|
||||
, class = enable_if_t<
|
||||
!is_same<decay_t<_ValueType>, any>::value
|
||||
&& is_copy_constructible<_ValueType>::value
|
||||
&& !__is_inplace_type<_ValueType>::value>
|
||||
>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
any & operator=(_ValueType && __rhs);
|
||||
|
||||
template <class _Tp, class ..._Args,
|
||||
class = enable_if_t<
|
||||
is_constructible<_Tp, _Args...>::value &&
|
||||
is_copy_constructible<_Tp>::value>
|
||||
>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
void emplace(_Args&&... args);
|
||||
|
||||
template <class _Tp, class _Up, class ..._Args,
|
||||
class = enable_if_t<
|
||||
is_constructible<_Tp, initializer_list<_Up>&, _Args...>::value &&
|
||||
is_copy_constructible<_Tp>::value>
|
||||
>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
void emplace(initializer_list<_Up>, _Args&&...);
|
||||
|
||||
// 6.3.3 any modifiers
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
void reset() _NOEXCEPT { if (__h) this->__call(_Action::_Destroy); }
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
void swap(any & __rhs) _NOEXCEPT;
|
||||
|
||||
// 6.3.4 any observers
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
bool has_value() const _NOEXCEPT { return __h != nullptr; }
|
||||
|
||||
#if !defined(_LIBCPP_NO_RTTI)
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
const type_info & type() const _NOEXCEPT {
|
||||
if (__h) {
|
||||
return *static_cast<type_info const *>(this->__call(_Action::_TypeInfo));
|
||||
} else {
|
||||
return typeid(void);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
typedef __any_imp::_Action _Action;
|
||||
using _HandleFuncPtr = void* (*)(_Action, any const *, any *, const type_info *,
|
||||
const void* __fallback_info);
|
||||
|
||||
union _Storage {
|
||||
constexpr _Storage() : __ptr(nullptr) {}
|
||||
void * __ptr;
|
||||
__any_imp::_Buffer __buf;
|
||||
};
|
||||
|
||||
_LIBCPP_ALWAYS_INLINE
|
||||
void * __call(_Action __a, any * __other = nullptr,
|
||||
type_info const * __info = nullptr,
|
||||
const void* __fallback_info = nullptr) const
|
||||
{
|
||||
return __h(__a, this, __other, __info, __fallback_info);
|
||||
}
|
||||
|
||||
_LIBCPP_ALWAYS_INLINE
|
||||
void * __call(_Action __a, any * __other = nullptr,
|
||||
type_info const * __info = nullptr,
|
||||
const void* __fallback_info = nullptr)
|
||||
{
|
||||
return __h(__a, this, __other, __info, __fallback_info);
|
||||
}
|
||||
|
||||
template <class>
|
||||
friend struct __any_imp::_SmallHandler;
|
||||
template <class>
|
||||
friend struct __any_imp::_LargeHandler;
|
||||
|
||||
template <class _ValueType>
|
||||
friend add_pointer_t<add_const_t<_ValueType>>
|
||||
any_cast(any const *) _NOEXCEPT;
|
||||
|
||||
template <class _ValueType>
|
||||
friend add_pointer_t<_ValueType>
|
||||
any_cast(any *) _NOEXCEPT;
|
||||
|
||||
_HandleFuncPtr __h = nullptr;
|
||||
_Storage __s;
|
||||
};
|
||||
|
||||
namespace __any_imp
|
||||
{
|
||||
template <class _Tp>
|
||||
struct _LIBCPP_TYPE_VIS_ONLY _SmallHandler
|
||||
{
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static void* __handle(_Action __act, any const * __this, any * __other,
|
||||
type_info const * __info, const void* __fallback_info)
|
||||
{
|
||||
switch (__act)
|
||||
{
|
||||
case _Action::_Destroy:
|
||||
__destroy(const_cast<any &>(*__this));
|
||||
return nullptr;
|
||||
case _Action::_Copy:
|
||||
__copy(*__this, *__other);
|
||||
return nullptr;
|
||||
case _Action::_Move:
|
||||
__move(const_cast<any &>(*__this), *__other);
|
||||
return nullptr;
|
||||
case _Action::_Get:
|
||||
return __get(const_cast<any &>(*__this), __info, __fallback_info);
|
||||
case _Action::_TypeInfo:
|
||||
return __type_info();
|
||||
}
|
||||
}
|
||||
|
||||
template <class ..._Args>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static void __create(any & __dest, _Args&&... __args) {
|
||||
::new (static_cast<void*>(&__dest.__s.__buf)) _Tp(_VSTD::forward<_Args>(__args)...);
|
||||
__dest.__h = &_SmallHandler::__handle;
|
||||
}
|
||||
|
||||
private:
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static void __destroy(any & __this) {
|
||||
_Tp & __value = *static_cast<_Tp *>(static_cast<void*>(&__this.__s.__buf));
|
||||
__value.~_Tp();
|
||||
__this.__h = nullptr;
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static void __copy(any const & __this, any & __dest) {
|
||||
_SmallHandler::__create(__dest, *static_cast<_Tp const *>(
|
||||
static_cast<void const *>(&__this.__s.__buf)));
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static void __move(any & __this, any & __dest) {
|
||||
_SmallHandler::__create(__dest, _VSTD::move(
|
||||
*static_cast<_Tp*>(static_cast<void*>(&__this.__s.__buf))));
|
||||
__destroy(__this);
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static void* __get(any & __this,
|
||||
type_info const * __info,
|
||||
const void* __fallback_id)
|
||||
{
|
||||
if (__any_imp::__compare_typeid<_Tp>(__info, __fallback_id))
|
||||
return static_cast<void*>(&__this.__s.__buf);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static void* __type_info()
|
||||
{
|
||||
#if !defined(_LIBCPP_NO_RTTI)
|
||||
return const_cast<void*>(static_cast<void const *>(&typeid(_Tp)));
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
struct _LIBCPP_TYPE_VIS_ONLY _LargeHandler
|
||||
{
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static void* __handle(_Action __act, any const * __this,
|
||||
any * __other, type_info const * __info,
|
||||
void const* __fallback_info)
|
||||
{
|
||||
switch (__act)
|
||||
{
|
||||
case _Action::_Destroy:
|
||||
__destroy(const_cast<any &>(*__this));
|
||||
return nullptr;
|
||||
case _Action::_Copy:
|
||||
__copy(*__this, *__other);
|
||||
return nullptr;
|
||||
case _Action::_Move:
|
||||
__move(const_cast<any &>(*__this), *__other);
|
||||
return nullptr;
|
||||
case _Action::_Get:
|
||||
return __get(const_cast<any &>(*__this), __info, __fallback_info);
|
||||
case _Action::_TypeInfo:
|
||||
return __type_info();
|
||||
}
|
||||
}
|
||||
|
||||
template <class ..._Args>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static void __create(any & __dest, _Args&&... __args) {
|
||||
typedef allocator<_Tp> _Alloc;
|
||||
typedef __allocator_destructor<_Alloc> _Dp;
|
||||
_Alloc __a;
|
||||
unique_ptr<_Tp, _Dp> __hold(__a.allocate(1), _Dp(__a, 1));
|
||||
::new ((void*)__hold.get()) _Tp(_VSTD::forward<_Args>(__args)...);
|
||||
__dest.__s.__ptr = __hold.release();
|
||||
__dest.__h = &_LargeHandler::__handle;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static void __destroy(any & __this){
|
||||
delete static_cast<_Tp*>(__this.__s.__ptr);
|
||||
__this.__h = nullptr;
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static void __copy(any const & __this, any & __dest) {
|
||||
_LargeHandler::__create(__dest, *static_cast<_Tp const *>(__this.__s.__ptr));
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static void __move(any & __this, any & __dest) {
|
||||
__dest.__s.__ptr = __this.__s.__ptr;
|
||||
__dest.__h = &_LargeHandler::__handle;
|
||||
__this.__h = nullptr;
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static void* __get(any & __this, type_info const * __info,
|
||||
void const* __fallback_info)
|
||||
{
|
||||
if (__any_imp::__compare_typeid<_Tp>(__info, __fallback_info))
|
||||
return static_cast<void*>(__this.__s.__ptr);
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
static void* __type_info()
|
||||
{
|
||||
#if !defined(_LIBCPP_NO_RTTI)
|
||||
return const_cast<void*>(static_cast<void const *>(&typeid(_Tp)));
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace __any_imp
|
||||
|
||||
|
||||
template <class _ValueType, class>
|
||||
any::any(_ValueType && __v) : __h(nullptr)
|
||||
{
|
||||
typedef typename decay<_ValueType>::type _Tp;
|
||||
static_assert(is_copy_constructible<_Tp>::value,
|
||||
"_ValueType must be CopyConstructible.");
|
||||
using _ForwardTp = conditional_t<
|
||||
is_move_constructible<_Tp>::value, _ValueType, _ValueType&>;
|
||||
typedef __any_imp::_Handler<_Tp> _HandlerType;
|
||||
_HandlerType::__create(*this, _VSTD::forward<_ForwardTp>(__v));
|
||||
}
|
||||
|
||||
template <class _Tp, class ..._Args, class>
|
||||
any::any(in_place_type_t<_Tp>, _Args&&... __args) {
|
||||
using _Hp = __any_imp::_Handler<_Tp>;
|
||||
_Hp::__create(*this, _VSTD::forward<_Args>(__args)...);
|
||||
};
|
||||
|
||||
template <class _Tp, class _Up, class ..._Args, class>
|
||||
any::any(in_place_type_t<_Tp>, initializer_list<_Up> __il, _Args&&... __args) {
|
||||
using _Hp = __any_imp::_Handler<_Tp>;
|
||||
_Hp::__create(*this, __il, _VSTD::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
template <class _ValueType, class>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
any & any::operator=(_ValueType && __v)
|
||||
{
|
||||
typedef typename decay<_ValueType>::type _Tp;
|
||||
static_assert(is_copy_constructible<_Tp>::value,
|
||||
"_ValueType must be CopyConstructible.");
|
||||
any(_VSTD::forward<_ValueType>(__v)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _Tp, class ..._Args, class>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
void any::emplace(_Args&&... __args) {
|
||||
using _Hp = __any_imp::_Handler<_Tp>;
|
||||
reset();
|
||||
_Hp::__create(*this, _VSTD::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
template <class _Tp, class _Up, class ..._Args, class>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
void any::emplace(initializer_list<_Up> __il, _Args&&... __args) {
|
||||
using _Hp = __any_imp::_Handler<_Tp>;
|
||||
reset();
|
||||
_Hp::__create(*this, __il, _VSTD::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
void any::swap(any & __rhs) _NOEXCEPT
|
||||
{
|
||||
if (__h && __rhs.__h) {
|
||||
any __tmp;
|
||||
__rhs.__call(_Action::_Move, &__tmp);
|
||||
this->__call(_Action::_Move, &__rhs);
|
||||
__tmp.__call(_Action::_Move, this);
|
||||
}
|
||||
else if (__h) {
|
||||
this->__call(_Action::_Move, &__rhs);
|
||||
}
|
||||
else if (__rhs.__h) {
|
||||
__rhs.__call(_Action::_Move, this);
|
||||
}
|
||||
}
|
||||
|
||||
// 6.4 Non-member functions
|
||||
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
void swap(any & __lhs, any & __rhs) _NOEXCEPT
|
||||
{
|
||||
__lhs.swap(__rhs);
|
||||
}
|
||||
|
||||
template <class _Tp, class ..._Args>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
any make_any(_Args&&... __args) {
|
||||
return any(in_place<_Tp>, _VSTD::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
template <class _Tp, class _Up, class ..._Args>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
any make_any(initializer_list<_Up> __il, _Args&&... __args) {
|
||||
return any(in_place<_Tp>, __il, _VSTD::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
template <class _ValueType>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
_ValueType any_cast(any const & __v)
|
||||
{
|
||||
static_assert(
|
||||
is_reference<_ValueType>::value
|
||||
|| is_copy_constructible<_ValueType>::value,
|
||||
"_ValueType is required to be a reference or a CopyConstructible type.");
|
||||
using _Tp = add_const_t<remove_reference_t<_ValueType>>;
|
||||
_Tp * __tmp = _VSTD::any_cast<_Tp>(&__v);
|
||||
if (__tmp == nullptr)
|
||||
__libcpp_throw(bad_any_cast());
|
||||
return *__tmp;
|
||||
}
|
||||
|
||||
template <class _ValueType>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
_ValueType any_cast(any & __v)
|
||||
{
|
||||
static_assert(
|
||||
is_reference<_ValueType>::value
|
||||
|| is_copy_constructible<_ValueType>::value,
|
||||
"_ValueType is required to be a reference or a CopyConstructible type.");
|
||||
typedef typename remove_reference<_ValueType>::type _Tp;
|
||||
_Tp * __tmp = _VSTD::any_cast<_Tp>(&__v);
|
||||
if (__tmp == nullptr)
|
||||
__libcpp_throw(bad_any_cast());
|
||||
return *__tmp;
|
||||
}
|
||||
|
||||
template <class _ValueType>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
_ValueType any_cast(any && __v)
|
||||
{
|
||||
static_assert(
|
||||
is_reference<_ValueType>::value
|
||||
|| is_copy_constructible<_ValueType>::value,
|
||||
"_ValueType is required to be a reference or a CopyConstructible type.");
|
||||
typedef typename remove_reference<_ValueType>::type _Tp;
|
||||
using _ForwardTp = conditional_t<
|
||||
is_reference<_ValueType>::value,
|
||||
_ValueType,
|
||||
conditional_t<is_move_constructible<_Tp>::value, _Tp, _Tp&>
|
||||
>;
|
||||
_Tp * __tmp = _VSTD::any_cast<_Tp>(&__v);
|
||||
if (__tmp == nullptr)
|
||||
__libcpp_throw(bad_any_cast());
|
||||
return _VSTD::forward<_ForwardTp>(*__tmp);
|
||||
}
|
||||
|
||||
template <class _ValueType>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
add_pointer_t<add_const_t<_ValueType>>
|
||||
any_cast(any const * __any) _NOEXCEPT
|
||||
{
|
||||
static_assert(!is_reference<_ValueType>::value,
|
||||
"_ValueType may not be a reference.");
|
||||
return _VSTD::any_cast<_ValueType>(const_cast<any *>(__any));
|
||||
}
|
||||
|
||||
template <class _ValueType>
|
||||
add_pointer_t<_ValueType>
|
||||
any_cast(any * __any) _NOEXCEPT
|
||||
{
|
||||
using __any_imp::_Action;
|
||||
static_assert(!is_reference<_ValueType>::value,
|
||||
"_ValueType may not be a reference.");
|
||||
typedef typename add_pointer<_ValueType>::type _ReturnType;
|
||||
if (__any && __any->__h) {
|
||||
return static_cast<_ReturnType>(
|
||||
__any->__call(_Action::_Get, nullptr,
|
||||
#if !defined(_LIBCPP_NO_RTTI)
|
||||
&typeid(_ValueType),
|
||||
#else
|
||||
nullptr,
|
||||
#endif
|
||||
__any_imp::__get_fallback_typeid<_ValueType>()
|
||||
));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif // _LIBCPP_STD_VER > 14
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP_ANY
|
|
@ -7,12 +7,17 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "any"
|
||||
#include "experimental/any"
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_LFTS
|
||||
|
||||
namespace std {
|
||||
const char* bad_any_cast::what() const _NOEXCEPT {
|
||||
return "bad any cast";
|
||||
}
|
||||
}
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_LFTS
|
||||
const char* bad_any_cast::what() const _NOEXCEPT {
|
||||
return "bad any cast";
|
||||
}
|
||||
_LIBCPP_END_NAMESPACE_LFTS
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
// Check that the size and alignment of any are what we expect.
|
||||
|
||||
#include <experimental/any>
|
||||
#include "any_helpers.h"
|
||||
#include "experimental_any_helpers.h"
|
||||
|
||||
constexpr std::size_t BufferSize = (sizeof(void*) * 3);
|
||||
constexpr std::size_t BufferAlignment = alignof(void*);
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11
|
||||
|
||||
// <any>
|
||||
|
||||
// Check that the size and alignment of any are what we expect.
|
||||
|
||||
#include <any>
|
||||
|
||||
int main()
|
||||
{
|
||||
using std::any;
|
||||
static_assert(sizeof(any) == sizeof(void*)*4, "");
|
||||
static_assert(alignof(any) == alignof(void*), "");
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11
|
||||
|
||||
// <any>
|
||||
|
||||
// Check that the size and alignment of any are what we expect.
|
||||
|
||||
#include <any>
|
||||
#include "any_helpers.h"
|
||||
|
||||
constexpr std::size_t BufferSize = (sizeof(void*) * 3);
|
||||
constexpr std::size_t BufferAlignment = alignof(void*);
|
||||
// Clang doesn't like "alignof(BufferAlignment * 2)" due to PR13986.
|
||||
// So we create "DoubleBufferAlignment" instead.
|
||||
constexpr std::size_t DoubleBufferAlignment = BufferAlignment * 2;
|
||||
|
||||
class SmallThrowsDtor
|
||||
{
|
||||
public:
|
||||
SmallThrowsDtor() {}
|
||||
SmallThrowsDtor(SmallThrowsDtor const &) noexcept {}
|
||||
SmallThrowsDtor(SmallThrowsDtor &&) noexcept {}
|
||||
~SmallThrowsDtor() noexcept(false) {}
|
||||
};
|
||||
|
||||
|
||||
struct alignas(1) MaxSizeType {
|
||||
char buff[BufferSize];
|
||||
};
|
||||
|
||||
struct alignas(BufferAlignment) MaxAlignType {
|
||||
};
|
||||
|
||||
struct alignas(BufferAlignment) MaxSizeAndAlignType {
|
||||
char buff[BufferSize];
|
||||
};
|
||||
|
||||
|
||||
struct alignas(1) OverSizeType {
|
||||
char buff[BufferSize + 1];
|
||||
};
|
||||
|
||||
struct alignas(DoubleBufferAlignment) OverAlignedType {
|
||||
};
|
||||
|
||||
struct alignas(DoubleBufferAlignment) OverSizeAndAlignedType {
|
||||
char buff[BufferSize + 1];
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
using std::any;
|
||||
using std::__any_imp::_IsSmallObject;
|
||||
static_assert(_IsSmallObject<small>::value, "");
|
||||
static_assert(_IsSmallObject<void*>::value, "");
|
||||
static_assert(!_IsSmallObject<SmallThrowsDtor>::value, "");
|
||||
static_assert(!_IsSmallObject<large>::value, "");
|
||||
{
|
||||
// Check a type that meets the size requirement *exactly* and has
|
||||
// a lesser alignment requirement is considered small.
|
||||
typedef MaxSizeType T;
|
||||
static_assert(sizeof(T) == BufferSize, "");
|
||||
static_assert(alignof(T) < BufferAlignment, "");
|
||||
static_assert(_IsSmallObject<T>::value, "");
|
||||
}
|
||||
{
|
||||
// Check a type that meets the alignment requirement *exactly* and has
|
||||
// a lesser size is considered small.
|
||||
typedef MaxAlignType T;
|
||||
static_assert(sizeof(T) < BufferSize, "");
|
||||
static_assert(alignof(T) == BufferAlignment, "");
|
||||
static_assert(_IsSmallObject<T>::value, "");
|
||||
}
|
||||
{
|
||||
// Check a type that meets the size and alignment requirements *exactly*
|
||||
// is considered small.
|
||||
typedef MaxSizeAndAlignType T;
|
||||
static_assert(sizeof(T) == BufferSize, "");
|
||||
static_assert(alignof(T) == BufferAlignment, "");
|
||||
static_assert(_IsSmallObject<T>::value, "");
|
||||
}
|
||||
{
|
||||
// Check a type that meets the alignment requirements but is over-sized
|
||||
// is not considered small.
|
||||
typedef OverSizeType T;
|
||||
static_assert(sizeof(T) > BufferSize, "");
|
||||
static_assert(alignof(T) < BufferAlignment, "");
|
||||
static_assert(!_IsSmallObject<T>::value, "");
|
||||
}
|
||||
{
|
||||
// Check a type that meets the size requirements but is over-aligned
|
||||
// is not considered small.
|
||||
typedef OverAlignedType T;
|
||||
static_assert(sizeof(T) < BufferSize, "");
|
||||
static_assert(alignof(T) > BufferAlignment, "");
|
||||
static_assert(!_IsSmallObject<T>::value, "");
|
||||
}
|
||||
{
|
||||
// Check a type that exceeds both the size an alignment requirements
|
||||
// is not considered small.
|
||||
typedef OverSizeAndAlignedType T;
|
||||
static_assert(sizeof(T) > BufferSize, "");
|
||||
static_assert(alignof(T) > BufferAlignment, "");
|
||||
static_assert(!_IsSmallObject<T>::value, "");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <any>
|
||||
|
||||
#include <any>
|
||||
|
||||
#ifndef _LIBCPP_VERSION
|
||||
#error _LIBCPP_VERSION not defined
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
}
|
|
@ -18,7 +18,7 @@
|
|||
#include <experimental/any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "experimental_any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <experimental/any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "experimental_any_helpers.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
using std::experimental::any;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <experimental/any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "experimental_any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <experimental/any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "experimental_any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "experimental_any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "experimental_any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <experimental/any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "experimental_any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <experimental/any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "experimental_any_helpers.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <experimental/any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "experimental_any_helpers.h"
|
||||
|
||||
using std::experimental::any;
|
||||
using std::experimental::any_cast;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <experimental/any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "experimental_any_helpers.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include <experimental/any>
|
||||
#include <cassert>
|
||||
#include "any_helpers.h"
|
||||
#include "experimental_any_helpers.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "experimental_any_helpers.h"
|
||||
|
||||
using std::experimental::any;
|
||||
using std::experimental::any_cast;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "experimental_any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// any& operator=(any const &);
|
||||
|
||||
// Test copy assignment
|
||||
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
template <class LHS, class RHS>
|
||||
void test_copy_assign() {
|
||||
assert(LHS::count == 0);
|
||||
assert(RHS::count == 0);
|
||||
LHS::reset();
|
||||
RHS::reset();
|
||||
{
|
||||
any lhs(LHS(1));
|
||||
any const rhs(RHS(2));
|
||||
|
||||
assert(LHS::count == 1);
|
||||
assert(RHS::count == 1);
|
||||
assert(RHS::copied == 0);
|
||||
|
||||
lhs = rhs;
|
||||
|
||||
assert(RHS::copied == 1);
|
||||
assert(LHS::count == 0);
|
||||
assert(RHS::count == 2);
|
||||
|
||||
assertContains<RHS>(lhs, 2);
|
||||
assertContains<RHS>(rhs, 2);
|
||||
}
|
||||
assert(LHS::count == 0);
|
||||
assert(RHS::count == 0);
|
||||
}
|
||||
|
||||
template <class LHS>
|
||||
void test_copy_assign_empty() {
|
||||
assert(LHS::count == 0);
|
||||
LHS::reset();
|
||||
{
|
||||
any lhs;
|
||||
any const rhs(LHS(42));
|
||||
|
||||
assert(LHS::count == 1);
|
||||
assert(LHS::copied == 0);
|
||||
|
||||
lhs = rhs;
|
||||
|
||||
assert(LHS::copied == 1);
|
||||
assert(LHS::count == 2);
|
||||
|
||||
assertContains<LHS>(lhs, 42);
|
||||
assertContains<LHS>(rhs, 42);
|
||||
}
|
||||
assert(LHS::count == 0);
|
||||
LHS::reset();
|
||||
{
|
||||
any lhs(LHS(1));
|
||||
any const rhs;
|
||||
|
||||
assert(LHS::count == 1);
|
||||
assert(LHS::copied == 0);
|
||||
|
||||
lhs = rhs;
|
||||
|
||||
assert(LHS::copied == 0);
|
||||
assert(LHS::count == 0);
|
||||
|
||||
assertEmpty<LHS>(lhs);
|
||||
assertEmpty(rhs);
|
||||
}
|
||||
assert(LHS::count == 0);
|
||||
}
|
||||
|
||||
void test_copy_assign_self() {
|
||||
// empty
|
||||
{
|
||||
any a;
|
||||
a = a;
|
||||
assertEmpty(a);
|
||||
assert(globalMemCounter.checkOutstandingNewEq(0));
|
||||
}
|
||||
assert(globalMemCounter.checkOutstandingNewEq(0));
|
||||
// small
|
||||
{
|
||||
any a((small(1)));
|
||||
assert(small::count == 1);
|
||||
|
||||
a = a;
|
||||
|
||||
assert(small::count == 1);
|
||||
assertContains<small>(a, 1);
|
||||
assert(globalMemCounter.checkOutstandingNewEq(0));
|
||||
}
|
||||
assert(small::count == 0);
|
||||
assert(globalMemCounter.checkOutstandingNewEq(0));
|
||||
// large
|
||||
{
|
||||
any a(large(1));
|
||||
assert(large::count == 1);
|
||||
|
||||
a = a;
|
||||
|
||||
assert(large::count == 1);
|
||||
assertContains<large>(a, 1);
|
||||
assert(globalMemCounter.checkOutstandingNewEq(1));
|
||||
}
|
||||
assert(large::count == 0);
|
||||
assert(globalMemCounter.checkOutstandingNewEq(0));
|
||||
}
|
||||
|
||||
template <class Tp>
|
||||
void test_copy_assign_throws()
|
||||
{
|
||||
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
||||
auto try_throw =
|
||||
[](any& lhs, any const& rhs) {
|
||||
try {
|
||||
lhs = rhs;
|
||||
assert(false);
|
||||
} catch (my_any_exception const &) {
|
||||
// do nothing
|
||||
} catch (...) {
|
||||
assert(false);
|
||||
}
|
||||
};
|
||||
// const lvalue to empty
|
||||
{
|
||||
any lhs;
|
||||
any const rhs((Tp(1)));
|
||||
assert(Tp::count == 1);
|
||||
|
||||
try_throw(lhs, rhs);
|
||||
|
||||
assert(Tp::count == 1);
|
||||
assertEmpty<Tp>(lhs);
|
||||
assertContains<Tp>(rhs);
|
||||
}
|
||||
{
|
||||
any lhs((small(2)));
|
||||
any const rhs((Tp(1)));
|
||||
assert(small::count == 1);
|
||||
assert(Tp::count == 1);
|
||||
|
||||
try_throw(lhs, rhs);
|
||||
|
||||
assert(small::count == 1);
|
||||
assert(Tp::count == 1);
|
||||
assertContains<small>(lhs, 2);
|
||||
assertContains<Tp>(rhs);
|
||||
}
|
||||
{
|
||||
any lhs((large(2)));
|
||||
any const rhs((Tp(1)));
|
||||
assert(large::count == 1);
|
||||
assert(Tp::count == 1);
|
||||
|
||||
try_throw(lhs, rhs);
|
||||
|
||||
assert(large::count == 1);
|
||||
assert(Tp::count == 1);
|
||||
assertContains<large>(lhs, 2);
|
||||
assertContains<Tp>(rhs);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_copy_assign<small1, small2>();
|
||||
test_copy_assign<large1, large2>();
|
||||
test_copy_assign<small, large>();
|
||||
test_copy_assign<large, small>();
|
||||
test_copy_assign_empty<small>();
|
||||
test_copy_assign_empty<large>();
|
||||
test_copy_assign_self();
|
||||
test_copy_assign_throws<small_throws_on_copy>();
|
||||
test_copy_assign_throws<large_throws_on_copy>();
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// any& operator=(any &&);
|
||||
|
||||
// Test move assignment.
|
||||
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
template <class LHS, class RHS>
|
||||
void test_move_assign() {
|
||||
assert(LHS::count == 0);
|
||||
assert(RHS::count == 0);
|
||||
{
|
||||
LHS const s1(1);
|
||||
any a(s1);
|
||||
RHS const s2(2);
|
||||
any a2(s2);
|
||||
|
||||
assert(LHS::count == 2);
|
||||
assert(RHS::count == 2);
|
||||
|
||||
a = std::move(a2);
|
||||
|
||||
assert(LHS::count == 1);
|
||||
assert(RHS::count == 2);
|
||||
|
||||
assertContains<RHS>(a, 2);
|
||||
assertEmpty<RHS>(a2);
|
||||
}
|
||||
assert(LHS::count == 0);
|
||||
assert(RHS::count == 0);
|
||||
}
|
||||
|
||||
template <class LHS>
|
||||
void test_move_assign_empty() {
|
||||
assert(LHS::count == 0);
|
||||
{
|
||||
any a;
|
||||
any a2((LHS(1)));
|
||||
|
||||
assert(LHS::count == 1);
|
||||
|
||||
a = std::move(a2);
|
||||
|
||||
assert(LHS::count == 1);
|
||||
|
||||
assertContains<LHS>(a, 1);
|
||||
assertEmpty<LHS>(a2);
|
||||
}
|
||||
assert(LHS::count == 0);
|
||||
{
|
||||
any a((LHS(1)));
|
||||
any a2;
|
||||
|
||||
assert(LHS::count == 1);
|
||||
|
||||
a = std::move(a2);
|
||||
|
||||
assert(LHS::count == 0);
|
||||
|
||||
assertEmpty<LHS>(a);
|
||||
assertEmpty(a2);
|
||||
}
|
||||
assert(LHS::count == 0);
|
||||
}
|
||||
|
||||
void test_move_assign_noexcept() {
|
||||
any a1;
|
||||
any a2;
|
||||
static_assert(
|
||||
noexcept(a1 = std::move(a2))
|
||||
, "any & operator=(any &&) must be noexcept"
|
||||
);
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_move_assign_noexcept();
|
||||
test_move_assign<small1, small2>();
|
||||
test_move_assign<large1, large2>();
|
||||
test_move_assign<small, large>();
|
||||
test_move_assign<large, small>();
|
||||
test_move_assign_empty<small>();
|
||||
test_move_assign_empty<large>();
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// any& operator=(any const &);
|
||||
|
||||
// Test value copy and move assignment.
|
||||
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
template <class LHS, class RHS>
|
||||
void test_assign_value() {
|
||||
assert(LHS::count == 0);
|
||||
assert(RHS::count == 0);
|
||||
LHS::reset();
|
||||
RHS::reset();
|
||||
{
|
||||
any lhs(LHS(1));
|
||||
any const rhs(RHS(2));
|
||||
|
||||
assert(LHS::count == 1);
|
||||
assert(RHS::count == 1);
|
||||
assert(RHS::copied == 0);
|
||||
|
||||
lhs = rhs;
|
||||
|
||||
assert(RHS::copied == 1);
|
||||
assert(LHS::count == 0);
|
||||
assert(RHS::count == 2);
|
||||
|
||||
assertContains<RHS>(lhs, 2);
|
||||
assertContains<RHS>(rhs, 2);
|
||||
}
|
||||
assert(LHS::count == 0);
|
||||
assert(RHS::count == 0);
|
||||
LHS::reset();
|
||||
RHS::reset();
|
||||
{
|
||||
any lhs(LHS(1));
|
||||
any rhs(RHS(2));
|
||||
|
||||
assert(LHS::count == 1);
|
||||
assert(RHS::count == 1);
|
||||
assert(RHS::moved == 1);
|
||||
|
||||
lhs = std::move(rhs);
|
||||
|
||||
assert(RHS::moved >= 1);
|
||||
assert(RHS::copied == 0);
|
||||
assert(LHS::count == 0);
|
||||
assert(RHS::count == 1);
|
||||
|
||||
assertContains<RHS>(lhs, 2);
|
||||
assertEmpty<RHS>(rhs);
|
||||
}
|
||||
assert(LHS::count == 0);
|
||||
assert(RHS::count == 0);
|
||||
}
|
||||
|
||||
template <class RHS>
|
||||
void test_assign_value_empty() {
|
||||
assert(RHS::count == 0);
|
||||
RHS::reset();
|
||||
{
|
||||
any lhs;
|
||||
RHS rhs(42);
|
||||
assert(RHS::count == 1);
|
||||
assert(RHS::copied == 0);
|
||||
|
||||
lhs = rhs;
|
||||
|
||||
assert(RHS::count == 2);
|
||||
assert(RHS::copied == 1);
|
||||
assert(RHS::moved >= 0);
|
||||
assertContains<RHS>(lhs, 42);
|
||||
}
|
||||
assert(RHS::count == 0);
|
||||
RHS::reset();
|
||||
{
|
||||
any lhs;
|
||||
RHS rhs(42);
|
||||
assert(RHS::count == 1);
|
||||
assert(RHS::moved == 0);
|
||||
|
||||
lhs = std::move(rhs);
|
||||
|
||||
assert(RHS::count == 2);
|
||||
assert(RHS::copied == 0);
|
||||
assert(RHS::moved >= 1);
|
||||
assertContains<RHS>(lhs, 42);
|
||||
}
|
||||
assert(RHS::count == 0);
|
||||
RHS::reset();
|
||||
}
|
||||
|
||||
|
||||
template <class Tp, bool Move = false>
|
||||
void test_assign_throws() {
|
||||
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
||||
auto try_throw=
|
||||
[](any& lhs, auto&& rhs) {
|
||||
try {
|
||||
Move ? lhs = std::move(rhs)
|
||||
: lhs = rhs;
|
||||
assert(false);
|
||||
} catch (my_any_exception const &) {
|
||||
// do nothing
|
||||
} catch (...) {
|
||||
assert(false);
|
||||
}
|
||||
};
|
||||
// const lvalue to empty
|
||||
{
|
||||
any lhs;
|
||||
Tp rhs(1);
|
||||
assert(Tp::count == 1);
|
||||
|
||||
try_throw(lhs, rhs);
|
||||
|
||||
assert(Tp::count == 1);
|
||||
assertEmpty<Tp>(lhs);
|
||||
}
|
||||
{
|
||||
any lhs((small(2)));
|
||||
Tp rhs(1);
|
||||
assert(small::count == 1);
|
||||
assert(Tp::count == 1);
|
||||
|
||||
try_throw(lhs, rhs);
|
||||
|
||||
assert(small::count == 1);
|
||||
assert(Tp::count == 1);
|
||||
assertContains<small>(lhs, 2);
|
||||
}
|
||||
{
|
||||
any lhs((large(2)));
|
||||
Tp rhs(1);
|
||||
assert(large::count == 1);
|
||||
assert(Tp::count == 1);
|
||||
|
||||
try_throw(lhs, rhs);
|
||||
|
||||
assert(large::count == 1);
|
||||
assert(Tp::count == 1);
|
||||
assertContains<large>(lhs, 2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Test that any& operator=(ValueType&&) is *never* selected for:
|
||||
// * std::in_place type.
|
||||
// * Non-copyable types
|
||||
void test_sfinae_constraints() {
|
||||
{
|
||||
using Tag = std::in_place_type_t<int>;
|
||||
using RawTag = std::remove_reference_t<Tag>;
|
||||
static_assert(!std::is_assignable<std::any, RawTag&&>::value, "");
|
||||
}
|
||||
{
|
||||
struct Dummy { Dummy() = delete; };
|
||||
using T = std::in_place_type_t<Dummy>;
|
||||
static_assert(!std::is_assignable<std::any, T>::value, "");
|
||||
}
|
||||
{
|
||||
// Test that the ValueType&& constructor SFINAE's away when the
|
||||
// argument is non-copyable
|
||||
struct NoCopy {
|
||||
NoCopy() = default;
|
||||
NoCopy(NoCopy const&) = delete;
|
||||
NoCopy(NoCopy&&) = default;
|
||||
};
|
||||
static_assert(!std::is_assignable<std::any, NoCopy>::value, "");
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_assign_value<small1, small2>();
|
||||
test_assign_value<large1, large2>();
|
||||
test_assign_value<small, large>();
|
||||
test_assign_value<large, small>();
|
||||
test_assign_value_empty<small>();
|
||||
test_assign_value_empty<large>();
|
||||
test_assign_throws<small_throws_on_copy>();
|
||||
test_assign_throws<large_throws_on_copy>();
|
||||
test_assign_throws<throws_on_move, /* Move = */ true>();
|
||||
test_sfinae_constraints();
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// any(any const &);
|
||||
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
template <class Type>
|
||||
void test_copy_throws() {
|
||||
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
||||
assert(Type::count == 0);
|
||||
{
|
||||
any const a((Type(42)));
|
||||
assert(Type::count == 1);
|
||||
try {
|
||||
any const a2(a);
|
||||
assert(false);
|
||||
} catch (my_any_exception const &) {
|
||||
// do nothing
|
||||
} catch (...) {
|
||||
assert(false);
|
||||
}
|
||||
assert(Type::count == 1);
|
||||
assertContains<Type>(a, 42);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_copy_empty() {
|
||||
DisableAllocationGuard g; ((void)g); // No allocations should occur.
|
||||
any a1;
|
||||
any a2(a1);
|
||||
|
||||
assertEmpty(a1);
|
||||
assertEmpty(a2);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void test_copy()
|
||||
{
|
||||
// Copying small types should not perform any allocations.
|
||||
DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
any a((Type(42)));
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
|
||||
any a2(a);
|
||||
|
||||
assert(Type::copied == 1);
|
||||
assert(Type::count == 2);
|
||||
assertContains<Type>(a, 42);
|
||||
assertContains<Type>(a, 42);
|
||||
|
||||
// Modify a and check that a2 is unchanged
|
||||
modifyValue<Type>(a, -1);
|
||||
assertContains<Type>(a, -1);
|
||||
assertContains<Type>(a2, 42);
|
||||
|
||||
// modify a2 and check that a is unchanged
|
||||
modifyValue<Type>(a2, 999);
|
||||
assertContains<Type>(a, -1);
|
||||
assertContains<Type>(a2, 999);
|
||||
|
||||
// clear a and check that a2 is unchanged
|
||||
a.reset();
|
||||
assertEmpty(a);
|
||||
assertContains<Type>(a2, 999);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_copy<small>();
|
||||
test_copy<large>();
|
||||
test_copy_empty();
|
||||
test_copy_throws<small_throws_on_copy>();
|
||||
test_copy_throws<large_throws_on_copy>();
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// any() noexcept;
|
||||
|
||||
#include <any>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
|
||||
#if TEST_HAS_BUILTIN_IDENTIFIER(__has_constant_initializer)
|
||||
// std::any must have a constexpr default constructor, but it's a non-literal
|
||||
// type so we can't create a constexpr variable. This tests that we actually
|
||||
// get 'constant initialization'.
|
||||
std::any a;
|
||||
static_assert(__has_constant_initializer(a),
|
||||
"any must be constant initializable");
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
using std::any;
|
||||
{
|
||||
static_assert(
|
||||
std::is_nothrow_default_constructible<any>::value
|
||||
, "Must be default constructible"
|
||||
);
|
||||
}
|
||||
{
|
||||
DisableAllocationGuard g; ((void)g);
|
||||
any const a;
|
||||
assertEmpty(a);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// template <class T, class ...Args> any(in_place_type_t<T>, Args&&...);
|
||||
// template <class T, class U, class ...Args>
|
||||
// any(in_place_type_t<T>, initializer_list<U>, Args&&...);
|
||||
|
||||
// Test construction from a value.
|
||||
// Concerns:
|
||||
// ---------
|
||||
// 1. The value is properly move/copied depending on the value category.
|
||||
// 2. Both small and large values are properly handled.
|
||||
|
||||
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
#include "test_convertible.hpp"
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
template <class Type>
|
||||
void test_in_place_type() {
|
||||
// constructing from a small type should perform no allocations.
|
||||
DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
any a(std::in_place<Type>);
|
||||
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 0);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
any a(std::in_place<Type>, 101);
|
||||
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 101);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
any a(std::in_place<Type>, -1, 42, -1);
|
||||
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 42);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void test_in_place_type_tracked() {
|
||||
// constructing from a small type should perform no allocations.
|
||||
DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
|
||||
{
|
||||
any a(std::in_place<Type>);
|
||||
assertArgsMatch<Type>(a);
|
||||
}
|
||||
{
|
||||
any a(std::in_place<Type>, -1, 42, -1);
|
||||
assertArgsMatch<Type, int, int, int>(a);
|
||||
}
|
||||
// initializer_list constructor tests
|
||||
{
|
||||
any a(std::in_place<Type>, {-1, 42, -1});
|
||||
assertArgsMatch<Type, std::initializer_list<int>>(a);
|
||||
}
|
||||
{
|
||||
int x = 42;
|
||||
any a(std::in_place<Type>, {-1, 42, -1}, x);
|
||||
assertArgsMatch<Type, std::initializer_list<int>, int&>(a);
|
||||
}
|
||||
}
|
||||
|
||||
void test_ctor_sfinae() {
|
||||
{
|
||||
// Test that the init-list ctor SFINAE's away properly when
|
||||
// construction would be ill-formed.
|
||||
using IL = std::initializer_list<int>;
|
||||
static_assert(!std::is_constructible<std::any,
|
||||
std::in_place_type_t<int>, IL>::value, "");
|
||||
static_assert(std::is_constructible<std::any,
|
||||
std::in_place_type_t<small_tracked_t>, IL>::value, "");
|
||||
}
|
||||
{
|
||||
// Test that the tagged dispatch constructor SFINAE's away when the
|
||||
// argument is non-copyable
|
||||
struct NoCopy {
|
||||
NoCopy() = default;
|
||||
NoCopy(NoCopy const&) = delete;
|
||||
NoCopy(int) {}
|
||||
NoCopy(std::initializer_list<int>, int) {}
|
||||
};
|
||||
using Tag = std::in_place_type_t<NoCopy>;
|
||||
using IL = std::initializer_list<int>;
|
||||
static_assert(!std::is_constructible<std::any, Tag>::value, "");
|
||||
static_assert(!std::is_constructible<std::any, Tag, int>::value, "");
|
||||
static_assert(!std::is_constructible<std::any, Tag, IL, int>::value, "");
|
||||
}
|
||||
}
|
||||
|
||||
struct Implicit {
|
||||
Implicit(int) {}
|
||||
Implicit(int, int, int) {}
|
||||
Implicit(std::initializer_list<int>, int) {}
|
||||
};
|
||||
|
||||
void test_constructor_explicit() {
|
||||
using I = Implicit;
|
||||
using IT = std::in_place_type_t<I>;
|
||||
static_assert(!test_convertible<std::any, IT, int>(), "");
|
||||
static_assert(std::is_constructible<std::any, IT, int>::value, "");
|
||||
static_assert(!test_convertible<std::any, IT, int, int, int>(), "");
|
||||
static_assert(std::is_constructible<std::any, IT, int, int, int>::value, "");
|
||||
static_assert(!test_convertible<std::any, IT, std::initializer_list<int>&, int>(), "");
|
||||
static_assert(std::is_constructible<std::any, IT, std::initializer_list<int>&, int>::value, "");
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_in_place_type<small>();
|
||||
test_in_place_type<large>();
|
||||
test_in_place_type<small_throws_on_copy>();
|
||||
test_in_place_type<large_throws_on_copy>();
|
||||
test_in_place_type<throws_on_move>();
|
||||
test_in_place_type_tracked<small_tracked_t>();
|
||||
test_in_place_type_tracked<large_tracked_t>();
|
||||
test_ctor_sfinae();
|
||||
test_constructor_explicit();
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// any(any &&) noexcept;
|
||||
|
||||
#include <any>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
// Moves are always noexcept. The throws_on_move object
|
||||
// must be stored dynamically so the pointer is moved and
|
||||
// not the stored object.
|
||||
void test_move_does_not_throw()
|
||||
{
|
||||
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
||||
assert(throws_on_move::count == 0);
|
||||
{
|
||||
throws_on_move v(42);
|
||||
any a(v);
|
||||
assert(throws_on_move::count == 2);
|
||||
// No allocations should be performed after this point.
|
||||
DisableAllocationGuard g; ((void)g);
|
||||
try {
|
||||
any const a2(std::move(a));
|
||||
assertEmpty(a);
|
||||
assertContains<throws_on_move>(a2, 42);
|
||||
} catch (...) {
|
||||
assert(false);
|
||||
}
|
||||
assert(throws_on_move::count == 1);
|
||||
assertEmpty(a);
|
||||
}
|
||||
assert(throws_on_move::count == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_move_empty() {
|
||||
DisableAllocationGuard g; ((void)g); // no allocations should be performed.
|
||||
|
||||
any a1;
|
||||
any a2(std::move(a1));
|
||||
|
||||
assertEmpty(a1);
|
||||
assertEmpty(a2);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void test_move() {
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
any a((Type(42)));
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 1);
|
||||
|
||||
// Moving should not perform allocations since it must be noexcept.
|
||||
DisableAllocationGuard g; ((void)g);
|
||||
|
||||
any a2(std::move(a));
|
||||
|
||||
assert(Type::moved >= 1); // zero or more move operations can be performed.
|
||||
assert(Type::copied == 0); // no copies can be performed.
|
||||
assert(Type::count == 1);
|
||||
assertEmpty(a); // Moves are always destructive.
|
||||
assertContains<Type>(a2, 42);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// noexcept test
|
||||
{
|
||||
static_assert(
|
||||
std::is_nothrow_move_constructible<any>::value
|
||||
, "any must be nothrow move constructible"
|
||||
);
|
||||
}
|
||||
test_move<small>();
|
||||
test_move<large>();
|
||||
test_move_empty();
|
||||
test_move_does_not_throw();
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// template <class Value> any(Value &&)
|
||||
|
||||
// Test construction from a value.
|
||||
// Concerns:
|
||||
// ---------
|
||||
// 1. The value is properly move/copied depending on the value category.
|
||||
// 2. Both small and large values are properly handled.
|
||||
|
||||
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
|
||||
template <class Type>
|
||||
void test_copy_value_throws()
|
||||
{
|
||||
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
||||
assert(Type::count == 0);
|
||||
{
|
||||
Type const t(42);
|
||||
assert(Type::count == 1);
|
||||
try {
|
||||
any const a2(t);
|
||||
assert(false);
|
||||
} catch (my_any_exception const &) {
|
||||
// do nothing
|
||||
} catch (...) {
|
||||
assert(false);
|
||||
}
|
||||
assert(Type::count == 1);
|
||||
assert(t.value == 42);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_move_value_throws()
|
||||
{
|
||||
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
||||
assert(throws_on_move::count == 0);
|
||||
{
|
||||
throws_on_move v;
|
||||
assert(throws_on_move::count == 1);
|
||||
try {
|
||||
any const a(std::move(v));
|
||||
assert(false);
|
||||
} catch (my_any_exception const &) {
|
||||
// do nothing
|
||||
} catch (...) {
|
||||
assert(false);
|
||||
}
|
||||
assert(throws_on_move::count == 1);
|
||||
}
|
||||
assert(throws_on_move::count == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void test_copy_move_value() {
|
||||
// constructing from a small type should perform no allocations.
|
||||
DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
Type t(42);
|
||||
assert(Type::count == 1);
|
||||
|
||||
any a(t);
|
||||
|
||||
assert(Type::count == 2);
|
||||
assert(Type::copied == 1);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 42);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
Type t(42);
|
||||
assert(Type::count == 1);
|
||||
|
||||
any a(std::move(t));
|
||||
|
||||
assert(Type::count == 2);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 1);
|
||||
assertContains<Type>(a, 42);
|
||||
}
|
||||
}
|
||||
|
||||
void test_non_moveable_type()
|
||||
{
|
||||
using Type = deleted_move;
|
||||
{
|
||||
deleted_move mv(42);
|
||||
std::any a(mv);
|
||||
assert(Type::count == 2);
|
||||
assert(Type::copied == 1);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 42);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
deleted_move mv(42);
|
||||
std::any a(std::move(mv));
|
||||
assert(Type::count == 2);
|
||||
assert(Type::copied == 1);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 42);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Test that any(ValueType&&) is *never* selected for a std::in_place type.
|
||||
void test_sfinae_constraints() {
|
||||
using Tag = std::in_place_type_t<int>;
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wignored-qualifiers"
|
||||
#endif
|
||||
static_assert(std::is_same<Tag, const Tag>::value, "");
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
// Test that the tag type is properly handled in SFINAE
|
||||
Tag t = std::in_place;
|
||||
{
|
||||
std::any a(t);
|
||||
assertContains<int>(a, 0);
|
||||
}
|
||||
{
|
||||
std::any a(std::move(t));
|
||||
assertContains<int>(a, 0);
|
||||
}
|
||||
{
|
||||
struct Dummy { Dummy() = delete; };
|
||||
using T = std::in_place_type_t<Dummy>;
|
||||
static_assert(!std::is_constructible<std::any, T>::value, "");
|
||||
}
|
||||
{
|
||||
// Test that the ValueType&& constructor SFINAE's away when the
|
||||
// argument is non-copyable
|
||||
struct NoCopy {
|
||||
NoCopy() = default;
|
||||
NoCopy(NoCopy const&) = delete;
|
||||
NoCopy(int) {}
|
||||
};
|
||||
static_assert(!std::is_constructible<std::any, NoCopy>::value, "");
|
||||
static_assert(!std::is_convertible<NoCopy, std::any>::value, "");
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_copy_move_value<small>();
|
||||
test_copy_move_value<large>();
|
||||
test_copy_value_throws<small_throws_on_copy>();
|
||||
test_copy_value_throws<large_throws_on_copy>();
|
||||
test_move_value_throws();
|
||||
test_non_moveable_type();
|
||||
test_sfinae_constraints();
|
||||
}
|
|
@ -0,0 +1,255 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// template <class T, class ...Args> emplace(Args&&...);
|
||||
// template <class T, class U, class ...Args>
|
||||
// void emplace(initializer_list<U>, Args&&...);
|
||||
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
struct Tracked {
|
||||
static int count;
|
||||
Tracked() {++count;}
|
||||
~Tracked() { --count; }
|
||||
};
|
||||
int Tracked::count = 0;
|
||||
|
||||
template <class Type>
|
||||
void test_emplace_type() {
|
||||
// constructing from a small type should perform no allocations.
|
||||
DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
any a(std::in_place<Tracked>);
|
||||
assert(Tracked::count == 1);
|
||||
|
||||
a.emplace<Type>();
|
||||
|
||||
assert(Tracked::count == 0);
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 0);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
any a(std::in_place<Tracked>);
|
||||
assert(Tracked::count == 1);
|
||||
|
||||
a.emplace<Type>(101);
|
||||
|
||||
assert(Tracked::count == 0);
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 101);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
any a(std::in_place<Tracked>);
|
||||
assert(Tracked::count == 1);
|
||||
|
||||
a.emplace<Type>(-1, 42, -1);
|
||||
|
||||
assert(Tracked::count == 0);
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 42);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void test_emplace_type_tracked() {
|
||||
// constructing from a small type should perform no allocations.
|
||||
DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
|
||||
{
|
||||
any a(std::in_place<Tracked>);
|
||||
assert(Tracked::count == 1);
|
||||
a.emplace<Type>();
|
||||
assert(Tracked::count == 0);
|
||||
assertArgsMatch<Type>(a);
|
||||
}
|
||||
{
|
||||
any a(std::in_place<Tracked>);
|
||||
assert(Tracked::count == 1);
|
||||
a.emplace<Type>(-1, 42, -1);
|
||||
assert(Tracked::count == 0);
|
||||
assertArgsMatch<Type, int, int, int>(a);
|
||||
}
|
||||
// initializer_list constructor tests
|
||||
{
|
||||
any a(std::in_place<Tracked>);
|
||||
assert(Tracked::count == 1);
|
||||
a.emplace<Type>({-1, 42, -1});
|
||||
assert(Tracked::count == 0);
|
||||
assertArgsMatch<Type, std::initializer_list<int>>(a);
|
||||
}
|
||||
{
|
||||
int x = 42;
|
||||
any a(std::in_place<Tracked>);
|
||||
assert(Tracked::count == 1);
|
||||
a.emplace<Type>({-1, 42, -1}, x);
|
||||
assert(Tracked::count == 0);
|
||||
assertArgsMatch<Type, std::initializer_list<int>, int&>(a);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef TEST_HAS_NO_EXCEPTIONS
|
||||
|
||||
struct SmallThrows {
|
||||
SmallThrows(int) { throw 42; }
|
||||
SmallThrows(std::initializer_list<int>, int) { throw 42; }
|
||||
};
|
||||
static_assert(IsSmallObject<SmallThrows>::value, "");
|
||||
|
||||
struct LargeThrows {
|
||||
LargeThrows(int) { throw 42; }
|
||||
LargeThrows(std::initializer_list<int>, int) { throw 42; }
|
||||
int data[10];
|
||||
};
|
||||
static_assert(!IsSmallObject<LargeThrows>::value, "");
|
||||
|
||||
template <class Type>
|
||||
void test_emplace_throws()
|
||||
{
|
||||
// any stores small type
|
||||
{
|
||||
std::any a(small{42});
|
||||
assert(small::count == 1);
|
||||
try {
|
||||
a.emplace<Type>(101);
|
||||
assert(false);
|
||||
} catch (int const&) {
|
||||
}
|
||||
assert(small::count == 0);
|
||||
}
|
||||
{
|
||||
std::any a(small{42});
|
||||
assert(small::count == 1);
|
||||
try {
|
||||
a.emplace<Type>({1, 2, 3}, 101);
|
||||
assert(false);
|
||||
} catch (int const&) {
|
||||
}
|
||||
assert(small::count == 0);
|
||||
}
|
||||
// any stores large type
|
||||
{
|
||||
std::any a(large{42});
|
||||
assert(large::count == 1);
|
||||
try {
|
||||
a.emplace<Type>(101);
|
||||
assert(false);
|
||||
} catch (int const&) {
|
||||
}
|
||||
assert(large::count == 0);
|
||||
}
|
||||
{
|
||||
std::any a(large{42});
|
||||
assert(large::count == 1);
|
||||
try {
|
||||
a.emplace<Type>({1, 2, 3}, 101);
|
||||
assert(false);
|
||||
} catch (int const&) {
|
||||
}
|
||||
assert(large::count == 0);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <class T, class ...Args>
|
||||
constexpr auto has_emplace(int)
|
||||
-> decltype(std::any{}.emplace<T>(std::declval<Args>()...), true) { return true; }
|
||||
|
||||
template <class ...Args>
|
||||
constexpr bool has_emplace(long) { return false; }
|
||||
|
||||
template <class ...Args>
|
||||
constexpr bool has_emplace() { return has_emplace<Args...>(0); }
|
||||
|
||||
|
||||
template <class T, class IT, class ...Args>
|
||||
constexpr auto has_emplace_init_list(int)
|
||||
-> decltype(std::any{}.emplace<T>(
|
||||
{std::declval<IT>(), std::declval<IT>(), std::declval<IT>()},
|
||||
std::declval<Args>()...), true) { return true; }
|
||||
|
||||
template <class ...Args>
|
||||
constexpr bool has_emplace_init_list(long) { return false; }
|
||||
|
||||
template <class ...Args>
|
||||
constexpr bool has_emplace_init_list() { return has_emplace_init_list<Args...>(0); }
|
||||
|
||||
|
||||
void test_emplace_sfinae_constraints() {
|
||||
{
|
||||
static_assert(has_emplace<int>(), "");
|
||||
static_assert(has_emplace<int, int>(), "");
|
||||
static_assert(!has_emplace<int, int, int>(), "not constructible");
|
||||
static_assert(!has_emplace_init_list<int, int>(), "not constructible from il");
|
||||
}
|
||||
{
|
||||
static_assert(has_emplace<small>(), "");
|
||||
static_assert(has_emplace<large>(), "");
|
||||
static_assert(!has_emplace<small, void*>(), "");
|
||||
static_assert(!has_emplace<large, void*>(), "");
|
||||
|
||||
static_assert(has_emplace_init_list<small, int>(), "");
|
||||
static_assert(has_emplace_init_list<large, int>(), "");
|
||||
static_assert(!has_emplace_init_list<small, void*>(), "");
|
||||
static_assert(!has_emplace_init_list<large, void*>(), "");
|
||||
}
|
||||
{
|
||||
// Test that the emplace SFINAE's away when the
|
||||
// argument is non-copyable
|
||||
struct NoCopy {
|
||||
NoCopy() = default;
|
||||
NoCopy(NoCopy const&) = delete;
|
||||
NoCopy(int) {}
|
||||
NoCopy(std::initializer_list<int>, int, int) {}
|
||||
};
|
||||
static_assert(!has_emplace<NoCopy>(), "");
|
||||
static_assert(!has_emplace<NoCopy, int>(), "");
|
||||
static_assert(!has_emplace_init_list<NoCopy, int, int, int>(), "");
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_emplace_type<small>();
|
||||
test_emplace_type<large>();
|
||||
test_emplace_type<small_throws_on_copy>();
|
||||
test_emplace_type<large_throws_on_copy>();
|
||||
test_emplace_type<throws_on_move>();
|
||||
test_emplace_type_tracked<small_tracked_t>();
|
||||
test_emplace_type_tracked<large_tracked_t>();
|
||||
test_emplace_sfinae_constraints();
|
||||
#ifndef TEST_HAS_NO_EXCEPTIONS
|
||||
test_emplace_throws<SmallThrows>();
|
||||
test_emplace_throws<LargeThrows>();
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// any::reset() noexcept
|
||||
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
// empty
|
||||
{
|
||||
any a;
|
||||
|
||||
// noexcept check
|
||||
static_assert(
|
||||
noexcept(a.reset())
|
||||
, "any.reset() must be noexcept"
|
||||
);
|
||||
|
||||
assertEmpty(a);
|
||||
|
||||
a.reset();
|
||||
|
||||
assertEmpty(a);
|
||||
}
|
||||
// small object
|
||||
{
|
||||
any a((small(1)));
|
||||
assert(small::count == 1);
|
||||
assertContains<small>(a, 1);
|
||||
|
||||
a.reset();
|
||||
|
||||
assertEmpty<small>(a);
|
||||
assert(small::count == 0);
|
||||
}
|
||||
// large object
|
||||
{
|
||||
any a(large(1));
|
||||
assert(large::count == 1);
|
||||
assertContains<large>(a);
|
||||
|
||||
a.reset();
|
||||
|
||||
assertEmpty<large>(a);
|
||||
assert(large::count == 0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// any::swap(any &) noexcept
|
||||
|
||||
// Test swap(large, small) and swap(small, large)
|
||||
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
template <class LHS, class RHS>
|
||||
void test_swap() {
|
||||
assert(LHS::count == 0);
|
||||
assert(RHS::count == 0);
|
||||
{
|
||||
any a1((LHS(1)));
|
||||
any a2(RHS{2});
|
||||
assert(LHS::count == 1);
|
||||
assert(RHS::count == 1);
|
||||
|
||||
a1.swap(a2);
|
||||
|
||||
assert(LHS::count == 1);
|
||||
assert(RHS::count == 1);
|
||||
|
||||
assertContains<RHS>(a1, 2);
|
||||
assertContains<LHS>(a2, 1);
|
||||
}
|
||||
assert(LHS::count == 0);
|
||||
assert(RHS::count == 0);
|
||||
assert(LHS::copied == 0);
|
||||
assert(RHS::copied == 0);
|
||||
}
|
||||
|
||||
template <class Tp>
|
||||
void test_swap_empty() {
|
||||
assert(Tp::count == 0);
|
||||
{
|
||||
any a1((Tp(1)));
|
||||
any a2;
|
||||
assert(Tp::count == 1);
|
||||
|
||||
a1.swap(a2);
|
||||
|
||||
assert(Tp::count == 1);
|
||||
|
||||
assertContains<Tp>(a2, 1);
|
||||
assertEmpty(a1);
|
||||
}
|
||||
assert(Tp::count == 0);
|
||||
{
|
||||
any a1((Tp(1)));
|
||||
any a2;
|
||||
assert(Tp::count == 1);
|
||||
|
||||
a2.swap(a1);
|
||||
|
||||
assert(Tp::count == 1);
|
||||
|
||||
assertContains<Tp>(a2, 1);
|
||||
assertEmpty(a1);
|
||||
}
|
||||
assert(Tp::count == 0);
|
||||
assert(Tp::copied == 0);
|
||||
}
|
||||
|
||||
void test_noexcept()
|
||||
{
|
||||
any a1;
|
||||
any a2;
|
||||
static_assert(
|
||||
noexcept(a1.swap(a2))
|
||||
, "any::swap(any&) must be noexcept"
|
||||
);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_noexcept();
|
||||
test_swap_empty<small>();
|
||||
test_swap_empty<large>();
|
||||
test_swap<small1, small2>();
|
||||
test_swap<large1, large2>();
|
||||
test_swap<small, large>();
|
||||
test_swap<large, small>();
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// any::has_value() noexcept
|
||||
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
using std::any;
|
||||
// noexcept test
|
||||
{
|
||||
any a;
|
||||
static_assert(noexcept(a.has_value()), "any::has_value() must be noexcept");
|
||||
}
|
||||
// empty
|
||||
{
|
||||
any a;
|
||||
assert(!a.has_value());
|
||||
|
||||
a.reset();
|
||||
assert(!a.has_value());
|
||||
|
||||
a = 42;
|
||||
assert(a.has_value());
|
||||
}
|
||||
// small object
|
||||
{
|
||||
small const s(1);
|
||||
any a(s);
|
||||
assert(a.has_value());
|
||||
|
||||
a.reset();
|
||||
assert(!a.has_value());
|
||||
|
||||
a = s;
|
||||
assert(a.has_value());
|
||||
}
|
||||
// large object
|
||||
{
|
||||
large const l(1);
|
||||
any a(l);
|
||||
assert(a.has_value());
|
||||
|
||||
a.reset();
|
||||
assert(!a.has_value());
|
||||
|
||||
a = l;
|
||||
assert(a.has_value());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// XFAIL: libcpp-no-rtti
|
||||
|
||||
// <any>
|
||||
|
||||
// any::type() noexcept
|
||||
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
#include "any_helpers.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
using std::any;
|
||||
{
|
||||
any const a;
|
||||
assert(a.type() == typeid(void));
|
||||
static_assert(noexcept(a.type()), "any::type() must be noexcept");
|
||||
}
|
||||
{
|
||||
small const s(1);
|
||||
any const a(s);
|
||||
assert(a.type() == typeid(small));
|
||||
|
||||
}
|
||||
{
|
||||
large const l(1);
|
||||
any const a(l);
|
||||
assert(a.type() == typeid(large));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// [Note any is a not a literal type --end note]
|
||||
|
||||
#include <any>
|
||||
#include <type_traits>
|
||||
|
||||
int main () {
|
||||
static_assert(!std::is_literal_type<std::any>::value, "");
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// template <class ValueType>
|
||||
// ValueType const* any_cast(any const *) noexcept;
|
||||
//
|
||||
// template <class ValueType>
|
||||
// ValueType * any_cast(any *) noexcept;
|
||||
|
||||
#include <any>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
// Test that the operators are properly noexcept.
|
||||
void test_cast_is_noexcept() {
|
||||
any a;
|
||||
static_assert(noexcept(any_cast<int>(&a)), "");
|
||||
|
||||
any const& ca = a;
|
||||
static_assert(noexcept(any_cast<int>(&ca)), "");
|
||||
}
|
||||
|
||||
// Test that the return type of any_cast is correct.
|
||||
void test_cast_return_type() {
|
||||
any a;
|
||||
static_assert(std::is_same<decltype(any_cast<int>(&a)), int*>::value, "");
|
||||
static_assert(std::is_same<decltype(any_cast<int const>(&a)), int const*>::value, "");
|
||||
|
||||
any const& ca = a;
|
||||
static_assert(std::is_same<decltype(any_cast<int>(&ca)), int const*>::value, "");
|
||||
static_assert(std::is_same<decltype(any_cast<int const>(&ca)), int const*>::value, "");
|
||||
}
|
||||
|
||||
// Test that any_cast handles null pointers.
|
||||
void test_cast_nullptr() {
|
||||
any* a = nullptr;
|
||||
assert(nullptr == any_cast<int>(a));
|
||||
assert(nullptr == any_cast<int const>(a));
|
||||
|
||||
any const* ca = nullptr;
|
||||
assert(nullptr == any_cast<int>(ca));
|
||||
assert(nullptr == any_cast<int const>(ca));
|
||||
}
|
||||
|
||||
// Test casting an empty object.
|
||||
void test_cast_empty() {
|
||||
{
|
||||
any a;
|
||||
assert(nullptr == any_cast<int>(&a));
|
||||
assert(nullptr == any_cast<int const>(&a));
|
||||
|
||||
any const& ca = a;
|
||||
assert(nullptr == any_cast<int>(&ca));
|
||||
assert(nullptr == any_cast<int const>(&ca));
|
||||
}
|
||||
// Create as non-empty, then make empty and run test.
|
||||
{
|
||||
any a(42);
|
||||
a.reset();
|
||||
assert(nullptr == any_cast<int>(&a));
|
||||
assert(nullptr == any_cast<int const>(&a));
|
||||
|
||||
any const& ca = a;
|
||||
assert(nullptr == any_cast<int>(&ca));
|
||||
assert(nullptr == any_cast<int const>(&ca));
|
||||
}
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void test_cast() {
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
any a((Type(42)));
|
||||
any const& ca = a;
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 1);
|
||||
|
||||
// Try a cast to a bad type.
|
||||
// NOTE: Type cannot be an int.
|
||||
assert(any_cast<int>(&a) == nullptr);
|
||||
assert(any_cast<int const>(&a) == nullptr);
|
||||
assert(any_cast<int const volatile>(&a) == nullptr);
|
||||
|
||||
// Try a cast to the right type, but as a pointer.
|
||||
assert(any_cast<Type*>(&a) == nullptr);
|
||||
assert(any_cast<Type const*>(&a) == nullptr);
|
||||
|
||||
// Check getting a unqualified type from a non-const any.
|
||||
Type* v = any_cast<Type>(&a);
|
||||
assert(v != nullptr);
|
||||
assert(v->value == 42);
|
||||
|
||||
// change the stored value and later check for the new value.
|
||||
v->value = 999;
|
||||
|
||||
// Check getting a const qualified type from a non-const any.
|
||||
Type const* cv = any_cast<Type const>(&a);
|
||||
assert(cv != nullptr);
|
||||
assert(cv == v);
|
||||
assert(cv->value == 999);
|
||||
|
||||
// Check getting a unqualified type from a const any.
|
||||
cv = any_cast<Type>(&ca);
|
||||
assert(cv != nullptr);
|
||||
assert(cv == v);
|
||||
assert(cv->value == 999);
|
||||
|
||||
// Check getting a const-qualified type from a const any.
|
||||
cv = any_cast<Type const>(&ca);
|
||||
assert(cv != nullptr);
|
||||
assert(cv == v);
|
||||
assert(cv->value == 999);
|
||||
|
||||
// Check that no more objects were created, copied or moved.
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 1);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
}
|
||||
|
||||
void test_cast_non_copyable_type()
|
||||
{
|
||||
// Even though 'any' never stores non-copyable types
|
||||
// we still need to support any_cast<NoCopy>(ptr)
|
||||
struct NoCopy { NoCopy(NoCopy const&) = delete; };
|
||||
std::any a(42);
|
||||
std::any const& ca = a;
|
||||
assert(std::any_cast<NoCopy>(&a) == nullptr);
|
||||
assert(std::any_cast<NoCopy>(&ca) == nullptr);
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_cast_is_noexcept();
|
||||
test_cast_return_type();
|
||||
test_cast_nullptr();
|
||||
test_cast_empty();
|
||||
test_cast<small>();
|
||||
test_cast<large>();
|
||||
test_cast_non_copyable_type();
|
||||
}
|
|
@ -0,0 +1,396 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// template <class ValueType>
|
||||
// ValueType const any_cast(any const&);
|
||||
//
|
||||
// template <class ValueType>
|
||||
// ValueType any_cast(any &);
|
||||
//
|
||||
// template <class ValueType>
|
||||
// ValueType any_cast(any &&);
|
||||
|
||||
#include <any>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
using std::bad_any_cast;
|
||||
|
||||
|
||||
// Test that the operators are NOT marked noexcept.
|
||||
void test_cast_is_not_noexcept() {
|
||||
any a;
|
||||
static_assert(!noexcept(any_cast<int>(static_cast<any&>(a))), "");
|
||||
static_assert(!noexcept(any_cast<int>(static_cast<any const&>(a))), "");
|
||||
static_assert(!noexcept(any_cast<int>(static_cast<any &&>(a))), "");
|
||||
}
|
||||
|
||||
// Test that the return type of any_cast is correct.
|
||||
void test_cast_return_type() {
|
||||
any a;
|
||||
static_assert(std::is_same<decltype(any_cast<int>(a)), int>::value, "");
|
||||
static_assert(std::is_same<decltype(any_cast<int const>(a)), int>::value, "");
|
||||
static_assert(std::is_same<decltype(any_cast<int&>(a)), int&>::value, "");
|
||||
static_assert(std::is_same<decltype(any_cast<int const&>(a)), int const&>::value, "");
|
||||
|
||||
static_assert(std::is_same<decltype(any_cast<int&&>(a)), int&&>::value, "");
|
||||
static_assert(std::is_same<decltype(any_cast<int const&&>(a)), int const&&>::value, "");
|
||||
|
||||
static_assert(std::is_same<decltype(any_cast<int>(std::move(a))), int>::value, "");
|
||||
static_assert(std::is_same<decltype(any_cast<int const>(std::move(a))), int>::value, "");
|
||||
static_assert(std::is_same<decltype(any_cast<int&>(std::move(a))), int&>::value, "");
|
||||
static_assert(std::is_same<decltype(any_cast<int const&>(std::move(a))), int const&>::value, "");
|
||||
|
||||
static_assert(std::is_same<decltype(any_cast<int&&>(std::move(a))), int&&>::value, "");
|
||||
static_assert(std::is_same<decltype(any_cast<int const&&>(std::move(a))), int const&&>::value, "");
|
||||
|
||||
any const& ca = a;
|
||||
static_assert(std::is_same<decltype(any_cast<int>(ca)), int>::value, "");
|
||||
static_assert(std::is_same<decltype(any_cast<int const>(ca)), int>::value, "");
|
||||
static_assert(std::is_same<decltype(any_cast<int const&>(ca)), int const&>::value, "");
|
||||
|
||||
static_assert(std::is_same<decltype(any_cast<int const&&>(ca)), int const&&>::value, "");
|
||||
}
|
||||
|
||||
template <class Type, class ConstT = Type>
|
||||
void checkThrows(any& a)
|
||||
{
|
||||
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
||||
try {
|
||||
any_cast<Type>(a);
|
||||
assert(false);
|
||||
} catch (bad_any_cast const &) {
|
||||
// do nothing
|
||||
} catch (...) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
try {
|
||||
any_cast<ConstT>(static_cast<any const&>(a));
|
||||
assert(false);
|
||||
} catch (bad_any_cast const &) {
|
||||
// do nothing
|
||||
} catch (...) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
try {
|
||||
any_cast<Type>(static_cast<any&&>(a));
|
||||
assert(false);
|
||||
} catch (bad_any_cast const &) {
|
||||
// do nothing
|
||||
} catch (...) {
|
||||
assert(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_cast_empty() {
|
||||
// None of these operations should allocate.
|
||||
DisableAllocationGuard g; ((void)g);
|
||||
any a;
|
||||
checkThrows<int>(a);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void test_cast_to_reference() {
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
any a((Type(42)));
|
||||
any const& ca = a;
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 1);
|
||||
|
||||
// Try a cast to a bad type.
|
||||
// NOTE: Type cannot be an int.
|
||||
checkThrows<int>(a);
|
||||
checkThrows<int&, int const&>(a);
|
||||
checkThrows<Type*, Type const*>(a);
|
||||
checkThrows<Type const*>(a);
|
||||
|
||||
// Check getting a type by reference from a non-const lvalue any.
|
||||
{
|
||||
Type& v = any_cast<Type&>(a);
|
||||
assert(v.value == 42);
|
||||
|
||||
Type const &cv = any_cast<Type const&>(a);
|
||||
assert(&cv == &v);
|
||||
}
|
||||
// Check getting a type by reference from a const lvalue any.
|
||||
{
|
||||
Type const& v = any_cast<Type const&>(ca);
|
||||
assert(v.value == 42);
|
||||
|
||||
Type const &cv = any_cast<Type const&>(ca);
|
||||
assert(&cv == &v);
|
||||
}
|
||||
// Check getting a type by reference from a non-const rvalue
|
||||
{
|
||||
Type& v = any_cast<Type&>(std::move(a));
|
||||
assert(v.value == 42);
|
||||
|
||||
Type const &cv = any_cast<Type const&>(std::move(a));
|
||||
assert(&cv == &v);
|
||||
}
|
||||
// Check getting a type by reference from a const rvalue any.
|
||||
{
|
||||
Type const& v = any_cast<Type const&>(std::move(ca));
|
||||
assert(v.value == 42);
|
||||
|
||||
Type const &cv = any_cast<Type const&>(std::move(ca));
|
||||
assert(&cv == &v);
|
||||
}
|
||||
// Check getting a type by reference from a const rvalue any.
|
||||
{
|
||||
Type&& v = any_cast<Type&&>(std::move(a));
|
||||
assert(v.value == 42);
|
||||
assert(any_cast<Type&>(a).value == 42);
|
||||
|
||||
Type&& cv = any_cast<Type&&>(std::move(a));
|
||||
assert(&cv == &v);
|
||||
assert(any_cast<Type&>(a).value == 42);
|
||||
}
|
||||
// Check getting a type by reference from a const rvalue any.
|
||||
{
|
||||
Type const&& v = any_cast<Type const&&>(std::move(a));
|
||||
assert(v.value == 42);
|
||||
assert(any_cast<Type&>(a).value == 42);
|
||||
|
||||
Type const&& cv = any_cast<Type const&&>(std::move(a));
|
||||
assert(&cv == &v);
|
||||
assert(any_cast<Type&>(a).value == 42);
|
||||
}
|
||||
// Check that the original object hasn't been changed.
|
||||
assertContains<Type>(a, 42);
|
||||
|
||||
// Check that no objects have been created/copied/moved.
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 1);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void test_cast_to_value() {
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
any a((Type(42)));
|
||||
any const& ca = a;
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 1);
|
||||
|
||||
// Try a cast to a bad type.
|
||||
// NOTE: Type cannot be an int.
|
||||
checkThrows<int>(a);
|
||||
checkThrows<int&, int const&>(a);
|
||||
checkThrows<Type*, Type const*>(a);
|
||||
checkThrows<Type const*>(a);
|
||||
|
||||
Type::reset(); // NOTE: reset does not modify Type::count
|
||||
// Check getting Type by value from a non-const lvalue any.
|
||||
// This should cause the non-const copy constructor to be called.
|
||||
{
|
||||
Type t = any_cast<Type>(a);
|
||||
|
||||
assert(Type::count == 2);
|
||||
assert(Type::copied == 1);
|
||||
assert(Type::const_copied == 0);
|
||||
assert(Type::non_const_copied == 1);
|
||||
assert(Type::moved == 0);
|
||||
assert(t.value == 42);
|
||||
}
|
||||
assert(Type::count == 1);
|
||||
Type::reset();
|
||||
// Check getting const Type by value from a non-const lvalue any.
|
||||
// This should cause the const copy constructor to be called.
|
||||
{
|
||||
Type t = any_cast<Type const>(a);
|
||||
|
||||
assert(Type::count == 2);
|
||||
assert(Type::copied == 1);
|
||||
assert(Type::const_copied == 1);
|
||||
assert(Type::non_const_copied == 0);
|
||||
assert(Type::moved == 0);
|
||||
assert(t.value == 42);
|
||||
}
|
||||
assert(Type::count == 1);
|
||||
Type::reset();
|
||||
// Check getting Type by value from a non-const lvalue any.
|
||||
// This should cause the const copy constructor to be called.
|
||||
{
|
||||
Type t = any_cast<Type>(static_cast<any const&>(a));
|
||||
|
||||
assert(Type::count == 2);
|
||||
assert(Type::copied == 1);
|
||||
assert(Type::const_copied == 1);
|
||||
assert(Type::non_const_copied == 0);
|
||||
assert(Type::moved == 0);
|
||||
assert(t.value == 42);
|
||||
}
|
||||
assert(Type::count == 1);
|
||||
Type::reset();
|
||||
// Check getting Type by value from a non-const rvalue any.
|
||||
// This should cause the non-const copy constructor to be called.
|
||||
{
|
||||
Type t = any_cast<Type>(static_cast<any &&>(a));
|
||||
|
||||
assert(Type::count == 2);
|
||||
assert(Type::moved == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::const_copied == 0);
|
||||
assert(Type::non_const_copied == 0);
|
||||
assert(t.value == 42);
|
||||
assert(any_cast<Type&>(a).value == 0);
|
||||
any_cast<Type&>(a).value = 42; // reset the value
|
||||
}
|
||||
assert(Type::count == 1);
|
||||
Type::reset();
|
||||
// Check getting const Type by value from a non-const rvalue any.
|
||||
// This should cause the const copy constructor to be called.
|
||||
{
|
||||
Type t = any_cast<Type const>(static_cast<any &&>(a));
|
||||
|
||||
assert(Type::count == 2);
|
||||
assert(Type::copied == 1);
|
||||
assert(Type::const_copied == 1);
|
||||
assert(Type::non_const_copied == 0);
|
||||
assert(Type::moved == 0);
|
||||
assert(t.value == 42);
|
||||
assert(any_cast<Type&>(a).value == 42);
|
||||
}
|
||||
assert(Type::count == 1);
|
||||
Type::reset();
|
||||
// Check getting Type by value from a const rvalue any.
|
||||
// This should cause the const copy constructor to be called.
|
||||
{
|
||||
Type t = any_cast<Type>(static_cast<any const&&>(a));
|
||||
|
||||
assert(Type::count == 2);
|
||||
assert(Type::copied == 1);
|
||||
assert(Type::const_copied == 1);
|
||||
assert(Type::non_const_copied == 0);
|
||||
assert(Type::moved == 0);
|
||||
assert(t.value == 42);
|
||||
assert(any_cast<Type&>(a).value == 42);
|
||||
}
|
||||
// Ensure we still only have 1 Type object alive.
|
||||
assert(Type::count == 1);
|
||||
|
||||
// Check that the original object hasn't been changed.
|
||||
assertContains<Type>(a, 42);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
}
|
||||
|
||||
void test_cast_to_value_deleted_move()
|
||||
{
|
||||
using Type = deleted_move;
|
||||
{
|
||||
std::any a(deleted_move(42));
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 1);
|
||||
assert(Type::moved == 0);
|
||||
|
||||
Type const& t = any_cast<Type>(a);
|
||||
assert(Type::count == 2);
|
||||
assert(Type::copied == 2);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 42);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
std::any a(deleted_move(42));
|
||||
std::any const& ca = a;
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 1);
|
||||
assert(Type::moved == 0);
|
||||
|
||||
Type const& t = any_cast<Type>(ca);
|
||||
assert(Type::count == 2);
|
||||
assert(Type::copied == 2);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 42);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
std::any a(deleted_move(42));
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 1);
|
||||
assert(Type::moved == 0);
|
||||
|
||||
Type&& t = any_cast<Type>(std::move(a));
|
||||
assert(Type::count == 2);
|
||||
assert(Type::copied == 2);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 42);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
std::any a(deleted_move(42));
|
||||
std::any const& ca = a;
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 1);
|
||||
assert(Type::moved == 0);
|
||||
|
||||
Type&& t = any_cast<Type>(std::move(ca));
|
||||
assert(Type::count == 2);
|
||||
assert(Type::copied == 2);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 42);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
}
|
||||
|
||||
// Even though you can't get a non-copyable class into std::any
|
||||
// the standard requires that these overloads compile and function.
|
||||
void test_non_copyable_ref() {
|
||||
struct no_copy
|
||||
{
|
||||
no_copy() {}
|
||||
no_copy(no_copy &&) {}
|
||||
private:
|
||||
no_copy(no_copy const &);
|
||||
};
|
||||
|
||||
any a;
|
||||
checkThrows<no_copy &, no_copy const&>(a);
|
||||
checkThrows<no_copy const&>(a);
|
||||
assertEmpty(a);
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_cast_is_not_noexcept();
|
||||
test_cast_return_type();
|
||||
test_cast_empty();
|
||||
test_cast_to_reference<small>();
|
||||
test_cast_to_reference<large>();
|
||||
test_cast_to_value<small>();
|
||||
test_cast_to_value<large>();
|
||||
test_cast_to_value_deleted_move();
|
||||
test_non_copyable_ref();
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// template <class ValueType>
|
||||
// ValueType any_cast(any const &);
|
||||
|
||||
// Try and cast away const.
|
||||
|
||||
#include <any>
|
||||
|
||||
struct TestType {};
|
||||
struct TestType2 {};
|
||||
|
||||
int main()
|
||||
{
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
any a;
|
||||
|
||||
// expected-error@any:* 2 {{binding value of type '_Tp' (aka 'const TestType') to reference to type 'TestType' drops 'const' qualifier}}
|
||||
any_cast<TestType &>(static_cast<any const&>(a)); // expected-note {{requested here}}
|
||||
any_cast<TestType &&>(static_cast<any const&>(a)); // expected-note {{requested here}}
|
||||
|
||||
// expected-error@any:* 2 {{binding value of type '_Tp' (aka 'const TestType2') to reference to type 'TestType2' drops 'const' qualifier}}
|
||||
any_cast<TestType2 &>(static_cast<any const&&>(a)); // expected-note {{requested here}}
|
||||
any_cast<TestType2 &&>(static_cast<any const&&>(a)); // expected-note {{requested here}}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// template <class ValueType>
|
||||
// ValueType const any_cast(any const&);
|
||||
//
|
||||
// template <class ValueType>
|
||||
// ValueType any_cast(any &);
|
||||
//
|
||||
// template <class ValueType>
|
||||
// ValueType any_cast(any &&);
|
||||
|
||||
// Test instantiating the any_cast with a non-copyable type.
|
||||
|
||||
#include <any>
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
struct no_copy
|
||||
{
|
||||
no_copy() {}
|
||||
no_copy(no_copy &&) {}
|
||||
private:
|
||||
no_copy(no_copy const &);
|
||||
};
|
||||
|
||||
int main() {
|
||||
any a;
|
||||
any_cast<no_copy>(static_cast<any&>(a)); // expected-note {{requested here}}
|
||||
any_cast<no_copy>(static_cast<any const&>(a)); // expected-note {{requested here}}
|
||||
any_cast<no_copy>(static_cast<any &&>(a)); // expected-note {{requested here}}
|
||||
// expected-error@any:* 3 {{static_assert failed "_ValueType is required to be a reference or a CopyConstructible type."}}
|
||||
// expected-error@any:* 2 {{calling a private constructor of class 'no_copy'}}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// template <class ValueType>
|
||||
// ValueType const* any_cast(any const *) noexcept;
|
||||
//
|
||||
// template <class ValueType>
|
||||
// ValueType * any_cast(any *) noexcept;
|
||||
|
||||
#include <any>
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
int main()
|
||||
{
|
||||
any a(1);
|
||||
any_cast<int &>(&a); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}}
|
||||
any_cast<int &&>(&a); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}}
|
||||
any_cast<int const &>(&a); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}}
|
||||
any_cast<int const&&>(&a); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}}
|
||||
any const& a2 = a;
|
||||
any_cast<int &>(&a2); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}}
|
||||
any_cast<int &&>(&a2); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}}
|
||||
any_cast<int const &>(&a2); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}}
|
||||
any_cast<int const &&>(&a2); // expected-error@any:* 1 {{static_assert failed "_ValueType may not be a reference."}}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// template <class T, class ...Args> any make_any(Args&&...);
|
||||
// template <class T, class U, class ...Args>
|
||||
// any make_any(initializer_list<U>, Args&&...);
|
||||
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
|
||||
#include "any_helpers.h"
|
||||
#include "count_new.hpp"
|
||||
#include "test_macros.h"
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
|
||||
template <class Type>
|
||||
void test_make_any_type() {
|
||||
// constructing from a small type should perform no allocations.
|
||||
DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
any a = std::make_any<Type>();
|
||||
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 0);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
any a = std::make_any<Type>(101);
|
||||
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 101);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
{
|
||||
any a = std::make_any<Type>(-1, 42, -1);
|
||||
|
||||
assert(Type::count == 1);
|
||||
assert(Type::copied == 0);
|
||||
assert(Type::moved == 0);
|
||||
assertContains<Type>(a, 42);
|
||||
}
|
||||
assert(Type::count == 0);
|
||||
Type::reset();
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void test_make_any_type_tracked() {
|
||||
// constructing from a small type should perform no allocations.
|
||||
DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
|
||||
{
|
||||
any a = std::make_any<Type>();
|
||||
assertArgsMatch<Type>(a);
|
||||
}
|
||||
{
|
||||
any a = std::make_any<Type>(-1, 42, -1);
|
||||
assertArgsMatch<Type, int, int, int>(a);
|
||||
}
|
||||
// initializer_list constructor tests
|
||||
{
|
||||
any a = std::make_any<Type>({-1, 42, -1});
|
||||
assertArgsMatch<Type, std::initializer_list<int>>(a);
|
||||
}
|
||||
{
|
||||
int x = 42;
|
||||
any a = std::make_any<Type>({-1, 42, -1}, x);
|
||||
assertArgsMatch<Type, std::initializer_list<int>, int&>(a);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef TEST_HAS_NO_EXCEPTIONS
|
||||
|
||||
struct SmallThrows {
|
||||
SmallThrows(int) { throw 42; }
|
||||
SmallThrows(std::initializer_list<int>, int) { throw 42; }
|
||||
};
|
||||
static_assert(IsSmallObject<SmallThrows>::value, "");
|
||||
|
||||
struct LargeThrows {
|
||||
LargeThrows(int) { throw 42; }
|
||||
LargeThrows(std::initializer_list<int>, int) { throw 42; }
|
||||
int data[10];
|
||||
};
|
||||
static_assert(!IsSmallObject<LargeThrows>::value, "");
|
||||
|
||||
template <class Type>
|
||||
void test_make_any_throws()
|
||||
{
|
||||
{
|
||||
try {
|
||||
std::make_any<Type>(101);
|
||||
assert(false);
|
||||
} catch (int const&) {
|
||||
}
|
||||
}
|
||||
{
|
||||
try {
|
||||
std::make_any<Type>({1, 2, 3}, 101);
|
||||
assert(false);
|
||||
} catch (int const&) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
test_make_any_type<small>();
|
||||
test_make_any_type<large>();
|
||||
test_make_any_type<small_throws_on_copy>();
|
||||
test_make_any_type<large_throws_on_copy>();
|
||||
test_make_any_type<throws_on_move>();
|
||||
test_make_any_type_tracked<small_tracked_t>();
|
||||
test_make_any_type_tracked<large_tracked_t>();
|
||||
#ifndef TEST_HAS_NO_EXCEPTIONS
|
||||
test_make_any_throws<SmallThrows>();
|
||||
test_make_any_throws<LargeThrows>();
|
||||
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// <any>
|
||||
|
||||
// void swap(any &, any &) noexcept
|
||||
|
||||
// swap(...) just wraps any::swap(...). That function is tested elsewhere.
|
||||
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
{ // test noexcept
|
||||
any a;
|
||||
static_assert(noexcept(swap(a, a)), "swap(any&, any&) must be noexcept");
|
||||
}
|
||||
{
|
||||
any a1(1);
|
||||
any a2(2);
|
||||
|
||||
swap(a1, a2);
|
||||
|
||||
assert(any_cast<int>(a1) == 2);
|
||||
assert(any_cast<int>(a2) == 1);
|
||||
}
|
||||
}
|
|
@ -9,12 +9,14 @@
|
|||
#ifndef ANY_HELPERS_H
|
||||
#define ANY_HELPERS_H
|
||||
|
||||
#include <experimental/any>
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
namespace std { namespace experimental {} }
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "type_id.h"
|
||||
|
||||
#if !defined(TEST_HAS_NO_RTTI)
|
||||
#define RTTI_ASSERT(X) assert(X)
|
||||
|
@ -32,42 +34,55 @@ template <class _Tp>
|
|||
>
|
||||
{};
|
||||
|
||||
template <class T>
|
||||
bool containsType(std::any const& a) {
|
||||
#if !defined(TEST_HAS_NO_RTTI)
|
||||
return a.type() == typeid(T);
|
||||
#else
|
||||
return a.has_value() && std::any_cast<T>(&a) != nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Return 'true' if 'Type' will be considered a small type by 'any'
|
||||
template <class Type>
|
||||
bool isSmallType() {
|
||||
#if defined(_LIBCPP_VERSION)
|
||||
return std::experimental::__any_imp::_IsSmallObject<Type>::value;
|
||||
#else
|
||||
return IsSmallObject<Type>::value;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// Assert that an object is empty. If the object used to contain an object
|
||||
// of type 'LastType' check that it can no longer be accessed.
|
||||
template <class LastType = int>
|
||||
void assertEmpty(std::experimental::any const& a) {
|
||||
assert(a.empty());
|
||||
void assertEmpty(std::any const& a) {
|
||||
using namespace std;
|
||||
assert(!a.has_value());
|
||||
RTTI_ASSERT(a.type() == typeid(void));
|
||||
assert(std::experimental::any_cast<LastType const>(&a) == nullptr);
|
||||
assert(any_cast<LastType const>(&a) == nullptr);
|
||||
}
|
||||
|
||||
// Assert that an 'any' object stores the specified 'Type' and 'value'.
|
||||
template <class Type>
|
||||
void assertContains(std::experimental::any const& a, int value = 1) {
|
||||
assert(!a.empty());
|
||||
RTTI_ASSERT(a.type() == typeid(Type));
|
||||
assert(std::experimental::any_cast<Type const &>(a).value == value);
|
||||
void assertContains(std::any const& a, int value = 1) {
|
||||
assert(a.has_value());
|
||||
assert(containsType<Type>(a));
|
||||
assert(std::any_cast<Type const &>(a).value == value);
|
||||
}
|
||||
|
||||
template <>
|
||||
void assertContains<int>(std::any const& a, int value) {
|
||||
assert(a.has_value());
|
||||
assert(containsType<int>(a));
|
||||
assert(std::any_cast<int const &>(a) == value);
|
||||
}
|
||||
|
||||
// Modify the value of a "test type" stored within an any to the specified
|
||||
// 'value'.
|
||||
template <class Type>
|
||||
void modifyValue(std::experimental::any& a, int value) {
|
||||
assert(!a.empty());
|
||||
RTTI_ASSERT(a.type() == typeid(Type));
|
||||
std::experimental::any_cast<Type&>(a).value = value;
|
||||
void modifyValue(std::any& a, int value) {
|
||||
using namespace std;
|
||||
using namespace std::experimental;
|
||||
assert(a.has_value());
|
||||
assert(containsType<Type>(a));
|
||||
any_cast<Type&>(a).value = value;
|
||||
}
|
||||
|
||||
// A test type that will trigger the small object optimization within 'any'.
|
||||
|
@ -89,25 +104,31 @@ struct small_type
|
|||
|
||||
int value;
|
||||
|
||||
explicit small_type(int val) : value(val) {
|
||||
explicit small_type(int val = 0) : value(val) {
|
||||
++count;
|
||||
}
|
||||
explicit small_type(int, int val, int) : value(val) {
|
||||
++count;
|
||||
}
|
||||
small_type(std::initializer_list<int> il) : value(*il.begin()) {
|
||||
++count;
|
||||
}
|
||||
|
||||
small_type(small_type const & other) throw() {
|
||||
small_type(small_type const & other) noexcept {
|
||||
value = other.value;
|
||||
++count;
|
||||
++copied;
|
||||
++const_copied;
|
||||
}
|
||||
|
||||
small_type(small_type& other) throw() {
|
||||
small_type(small_type& other) noexcept {
|
||||
value = other.value;
|
||||
++count;
|
||||
++copied;
|
||||
++non_const_copied;
|
||||
}
|
||||
|
||||
small_type(small_type && other) throw() {
|
||||
small_type(small_type && other) noexcept {
|
||||
value = other.value;
|
||||
other.value = 0;
|
||||
++count;
|
||||
|
@ -163,11 +184,17 @@ struct large_type
|
|||
|
||||
int value;
|
||||
|
||||
large_type(int val) : value(val) {
|
||||
large_type(int val = 0) : value(val) {
|
||||
++count;
|
||||
data[0] = 0;
|
||||
}
|
||||
|
||||
large_type(int, int val, int) : value(val) {
|
||||
++count;
|
||||
data[0] = 0;
|
||||
}
|
||||
large_type(std::initializer_list<int> il) : value(*il.begin()) {
|
||||
++count;
|
||||
}
|
||||
large_type(large_type const & other) {
|
||||
value = other.value;
|
||||
++count;
|
||||
|
@ -219,6 +246,67 @@ typedef large_type<> large;
|
|||
typedef large_type<1> large1;
|
||||
typedef large_type<2> large2;
|
||||
|
||||
|
||||
struct deleted_move
|
||||
{
|
||||
static int count;
|
||||
static int copied;
|
||||
static int moved;
|
||||
static int const_copied;
|
||||
static int non_const_copied;
|
||||
|
||||
static void reset() {
|
||||
deleted_move::copied = 0;
|
||||
deleted_move::moved = 0;
|
||||
deleted_move::const_copied = 0;
|
||||
deleted_move::non_const_copied = 0;
|
||||
}
|
||||
|
||||
int value;
|
||||
|
||||
explicit deleted_move(int val = 0) : value(val) {
|
||||
++count;
|
||||
}
|
||||
explicit deleted_move(int, int val, int) : value(val) {
|
||||
++count;
|
||||
}
|
||||
deleted_move(std::initializer_list<int> il) : value(*il.begin()) {
|
||||
++count;
|
||||
}
|
||||
|
||||
deleted_move(deleted_move const & other) noexcept {
|
||||
value = other.value;
|
||||
++count;
|
||||
++copied;
|
||||
++const_copied;
|
||||
}
|
||||
|
||||
deleted_move(deleted_move& other) noexcept {
|
||||
value = other.value;
|
||||
++count;
|
||||
++copied;
|
||||
++non_const_copied;
|
||||
}
|
||||
|
||||
deleted_move(deleted_move && other) = delete;
|
||||
|
||||
~deleted_move() {
|
||||
value = -1;
|
||||
--count;
|
||||
}
|
||||
|
||||
private:
|
||||
deleted_move& operator=(deleted_move const&) = delete;
|
||||
deleted_move& operator=(deleted_move&&) = delete;
|
||||
};
|
||||
|
||||
int deleted_move::count = 0;
|
||||
int deleted_move::copied = 0;
|
||||
int deleted_move::moved = 0;
|
||||
int deleted_move::const_copied = 0;
|
||||
int deleted_move::non_const_copied = 0;
|
||||
|
||||
|
||||
// The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy'
|
||||
// and 'throws_on_move'.
|
||||
struct my_any_exception {};
|
||||
|
@ -236,19 +324,24 @@ void throwMyAnyExpression() {
|
|||
struct small_throws_on_copy
|
||||
{
|
||||
static int count;
|
||||
static int copied;
|
||||
static int moved;
|
||||
static void reset() { count = copied = moved = 0; }
|
||||
int value;
|
||||
|
||||
explicit small_throws_on_copy(int val = 0) : value(val) {
|
||||
++count;
|
||||
}
|
||||
|
||||
explicit small_throws_on_copy(int, int val, int) : value(val) {
|
||||
++count;
|
||||
}
|
||||
small_throws_on_copy(small_throws_on_copy const &) {
|
||||
throwMyAnyExpression();
|
||||
}
|
||||
|
||||
small_throws_on_copy(small_throws_on_copy && other) throw() {
|
||||
value = other.value;
|
||||
++count;
|
||||
++count; ++moved;
|
||||
}
|
||||
|
||||
~small_throws_on_copy() {
|
||||
|
@ -260,26 +353,35 @@ private:
|
|||
};
|
||||
|
||||
int small_throws_on_copy::count = 0;
|
||||
int small_throws_on_copy::copied = 0;
|
||||
int small_throws_on_copy::moved = 0;
|
||||
|
||||
|
||||
// A test type that will NOT trigger the small object optimization within 'any'.
|
||||
// this type throws if it is copied.
|
||||
struct large_throws_on_copy
|
||||
{
|
||||
static int count;
|
||||
static int copied;
|
||||
static int moved;
|
||||
static void reset() { count = copied = moved = 0; }
|
||||
int value = 0;
|
||||
|
||||
explicit large_throws_on_copy(int val = 0) : value(val) {
|
||||
data[0] = 0;
|
||||
++count;
|
||||
}
|
||||
|
||||
explicit large_throws_on_copy(int, int val, int) : value(val) {
|
||||
data[0] = 0;
|
||||
++count;
|
||||
}
|
||||
large_throws_on_copy(large_throws_on_copy const &) {
|
||||
throwMyAnyExpression();
|
||||
}
|
||||
|
||||
large_throws_on_copy(large_throws_on_copy && other) throw() {
|
||||
value = other.value;
|
||||
++count;
|
||||
++count; ++moved;
|
||||
}
|
||||
|
||||
~large_throws_on_copy() {
|
||||
|
@ -293,19 +395,24 @@ private:
|
|||
};
|
||||
|
||||
int large_throws_on_copy::count = 0;
|
||||
int large_throws_on_copy::copied = 0;
|
||||
int large_throws_on_copy::moved = 0;
|
||||
|
||||
// A test type that throws when it is moved. This object will NOT trigger
|
||||
// the small object optimization in 'any'.
|
||||
struct throws_on_move
|
||||
{
|
||||
static int count;
|
||||
static int copied;
|
||||
static int moved;
|
||||
static void reset() { count = copied = moved = 0; }
|
||||
int value;
|
||||
|
||||
explicit throws_on_move(int val = 0) : value(val) { ++count; }
|
||||
|
||||
explicit throws_on_move(int, int val, int) : value(val) { ++count; }
|
||||
throws_on_move(throws_on_move const & other) {
|
||||
value = other.value;
|
||||
++count;
|
||||
++count; ++copied;
|
||||
}
|
||||
|
||||
throws_on_move(throws_on_move &&) {
|
||||
|
@ -321,6 +428,56 @@ private:
|
|||
};
|
||||
|
||||
int throws_on_move::count = 0;
|
||||
int throws_on_move::copied = 0;
|
||||
int throws_on_move::moved = 0;
|
||||
|
||||
struct small_tracked_t {
|
||||
small_tracked_t()
|
||||
: arg_types(&makeArgumentID<>()) {}
|
||||
small_tracked_t(small_tracked_t const&) noexcept
|
||||
: arg_types(&makeArgumentID<small_tracked_t const&>()) {}
|
||||
small_tracked_t(small_tracked_t &&) noexcept
|
||||
: arg_types(&makeArgumentID<small_tracked_t &&>()) {}
|
||||
template <class ...Args>
|
||||
explicit small_tracked_t(Args&&...)
|
||||
: arg_types(&makeArgumentID<Args...>()) {}
|
||||
template <class ...Args>
|
||||
explicit small_tracked_t(std::initializer_list<int>, Args&&...)
|
||||
: arg_types(&makeArgumentID<std::initializer_list<int>, Args...>()) {}
|
||||
|
||||
TypeID const* arg_types;
|
||||
};
|
||||
static_assert(IsSmallObject<small_tracked_t>::value, "must be small");
|
||||
|
||||
struct large_tracked_t {
|
||||
large_tracked_t()
|
||||
: arg_types(&makeArgumentID<>()) { dummy[0] = 42; }
|
||||
large_tracked_t(large_tracked_t const&) noexcept
|
||||
: arg_types(&makeArgumentID<large_tracked_t const&>()) {}
|
||||
large_tracked_t(large_tracked_t &&) noexcept
|
||||
: arg_types(&makeArgumentID<large_tracked_t &&>()) {}
|
||||
template <class ...Args>
|
||||
explicit large_tracked_t(Args&&...)
|
||||
: arg_types(&makeArgumentID<Args...>()) {}
|
||||
template <class ...Args>
|
||||
explicit large_tracked_t(std::initializer_list<int>, Args&&...)
|
||||
: arg_types(&makeArgumentID<std::initializer_list<int>, Args...>()) {}
|
||||
|
||||
TypeID const* arg_types;
|
||||
int dummy[10];
|
||||
};
|
||||
|
||||
static_assert(!IsSmallObject<large_tracked_t>::value, "must be small");
|
||||
|
||||
|
||||
template <class Type, class ...Args>
|
||||
void assertArgsMatch(std::any const& a) {
|
||||
using namespace std;
|
||||
using namespace std::experimental;
|
||||
assert(a.has_value());
|
||||
assert(containsType<Type>(a));
|
||||
assert(any_cast<Type const &>(a).arg_types == &makeArgumentID<Args...>());
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,326 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef EXPERIMENTAL_ANY_HELPERS_H
|
||||
#define EXPERIMENTAL_ANY_HELPERS_H
|
||||
|
||||
#include <experimental/any>
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
#if !defined(TEST_HAS_NO_RTTI)
|
||||
#define RTTI_ASSERT(X) assert(X)
|
||||
#else
|
||||
#define RTTI_ASSERT(X)
|
||||
#endif
|
||||
|
||||
template <class _Tp>
|
||||
struct IsSmallObject
|
||||
: public std::integral_constant<bool
|
||||
, sizeof(_Tp) <= (sizeof(void*)*3)
|
||||
&& std::alignment_of<void*>::value
|
||||
% std::alignment_of<_Tp>::value == 0
|
||||
&& std::is_nothrow_move_constructible<_Tp>::value
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
// Return 'true' if 'Type' will be considered a small type by 'any'
|
||||
template <class Type>
|
||||
bool isSmallType() {
|
||||
#if defined(_LIBCPP_VERSION)
|
||||
return std::experimental::__any_imp::_IsSmallObject<Type>::value;
|
||||
#else
|
||||
return IsSmallObject<Type>::value;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// Assert that an object is empty. If the object used to contain an object
|
||||
// of type 'LastType' check that it can no longer be accessed.
|
||||
template <class LastType = int>
|
||||
void assertEmpty(std::experimental::any const& a) {
|
||||
assert(a.empty());
|
||||
RTTI_ASSERT(a.type() == typeid(void));
|
||||
assert(std::experimental::any_cast<LastType const>(&a) == nullptr);
|
||||
}
|
||||
|
||||
// Assert that an 'any' object stores the specified 'Type' and 'value'.
|
||||
template <class Type>
|
||||
void assertContains(std::experimental::any const& a, int value = 1) {
|
||||
assert(!a.empty());
|
||||
RTTI_ASSERT(a.type() == typeid(Type));
|
||||
assert(std::experimental::any_cast<Type const &>(a).value == value);
|
||||
}
|
||||
|
||||
// Modify the value of a "test type" stored within an any to the specified
|
||||
// 'value'.
|
||||
template <class Type>
|
||||
void modifyValue(std::experimental::any& a, int value) {
|
||||
assert(!a.empty());
|
||||
RTTI_ASSERT(a.type() == typeid(Type));
|
||||
std::experimental::any_cast<Type&>(a).value = value;
|
||||
}
|
||||
|
||||
// A test type that will trigger the small object optimization within 'any'.
|
||||
template <int Dummy = 0>
|
||||
struct small_type
|
||||
{
|
||||
static int count;
|
||||
static int copied;
|
||||
static int moved;
|
||||
static int const_copied;
|
||||
static int non_const_copied;
|
||||
|
||||
static void reset() {
|
||||
small_type::copied = 0;
|
||||
small_type::moved = 0;
|
||||
small_type::const_copied = 0;
|
||||
small_type::non_const_copied = 0;
|
||||
}
|
||||
|
||||
int value;
|
||||
|
||||
explicit small_type(int val) : value(val) {
|
||||
++count;
|
||||
}
|
||||
|
||||
small_type(small_type const & other) throw() {
|
||||
value = other.value;
|
||||
++count;
|
||||
++copied;
|
||||
++const_copied;
|
||||
}
|
||||
|
||||
small_type(small_type& other) throw() {
|
||||
value = other.value;
|
||||
++count;
|
||||
++copied;
|
||||
++non_const_copied;
|
||||
}
|
||||
|
||||
small_type(small_type && other) throw() {
|
||||
value = other.value;
|
||||
other.value = 0;
|
||||
++count;
|
||||
++moved;
|
||||
}
|
||||
|
||||
~small_type() {
|
||||
value = -1;
|
||||
--count;
|
||||
}
|
||||
|
||||
private:
|
||||
small_type& operator=(small_type const&) = delete;
|
||||
small_type& operator=(small_type&&) = delete;
|
||||
};
|
||||
|
||||
template <int Dummy>
|
||||
int small_type<Dummy>::count = 0;
|
||||
|
||||
template <int Dummy>
|
||||
int small_type<Dummy>::copied = 0;
|
||||
|
||||
template <int Dummy>
|
||||
int small_type<Dummy>::moved = 0;
|
||||
|
||||
template <int Dummy>
|
||||
int small_type<Dummy>::const_copied = 0;
|
||||
|
||||
template <int Dummy>
|
||||
int small_type<Dummy>::non_const_copied = 0;
|
||||
|
||||
typedef small_type<> small;
|
||||
typedef small_type<1> small1;
|
||||
typedef small_type<2> small2;
|
||||
|
||||
|
||||
// A test type that will NOT trigger the small object optimization in any.
|
||||
template <int Dummy = 0>
|
||||
struct large_type
|
||||
{
|
||||
static int count;
|
||||
static int copied;
|
||||
static int moved;
|
||||
static int const_copied;
|
||||
static int non_const_copied;
|
||||
|
||||
static void reset() {
|
||||
large_type::copied = 0;
|
||||
large_type::moved = 0;
|
||||
large_type::const_copied = 0;
|
||||
large_type::non_const_copied = 0;
|
||||
}
|
||||
|
||||
int value;
|
||||
|
||||
large_type(int val) : value(val) {
|
||||
++count;
|
||||
data[0] = 0;
|
||||
}
|
||||
|
||||
large_type(large_type const & other) {
|
||||
value = other.value;
|
||||
++count;
|
||||
++copied;
|
||||
++const_copied;
|
||||
}
|
||||
|
||||
large_type(large_type & other) {
|
||||
value = other.value;
|
||||
++count;
|
||||
++copied;
|
||||
++non_const_copied;
|
||||
}
|
||||
|
||||
large_type(large_type && other) {
|
||||
value = other.value;
|
||||
other.value = 0;
|
||||
++count;
|
||||
++moved;
|
||||
}
|
||||
|
||||
~large_type() {
|
||||
value = 0;
|
||||
--count;
|
||||
}
|
||||
|
||||
private:
|
||||
large_type& operator=(large_type const&) = delete;
|
||||
large_type& operator=(large_type &&) = delete;
|
||||
int data[10];
|
||||
};
|
||||
|
||||
template <int Dummy>
|
||||
int large_type<Dummy>::count = 0;
|
||||
|
||||
template <int Dummy>
|
||||
int large_type<Dummy>::copied = 0;
|
||||
|
||||
template <int Dummy>
|
||||
int large_type<Dummy>::moved = 0;
|
||||
|
||||
template <int Dummy>
|
||||
int large_type<Dummy>::const_copied = 0;
|
||||
|
||||
template <int Dummy>
|
||||
int large_type<Dummy>::non_const_copied = 0;
|
||||
|
||||
typedef large_type<> large;
|
||||
typedef large_type<1> large1;
|
||||
typedef large_type<2> large2;
|
||||
|
||||
// The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy'
|
||||
// and 'throws_on_move'.
|
||||
struct my_any_exception {};
|
||||
|
||||
void throwMyAnyExpression() {
|
||||
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
||||
throw my_any_exception();
|
||||
#else
|
||||
assert(false && "Exceptions are disabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
// A test type that will trigger the small object optimization within 'any'.
|
||||
// this type throws if it is copied.
|
||||
struct small_throws_on_copy
|
||||
{
|
||||
static int count;
|
||||
int value;
|
||||
|
||||
explicit small_throws_on_copy(int val = 0) : value(val) {
|
||||
++count;
|
||||
}
|
||||
|
||||
small_throws_on_copy(small_throws_on_copy const &) {
|
||||
throwMyAnyExpression();
|
||||
}
|
||||
|
||||
small_throws_on_copy(small_throws_on_copy && other) throw() {
|
||||
value = other.value;
|
||||
++count;
|
||||
}
|
||||
|
||||
~small_throws_on_copy() {
|
||||
--count;
|
||||
}
|
||||
private:
|
||||
small_throws_on_copy& operator=(small_throws_on_copy const&) = delete;
|
||||
small_throws_on_copy& operator=(small_throws_on_copy &&) = delete;
|
||||
};
|
||||
|
||||
int small_throws_on_copy::count = 0;
|
||||
|
||||
// A test type that will NOT trigger the small object optimization within 'any'.
|
||||
// this type throws if it is copied.
|
||||
struct large_throws_on_copy
|
||||
{
|
||||
static int count;
|
||||
int value = 0;
|
||||
|
||||
explicit large_throws_on_copy(int val = 0) : value(val) {
|
||||
data[0] = 0;
|
||||
++count;
|
||||
}
|
||||
|
||||
large_throws_on_copy(large_throws_on_copy const &) {
|
||||
throwMyAnyExpression();
|
||||
}
|
||||
|
||||
large_throws_on_copy(large_throws_on_copy && other) throw() {
|
||||
value = other.value;
|
||||
++count;
|
||||
}
|
||||
|
||||
~large_throws_on_copy() {
|
||||
--count;
|
||||
}
|
||||
|
||||
private:
|
||||
large_throws_on_copy& operator=(large_throws_on_copy const&) = delete;
|
||||
large_throws_on_copy& operator=(large_throws_on_copy &&) = delete;
|
||||
int data[10];
|
||||
};
|
||||
|
||||
int large_throws_on_copy::count = 0;
|
||||
|
||||
// A test type that throws when it is moved. This object will NOT trigger
|
||||
// the small object optimization in 'any'.
|
||||
struct throws_on_move
|
||||
{
|
||||
static int count;
|
||||
int value;
|
||||
|
||||
explicit throws_on_move(int val = 0) : value(val) { ++count; }
|
||||
|
||||
throws_on_move(throws_on_move const & other) {
|
||||
value = other.value;
|
||||
++count;
|
||||
}
|
||||
|
||||
throws_on_move(throws_on_move &&) {
|
||||
throwMyAnyExpression();
|
||||
}
|
||||
|
||||
~throws_on_move() {
|
||||
--count;
|
||||
}
|
||||
private:
|
||||
throws_on_move& operator=(throws_on_move const&) = delete;
|
||||
throws_on_move& operator=(throws_on_move &&) = delete;
|
||||
};
|
||||
|
||||
int throws_on_move::count = 0;
|
||||
|
||||
|
||||
#endif
|
|
@ -33,6 +33,13 @@
|
|||
#else
|
||||
#define TEST_HAS_BUILTIN(X) 0
|
||||
#endif
|
||||
#ifdef __is_identifier
|
||||
// '__is_identifier' returns '0' if '__x' is a reserved identifier provided by
|
||||
// the compiler and '1' otherwise.
|
||||
#define TEST_HAS_BUILTIN_IDENTIFIER(X) !__is_identifier(X)
|
||||
#else
|
||||
#define TEST_HAS_BUILTIN_IDENTIFIER(X) 0
|
||||
#endif
|
||||
|
||||
#if defined(__apple_build_version__)
|
||||
#define TEST_APPLE_CLANG_VER (__clang_major__ * 100) + __clang_minor__
|
||||
|
|
|
@ -271,7 +271,7 @@
|
|||
<tr><td><a href="http://wg21.link/LWG2436">2436</a></td><td>Comparators for associative containers should always be CopyConstructible</td><td>Oulu</td><td>Complete</td></tr>
|
||||
<tr><td><a href="http://wg21.link/LWG2441">2441</a></td><td>Exact-width atomic typedefs should be provided</td><td>Oulu</td><td>Complete</td></tr>
|
||||
<tr><td><a href="http://wg21.link/LWG2451">2451</a></td><td>[fund.ts.v2] optional should 'forward' T's implicit conversions</td><td>Oulu</td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/LWG2509">2509</a></td><td>[fund.ts.v2] any_cast doesn't work with rvalue reference targets and cannot move with a value target</td><td>Oulu</td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/LWG2509">2509</a></td><td>[fund.ts.v2] any_cast doesn't work with rvalue reference targets and cannot move with a value target</td><td>Oulu</td><td>Complete</td></tr>
|
||||
<tr><td><a href="http://wg21.link/LWG2516">2516</a></td><td>[fund.ts.v2] Public "exposition only" members in observer_ptr</td><td>Oulu</td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/LWG2542">2542</a></td><td>Missing const requirements for associative containers</td><td>Oulu</td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/LWG2549">2549</a></td><td>Tuple EXPLICIT constructor templates that take tuple parameters end up taking references to temporaries and will create dangling references</td><td>Oulu</td><td>Complete</td></tr>
|
||||
|
|
Loading…
Reference in New Issue