diff --git a/libcxx/include/experimental/any b/libcxx/include/experimental/any new file mode 100644 index 000000000000..d99b787e5090 --- /dev/null +++ b/libcxx/include/experimental/any @@ -0,0 +1,591 @@ +// -*- 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_EXPERIMENTAL_ANY +#define _LIBCPP_EXPERIMENTAL_ANY + +/* + experimental/any synopsis + +namespace std { +namespace experimental { +inline namespace fundamentals_v1 { + + 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 + any(ValueType&& value); + + ~any(); + + // 6.3.2 any assignments + any& operator=(const any& rhs); + any& operator=(any&& rhs) noexcept; + + template + any& operator=(ValueType&& rhs); + + // 6.3.3 any modifiers + void clear() noexcept; + void swap(any& rhs) noexcept; + + // 6.3.4 any observers + bool empty() const noexcept; + const type_info& type() const noexcept; + }; + + // 6.4 Non-member functions + void swap(any& x, any& y) noexcept; + + template + ValueType any_cast(const any& operand); + template + ValueType any_cast(any& operand); + template + ValueType any_cast(any&& operand); + + template + const ValueType* any_cast(const any* operand) noexcept; + template + ValueType* any_cast(any* operand) noexcept; + +} // namespace fundamentals_v1 +} // namespace experimental +} // namespace std + +*/ + +#include +#include +#include +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_LFTS + +class _LIBCPP_EXCEPTION_ABI bad_any_cast : public bad_cast +{ +public: + bad_any_cast() _NOEXCEPT; + virtual ~bad_any_cast() _NOEXCEPT; + virtual const char* what() const _NOEXCEPT; +}; + +#if _LIBCPP_STD_VER > 11 // C++ > 11 + +_LIBCPP_NORETURN _LIBCPP_INLINE_VISIBILITY +inline void __throw_bad_any_cast() +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + throw bad_any_cast(); +#else + _VSTD::abort(); +#endif +} + +// Forward declarations +class any; + +template +typename add_pointer::type>::type +any_cast(any const *) _NOEXCEPT; + +template +typename add_pointer<_ValueType>::type +any_cast(any *) _NOEXCEPT; + +namespace __any_imp +{ + typedef typename aligned_storage<3*sizeof(void*), alignment_of::value>::type + _Buffer; + + template + struct _IsSmallObject + : public integral_constant::value + % alignment_of<_Tp>::value == 0 + && is_nothrow_move_constructible<_Tp>::value + > + {}; + + enum class _Action + { + _Destroy, + _Copy, + _Move, + _Get, + _TypeInfo + }; + + template + struct _SmallHandler; + + template + struct _LargeHandler; + + template + using _Handler = typename conditional<_IsSmallObject<_Tp>::value + , _SmallHandler<_Tp> + , _LargeHandler<_Tp> + >::type; + template + using _EnableIfNotAny = typename + enable_if< + !is_same::type, any>::value + >::type; + +} // namespace __any_imp + +class any +{ +public: + // 6.3.1 any construct/destruct + _LIBCPP_INLINE_VISIBILITY + 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 = __any_imp::_EnableIfNotAny<_ValueType> + > + any(_ValueType && __value); + + _LIBCPP_INLINE_VISIBILITY + ~any() + { + this->clear(); + } + + // 6.3.2 any 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; + } + + template < + class _ValueType + , class = __any_imp::_EnableIfNotAny<_ValueType> + > + any & operator=(_ValueType && __rhs); + + // 6.3.3 any modifiers + _LIBCPP_INLINE_VISIBILITY + void clear() _NOEXCEPT + { + if (__h) this->__call(_Action::_Destroy); + } + + void swap(any & __rhs) _NOEXCEPT; + + // 6.3.4 any observers + _LIBCPP_INLINE_VISIBILITY + bool empty() const _NOEXCEPT + { + return __h == nullptr; + } + +#if !defined(_LIBCPP_NO_RTTI) + _LIBCPP_INLINE_VISIBILITY + const type_info & type() const _NOEXCEPT + { + if (__h) { + return *static_cast(this->__call(_Action::_TypeInfo)); + } else { + return typeid(void); + } + } +#endif + +private: + typedef __any_imp::_Action _Action; + + typedef void* (*_HandleFuncPtr)(_Action, any const *, any *, const type_info *); + + union _Storage + { + void * __ptr; + __any_imp::_Buffer __buf; + }; + + _LIBCPP_ALWAYS_INLINE + void * __call(_Action __a, any * __other = nullptr, + type_info const * __info = nullptr) const + { + return __h(__a, this, __other, __info); + } + + _LIBCPP_ALWAYS_INLINE + void * __call(_Action __a, any * __other = nullptr, + type_info const * __info = nullptr) + { + return __h(__a, this, __other, __info); + } + + template + friend struct __any_imp::_SmallHandler; + template + friend struct __any_imp::_LargeHandler; + + template + friend typename add_pointer::type>::type + any_cast(any const *) _NOEXCEPT; + + template + friend typename add_pointer<_ValueType>::type + any_cast(any *) _NOEXCEPT; + + _HandleFuncPtr __h; + _Storage __s; +}; + +namespace __any_imp +{ + + template + struct _LIBCPP_TYPE_VIS_ONLY _SmallHandler + { + _LIBCPP_INLINE_VISIBILITY + static void* __handle(_Action __act, any const * __this, any * __other, + type_info const * __info) + { + switch (__act) + { + case _Action::_Destroy: + __destroy(const_cast(*__this)); + return nullptr; + case _Action::_Copy: + __copy(*__this, *__other); + return nullptr; + case _Action::_Move: + __move(const_cast(*__this), *__other); + return nullptr; + case _Action::_Get: + return __get(const_cast(*__this), __info); + case _Action::_TypeInfo: + return __type_info(); + } + } + + template + _LIBCPP_INLINE_VISIBILITY + static void __create(any & __dest, _Up && __v) + { + ::new (static_cast(&__dest.__s.__buf)) _Tp(_VSTD::forward<_Up>(__v)); + __dest.__h = &_SmallHandler::__handle; + } + + private: + _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY + static void __destroy(any & __this) + { + _Tp & __value = *static_cast<_Tp *>(static_cast(&__this.__s.__buf)); + __value.~_Tp(); + __this.__h = nullptr; + } + + _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY + static void __copy(any const & __this, any & __dest) + { + _SmallHandler::__create(__dest, *static_cast<_Tp const *>( + static_cast(&__this.__s.__buf))); + } + + _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY + static void __move(any & __this, any & __dest) + { + _SmallHandler::__create(__dest, _VSTD::move( + *static_cast<_Tp*>(static_cast(&__this.__s.__buf)))); + __destroy(__this); + } + + _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY + static void* __get(any & __this, type_info const * __info) + { +#if !defined(_LIBCPP_NO_RTTI) + if (typeid(_Tp) == *__info) { + return static_cast(&__this.__s.__buf); + } + return nullptr; +#else + return static_cast(&__this.__s.__buf); +#endif + } + + _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY + static void* __type_info() + { +#if !defined(_LIBCPP_NO_RTTI) + return const_cast(static_cast(&typeid(_Tp))); +#else + return nullptr; +#endif + } + }; + + template + struct _LIBCPP_TYPE_VIS_ONLY _LargeHandler + { + _LIBCPP_INLINE_VISIBILITY + static void* __handle(_Action __act, any const * __this, any * __other, + type_info const * __info) + { + switch (__act) + { + case _Action::_Destroy: + __destroy(const_cast(*__this)); + return nullptr; + case _Action::_Copy: + __copy(*__this, *__other); + return nullptr; + case _Action::_Move: + __move(const_cast(*__this), *__other); + return nullptr; + case _Action::_Get: + return __get(const_cast(*__this), __info); + case _Action::_TypeInfo: + return __type_info(); + } + } + + template + _LIBCPP_INLINE_VISIBILITY + static void __create(any & __dest, _Up && __v) + { + 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<_Up>(__v)); + __dest.__s.__ptr = __hold.release(); + __dest.__h = &_LargeHandler::__handle; + } + + private: + + _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY + static void __destroy(any & __this) + { + delete static_cast<_Tp*>(__this.__s.__ptr); + __this.__h = nullptr; + } + + _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY + static void __copy(any const & __this, any & __dest) + { + _LargeHandler::__create(__dest, *static_cast<_Tp const *>(__this.__s.__ptr)); + } + + _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY + static void __move(any & __this, any & __dest) + { + __dest.__s.__ptr = __this.__s.__ptr; + __dest.__h = &_LargeHandler::__handle; + __this.__h = nullptr; + } + + _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY + static void* __get(any & __this, type_info const * __info) + { +#if !defined(_LIBCPP_NO_RTTI) + if (typeid(_Tp) == *__info) { + return static_cast(__this.__s.__ptr); + } + return nullptr; +#else + return static_cast(__this.__s.__ptr); +#endif + } + + _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY + static void* __type_info() + { +#if !defined(_LIBCPP_NO_RTTI) + return const_cast(static_cast(&typeid(_Tp))); +#else + return nullptr; +#endif + } + }; + +} // namespace __any_imp + + +template +_LIBCPP_INLINE_VISIBILITY +any::any(_ValueType && __v) : __h(nullptr) +{ + typedef typename decay<_ValueType>::type _Tp; + static_assert(is_copy_constructible<_Tp>::value, + "_ValueType must be CopyConstructible."); + typedef __any_imp::_Handler<_Tp> _HandlerType; + _HandlerType::__create(*this, _VSTD::forward<_ValueType>(__v)); +} + +template +_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; +} + +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 +_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."); + typedef typename add_const::type>::type + _Tp; + _Tp * __tmp = any_cast<_Tp>(&__v); + if (__tmp == nullptr) + __throw_bad_any_cast(); + return *__tmp; +} + +template +_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 = any_cast<_Tp>(&__v); + if (__tmp == nullptr) + __throw_bad_any_cast(); + return *__tmp; +} + +template +_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 = any_cast<_Tp>(&__v); + if (__tmp == nullptr) + __throw_bad_any_cast(); + return *__tmp; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +typename add_pointer::type>::type +any_cast(any const * __any) _NOEXCEPT +{ + static_assert(!is_reference<_ValueType>::value, + "_ValueType may not be a reference."); + return any_cast<_ValueType>(const_cast(__any)); +} + +template +_LIBCPP_INLINE_VISIBILITY +typename add_pointer<_ValueType>::type +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 + )); + + } + return nullptr; +} + +#endif // _LIBCPP_STD_VER > 11 + +_LIBCPP_END_NAMESPACE_LFTS + +#endif // _LIBCPP_EXPERIMENTAL_ANY diff --git a/libcxx/src/any.cpp b/libcxx/src/any.cpp new file mode 100644 index 000000000000..49683db96857 --- /dev/null +++ b/libcxx/src/any.cpp @@ -0,0 +1,22 @@ +//===---------------------------- any.cpp ---------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "experimental/any" + +_LIBCPP_BEGIN_NAMESPACE_LFTS + +bad_any_cast::bad_any_cast() _NOEXCEPT {} + +bad_any_cast::~bad_any_cast() _NOEXCEPT {} + +const char* bad_any_cast::what() const _NOEXCEPT { + return "bad any cast"; +} + +_LIBCPP_END_NAMESPACE_LFTS diff --git a/libcxx/test/libcxx/experimental/any/size_and_alignment.pass.cpp b/libcxx/test/libcxx/experimental/any/size_and_alignment.pass.cpp new file mode 100644 index 000000000000..b7db54020478 --- /dev/null +++ b/libcxx/test/libcxx/experimental/any/size_and_alignment.pass.cpp @@ -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 + +// + +// Check that the size and alignment of any are what we expect. + +#include + +int main() +{ + using std::experimental::any; + static_assert(sizeof(any) == sizeof(void*)*4, ""); + static_assert(alignof(any) == alignof(void*), ""); +} diff --git a/libcxx/test/libcxx/experimental/any/small_type.pass.cpp b/libcxx/test/libcxx/experimental/any/small_type.pass.cpp new file mode 100644 index 000000000000..bcd15f181fd6 --- /dev/null +++ b/libcxx/test/libcxx/experimental/any/small_type.pass.cpp @@ -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 + +// + +// Check that the size and alignment of any are what we expect. + +#include +#include "any_helpers.h" + +class SmallThrowsDtor +{ +public: + SmallThrowsDtor() {} + SmallThrowsDtor(SmallThrowsDtor const &) noexcept {} + SmallThrowsDtor(SmallThrowsDtor &&) noexcept {} + ~SmallThrowsDtor() noexcept(false) {} +}; + +int main() +{ + using std::experimental::any; + using std::experimental::__any_imp::_IsSmallObject; + static_assert(_IsSmallObject::value, ""); + static_assert(_IsSmallObject::value, ""); + static_assert(!_IsSmallObject::value, ""); + static_assert(!_IsSmallObject::value, ""); + // long double is over aligned. + static_assert(sizeof(long double) <= sizeof(void*) * 3, ""); + static_assert(alignof(long double) > alignof(void*), ""); + static_assert(!_IsSmallObject::value, ""); +} diff --git a/libcxx/test/libcxx/experimental/any/version.pass.cpp b/libcxx/test/libcxx/experimental/any/version.pass.cpp new file mode 100644 index 000000000000..611d65027b19 --- /dev/null +++ b/libcxx/test/libcxx/experimental/any/version.pass.cpp @@ -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. +// +//===----------------------------------------------------------------------===// + +// + +#include + +#ifndef _LIBCPP_VERSION +#error _LIBCPP_VERSION not defined +#endif + +int main() +{ +} diff --git a/libcxx/test/std/experimental/any/any.class/any.assign/copy.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.assign/copy.pass.cpp new file mode 100644 index 000000000000..8ee575c408f9 --- /dev/null +++ b/libcxx/test/std/experimental/any/any.class/any.assign/copy.pass.cpp @@ -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 + +// + +// any& operator=(any const &); + +// Test copy assignment + +#include +#include + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::experimental::any; +using std::experimental::any_cast; + +template +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(lhs, 2); + assertContains(rhs, 2); + } + assert(LHS::count == 0); + assert(RHS::count == 0); +} + +template +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, 42); + assertContains(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); + 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(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(a, 1); + assert(globalMemCounter.checkOutstandingNewEq(1)); + } + assert(large::count == 0); + assert(globalMemCounter.checkOutstandingNewEq(0)); +} + +template +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(lhs); + assertContains(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(lhs, 2); + assertContains(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(lhs, 2); + assertContains(rhs); + } +#endif +} + +int main() { + test_copy_assign(); + test_copy_assign(); + test_copy_assign(); + test_copy_assign(); + test_copy_assign_empty(); + test_copy_assign_empty(); + test_copy_assign_self(); + test_copy_assign_throws(); + test_copy_assign_throws(); +} diff --git a/libcxx/test/std/experimental/any/any.class/any.assign/move.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.assign/move.pass.cpp new file mode 100644 index 000000000000..0a2d71967cd4 --- /dev/null +++ b/libcxx/test/std/experimental/any/any.class/any.assign/move.pass.cpp @@ -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 + +// + +// any& operator=(any &&); + +// Test move assignment. + +#include +#include + +#include "any_helpers.h" +#include "test_macros.h" + +using std::experimental::any; +using std::experimental::any_cast; + +template +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(a, 2); + assertEmpty(a2); + } + assert(LHS::count == 0); + assert(RHS::count == 0); +} + +template +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(a, 1); + assertEmpty(a2); + } + assert(LHS::count == 0); + { + any a((LHS(1))); + any a2; + + assert(LHS::count == 1); + + a = std::move(a2); + + assert(LHS::count == 0); + + assertEmpty(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(); + test_move_assign(); + test_move_assign(); + test_move_assign(); + test_move_assign_empty(); + test_move_assign_empty(); +} diff --git a/libcxx/test/std/experimental/any/any.class/any.assign/value.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.assign/value.pass.cpp new file mode 100644 index 000000000000..8262990523c3 --- /dev/null +++ b/libcxx/test/std/experimental/any/any.class/any.assign/value.pass.cpp @@ -0,0 +1,177 @@ +//===----------------------------------------------------------------------===// +// +// 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& operator=(any const &); + +// Test value copy and move assignment. + +#include +#include + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::experimental::any; +using std::experimental::any_cast; + +template +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(lhs, 2); + assertContains(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(lhs, 2); + assertEmpty(rhs); + } + assert(LHS::count == 0); + assert(RHS::count == 0); +} + +template +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(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(lhs, 42); + } + assert(RHS::count == 0); + RHS::reset(); +} + + +template +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(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(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(lhs, 2); + } +#endif +} + +int main() { + test_assign_value(); + test_assign_value(); + test_assign_value(); + test_assign_value(); + test_assign_value_empty(); + test_assign_value_empty(); + test_assign_throws(); + test_assign_throws(); + test_assign_throws(); +} \ No newline at end of file diff --git a/libcxx/test/std/experimental/any/any.class/any.assign/value_non_copyable_assign.fail.cpp b/libcxx/test/std/experimental/any/any.class/any.assign/value_non_copyable_assign.fail.cpp new file mode 100644 index 000000000000..ce0d44f32d98 --- /dev/null +++ b/libcxx/test/std/experimental/any/any.class/any.assign/value_non_copyable_assign.fail.cpp @@ -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 + +// + +// template +// any& operator=(Value &&); + +// Instantiate the value assignment operator with a non-copyable type. + +#include + +class non_copyable +{ + non_copyable(non_copyable const &); + +public: + non_copyable() {} + non_copyable(non_copyable &&) {} +}; + +int main() +{ + using namespace std::experimental; + non_copyable nc; + any a; + a = static_cast(nc); // expected-error@experimental/any:* 2 {{static_assert failed "_ValueType must be CopyConstructible."}} + // expected-error@experimental/any:* {{calling a private constructor of class 'non_copyable'}} + +} diff --git a/libcxx/test/std/experimental/any/any.class/any.cons/copy.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.cons/copy.pass.cpp new file mode 100644 index 000000000000..3d0b34b27406 --- /dev/null +++ b/libcxx/test/std/experimental/any/any.class/any.cons/copy.pass.cpp @@ -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 + +// + +// any(any const &); + +#include +#include + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::experimental::any; +using std::experimental::any_cast; + +template +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(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 +void test_copy() +{ + // Copying small types should not perform any allocations. + DisableAllocationGuard g(isSmallType()); ((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(a, 42); + assertContains(a, 42); + + // Modify a and check that a2 is unchanged + modifyValue(a, -1); + assertContains(a, -1); + assertContains(a2, 42); + + // modify a2 and check that a is unchanged + modifyValue(a2, 999); + assertContains(a, -1); + assertContains(a2, 999); + + // clear a and check that a2 is unchanged + a.clear(); + assertEmpty(a); + assertContains(a2, 999); + } + assert(Type::count == 0); +} + +int main() { + test_copy(); + test_copy(); + test_copy_empty(); + test_copy_throws(); + test_copy_throws(); +} diff --git a/libcxx/test/std/experimental/any/any.class/any.cons/default.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.cons/default.pass.cpp new file mode 100644 index 000000000000..b52c83fc3881 --- /dev/null +++ b/libcxx/test/std/experimental/any/any.class/any.cons/default.pass.cpp @@ -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 + +// + +// any() noexcept; + +#include +#include +#include + +#include "any_helpers.h" +#include "count_new.hpp" + + +int main() +{ + using std::experimental::any; + { + static_assert( + std::is_nothrow_default_constructible::value + , "Must be default constructible" + ); + } + { + DisableAllocationGuard g; ((void)g); + any const a; + assertEmpty(a); + } +} diff --git a/libcxx/test/std/experimental/any/any.class/any.cons/move.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.cons/move.pass.cpp new file mode 100644 index 000000000000..40534cb55066 --- /dev/null +++ b/libcxx/test/std/experimental/any/any.class/any.cons/move.pass.cpp @@ -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 + +// + +// any(any &&) noexcept; + +#include +#include +#include +#include + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::experimental::any; +using std::experimental::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(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 +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(a2, 42); + } + assert(Type::count == 0); +} + +int main() +{ + // noexcept test + { + static_assert( + std::is_nothrow_move_constructible::value + , "any must be nothrow move constructible" + ); + } + test_move(); + test_move(); + test_move_empty(); + test_move_does_not_throw(); +} diff --git a/libcxx/test/std/experimental/any/any.class/any.cons/non_copyable_value.fail.cpp b/libcxx/test/std/experimental/any/any.class/any.cons/non_copyable_value.fail.cpp new file mode 100644 index 000000000000..643b9621ca2f --- /dev/null +++ b/libcxx/test/std/experimental/any/any.class/any.cons/non_copyable_value.fail.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// 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::any(Value &&) + +// Attempt to construct any with a non-copyable type. + +#include + +class non_copyable +{ + non_copyable(non_copyable const &); + +public: + non_copyable() {} + non_copyable(non_copyable &&) {} +}; + +int main() +{ + using namespace std::experimental; + non_copyable nc; + any a(static_cast(nc)); + // expected-error@experimental/any:* 1 {{static_assert failed "_ValueType must be CopyConstructible."}} + // expected-error@experimental/any:* 1 {{calling a private constructor of class 'non_copyable'}} +} diff --git a/libcxx/test/std/experimental/any/any.class/any.cons/value.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.cons/value.pass.cpp new file mode 100644 index 000000000000..7bb134efd28a --- /dev/null +++ b/libcxx/test/std/experimental/any/any.class/any.cons/value.pass.cpp @@ -0,0 +1,116 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template 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 +#include + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::experimental::any; +using std::experimental::any_cast; + +template +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 +void test_copy_move_value() { + // constructing from a small type should perform no allocations. + DisableAllocationGuard g(isSmallType()); ((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(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(a, 42); + } +} + + +int main() { + test_copy_move_value(); + test_copy_move_value(); + test_copy_value_throws(); + test_copy_value_throws(); + test_move_value_throws(); +} \ No newline at end of file diff --git a/libcxx/test/std/experimental/any/any.class/any.modifiers/clear.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.modifiers/clear.pass.cpp new file mode 100644 index 000000000000..603490cef43d --- /dev/null +++ b/libcxx/test/std/experimental/any/any.class/any.modifiers/clear.pass.cpp @@ -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 + +// + +// any::clear() noexcept + +#include +#include + +#include "any_helpers.h" + +int main() +{ + using std::experimental::any; + using std::experimental::any_cast; + // empty + { + any a; + + // noexcept check + static_assert( + noexcept(a.clear()) + , "any.clear() must be noexcept" + ); + + assertEmpty(a); + + a.clear(); + + assertEmpty(a); + } + // small object + { + any a((small(1))); + assert(small::count == 1); + assertContains(a, 1); + + a.clear(); + + assertEmpty(a); + assert(small::count == 0); + } + // large object + { + any a(large(1)); + assert(large::count == 1); + assertContains(a); + + a.clear(); + + assertEmpty(a); + assert(large::count == 0); + } +} diff --git a/libcxx/test/std/experimental/any/any.class/any.modifiers/swap.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.modifiers/swap.pass.cpp new file mode 100644 index 000000000000..064935167eb5 --- /dev/null +++ b/libcxx/test/std/experimental/any/any.class/any.modifiers/swap.pass.cpp @@ -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 + +// + +// any::swap(any &) noexcept + +// Test swap(large, small) and swap(small, large) + +#include +#include + +#include "any_helpers.h" + +using std::experimental::any; +using std::experimental::any_cast; + +template +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(a1, 2); + assertContains(a2, 1); + } + assert(LHS::count == 0); + assert(RHS::count == 0); + assert(LHS::copied == 0); + assert(RHS::copied == 0); +} + +template +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(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(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(); + test_swap_empty(); + test_swap(); + test_swap(); + test_swap(); + test_swap(); +} diff --git a/libcxx/test/std/experimental/any/any.class/any.observers/empty.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.observers/empty.pass.cpp new file mode 100644 index 000000000000..8c681f37017f --- /dev/null +++ b/libcxx/test/std/experimental/any/any.class/any.observers/empty.pass.cpp @@ -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 + +// + +// any::empty() noexcept + +#include +#include + +#include "any_helpers.h" + +int main() +{ + using std::experimental::any; + // noexcept test + { + any a; + static_assert(noexcept(a.empty()), "any::empty() must be noexcept"); + } + // empty + { + any a; + assert(a.empty()); + + a.clear(); + assert(a.empty()); + + a = 42; + assert(!a.empty()); + } + // small object + { + small const s(1); + any a(s); + assert(!a.empty()); + + a.clear(); + assert(a.empty()); + + a = s; + assert(!a.empty()); + } + // large object + { + large const l(1); + any a(l); + assert(!a.empty()); + + a.clear(); + assert(a.empty()); + + a = l; + assert(!a.empty()); + } +} diff --git a/libcxx/test/std/experimental/any/any.class/any.observers/type.pass.cpp b/libcxx/test/std/experimental/any/any.class/any.observers/type.pass.cpp new file mode 100644 index 000000000000..682b73bc98c4 --- /dev/null +++ b/libcxx/test/std/experimental/any/any.class/any.observers/type.pass.cpp @@ -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 + +// XFAIL: libcpp-no-rtti + +// + +// any::type() noexcept + +#include +#include +#include "any_helpers.h" + +int main() +{ + using std::experimental::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)); + } +} diff --git a/libcxx/test/std/experimental/any/any.class/nothing_to_do.pass.cpp b/libcxx/test/std/experimental/any/any.class/nothing_to_do.pass.cpp new file mode 100644 index 000000000000..c21f8a701685 --- /dev/null +++ b/libcxx/test/std/experimental/any/any.class/nothing_to_do.pass.cpp @@ -0,0 +1,12 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include + +int main () {} diff --git a/libcxx/test/std/experimental/any/any.nonmembers/any.cast/any_cast_pointer.pass.cpp b/libcxx/test/std/experimental/any/any.nonmembers/any.cast/any_cast_pointer.pass.cpp new file mode 100644 index 000000000000..9d9a5cdb4726 --- /dev/null +++ b/libcxx/test/std/experimental/any/any.nonmembers/any.cast/any_cast_pointer.pass.cpp @@ -0,0 +1,146 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// ValueType const* any_cast(any const *) noexcept; +// +// template +// ValueType * any_cast(any *) noexcept; + +#include +#include +#include + +#include "any_helpers.h" + +using std::experimental::any; +using std::experimental::any_cast; + +// Test that the operators are properly noexcept. +void test_cast_is_noexcept() { + any a; + static_assert(noexcept(any_cast(&a)), ""); + + any const& ca = a; + static_assert(noexcept(any_cast(&ca)), ""); +} + +// Test that the return type of any_cast is correct. +void test_cast_return_type() { + any a; + static_assert(std::is_same(&a)), int*>::value, ""); + static_assert(std::is_same(&a)), int const*>::value, ""); + + any const& ca = a; + static_assert(std::is_same(&ca)), int const*>::value, ""); + static_assert(std::is_same(&ca)), int const*>::value, ""); +} + +// Test that any_cast handles null pointers. +void test_cast_nullptr() { + any* a = nullptr; + assert(nullptr == any_cast(a)); + assert(nullptr == any_cast(a)); + + any const* ca = nullptr; + assert(nullptr == any_cast(ca)); + assert(nullptr == any_cast(ca)); +} + +// Test casting an empty object. +void test_cast_empty() { + { + any a; + assert(nullptr == any_cast(&a)); + assert(nullptr == any_cast(&a)); + + any const& ca = a; + assert(nullptr == any_cast(&ca)); + assert(nullptr == any_cast(&ca)); + } + // Create as non-empty, then make empty and run test. + { + any a(42); + a.clear(); + assert(nullptr == any_cast(&a)); + assert(nullptr == any_cast(&a)); + + any const& ca = a; + assert(nullptr == any_cast(&ca)); + assert(nullptr == any_cast(&ca)); + } +} + +template +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(&a) == nullptr); + assert(any_cast(&a) == nullptr); + assert(any_cast(&a) == nullptr); + + // Try a cast to the right type, but as a pointer. + assert(any_cast(&a) == nullptr); + assert(any_cast(&a) == nullptr); + + // Check getting a unqualified type from a non-const any. + Type* v = any_cast(&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(&a); + assert(cv != nullptr); + assert(cv == v); + assert(cv->value == 999); + + // Check getting a unqualified type from a const any. + cv = any_cast(&ca); + assert(cv != nullptr); + assert(cv == v); + assert(cv->value == 999); + + // Check getting a const-qualified type from a const any. + cv = any_cast(&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); +} + +int main() { + test_cast_is_noexcept(); + test_cast_return_type(); + test_cast_nullptr(); + test_cast_empty(); + test_cast(); + test_cast(); +} diff --git a/libcxx/test/std/experimental/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp b/libcxx/test/std/experimental/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp new file mode 100644 index 000000000000..e97560937fb0 --- /dev/null +++ b/libcxx/test/std/experimental/any/any.nonmembers/any.cast/any_cast_reference.pass.cpp @@ -0,0 +1,309 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// ValueType const any_cast(any const&); +// +// template +// ValueType any_cast(any &); +// +// template +// ValueType any_cast(any &&); + +#include +#include +#include + +#include "any_helpers.h" +#include "count_new.hpp" +#include "test_macros.h" + +using std::experimental::any; +using std::experimental::any_cast; +using std::experimental::bad_any_cast; + + +// Test that the operators are NOT marked noexcept. +void test_cast_is_not_noexcept() { + any a; + static_assert(!noexcept(any_cast(static_cast(a))), ""); + static_assert(!noexcept(any_cast(static_cast(a))), ""); + static_assert(!noexcept(any_cast(static_cast(a))), ""); +} + +// Test that the return type of any_cast is correct. +void test_cast_return_type() { + any a; + static_assert(std::is_same(a)), int>::value, ""); + static_assert(std::is_same(a)), int>::value, ""); + static_assert(std::is_same(a)), int&>::value, ""); + static_assert(std::is_same(a)), int const&>::value, ""); + + //static_assert(std::is_same(a)), int&&>::value, ""); + //static_assert(std::is_same(a)), int const&&>::value, ""); + + static_assert(std::is_same(std::move(a))), int>::value, ""); + static_assert(std::is_same(std::move(a))), int>::value, ""); + static_assert(std::is_same(std::move(a))), int&>::value, ""); + static_assert(std::is_same(std::move(a))), int const&>::value, ""); + + //static_assert(std::is_same(std::move(a))), int&&>::value, ""); + //static_assert(std::is_same(std::move(a))), int const&&>::value, ""); + + any const& ca = a; + static_assert(std::is_same(ca)), int>::value, ""); + static_assert(std::is_same(ca)), int>::value, ""); + static_assert(std::is_same(ca)), int const&>::value, ""); + + //static_assert(std::is_same(ca)), int const&&>::value, ""); +} + +template +void checkThrows(any& a) +{ +#if !defined(TEST_HAS_NO_EXCEPTIONS) + try { + any_cast(a); + assert(false); + } catch (bad_any_cast const &) { + // do nothing + } catch (...) { + assert(false); + } + + try { + any_cast(static_cast(a)); + assert(false); + } catch (bad_any_cast const &) { + // do nothing + } catch (...) { + assert(false); + } + + try { + any_cast(static_cast(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(a); +} + +template +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(a); + checkThrows(a); + checkThrows(a); + checkThrows(a); + + // Check getting a type by reference from a non-const lvalue any. + { + Type& v = any_cast(a); + assert(v.value == 42); + + Type const &cv = any_cast(a); + assert(&cv == &v); + } + // Check getting a type by reference from a const lvalue any. + { + Type const& v = any_cast(ca); + assert(v.value == 42); + + Type const &cv = any_cast(ca); + assert(&cv == &v); + } + // Check getting a type by reference from a non-const rvalue + { + Type& v = any_cast(std::move(a)); + assert(v.value == 42); + + Type const &cv = any_cast(std::move(a)); + assert(&cv == &v); + } + // Check getting a type by reference from a const rvalue any. + { + Type const& v = any_cast(std::move(ca)); + assert(v.value == 42); + + Type const &cv = any_cast(std::move(ca)); + assert(&cv == &v); + } + + // Check that the original object hasn't been changed. + assertContains(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 +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(a); + checkThrows(a); + checkThrows(a); + checkThrows(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(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(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(static_cast(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(static_cast(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 rvalue any. + // This should cause the const copy constructor to be called. + { + Type t = any_cast(static_cast(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 const rvalue any. + // This should cause the const copy constructor to be called. + { + Type t = any_cast(static_cast(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); + } + // Ensure we still only have 1 Type object alive. + assert(Type::count == 1); + + // Check that the original object hasn't been changed. + assertContains(a, 42); + } + assert(Type::count == 0); +} + +// 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(a); + checkThrows(a); + assertEmpty(a); +} + +int main() { + test_cast_is_not_noexcept(); + test_cast_return_type(); + test_cast_empty(); + test_cast_to_reference(); + test_cast_to_reference(); + test_cast_to_value(); + test_cast_to_value(); + test_non_copyable_ref(); +} diff --git a/libcxx/test/std/experimental/any/any.nonmembers/any.cast/const_correctness.fail.cpp b/libcxx/test/std/experimental/any/any.nonmembers/any.cast/const_correctness.fail.cpp new file mode 100644 index 000000000000..db5149265ccc --- /dev/null +++ b/libcxx/test/std/experimental/any/any.nonmembers/any.cast/const_correctness.fail.cpp @@ -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 + +// + +// template +// ValueType any_cast(any const &); + +// Try and cast away const. + +#include + +struct TestType {}; +struct TestType2 {}; + +int main() +{ + using std::experimental::any; + using std::experimental::any_cast; + + any a; + + // expected-error@experimental/any:* 2 {{binding value of type '_Tp' (aka 'const TestType') to reference to type 'TestType' drops 'const' qualifier}} + any_cast(static_cast(a)); // expected-note {{requested here}} + any_cast(static_cast(a)); // expected-note {{requested here}} + + // expected-error@experimental/any:* 2 {{binding value of type '_Tp' (aka 'const TestType2') to reference to type 'TestType2' drops 'const' qualifier}} + any_cast(static_cast(a)); // expected-note {{requested here}} + any_cast(static_cast(a)); // expected-note {{requested here}} +} diff --git a/libcxx/test/std/experimental/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp b/libcxx/test/std/experimental/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp new file mode 100644 index 000000000000..c6cc68d72706 --- /dev/null +++ b/libcxx/test/std/experimental/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp @@ -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 + +// + +// template +// ValueType const any_cast(any const&); +// +// template +// ValueType any_cast(any &); +// +// template +// ValueType any_cast(any &&); + +// Test instantiating the any_cast with a non-copyable type. + +#include + +using std::experimental::any; +using std::experimental::any_cast; + +struct no_copy +{ + no_copy() {} + no_copy(no_copy &&) {} +private: + no_copy(no_copy const &); +}; + +int main() { + any a; + any_cast(static_cast(a)); + any_cast(static_cast(a)); + any_cast(static_cast(a)); + // expected-error@experimental/any:* 3 {{static_assert failed "_ValueType is required to be a reference or a CopyConstructible type."}} + // expected-error@experimental/any:* 3 {{calling a private constructor of class 'no_copy'}} +} \ No newline at end of file diff --git a/libcxx/test/std/experimental/any/any.nonmembers/any.cast/reference_types.fail.cpp b/libcxx/test/std/experimental/any/any.nonmembers/any.cast/reference_types.fail.cpp new file mode 100644 index 000000000000..6c6ccc68787a --- /dev/null +++ b/libcxx/test/std/experimental/any/any.nonmembers/any.cast/reference_types.fail.cpp @@ -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 + +// + +// template +// ValueType const* any_cast(any const *) noexcept; +// +// template +// ValueType * any_cast(any *) noexcept; + +#include + +using std::experimental::any; +using std::experimental::any_cast; + +int main() +{ + any a(1); + any_cast(&a); // expected-error@experimental/any:* 1 {{static_assert failed "_ValueType may not be a reference."}} + any_cast(&a); // expected-error@experimental/any:* 1 {{static_assert failed "_ValueType may not be a reference."}} + any_cast(&a); // expected-error@experimental/any:* 1 {{static_assert failed "_ValueType may not be a reference."}} + any_cast(&a); // expected-error@experimental/any:* 1 {{static_assert failed "_ValueType may not be a reference."}} + any const& a2 = a; + any_cast(&a2); // expected-error@experimental/any:* 1 {{static_assert failed "_ValueType may not be a reference."}} + any_cast(&a2); // expected-error@experimental/any:* 1 {{static_assert failed "_ValueType may not be a reference."}} + any_cast(&a2); // expected-error@experimental/any:* 1 {{static_assert failed "_ValueType may not be a reference."}} + any_cast(&a2); // expected-error@experimental/any:* 1 {{static_assert failed "_ValueType may not be a reference."}} +} diff --git a/libcxx/test/std/experimental/any/any.nonmembers/swap.pass.cpp b/libcxx/test/std/experimental/any/any.nonmembers/swap.pass.cpp new file mode 100644 index 000000000000..a3fbd43d9247 --- /dev/null +++ b/libcxx/test/std/experimental/any/any.nonmembers/swap.pass.cpp @@ -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 + +// + +// void swap(any &, any &) noexcept + +// swap(...) just wraps any::swap(...). That function is tested elsewhere. + +#include +#include + +using std::experimental::any; +using std::experimental::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(a1) == 2); + assert(any_cast(a2) == 1); + } +} diff --git a/libcxx/test/support/any_helpers.h b/libcxx/test/support/any_helpers.h new file mode 100644 index 000000000000..76b1922fb1f1 --- /dev/null +++ b/libcxx/test/support/any_helpers.h @@ -0,0 +1,318 @@ +#ifndef ANY_HELPERS_H +#define ANY_HELPERS_H + +#include +#include +#include +#include + +#include "test_macros.h" + +#if !defined(TEST_HAS_NO_RTTI) +#define RTTI_ASSERT(X) assert(X) +#else +#define RTTI_ASSERT(X) +#endif + +template + struct IsSmallObject + : public std::integral_constant::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 +bool isSmallType() { +#if defined(_LIBCPP_VERSION) + return std::experimental::__any_imp::_IsSmallObject::value; +#else + return IsSmallObject::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 +void assertEmpty(std::experimental::any const& a) { + assert(a.empty()); + RTTI_ASSERT(a.type() == typeid(void)); + assert(std::experimental::any_cast(&a) == nullptr); +} + +// Assert that an 'any' object stores the specified 'Type' and 'value'. +template +void assertContains(std::experimental::any const& a, int value = 1) { + assert(!a.empty()); + RTTI_ASSERT(a.type() == typeid(Type)); + assert(std::experimental::any_cast(a).value == value); +} + +// Modify the value of a "test type" stored within an any to the specified +// 'value'. +template +void modifyValue(std::experimental::any& a, int value) { + assert(!a.empty()); + RTTI_ASSERT(a.type() == typeid(Type)); + std::experimental::any_cast(a).value = value; +} + +// A test type that will trigger the small object optimization within 'any'. +template +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 small_type::count = 0; + +template +int small_type::copied = 0; + +template +int small_type::moved = 0; + +template +int small_type::const_copied = 0; + +template +int small_type::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 +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 large_type::count = 0; + +template +int large_type::copied = 0; + +template +int large_type::moved = 0; + +template +int large_type::const_copied = 0; + +template +int large_type::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 diff --git a/libcxx/test/support/count_new.hpp b/libcxx/test/support/count_new.hpp index ddaf036f7d16..57aca7def335 100644 --- a/libcxx/test/support/count_new.hpp +++ b/libcxx/test/support/count_new.hpp @@ -30,6 +30,10 @@ public: // All checks return true when disable_checking is enabled. static const bool disable_checking; + // Disallow any allocations from occurring. Useful for testing that + // code doesn't perform any allocations. + bool disable_allocations; + int outstanding_new; int new_called; int delete_called; @@ -43,6 +47,7 @@ public: public: void newCalled(std::size_t s) { + assert(disable_allocations == false); assert(s); ++new_called; ++outstanding_new; @@ -58,6 +63,7 @@ public: void newArrayCalled(std::size_t s) { + assert(disable_allocations == false); assert(s); ++outstanding_array_new; ++new_array_called; @@ -71,8 +77,20 @@ public: ++delete_array_called; } + void disableAllocations() + { + disable_allocations = true; + } + + void enableAllocations() + { + disable_allocations = false; + } + void reset() { + disable_allocations = false; + outstanding_new = 0; new_called = 0; delete_called = 0; @@ -203,4 +221,29 @@ void operator delete[](void* p) throw() #endif // DISABLE_NEW_COUNT + +struct DisableAllocationGuard { + explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable) + { + // Don't re-disable if already disabled. + if (globalMemCounter.disable_allocations == true) m_disabled = false; + if (m_disabled) globalMemCounter.disableAllocations(); + } + + void release() { + if (m_disabled) globalMemCounter.enableAllocations(); + m_disabled = false; + } + + ~DisableAllocationGuard() { + release(); + } + +private: + bool m_disabled; + + DisableAllocationGuard(DisableAllocationGuard const&); + DisableAllocationGuard& operator=(DisableAllocationGuard const&); +}; + #endif /* COUNT_NEW_HPP */ diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h index a08ca87be935..08ec28f7c7b6 100644 --- a/libcxx/test/support/test_macros.h +++ b/libcxx/test/support/test_macros.h @@ -14,6 +14,12 @@ #define TEST_CONCAT1(X, Y) X##Y #define TEST_CONCAT(X, Y) TEST_CONCAT1(X, Y) +#ifdef __has_feature +#define TEST_HAS_FEATURE(X) __has_feature(X) +#else +#define TEST_HAS_FEATURE(X) 0 +#endif + #ifdef __has_extension #define TEST_HAS_EXTENSION(X) __has_extension(X) #else @@ -80,4 +86,12 @@ template struct static_assert_check {}; } // end namespace test_detail +#if !TEST_HAS_FEATURE(cxx_rtti) && !defined(__cxx_rtti) +#define TEST_HAS_NO_RTTI +#endif + +#if !TEST_HAS_FEATURE(cxx_exceptions) && !defined(__cxx_exceptions) +#define TEST_HAS_NO_EXCEPTIONS +#endif + #endif // SUPPORT_TEST_MACROS_HPP