summaryrefslogtreecommitdiff
path: root/test/support
diff options
context:
space:
mode:
Diffstat (limited to 'test/support')
-rw-r--r--test/support/Counter.h4
-rw-r--r--test/support/MoveOnly.h2
-rw-r--r--test/support/allocators.h2
-rw-r--r--test/support/asan_testing.h10
-rw-r--r--test/support/assert_checkpoint.h73
-rw-r--r--test/support/constexpr_char_traits.hpp42
-rw-r--r--test/support/container_test_types.h492
-rw-r--r--test/support/count_new.hpp78
-rw-r--r--test/support/counting_predicates.hpp6
-rw-r--r--test/support/disable_missing_braces_warning.h2
-rw-r--r--test/support/filesystem_dynamic_test_helper.py85
-rw-r--r--test/support/filesystem_test_helper.hpp403
-rw-r--r--test/support/hexfloat.h20
-rw-r--r--test/support/is_transparent.h4
-rw-r--r--test/support/min_allocator.h58
-rw-r--r--test/support/nasty_containers.hpp51
-rw-r--r--test/support/platform_support.h23
-rw-r--r--test/support/propagate_const_helpers.h119
-rw-r--r--test/support/rapid-cxx-test.hpp847
-rw-r--r--test/support/test.support/test_convertible_header.pass.cpp68
-rw-r--r--test/support/test.support/test_macros_header_exceptions.fail.cpp24
-rw-r--r--test/support/test.support/test_macros_header_exceptions.pass.cpp24
-rw-r--r--test/support/test.support/test_macros_header_rtti.fail.cpp29
-rw-r--r--test/support/test.support/test_macros_header_rtti.pass.cpp28
-rw-r--r--test/support/test_allocator.h113
-rw-r--r--test/support/test_convertible.hpp42
-rw-r--r--test/support/test_iterators.h344
-rw-r--r--test/support/test_macros.h81
-rw-r--r--test/support/test_memory_resource.hpp507
-rw-r--r--test/support/type_id.h57
-rw-r--r--test/support/uses_alloc_types.hpp298
31 files changed, 3655 insertions, 281 deletions
diff --git a/test/support/Counter.h b/test/support/Counter.h
index 2bc3642f50594..eb6e04e72ef62 100644
--- a/test/support/Counter.h
+++ b/test/support/Counter.h
@@ -13,7 +13,7 @@
#include <functional> // for std::hash
struct Counter_base { static int gConstructed; };
-
+
template <typename T>
class Counter : public Counter_base
{
@@ -27,7 +27,7 @@ public:
Counter& operator=(Counter&& rhs) { ++gConstructed; data_ = std::move(rhs.data_); return *this; }
#endif
~Counter() { --gConstructed; }
-
+
const T& get() const {return data_;}
bool operator==(const Counter& x) const {return data_ == x.data_;}
diff --git a/test/support/MoveOnly.h b/test/support/MoveOnly.h
index ee6ae7c7e5f9e..a3e9cca89ee50 100644
--- a/test/support/MoveOnly.h
+++ b/test/support/MoveOnly.h
@@ -10,6 +10,8 @@
#ifndef MOVEONLY_H
#define MOVEONLY_H
+#include "test_macros.h"
+
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
#include <cstddef>
diff --git a/test/support/allocators.h b/test/support/allocators.h
index 7c2103ff27216..4aa467f824aa6 100644
--- a/test/support/allocators.h
+++ b/test/support/allocators.h
@@ -101,7 +101,7 @@ public:
A2& operator=(const A2& a) TEST_NOEXCEPT { id_ = a.id(); copy_called = true; return *this;}
A2& operator=(A2&& a) TEST_NOEXCEPT { id_ = a.id(); move_called = true; return *this;}
- T* allocate(std::size_t n, const void* hint)
+ T* allocate(std::size_t, const void* hint)
{
allocate_called = true;
return (T*)hint;
diff --git a/test/support/asan_testing.h b/test/support/asan_testing.h
index 45ad04b1bb2ca..678f12a91b65a 100644
--- a/test/support/asan_testing.h
+++ b/test/support/asan_testing.h
@@ -10,12 +10,12 @@
#ifndef ASAN_TESTING_H
#define ASAN_TESTING_H
-#include <__config>
+#include "test_macros.h"
-#ifndef _LIBCPP_HAS_NO_ASAN
+#if TEST_HAS_FEATURE(address_sanitizer)
extern "C" int __sanitizer_verify_contiguous_container
( const void *beg, const void *mid, const void *end );
-
+
template <typename T, typename Alloc>
bool is_contiguous_container_asan_correct ( const std::vector<T, Alloc> &c )
{
@@ -27,11 +27,11 @@ bool is_contiguous_container_asan_correct ( const std::vector<T, Alloc> &c )
#else
template <typename T, typename Alloc>
-bool is_contiguous_container_asan_correct ( const std::vector<T, Alloc> &c )
+bool is_contiguous_container_asan_correct ( const std::vector<T, Alloc> &)
{
return true;
}
#endif
-
+
#endif // ASAN_TESTING_H
diff --git a/test/support/assert_checkpoint.h b/test/support/assert_checkpoint.h
new file mode 100644
index 0000000000000..6627b35eb30d1
--- /dev/null
+++ b/test/support/assert_checkpoint.h
@@ -0,0 +1,73 @@
+#ifndef SUPPORT_ASSERT_CHECKPOINT_H
+#define SUPPORT_ASSERT_CHECKPOINT_H
+
+#include <csignal>
+#include <iostream>
+#include <cstdlib>
+
+struct Checkpoint {
+ const char* file;
+ const char* func;
+ int line;
+ const char* msg;
+
+ Checkpoint() : file(nullptr), func(nullptr), line(-1), msg(nullptr) {}
+ Checkpoint(const char* xfile, const char* xfunc, int xline, const char* xmsg)
+ : file(xfile), func(xfunc), line(xline), msg(xmsg)
+ {}
+
+ template <class Stream>
+ void print(Stream& s) const {
+ if (!file) {
+ s << "NO CHECKPOINT\n";
+ return;
+ }
+ s << file << ":" << line << " " << func << ": Checkpoint";
+ if (msg)
+ s << " '" << msg << "'";
+ s << std::endl;
+ }
+};
+
+inline Checkpoint& globalCheckpoint() {
+ static Checkpoint C;
+ return C;
+}
+
+inline void clearCheckpoint() {
+ globalCheckpoint() = Checkpoint();
+}
+
+#if defined(__GNUC__)
+#define CHECKPOINT_FUNCTION_NAME __PRETTY_FUNCTION__
+#else
+#define CHECKPOINT_FUNCTION_NAME __func__
+#endif
+
+#define CHECKPOINT(msg) globalCheckpoint() = Checkpoint(__FILE__, CHECKPOINT_FUNCTION_NAME, __LINE__, msg);
+
+inline void checkpointSignalHandler(int signal) {
+ if (signal == SIGABRT) {
+ globalCheckpoint().print(std::cerr);
+ } else {
+ std::cerr << "Unexpected signal " << signal << " received\n";
+ }
+ std::_Exit(EXIT_FAILURE);
+}
+
+inline bool initCheckpointHandler() {
+ typedef void(*HandlerT)(int);
+ static bool isInit = false;
+ if (isInit) return true;
+ HandlerT prev_h = std::signal(SIGABRT, checkpointSignalHandler);
+ if (prev_h == SIG_ERR) {
+ std::cerr << "Setup failed.\n";
+ std::_Exit(EXIT_FAILURE);
+ }
+ isInit = true;
+ return false;
+}
+
+static bool initDummy = initCheckpointHandler();
+
+#endif
diff --git a/test/support/constexpr_char_traits.hpp b/test/support/constexpr_char_traits.hpp
index b069c90076a2c..0a73d3ad1eadd 100644
--- a/test/support/constexpr_char_traits.hpp
+++ b/test/support/constexpr_char_traits.hpp
@@ -11,9 +11,9 @@
#ifndef _CONSTEXPR_CHAR_TRAITS
#define _CONSTEXPR_CHAR_TRAITS
-#include <__config>
#include <string>
+#include "test_macros.h"
template <class _CharT>
struct constexpr_char_traits
@@ -24,41 +24,41 @@ struct constexpr_char_traits
typedef std::streampos pos_type;
typedef std::mbstate_t state_type;
- static _LIBCPP_CONSTEXPR_AFTER_CXX11 void assign(char_type& __c1, const char_type& __c2) _NOEXCEPT
+ static TEST_CONSTEXPR_CXX14 void assign(char_type& __c1, const char_type& __c2) TEST_NOEXCEPT
{__c1 = __c2;}
- static _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT
+ static TEST_CONSTEXPR bool eq(char_type __c1, char_type __c2) TEST_NOEXCEPT
{return __c1 == __c2;}
- static _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT
+ static TEST_CONSTEXPR bool lt(char_type __c1, char_type __c2) TEST_NOEXCEPT
{return __c1 < __c2;}
- static _LIBCPP_CONSTEXPR_AFTER_CXX11 int compare(const char_type* __s1, const char_type* __s2, size_t __n);
- static _LIBCPP_CONSTEXPR_AFTER_CXX11 size_t length(const char_type* __s);
- static _LIBCPP_CONSTEXPR_AFTER_CXX11 const char_type* find(const char_type* __s, size_t __n, const char_type& __a);
- static _LIBCPP_CONSTEXPR_AFTER_CXX11 char_type* move(char_type* __s1, const char_type* __s2, size_t __n);
- static _LIBCPP_CONSTEXPR_AFTER_CXX11 char_type* copy(char_type* __s1, const char_type* __s2, size_t __n);
- static _LIBCPP_CONSTEXPR_AFTER_CXX11 char_type* assign(char_type* __s, size_t __n, char_type __a);
+ static TEST_CONSTEXPR_CXX14 int compare(const char_type* __s1, const char_type* __s2, size_t __n);
+ static TEST_CONSTEXPR_CXX14 size_t length(const char_type* __s);
+ static TEST_CONSTEXPR_CXX14 const char_type* find(const char_type* __s, size_t __n, const char_type& __a);
+ static TEST_CONSTEXPR_CXX14 char_type* move(char_type* __s1, const char_type* __s2, size_t __n);
+ static TEST_CONSTEXPR_CXX14 char_type* copy(char_type* __s1, const char_type* __s2, size_t __n);
+ static TEST_CONSTEXPR_CXX14 char_type* assign(char_type* __s, size_t __n, char_type __a);
- static _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT
+ static TEST_CONSTEXPR int_type not_eof(int_type __c) TEST_NOEXCEPT
{return eq_int_type(__c, eof()) ? ~eof() : __c;}
- static _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT
+ static TEST_CONSTEXPR char_type to_char_type(int_type __c) TEST_NOEXCEPT
{return char_type(__c);}
- static _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT
+ static TEST_CONSTEXPR int_type to_int_type(char_type __c) TEST_NOEXCEPT
{return int_type(__c);}
- static _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT
+ static TEST_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) TEST_NOEXCEPT
{return __c1 == __c2;}
- static _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT
+ static TEST_CONSTEXPR int_type eof() TEST_NOEXCEPT
{return int_type(EOF);}
};
template <class _CharT>
-_LIBCPP_CONSTEXPR_AFTER_CXX11 int
+TEST_CONSTEXPR_CXX14 int
constexpr_char_traits<_CharT>::compare(const char_type* __s1, const char_type* __s2, size_t __n)
{
for (; __n; --__n, ++__s1, ++__s2)
@@ -72,7 +72,7 @@ constexpr_char_traits<_CharT>::compare(const char_type* __s1, const char_type* _
}
template <class _CharT>
-_LIBCPP_CONSTEXPR_AFTER_CXX11 size_t
+TEST_CONSTEXPR_CXX14 size_t
constexpr_char_traits<_CharT>::length(const char_type* __s)
{
size_t __len = 0;
@@ -82,7 +82,7 @@ constexpr_char_traits<_CharT>::length(const char_type* __s)
}
template <class _CharT>
-_LIBCPP_CONSTEXPR_AFTER_CXX11 const _CharT*
+TEST_CONSTEXPR_CXX14 const _CharT*
constexpr_char_traits<_CharT>::find(const char_type* __s, size_t __n, const char_type& __a)
{
for (; __n; --__n)
@@ -95,7 +95,7 @@ constexpr_char_traits<_CharT>::find(const char_type* __s, size_t __n, const char
}
template <class _CharT>
-_LIBCPP_CONSTEXPR_AFTER_CXX11 _CharT*
+TEST_CONSTEXPR_CXX14 _CharT*
constexpr_char_traits<_CharT>::move(char_type* __s1, const char_type* __s2, size_t __n)
{
char_type* __r = __s1;
@@ -115,7 +115,7 @@ constexpr_char_traits<_CharT>::move(char_type* __s1, const char_type* __s2, size
}
template <class _CharT>
-_LIBCPP_CONSTEXPR_AFTER_CXX11 _CharT*
+TEST_CONSTEXPR_CXX14 _CharT*
constexpr_char_traits<_CharT>::copy(char_type* __s1, const char_type* __s2, size_t __n)
{
_LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
@@ -126,7 +126,7 @@ constexpr_char_traits<_CharT>::copy(char_type* __s1, const char_type* __s2, size
}
template <class _CharT>
-_LIBCPP_CONSTEXPR_AFTER_CXX11 _CharT*
+TEST_CONSTEXPR_CXX14 _CharT*
constexpr_char_traits<_CharT>::assign(char_type* __s, size_t __n, char_type __a)
{
char_type* __r = __s;
diff --git a/test/support/container_test_types.h b/test/support/container_test_types.h
new file mode 100644
index 0000000000000..0b97f2e94e75a
--- /dev/null
+++ b/test/support/container_test_types.h
@@ -0,0 +1,492 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 SUPPORT_CONTAINER_TEST_TYPES_H
+#define SUPPORT_CONTAINER_TEST_TYPES_H
+
+// container_test_types.h - A set of types used for testing STL containers.
+// The types container within this header are used to test the requirements in
+// [container.requirements.general]. The header is made up of 3 main components:
+//
+// * test-types: 'CopyInsertable', 'MoveInsertable' and 'EmplaceConstructible' -
+// These test types are used to test the container requirements of the same
+// name. These test types use the global 'AllocatorConstructController' to
+// assert that they are only constructed by the containers allocator.
+//
+// * test-allocator: 'ContainerTestAllocator' - This test allocator is used to
+// test the portions of [container.requirements.general] that pertain to the
+// containers allocator. The three primary jobs of the test allocator are:
+// 1. Enforce that 'a.construct(...)' and 'a.destroy(...)' are only ever
+// instantiated for 'Container::value_type'.
+// 2. Provide a mechanism of checking calls to 'a.construct(Args...)'.
+// Including controlling when and with what types 'a.construct(...)'
+// may be called with.
+// 3. Support the test types internals by controlling the global
+// 'AllocatorConstructController' object.
+//
+// * 'AllocatorConstructController' - This type defines an interface for testing
+// the construction of types using an allocator. This type is used to communicate
+// between the test author, the containers allocator, and the types
+// being constructed by the container.
+// The controllers primary functions are:
+// 1. Allow calls to 'a.construct(p, args...)' to be checked by a test.
+// The test uses 'cc->expect<Args...>()' to specify that the allocator
+// should expect one call to 'a.construct' with the specified argument
+// types.
+// 2. Controlling the value of 'cc->isInAllocatorConstruct()' within the
+// 'construct' method. The test-types use this value to assert that
+// they are being constructed by the allocator.
+//
+// 'AllocatorConstructController' enforces the Singleton pattern since the
+// test-types, test-allocator and test need to share the same controller
+// object. A pointer to the global controller is returned by
+// 'getConstructController()'.
+//
+//----------------------------------------------------------------------------
+/*
+ * Usage: The following example checks that 'unordered_map::emplace(Args&&...)'
+ * with 'Args = [CopyInsertable<1> const&, CopyInsertible<2>&&]'
+ * calls 'alloc.construct(value_type*, Args&&...)' with the same types.
+ *
+ * // Typedefs for container
+ * using Key = CopyInsertible<1>;
+ * using Value = CopyInsertible<2>;
+ * using ValueTp = std::pair<const Key, Value>;
+ * using Alloc = ContainerTestAllocator<ValueTp, ValueTp>;
+ * using Map = std::unordered_map<Key, Value, std::hash<Key>, std::equal_to<Key>, Alloc>;
+ *
+ * // Get the global controller, reset it, and construct an allocator with
+ * // the controller.
+ * ConstructController* cc = getConstructController();
+ * cc->reset();
+ *
+ * // Create a Map and a Key and Value to insert. Note that the test-allocator
+ * // does not need to be given 'cc'.
+ * Map m;
+ * const Key k(1);
+ * Value v(1);
+ *
+ * // Tell the controller to expect a construction from the specified types.
+ * cc->expect<Key const&, Value&&>();
+ *
+ * // Emplace the objects into the container. 'Alloc.construct(p, UArgs...)'
+ * // will assert 'cc->check<UArgs&&>()' is true which will consume
+ * // the call to 'cc->expect<...>()'.
+ * m.emplace(k, std::move(v));
+ *
+ * // Assert that the "expect" was consumed by a matching "check" call within
+ * // Alloc.
+ * assert(!cc->unexpected());
+ *
+ */
+
+#include <functional>
+#include <cassert>
+
+#include "test_macros.h"
+
+#if TEST_STD_VER < 11
+#error This header requires C++11 or greater
+#endif
+
+namespace detail {
+// TypeID - Represent a unique identifier for a type. TypeID allows equality
+// comparisons between different types.
+struct TypeID {
+ friend bool operator==(TypeID const& LHS, TypeID const& RHS)
+ {return LHS.m_id == RHS.m_id; }
+ friend bool operator!=(TypeID const& LHS, TypeID const& RHS)
+ {return LHS.m_id != RHS.m_id; }
+private:
+ explicit constexpr TypeID(const int* xid) : m_id(xid) {}
+ const int* const m_id;
+ template <class T> friend class TypeInfo;
+};
+
+// TypeInfo - Represent information for the specified type 'T', including a
+// unique TypeID.
+template <class T>
+class TypeInfo {
+public:
+ typedef T value_type;
+ typedef TypeID ID;
+ static ID const& GetID() { static ID id(&dummy_addr); return id; }
+
+private:
+ static const int dummy_addr;
+};
+
+template <class L, class R>
+inline bool operator==(TypeInfo<L> const&, TypeInfo<R> const&)
+{ return std::is_same<L, R>::value; }
+
+template <class L, class R>
+inline bool operator!=(TypeInfo<L> const& lhs, TypeInfo<R> const& rhs)
+{ return !(lhs == rhs); }
+
+template <class T>
+const int TypeInfo<T>::dummy_addr = 42;
+
+// makeTypeID - Return the TypeID for the specified type 'T'.
+template <class T>
+inline constexpr TypeID const& makeTypeID() { return TypeInfo<T>::GetID(); }
+
+template <class ...Args>
+struct ArgumentListID {};
+
+// makeArgumentID - Create and return a unique identifier for a given set
+// of arguments.
+template <class ...Args>
+inline constexpr TypeID const& makeArgumentID() {
+ return makeTypeID<ArgumentListID<Args...>>();
+}
+
+} // namespace detail
+
+//===----------------------------------------------------------------------===//
+// AllocatorConstructController
+//===----------------------------------------------------------------------===//
+
+struct AllocatorConstructController {
+ const detail::TypeID* m_expected_args;
+ bool m_allow_constructions;
+ bool m_allow_unchecked;
+ int m_expected_count;
+
+ void clear() {
+ m_expected_args = nullptr;
+ m_expected_count = -1;
+ }
+
+ // Check for and consume an expected construction added by 'expect'.
+ // Return true if the construction was expected and false otherwise.
+ // This should only be called by 'Allocator.construct'.
+ bool check(detail::TypeID const& tid) {
+ if (!m_expected_args)
+ assert(m_allow_unchecked);
+ bool res = *m_expected_args == tid;
+ if (m_expected_count == -1 || --m_expected_count == -1)
+ m_expected_args = nullptr;
+ return res;
+ }
+
+ // Return true iff there is an unchecked construction expression.
+ bool unchecked() {
+ return m_expected_args != nullptr;
+ }
+
+ // Expect a call to Allocator::construct with Args that match 'tid'.
+ void expect(detail::TypeID const& tid) {
+ assert(!unchecked());
+ m_expected_args = &tid;
+ }
+
+ template <class ...Args>
+ void expect(int times = 1) {
+ assert(!unchecked());
+ assert(times > 0);
+ m_expected_count = times - 1;
+ m_expected_args = &detail::makeArgumentID<Args...>();
+ }
+ template <class ...Args>
+ bool check() {
+ return check(detail::makeArgumentID<Args...>());
+ }
+
+
+ // Return true iff the program is currently within a call to "Allocator::construct"
+ bool isInAllocatorConstruct() const {
+ return m_allow_constructions;
+ }
+
+ void inAllocatorConstruct(bool value = true) {
+ m_allow_constructions = value;
+ }
+
+ void allowUnchecked(bool value = true) {
+ m_allow_unchecked = value;
+ }
+
+ void reset() {
+ m_allow_constructions = false;
+ m_expected_args = nullptr;
+ m_allow_unchecked = false;
+ m_expected_count = -1;
+ }
+
+private:
+ friend AllocatorConstructController* getConstructController();
+ AllocatorConstructController() { reset(); }
+ AllocatorConstructController(AllocatorConstructController const&);
+ AllocatorConstructController& operator=(AllocatorConstructController const&);
+};
+
+typedef AllocatorConstructController ConstructController;
+
+// getConstructController - Return the global allocator construction controller.
+inline ConstructController* getConstructController() {
+ static ConstructController c;
+ return &c;
+}
+
+//===----------------------------------------------------------------------===//
+// ContainerTestAllocator
+//===----------------------------------------------------------------------===//
+
+// ContainerTestAllocator - A STL allocator type that only allows 'construct'
+// and 'destroy' to be called for 'AllowConstructT' types. ContainerTestAllocator
+// uses the 'AllocatorConstructionController' interface.
+template <class T, class AllowConstructT>
+class ContainerTestAllocator
+{
+ struct InAllocatorConstructGuard {
+ ConstructController *m_cc;
+ bool m_old;
+ InAllocatorConstructGuard(ConstructController* cc) : m_cc(cc) {
+ if (m_cc) {
+ m_old = m_cc->isInAllocatorConstruct();
+ m_cc->inAllocatorConstruct(true);
+ }
+ }
+ ~InAllocatorConstructGuard() {
+ if (m_cc) m_cc->inAllocatorConstruct(m_old);
+ }
+ private:
+ InAllocatorConstructGuard(InAllocatorConstructGuard const&);
+ InAllocatorConstructGuard& operator=(InAllocatorConstructGuard const&);
+ };
+
+public:
+ typedef T value_type;
+
+ int construct_called;
+ int destroy_called;
+ ConstructController* controller;
+
+ ContainerTestAllocator() TEST_NOEXCEPT
+ : controller(getConstructController()) {}
+
+ explicit ContainerTestAllocator(ConstructController* c)
+ : controller(c)
+ {}
+
+ template <class U>
+ ContainerTestAllocator(ContainerTestAllocator<U, AllowConstructT> other) TEST_NOEXCEPT
+ : controller(other.controller)
+ {}
+
+ T* allocate(std::size_t n)
+ {
+ return static_cast<T*>(::operator new(n*sizeof(T)));
+ }
+
+ void deallocate(T* p, std::size_t)
+ {
+ return ::operator delete(static_cast<void*>(p));
+ }
+
+ template <class Up, class ...Args>
+ void construct(Up* p, Args&&... args) {
+ static_assert((std::is_same<Up, AllowConstructT>::value),
+ "Only allowed to construct Up");
+ assert(controller->check<Args&&...>());
+ {
+ InAllocatorConstructGuard g(controller);
+ ::new ((void*)p) Up(std::forward<Args>(args)...);
+ }
+ }
+
+ template <class Up>
+ void destroy(Up* p) {
+ static_assert((std::is_same<Up, AllowConstructT>::value),
+ "Only allowed to destroy Up");
+ {
+ InAllocatorConstructGuard g(controller);
+ p->~Up();
+ }
+ }
+
+ friend bool operator==(ContainerTestAllocator, ContainerTestAllocator) {return true;}
+ friend bool operator!=(ContainerTestAllocator x, ContainerTestAllocator y) {return !(x == y);}
+};
+
+
+namespace test_detail {
+typedef ContainerTestAllocator<int, int> A1;
+typedef std::allocator_traits<A1> A1T;
+typedef ContainerTestAllocator<float, int> A2;
+typedef std::allocator_traits<A2> A2T;
+
+static_assert(std::is_same<A1T::rebind_traits<float>, A2T>::value, "");
+static_assert(std::is_same<A2T::rebind_traits<int>, A1T>::value, "");
+} // end namespace test_detail
+
+//===----------------------------------------------------------------------===//
+// 'CopyInsertable', 'MoveInsertable' and 'EmplaceConstructible' test types
+//===----------------------------------------------------------------------===//
+
+template <int Dummy = 0>
+struct CopyInsertable {
+ int data;
+ mutable bool copied_once;
+ bool constructed_under_allocator;
+
+ explicit CopyInsertable(int val) : data(val), copied_once(false),
+ constructed_under_allocator(false) {
+ if (getConstructController()->isInAllocatorConstruct()) {
+ copied_once = true;
+ constructed_under_allocator = true;
+ }
+ }
+
+ CopyInsertable() : data(0), copied_once(false), constructed_under_allocator(true)
+ {
+ assert(getConstructController()->isInAllocatorConstruct());
+ }
+
+ CopyInsertable(CopyInsertable const& other) : data(other.data),
+ copied_once(true),
+ constructed_under_allocator(true) {
+ assert(getConstructController()->isInAllocatorConstruct());
+ assert(other.copied_once == false);
+ other.copied_once = true;
+ }
+
+ CopyInsertable(CopyInsertable& other) : data(other.data), copied_once(true),
+ constructed_under_allocator(true) {
+ assert(getConstructController()->isInAllocatorConstruct());
+ assert(other.copied_once == false);
+ other.copied_once = true;
+ }
+
+ CopyInsertable(CopyInsertable&& other) : CopyInsertable(other) {}
+
+ // Forgive pair for not downcasting this to an lvalue it its constructors.
+ CopyInsertable(CopyInsertable const && other) : CopyInsertable(other) {}
+
+
+ template <class ...Args>
+ CopyInsertable(Args&&... args) {
+ assert(false);
+ }
+
+ ~CopyInsertable() {
+ assert(constructed_under_allocator == getConstructController()->isInAllocatorConstruct());
+ }
+
+ void reset(int value) {
+ data = value;
+ copied_once = false;
+ constructed_under_allocator = false;
+ }
+};
+
+template <int ID>
+bool operator==(CopyInsertable<ID> const& L, CopyInsertable<ID> const& R) {
+ return L.data == R.data;
+}
+
+
+template <int ID>
+bool operator!=(CopyInsertable<ID> const& L, CopyInsertable<ID> const& R) {
+ return L.data != R.data;
+}
+
+template <int ID>
+bool operator <(CopyInsertable<ID> const& L, CopyInsertable<ID> const& R) {
+ return L.data < R.data;
+}
+
+
+#ifdef _LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_NAMESPACE_STD
+#else
+namespace std {
+#endif
+ template <int ID>
+ struct hash< ::CopyInsertable<ID> > {
+ typedef ::CopyInsertable<ID> argument_type;
+ typedef size_t result_type;
+
+ size_t operator()(argument_type const& arg) const {
+ return arg.data;
+ }
+ };
+
+ template <class _Key, class _Value, class _Less, class _Alloc>
+ class map;
+ template <class _Key, class _Value, class _Less, class _Alloc>
+ class multimap;
+ template <class _Value, class _Less, class _Alloc>
+ class set;
+ template <class _Value, class _Less, class _Alloc>
+ class multiset;
+ template <class _Key, class _Value, class _Hash, class _Equals, class _Alloc>
+ class unordered_map;
+ template <class _Key, class _Value, class _Hash, class _Equals, class _Alloc>
+ class unordered_multimap;
+ template <class _Value, class _Hash, class _Equals, class _Alloc>
+ class unordered_set;
+ template <class _Value, class _Hash, class _Equals, class _Alloc>
+ class unordered_multiset;
+
+#ifdef _LIBCPP_END_NAMESPACE_STD
+_LIBCPP_END_NAMESPACE_STD
+#else
+} // end namespace std
+#endif
+
+// TCT - Test container type
+namespace TCT {
+
+template <class Key = CopyInsertable<1>, class Value = CopyInsertable<2>,
+ class ValueTp = std::pair<const Key, Value> >
+using unordered_map =
+ std::unordered_map<Key, Value, std::hash<Key>, std::equal_to<Key>,
+ ContainerTestAllocator<ValueTp, ValueTp> >;
+
+template <class Key = CopyInsertable<1>, class Value = CopyInsertable<2>,
+ class ValueTp = std::pair<const Key, Value> >
+using map =
+ std::map<Key, Value, std::less<Key>,
+ ContainerTestAllocator<ValueTp, ValueTp> >;
+
+template <class Key = CopyInsertable<1>, class Value = CopyInsertable<2>,
+ class ValueTp = std::pair<const Key, Value> >
+using unordered_multimap =
+ std::unordered_multimap<Key, Value, std::hash<Key>, std::equal_to<Key>,
+ ContainerTestAllocator<ValueTp, ValueTp> >;
+
+template <class Key = CopyInsertable<1>, class Value = CopyInsertable<2>,
+ class ValueTp = std::pair<const Key, Value> >
+using multimap =
+ std::multimap<Key, Value, std::less<Key>,
+ ContainerTestAllocator<ValueTp, ValueTp> >;
+
+template <class Value = CopyInsertable<1> >
+using unordered_set =
+ std::unordered_set<Value, std::hash<Value>, std::equal_to<Value>,
+ ContainerTestAllocator<Value, Value> >;
+
+template <class Value = CopyInsertable<1> >
+using set =
+ std::set<Value, std::less<Value>, ContainerTestAllocator<Value, Value> >;
+
+template <class Value = CopyInsertable<1> >
+using unordered_multiset =
+ std::unordered_multiset<Value, std::hash<Value>, std::equal_to<Value>,
+ ContainerTestAllocator<Value, Value> >;
+
+template <class Value = CopyInsertable<1> >
+using multiset =
+ std::multiset<Value, std::less<Value>, ContainerTestAllocator<Value, Value> >;
+
+} // end namespace TCT
+
+
+#endif // SUPPORT_CONTAINER_TEST_TYPES_H
diff --git a/test/support/count_new.hpp b/test/support/count_new.hpp
index e8968a93de980..923e495134871 100644
--- a/test/support/count_new.hpp
+++ b/test/support/count_new.hpp
@@ -14,16 +14,24 @@
# include <cassert>
# include <new>
-#ifndef __has_feature
-# define __has_feature(x) 0
-#endif
+#include "test_macros.h"
-#if __has_feature(address_sanitizer) \
- || __has_feature(memory_sanitizer) \
- || __has_feature(thread_sanitizer)
+#if defined(TEST_HAS_SANITIZERS)
#define DISABLE_NEW_COUNT
#endif
+namespace detail
+{
+ TEST_NORETURN
+ inline void throw_bad_alloc_helper() {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ throw std::bad_alloc();
+#else
+ std::abort();
+#endif
+ }
+}
+
class MemCounter
{
public:
@@ -43,6 +51,11 @@ public:
// code doesn't perform any allocations.
bool disable_allocations;
+ // number of allocations to throw after. Default (unsigned)-1. If
+ // throw_after has the default value it will never be decremented.
+ static const unsigned never_throw_value = static_cast<unsigned>(-1);
+ unsigned throw_after;
+
int outstanding_new;
int new_called;
int delete_called;
@@ -58,6 +71,12 @@ public:
{
assert(disable_allocations == false);
assert(s);
+ if (throw_after == 0) {
+ throw_after = never_throw_value;
+ detail::throw_bad_alloc_helper();
+ } else if (throw_after != never_throw_value) {
+ --throw_after;
+ }
++new_called;
++outstanding_new;
last_new_size = s;
@@ -74,6 +93,12 @@ public:
{
assert(disable_allocations == false);
assert(s);
+ if (throw_after == 0) {
+ throw_after = never_throw_value;
+ detail::throw_bad_alloc_helper();
+ } else {
+ // don't decrement throw_after here. newCalled will end up doing that.
+ }
++outstanding_array_new;
++new_array_called;
last_new_array_size = s;
@@ -96,9 +121,11 @@ public:
disable_allocations = false;
}
+
void reset()
{
disable_allocations = false;
+ throw_after = never_throw_value;
outstanding_new = 0;
new_called = 0;
@@ -132,6 +159,11 @@ public:
return disable_checking || n != new_called;
}
+ bool checkNewCalledGreaterThan(int n) const
+ {
+ return disable_checking || new_called > n;
+ }
+
bool checkDeleteCalledEq(int n) const
{
return disable_checking || n == delete_called;
@@ -205,7 +237,10 @@ MemCounter globalMemCounter((MemCounter::MemCounterCtorArg_()));
void* operator new(std::size_t s) throw(std::bad_alloc)
{
globalMemCounter.newCalled(s);
- return std::malloc(s);
+ void* ret = std::malloc(s);
+ if (ret == nullptr)
+ detail::throw_bad_alloc_helper();
+ return ret;
}
void operator delete(void* p) throw()
@@ -255,4 +290,33 @@ private:
DisableAllocationGuard& operator=(DisableAllocationGuard const&);
};
+
+struct RequireAllocationGuard {
+ explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1)
+ : m_req_alloc(RequireAtLeast),
+ m_new_count_on_init(globalMemCounter.new_called),
+ m_outstanding_new_on_init(globalMemCounter.outstanding_new),
+ m_exactly(false)
+ {
+ }
+
+ void requireAtLeast(std::size_t N) { m_req_alloc = N; m_exactly = false; }
+ void requireExactly(std::size_t N) { m_req_alloc = N; m_exactly = true; }
+
+ ~RequireAllocationGuard() {
+ assert(globalMemCounter.checkOutstandingNewEq(m_outstanding_new_on_init));
+ std::size_t Expect = m_new_count_on_init + m_req_alloc;
+ assert(globalMemCounter.checkNewCalledEq(Expect) ||
+ (!m_exactly && globalMemCounter.checkNewCalledGreaterThan(Expect)));
+ }
+
+private:
+ std::size_t m_req_alloc;
+ const std::size_t m_new_count_on_init;
+ const std::size_t m_outstanding_new_on_init;
+ bool m_exactly;
+ RequireAllocationGuard(RequireAllocationGuard const&);
+ RequireAllocationGuard& operator=(RequireAllocationGuard const&);
+};
+
#endif /* COUNT_NEW_HPP */
diff --git a/test/support/counting_predicates.hpp b/test/support/counting_predicates.hpp
index aab6a9785772c..2bd1426934e51 100644
--- a/test/support/counting_predicates.hpp
+++ b/test/support/counting_predicates.hpp
@@ -16,11 +16,11 @@ struct unary_counting_predicate : public std::unary_function<Arg, bool> {
public:
unary_counting_predicate(Predicate p) : p_(p), count_(0) {}
~unary_counting_predicate() {}
-
+
bool operator () (const Arg &a) const { ++count_; return p_(a); }
size_t count() const { return count_; }
void reset() { count_ = 0; }
-
+
private:
Predicate p_;
mutable size_t count_;
@@ -33,7 +33,7 @@ public:
binary_counting_predicate ( Predicate p ) : p_(p), count_(0) {}
~binary_counting_predicate() {}
-
+
bool operator () (const Arg1 &a1, const Arg2 &a2) const { ++count_; return p_(a1, a2); }
size_t count() const { return count_; }
void reset() { count_ = 0; }
diff --git a/test/support/disable_missing_braces_warning.h b/test/support/disable_missing_braces_warning.h
index 97fd8a89a51a3..c53eef8a951d1 100644
--- a/test/support/disable_missing_braces_warning.h
+++ b/test/support/disable_missing_braces_warning.h
@@ -11,6 +11,8 @@
// std::array is explicitly allowed to be initialized with A a = { init-list };.
// Disable the missing braces warning for this reason.
+#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wmissing-braces"
+#endif
#endif // SUPPORT_DISABLE_MISSING_BRACES_WARNING_H
diff --git a/test/support/filesystem_dynamic_test_helper.py b/test/support/filesystem_dynamic_test_helper.py
new file mode 100644
index 0000000000000..1f48c95279829
--- /dev/null
+++ b/test/support/filesystem_dynamic_test_helper.py
@@ -0,0 +1,85 @@
+import sys
+import os
+import stat
+
+# Ensure that this is being run on a specific platform
+assert sys.platform.startswith('linux') or sys.platform.startswith('darwin') \
+ or sys.platform.startswith('cygwin') or sys.platform.startswith('freebsd')
+
+def env_path():
+ ep = os.environ.get('LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT')
+ assert ep is not None
+ ep = os.path.realpath(ep)
+ assert os.path.isdir(ep)
+ return ep
+
+env_path_global = env_path()
+
+# Make sure we don't try and write outside of env_path.
+# All paths used should be sanitized
+def sanitize(p):
+ p = os.path.realpath(p)
+ if os.path.commonprefix([env_path_global, p]):
+ return p
+ assert False
+
+"""
+Some of the tests restrict permissions to induce failures.
+Before we delete the test enviroment, we have to walk it and re-raise the
+permissions.
+"""
+def clean_recursive(root_p):
+ if not os.path.islink(root_p):
+ os.chmod(root_p, 0o777)
+ for ent in os.listdir(root_p):
+ p = os.path.join(root_p, ent)
+ if os.path.islink(p) or not os.path.isdir(p):
+ os.remove(p)
+ else:
+ assert os.path.isdir(p)
+ clean_recursive(p)
+ os.rmdir(p)
+
+
+def init_test_directory(root_p):
+ root_p = sanitize(root_p)
+ assert not os.path.exists(root_p)
+ os.makedirs(root_p)
+
+
+def destroy_test_directory(root_p):
+ root_p = sanitize(root_p)
+ clean_recursive(root_p)
+ os.rmdir(root_p)
+
+
+def create_file(fname, size):
+ with open(sanitize(fname), 'w') as f:
+ f.write('c' * size)
+
+
+def create_dir(dname):
+ os.mkdir(sanitize(dname))
+
+
+def create_symlink(source, link):
+ os.symlink(sanitize(source), sanitize(link))
+
+
+def create_hardlink(source, link):
+ os.link(sanitize(source), sanitize(link))
+
+
+def create_fifo(source):
+ os.mkfifo(sanitize(source))
+
+
+def create_socket(source):
+ mode = 0600|stat.S_IFSOCK
+ os.mknod(sanitize(source), mode)
+
+
+if __name__ == '__main__':
+ command = " ".join(sys.argv[1:])
+ eval(command)
+ sys.exit(0)
diff --git a/test/support/filesystem_test_helper.hpp b/test/support/filesystem_test_helper.hpp
new file mode 100644
index 0000000000000..7150f79739b61
--- /dev/null
+++ b/test/support/filesystem_test_helper.hpp
@@ -0,0 +1,403 @@
+#ifndef FILESYSTEM_TEST_HELPER_HPP
+#define FILESYSTEM_TEST_HELPER_HPP
+
+#include <experimental/filesystem>
+#include <cassert>
+#include <cstdio> // for printf
+#include <string>
+#include <fstream>
+#include <random>
+#include <chrono>
+
+namespace fs = std::experimental::filesystem;
+
+// static test helpers
+
+#ifndef LIBCXX_FILESYSTEM_STATIC_TEST_ROOT
+#warning "STATIC TESTS DISABLED"
+#else // LIBCXX_FILESYSTEM_STATIC_TEST_ROOT
+
+namespace StaticEnv {
+
+inline fs::path makePath(fs::path const& p) {
+ // env_path is expected not to contain symlinks.
+ static const fs::path env_path = LIBCXX_FILESYSTEM_STATIC_TEST_ROOT;
+ return env_path / p;
+}
+
+static const fs::path Root = LIBCXX_FILESYSTEM_STATIC_TEST_ROOT;
+
+static const fs::path TestFileList[] = {
+ makePath("empty_file"),
+ makePath("non_empty_file"),
+ makePath("dir1/file1"),
+ makePath("dir1/file2")
+};
+const std::size_t TestFileListSize = sizeof(TestFileList) / sizeof(fs::path);
+
+static const fs::path TestDirList[] = {
+ makePath("dir1"),
+ makePath("dir1/dir2"),
+ makePath("dir1/dir2/dir3")
+};
+const std::size_t TestDirListSize = sizeof(TestDirList) / sizeof(fs::path);
+
+static const fs::path File = TestFileList[0];
+static const fs::path Dir = TestDirList[0];
+static const fs::path Dir2 = TestDirList[1];
+static const fs::path Dir3 = TestDirList[2];
+static const fs::path SymlinkToFile = makePath("symlink_to_empty_file");
+static const fs::path SymlinkToDir = makePath("symlink_to_dir");
+static const fs::path BadSymlink = makePath("bad_symlink");
+static const fs::path DNE = makePath("DNE");
+static const fs::path EmptyFile = TestFileList[0];
+static const fs::path NonEmptyFile = TestFileList[1];
+static const fs::path CharFile = "/dev/null"; // Hopefully this exists
+
+static const fs::path DirIterationList[] = {
+ makePath("dir1/dir2"),
+ makePath("dir1/file1"),
+ makePath("dir1/file2")
+};
+const std::size_t DirIterationListSize = sizeof(DirIterationList)
+ / sizeof(fs::path);
+
+static const fs::path DirIterationListDepth1[] = {
+ makePath("dir1/dir2/afile3"),
+ makePath("dir1/dir2/dir3"),
+ makePath("dir1/dir2/symlink_to_dir3"),
+ makePath("dir1/dir2/file4"),
+};
+
+static const fs::path RecDirIterationList[] = {
+ makePath("dir1/dir2"),
+ makePath("dir1/file1"),
+ makePath("dir1/file2"),
+ makePath("dir1/dir2/afile3"),
+ makePath("dir1/dir2/dir3"),
+ makePath("dir1/dir2/symlink_to_dir3"),
+ makePath("dir1/dir2/file4"),
+ makePath("dir1/dir2/dir3/file5")
+};
+
+static const fs::path RecDirFollowSymlinksIterationList[] = {
+ makePath("dir1/dir2"),
+ makePath("dir1/file1"),
+ makePath("dir1/file2"),
+ makePath("dir1/dir2/afile3"),
+ makePath("dir1/dir2/dir3"),
+ makePath("dir1/dir2/file4"),
+ makePath("dir1/dir2/dir3/file5"),
+ makePath("dir1/dir2/symlink_to_dir3"),
+ makePath("dir1/dir2/symlink_to_dir3/file5"),
+};
+
+} // namespace StaticEnv
+
+#endif // LIBCXX_FILESYSTEM_STATIC_TEST_ROOT
+
+#ifndef LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT
+#warning LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT must be defined
+#else // LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT
+
+#ifndef LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER
+#error LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER must be defined
+#endif
+
+struct scoped_test_env
+{
+ scoped_test_env() : test_root(random_env_path())
+ { fs_helper_run(fs_make_cmd("init_test_directory", test_root)); }
+
+ ~scoped_test_env()
+ { fs_helper_run(fs_make_cmd("destroy_test_directory", test_root)); }
+
+ scoped_test_env(scoped_test_env const &) = delete;
+ scoped_test_env & operator=(scoped_test_env const &) = delete;
+
+ fs::path make_env_path(std::string p) { return sanitize_path(p); }
+
+ std::string sanitize_path(std::string raw) {
+ assert(raw.find("..") == std::string::npos);
+ std::string const& root = test_root.native();
+ if (root.compare(0, root.size(), raw, 0, root.size()) != 0) {
+ assert(raw.front() != '\\');
+ fs::path tmp(test_root);
+ tmp /= raw;
+ return std::move(const_cast<std::string&>(tmp.native()));
+ }
+ return raw;
+ }
+
+ std::string create_file(std::string filename, std::size_t size = 0) {
+ filename = sanitize_path(std::move(filename));
+ std::string out_str(size, 'a');
+ {
+ std::ofstream out(filename.c_str());
+ out << out_str;
+ }
+ return filename;
+ }
+
+ std::string create_dir(std::string filename) {
+ filename = sanitize_path(std::move(filename));
+ fs_helper_run(fs_make_cmd("create_dir", filename));
+ return filename;
+ }
+
+ std::string create_symlink(std::string source, std::string to) {
+ source = sanitize_path(std::move(source));
+ to = sanitize_path(std::move(to));
+ fs_helper_run(fs_make_cmd("create_symlink", source, to));
+ return to;
+ }
+
+ std::string create_hardlink(std::string source, std::string to) {
+ source = sanitize_path(std::move(source));
+ to = sanitize_path(std::move(to));
+ fs_helper_run(fs_make_cmd("create_hardlink", source, to));
+ return to;
+ }
+
+ std::string create_fifo(std::string file) {
+ file = sanitize_path(std::move(file));
+ fs_helper_run(fs_make_cmd("create_fifo", file));
+ return file;
+ }
+
+ // OS X and FreeBSD doesn't support socket files so we shouldn't even
+ // allow tests to call this unguarded.
+#if !defined(__FreeBSD__) && !defined(__APPLE__)
+ std::string create_socket(std::string file) {
+ file = sanitize_path(std::move(file));
+ fs_helper_run(fs_make_cmd("create_socket", file));
+ return file;
+ }
+#endif
+
+ fs::path const test_root;
+
+private:
+ static char to_hex(int ch) {
+ return ch < 10 ? static_cast<char>('0' + ch)
+ : static_cast<char>('a' + (ch - 10));
+ }
+
+ static char random_hex_char() {
+ static std::mt19937 rd { std::random_device{}() };
+ static std::uniform_int_distribution<int> mrand{0, 15};
+ return to_hex( mrand(rd) );
+ }
+
+ static std::string unique_path_suffix() {
+ std::string model = "test.%%%%%%";
+ for (auto & ch : model) {
+ if (ch == '%') ch = random_hex_char();
+ }
+ return model;
+ }
+
+ // This could potentially introduce a filesystem race with other tests
+ // running at the same time, but oh well, it's just test code.
+ static inline fs::path random_env_path() {
+ static const char* env_path = LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT;
+ fs::path p = fs::path(env_path) / unique_path_suffix();
+ assert(p.parent_path() == env_path);
+ return p;
+ }
+
+ static inline std::string make_arg(std::string const& arg) {
+ return "'" + arg + "'";
+ }
+
+ static inline std::string make_arg(std::size_t arg) {
+ return std::to_string(arg);
+ }
+
+ template <class T>
+ static inline std::string
+ fs_make_cmd(std::string const& cmd_name, T const& arg) {
+ return cmd_name + "(" + make_arg(arg) + ")";
+ }
+
+ template <class T, class U>
+ static inline std::string
+ fs_make_cmd(std::string const& cmd_name, T const& arg1, U const& arg2) {
+ return cmd_name + "(" + make_arg(arg1) + ", " + make_arg(arg2) + ")";
+ }
+
+ static inline void fs_helper_run(std::string const& raw_cmd) {
+ // check that the fs test root in the enviroment matches what we were
+ // compiled with.
+ static bool checked = checkDynamicTestRoot();
+ std::string cmd = LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER;
+ cmd += " \"" + raw_cmd + "\"";
+ int ret = std::system(cmd.c_str());
+ assert(ret == 0);
+ }
+
+ static bool checkDynamicTestRoot() {
+ // LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT is expected not to contain symlinks.
+ char* fs_root = std::getenv("LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT");
+ if (!fs_root) {
+ std::printf("ERROR: LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT must be a defined "
+ "environment variable when running the test.\n");
+ std::abort();
+ }
+ if (std::string(fs_root) != LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT) {
+ std::printf("ERROR: LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT enviroment variable"
+ " must have the same value as when the test was compiled.\n");
+ std::printf(" Current Value: '%s'\n", fs_root);
+ std::printf(" Expected Value: '%s'\n", LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT);
+ std::abort();
+ }
+ return true;
+ }
+
+};
+
+#endif // LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT
+
+// Misc test types
+
+#define CONCAT2(LHS, RHS) LHS##RHS
+#define CONCAT(LHS, RHS) CONCAT2(LHS, RHS)
+#define MKSTR(Str) {Str, CONCAT(L, Str), CONCAT(u, Str), CONCAT(U, Str)}
+
+struct MultiStringType {
+ const char* s;
+ const wchar_t* w;
+ const char16_t* u16;
+ const char32_t* u32;
+
+ operator const char* () const { return s; }
+ operator const wchar_t* () const { return w; }
+ operator const char16_t* () const { return u16; }
+ operator const char32_t* () const { return u32; }
+};
+
+const MultiStringType PathList[] = {
+ MKSTR(""),
+ MKSTR(" "),
+ MKSTR("//"),
+ MKSTR("."),
+ MKSTR(".."),
+ MKSTR("foo"),
+ MKSTR("/"),
+ MKSTR("/foo"),
+ MKSTR("foo/"),
+ MKSTR("/foo/"),
+ MKSTR("foo/bar"),
+ MKSTR("/foo/bar"),
+ MKSTR("//net"),
+ MKSTR("//net/foo"),
+ MKSTR("///foo///"),
+ MKSTR("///foo///bar"),
+ MKSTR("/."),
+ MKSTR("./"),
+ MKSTR("/.."),
+ MKSTR("../"),
+ MKSTR("foo/."),
+ MKSTR("foo/.."),
+ MKSTR("foo/./"),
+ MKSTR("foo/./bar"),
+ MKSTR("foo/../"),
+ MKSTR("foo/../bar"),
+ MKSTR("c:"),
+ MKSTR("c:/"),
+ MKSTR("c:foo"),
+ MKSTR("c:/foo"),
+ MKSTR("c:foo/"),
+ MKSTR("c:/foo/"),
+ MKSTR("c:/foo/bar"),
+ MKSTR("prn:"),
+ MKSTR("c:\\"),
+ MKSTR("c:\\foo"),
+ MKSTR("c:foo\\"),
+ MKSTR("c:\\foo\\"),
+ MKSTR("c:\\foo/"),
+ MKSTR("c:/foo\\bar"),
+ MKSTR("//"),
+ MKSTR("/finally/we/need/one/really/really/really/really/really/really/really/long/string")
+};
+const unsigned PathListSize = sizeof(PathList) / sizeof(MultiStringType);
+
+template <class Iter>
+Iter IterEnd(Iter B) {
+ using VT = typename std::iterator_traits<Iter>::value_type;
+ for (; *B != VT{}; ++B)
+ ;
+ return B;
+}
+
+template <class CharT>
+const CharT* StrEnd(CharT const* P) {
+ return IterEnd(P);
+}
+
+template <class CharT>
+std::size_t StrLen(CharT const* P) {
+ return StrEnd(P) - P;
+}
+
+// Testing the allocation behavior of the code_cvt functions requires
+// *knowing* that the allocation was not done by "path::__str_".
+// This hack forces path to allocate enough memory.
+inline void PathReserve(fs::path& p, std::size_t N) {
+ auto const& native_ref = p.native();
+ const_cast<std::string&>(native_ref).reserve(N);
+}
+
+template <class Iter1, class Iter2>
+bool checkCollectionsEqual(
+ Iter1 start1, Iter1 const end1
+ , Iter2 start2, Iter2 const end2
+ )
+{
+ while (start1 != end1 && start2 != end2) {
+ if (*start1 != *start2) {
+ return false;
+ }
+ ++start1; ++start2;
+ }
+ return (start1 == end1 && start2 == end2);
+}
+
+
+template <class Iter1, class Iter2>
+bool checkCollectionsEqualBackwards(
+ Iter1 const start1, Iter1 end1
+ , Iter2 const start2, Iter2 end2
+ )
+{
+ while (start1 != end1 && start2 != end2) {
+ --end1; --end2;
+ if (*end1 != *end2) {
+ return false;
+ }
+ }
+ return (start1 == end1 && start2 == end2);
+}
+
+// We often need to test that the error_code was cleared if no error occurs
+// this function returns a error_code which is set to an error that will
+// never be returned by the filesystem functions.
+inline std::error_code GetTestEC() {
+ return std::make_error_code(std::errc::address_family_not_supported);
+}
+
+// Provide our own Sleep routine since std::this_thread::sleep_for is not
+// available in single-threaded mode.
+void SleepFor(std::chrono::seconds dur) {
+ using namespace std::chrono;
+#if defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK)
+ using Clock = system_clock;
+#else
+ using Clock = steady_clock;
+#endif
+ const auto wake_time = Clock::now() + dur;
+ while (Clock::now() < wake_time)
+ ;
+}
+
+#endif /* FILESYSTEM_TEST_HELPER_HPP */
diff --git a/test/support/hexfloat.h b/test/support/hexfloat.h
index 7ef093714fed0..19008d1d54abb 100644
--- a/test/support/hexfloat.h
+++ b/test/support/hexfloat.h
@@ -15,7 +15,6 @@
#ifndef HEXFLOAT_H
#define HEXFLOAT_H
-#include <algorithm>
#include <cmath>
#include <climits>
@@ -23,13 +22,26 @@ template <class T>
class hexfloat
{
T value_;
+
+ static int CountLeadingZeros(unsigned long long n) {
+ const std::size_t Digits = sizeof(unsigned long long) * CHAR_BIT;
+ const unsigned long long TopBit = 1ull << (Digits - 1);
+ if (n == 0) return Digits;
+ int LeadingZeros = 0;
+ while ((n & TopBit) == 0) {
+ ++LeadingZeros;
+ n <<= 1;
+ }
+ return LeadingZeros;
+ }
+
public:
hexfloat(long long m1, unsigned long long m0, int exp)
{
- const std::size_t n = sizeof(unsigned long long) * CHAR_BIT;
+ const std::size_t Digits = sizeof(unsigned long long) * CHAR_BIT;
int s = m1 < 0 ? -1 : 1;
- value_ = std::ldexp(m1 + s * std::ldexp(T(m0), -static_cast<int>(n -
- std::__clz(m0)/4*4)), exp);
+ int exp2 = -static_cast<int>(Digits - CountLeadingZeros(m0)/4*4);
+ value_ = std::ldexp(m1 + s * std::ldexp(T(m0), exp2), exp);
}
operator T() const {return value_;}
diff --git a/test/support/is_transparent.h b/test/support/is_transparent.h
index 58255248abc9c..d76b00536b526 100644
--- a/test/support/is_transparent.h
+++ b/test/support/is_transparent.h
@@ -10,7 +10,7 @@
#ifndef TRANSPARENT_H
#define TRANSPARENT_H
-// testing transparent
+// testing transparent
#if _LIBCPP_STD_VER > 11
struct transparent_less
@@ -63,7 +63,7 @@ struct C2Int { // comparable to int
private:
int i_;
};
-
+
bool operator <(int rhs, const C2Int& lhs) { return rhs < lhs.get(); }
bool operator <(const C2Int& rhs, const C2Int& lhs) { return rhs.get() < lhs.get(); }
bool operator <(const C2Int& rhs, int lhs) { return rhs.get() < lhs; }
diff --git a/test/support/min_allocator.h b/test/support/min_allocator.h
index 5e3ae5d2a136b..701159e0481a2 100644
--- a/test/support/min_allocator.h
+++ b/test/support/min_allocator.h
@@ -11,6 +11,9 @@
#define MIN_ALLOCATOR_H
#include <cstddef>
+#include <cstdlib>
+#include <cstddef>
+#include <cassert>
#include "test_macros.h"
@@ -39,8 +42,59 @@ public:
friend bool operator!=(bare_allocator x, bare_allocator y) {return !(x == y);}
};
+struct malloc_allocator_base {
+ static size_t alloc_count;
+ static size_t dealloc_count;
+ static bool disable_default_constructor;
+
+ static size_t outstanding_alloc() {
+ assert(alloc_count >= dealloc_count);
+ return (alloc_count - dealloc_count);
+ }
+
+ static void reset() {
+ assert(outstanding_alloc() == 0);
+ disable_default_constructor = false;
+ alloc_count = 0;
+ dealloc_count = 0;
+ }
+};
+
+
+size_t malloc_allocator_base::alloc_count = 0;
+size_t malloc_allocator_base::dealloc_count = 0;
+bool malloc_allocator_base::disable_default_constructor = false;
+
+
+template <class T>
+class malloc_allocator : public malloc_allocator_base
+{
+public:
+ typedef T value_type;
+
+ malloc_allocator() TEST_NOEXCEPT { assert(!disable_default_constructor); }
+
+ template <class U>
+ malloc_allocator(malloc_allocator<U>) TEST_NOEXCEPT {}
+
+ T* allocate(std::size_t n)
+ {
+ ++alloc_count;
+ return static_cast<T*>(std::malloc(n*sizeof(T)));
+ }
+
+ void deallocate(T* p, std::size_t)
+ {
+ ++dealloc_count;
+ std::free(static_cast<void*>(p));
+ }
+
+ friend bool operator==(malloc_allocator, malloc_allocator) {return true;}
+ friend bool operator!=(malloc_allocator x, malloc_allocator y) {return !(x == y);}
+};
+
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
#include <memory>
@@ -286,6 +340,6 @@ public:
friend bool operator!=(min_allocator x, min_allocator y) {return !(x == y);}
};
-#endif // __cplusplus >= 201103L
+#endif // TEST_STD_VER >= 11
#endif // MIN_ALLOCATOR_H
diff --git a/test/support/nasty_containers.hpp b/test/support/nasty_containers.hpp
index 5a2e19505424b..b571469227d41 100644
--- a/test/support/nasty_containers.hpp
+++ b/test/support/nasty_containers.hpp
@@ -7,9 +7,10 @@
//
//===----------------------------------------------------------------------===//
-#ifndef NASTY_VECTOR_H
-#define NASTY_VECTOR_H
+#ifndef NASTY_CONTAINERS_H
+#define NASTY_CONTAINERS_H
+#include <cassert>
#include <vector>
#include <list>
@@ -99,7 +100,7 @@ public:
{ return v_.emplace(pos, std::forward<Args>(args)...); }
#endif
#endif
-
+
iterator insert(const_iterator pos, const value_type& x) { return v_.insert(pos, x); }
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
iterator insert(const_iterator pos, value_type&& x) { return v_.insert(pos, std::forward<value_type>(x)); }
@@ -123,10 +124,10 @@ public:
void swap(nasty_vector &nv) _NOEXCEPT_(std::__is_nothrow_swappable<nested_container>::value)
{ v_.swap(nv.v_); }
-
- nasty_vector *operator &() { return nullptr; } // nasty
- const nasty_vector *operator &() const { return nullptr; } // nasty
-
+
+ nasty_vector *operator &() { assert(false); return nullptr; } // nasty
+ const nasty_vector *operator &() const { assert(false); return nullptr; } // nasty
+
nested_container v_;
};
@@ -220,7 +221,7 @@ public:
{ return l_.emplace(pos, std::forward<Args>(args)...); }
#endif
#endif
-
+
iterator insert(const_iterator pos, const value_type& x) { return l_.insert(pos, x); }
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
iterator insert(const_iterator pos, value_type&& x) { return l_.insert(pos, std::forward<value_type>(x)); }
@@ -242,7 +243,7 @@ public:
void swap(nasty_list &nl) _NOEXCEPT_(std::__is_nothrow_swappable<nested_container>::value)
{ l_.swap(nl.l_); }
-
+
void clear() _NOEXCEPT { l_.clear(); }
// void splice(const_iterator position, list& x);
@@ -253,7 +254,7 @@ public:
// const_iterator last);
// void splice(const_iterator position, list&& x, const_iterator first,
// const_iterator last);
-//
+//
// void remove(const value_type& value);
// template <class Pred> void remove_if(Pred pred);
// void unique();
@@ -270,8 +271,8 @@ public:
// void sort(Compare comp);
// void reverse() noexcept;
- nasty_list *operator &() { return nullptr; } // nasty
- const nasty_list *operator &() const { return nullptr; } // nasty
+ nasty_list *operator &() { assert(false); return nullptr; } // nasty
+ const nasty_list *operator &() const { assert(false); return nullptr; } // nasty
nested_container l_;
};
@@ -279,4 +280,30 @@ public:
template <class T>
bool operator==(const nasty_list<T>& x, const nasty_list<T>& y) { return x.l_ == y.l_; }
+// Not really a mutex, but can play one in tests
+class nasty_mutex
+{
+public:
+ nasty_mutex() _NOEXCEPT {}
+ ~nasty_mutex() {}
+
+ nasty_mutex *operator& () { assert(false); return nullptr; }
+ template <typename T>
+ void operator, (const T &) { assert(false); }
+
+private:
+ nasty_mutex(const nasty_mutex&) { assert(false); }
+ nasty_mutex& operator=(const nasty_mutex&) { assert(false); return *this; }
+
+public:
+ void lock() {}
+ bool try_lock() _NOEXCEPT { return true; }
+ void unlock() _NOEXCEPT {}
+
+ // Shared ownership
+ void lock_shared() {}
+ bool try_lock_shared() { return true; }
+ void unlock_shared() {}
+};
+
#endif
diff --git a/test/support/platform_support.h b/test/support/platform_support.h
index 233e721ff5155..f4c2247e0dfbc 100644
--- a/test/support/platform_support.h
+++ b/test/support/platform_support.h
@@ -15,8 +15,6 @@
#ifndef PLATFORM_SUPPORT_H
#define PLATFORM_SUPPORT_H
-#include <__config>
-
// locale names
#ifdef _WIN32
// WARNING: Windows does not support UTF-8 codepages.
@@ -54,8 +52,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string>
-#if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
-#include <io.h> // _mktemp
+#if defined(_WIN32) || defined(__MINGW32__)
+#include <io.h> // _mktemp_s
#else
#include <unistd.h> // close
#endif
@@ -67,17 +65,20 @@ extern "C" {
}
#endif
-#ifndef _LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE
+#ifndef __CloudABI__
inline
-std::string
-get_temp_file_name()
+std::string get_temp_file_name()
{
-#if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
- char Path[MAX_PATH+1];
- char FN[MAX_PATH+1];
+#if defined(__MINGW32__)
+ char Path[MAX_PATH + 1];
+ char FN[MAX_PATH + 1];
do { } while (0 == GetTempPath(MAX_PATH+1, Path));
do { } while (0 == GetTempFileName(Path, "libcxx", 0, FN));
return FN;
+#elif defined(_WIN32)
+ char Name[] = "libcxx.XXXXXX";
+ if (_mktemp_s(Name, sizeof(Name)) != 0) abort();
+ return Name;
#else
std::string Name;
int FD = -1;
@@ -93,6 +94,6 @@ get_temp_file_name()
return Name;
#endif
}
-#endif // _LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE
+#endif // __CloudABI__
#endif // PLATFORM_SUPPORT_H
diff --git a/test/support/propagate_const_helpers.h b/test/support/propagate_const_helpers.h
new file mode 100644
index 0000000000000..581565a342708
--- /dev/null
+++ b/test/support/propagate_const_helpers.h
@@ -0,0 +1,119 @@
+ // A lightweight class, with pointer-like methods, that contains an int
+struct X
+{
+ int i_;
+
+ constexpr const int &operator*() const { return i_; }
+ constexpr int &operator*() { return i_; }
+ constexpr const int *get() const { return &i_; }
+ constexpr int *get() { return &i_; }
+ constexpr const int *operator->() const { return &i_; }
+ constexpr int *operator->() { return &i_; }
+
+ constexpr X(int i) : i_(i) {}
+};
+
+struct XWithImplicitIntStarConversion
+{
+ int i_;
+
+ constexpr const int &operator*() const { return i_; }
+ constexpr int &operator*() { return i_; }
+ constexpr const int *get() const { return &i_; }
+ constexpr int *get() { return &i_; }
+ constexpr const int *operator->() const { return &i_; }
+ constexpr int *operator->() { return &i_; }
+ constexpr operator int* () { return &i_; }
+
+ constexpr XWithImplicitIntStarConversion(int i) : i_(i) {}
+};
+
+struct XWithImplicitConstIntStarConversion
+{
+ int i_;
+
+ constexpr const int &operator*() const { return i_; }
+ constexpr int &operator*() { return i_; }
+ constexpr const int *get() const { return &i_; }
+ constexpr int *get() { return &i_; }
+ constexpr const int *operator->() const { return &i_; }
+ constexpr int *operator->() { return &i_; }
+ constexpr operator const int* () const { return &i_; }
+
+ constexpr XWithImplicitConstIntStarConversion(int i) : i_(i) {}
+};
+
+struct ExplicitX
+{
+ int i_;
+
+ constexpr const int &operator*() const { return i_; }
+ constexpr int &operator*() { return i_; }
+ constexpr const int *get() const { return &i_; }
+ constexpr int *get() { return &i_; }
+ constexpr const int *operator->() const { return &i_; }
+ constexpr int *operator->() { return &i_; }
+
+ constexpr explicit ExplicitX(int i) : i_(i) {}
+};
+
+struct MoveConstructibleFromX
+{
+ int i_;
+
+ constexpr const int &operator*() const { return i_; }
+ constexpr int &operator*() { return i_; }
+ constexpr const int *get() const { return &i_; }
+ constexpr int *get() { return &i_; }
+ constexpr const int *operator->() const { return &i_; }
+ constexpr int *operator->() { return &i_; }
+
+ constexpr MoveConstructibleFromX(int i) : i_(i) {}
+ constexpr MoveConstructibleFromX(X&& x) : i_(x.i_) {}
+};
+
+struct ExplicitMoveConstructibleFromX
+{
+ int i_;
+
+ constexpr const int &operator*() const { return i_; }
+ constexpr int &operator*() { return i_; }
+ constexpr const int *get() const { return &i_; }
+ constexpr int *get() { return &i_; }
+ constexpr const int *operator->() const { return &i_; }
+ constexpr int *operator->() { return &i_; }
+
+ constexpr ExplicitMoveConstructibleFromX(int i) : i_(i) {}
+ constexpr explicit ExplicitMoveConstructibleFromX(X&& x) : i_(x.i_) {}
+};
+
+struct CopyConstructibleFromX
+{
+ int i_;
+
+ constexpr const int &operator*() const { return i_; }
+ constexpr int &operator*() { return i_; }
+ constexpr const int *get() const { return &i_; }
+ constexpr int *get() { return &i_; }
+ constexpr const int *operator->() const { return &i_; }
+ constexpr int *operator->() { return &i_; }
+
+ constexpr CopyConstructibleFromX(int i) : i_(i) {}
+ constexpr CopyConstructibleFromX(const X& x) : i_(x.i_) {}
+};
+
+struct ExplicitCopyConstructibleFromX
+{
+ int i_;
+
+ constexpr const int &operator*() const { return i_; }
+ constexpr int &operator*() { return i_; }
+ constexpr const int *get() const { return &i_; }
+ constexpr int *get() { return &i_; }
+ constexpr const int *operator->() const { return &i_; }
+ constexpr int *operator->() { return &i_; }
+
+ constexpr ExplicitCopyConstructibleFromX(int i) : i_(i) {}
+ constexpr explicit ExplicitCopyConstructibleFromX(const X& x) : i_(x.i_) {}
+};
+
diff --git a/test/support/rapid-cxx-test.hpp b/test/support/rapid-cxx-test.hpp
new file mode 100644
index 0000000000000..a25bda53109cf
--- /dev/null
+++ b/test/support/rapid-cxx-test.hpp
@@ -0,0 +1,847 @@
+#ifndef RAPID_CXX_TEST_HPP
+#define RAPID_CXX_TEST_HPP
+
+# include <cstddef>
+# include <cstdlib>
+# include <cstdio>
+# include <cstring>
+# include <cassert>
+
+#include "test_macros.h"
+
+#if !defined(RAPID_CXX_TEST_NO_SYSTEM_HEADER) || !defined(__GNUC__)
+#pragma GCC system_header
+#endif
+
+# define RAPID_CXX_TEST_PP_CAT(x, y) RAPID_CXX_TEST_PP_CAT_2(x, y)
+# define RAPID_CXX_TEST_PP_CAT_2(x, y) x##y
+
+# define RAPID_CXX_TEST_PP_STR(...) RAPID_CXX_TEST_PP_STR_2(__VA_ARGS__)
+# define RAPID_CXX_TEST_PP_STR_2(...) #__VA_ARGS__
+
+# if defined(__GNUC__)
+# define TEST_FUNC_NAME() __PRETTY_FUNCTION__
+# define RAPID_CXX_TEST_UNUSED __attribute__((unused))
+# else
+# define TEST_FUNC_NAME() __func__
+# define RAPID_CXX_TEST_UNUSED
+# endif
+
+////////////////////////////////////////////////////////////////////////////////
+// TEST_SUITE
+////////////////////////////////////////////////////////////////////////////////
+# define TEST_SUITE(Name) \
+namespace Name \
+{ \
+ inline ::rapid_cxx_test::test_suite & get_test_suite() \
+ { \
+ static ::rapid_cxx_test::test_suite m_suite(#Name); \
+ return m_suite; \
+ } \
+ \
+ inline int unit_test_main(int, char**) \
+ { \
+ ::rapid_cxx_test::test_runner runner(get_test_suite()); \
+ return runner.run(); \
+ } \
+} \
+int main(int argc, char **argv) \
+{ \
+ return Name::unit_test_main(argc, argv); \
+} \
+namespace Name \
+{ /* namespace closed in TEST_SUITE_END */
+#
+
+////////////////////////////////////////////////////////////////////////////////
+// TEST_SUITE_END
+////////////////////////////////////////////////////////////////////////////////
+# define TEST_SUITE_END() \
+} /* namespace opened in TEST_SUITE(...) */
+#
+
+////////////////////////////////////////////////////////////////////////////////
+// TEST_CASE
+////////////////////////////////////////////////////////////////////////////////
+
+# if !defined(__clang__)
+#
+# define TEST_CASE(Name) \
+ void Name(); \
+ static void RAPID_CXX_TEST_PP_CAT(Name, _invoker)() \
+ { \
+ Name(); \
+ } \
+ static ::rapid_cxx_test::registrar \
+ RAPID_CXX_TEST_PP_CAT(rapid_cxx_test_registrar_, Name)( \
+ get_test_suite() \
+ , ::rapid_cxx_test::test_case(__FILE__, #Name, __LINE__, & RAPID_CXX_TEST_PP_CAT(Name, _invoker)) \
+ ); \
+ void Name()
+#
+# else /* __clang__ */
+#
+# define TEST_CASE(Name) \
+ void Name(); \
+ static void RAPID_CXX_TEST_PP_CAT(Name, _invoker)() \
+ { \
+ Name(); \
+ } \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") \
+ static ::rapid_cxx_test::registrar \
+ RAPID_CXX_TEST_PP_CAT(rapid_cxx_test_registrar_, Name)( \
+ get_test_suite() \
+ , ::rapid_cxx_test::test_case(__FILE__, #Name, __LINE__, & RAPID_CXX_TEST_PP_CAT(Name, _invoker)) \
+ ); \
+ _Pragma("clang diagnostic pop") \
+ void Name()
+#
+# endif /* !defined(__clang__) */
+
+
+# define TEST_SET_CHECKPOINT() ::rapid_cxx_test::set_checkpoint(__FILE__, TEST_FUNC_NAME(), __LINE__)
+
+#define RAPID_CXX_TEST_OUTCOME()
+
+////////////////////////////////////////////////////////////////////////////////
+// TEST_UNSUPPORTED
+////////////////////////////////////////////////////////////////////////////////
+# define TEST_UNSUPPORTED() \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::unsupported, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "", "" \
+ ); \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ return; \
+ } while (false)
+#
+
+
+////////////////////////////////////////////////////////////////////////////////
+// BASIC ASSERTIONS
+////////////////////////////////////////////////////////////////////////////////
+# define TEST_WARN(...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_WARN(" #__VA_ARGS__ ")", "" \
+ ); \
+ if (not (__VA_ARGS__)) { \
+ m_f.type = ::rapid_cxx_test::failure_type::warn; \
+ } \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ } while (false)
+#
+
+# define TEST_CHECK(...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_CHECK(" #__VA_ARGS__ ")", "" \
+ ); \
+ if (not (__VA_ARGS__)) { \
+ m_f.type = ::rapid_cxx_test::failure_type::check; \
+ } \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ } while (false)
+#
+
+# define TEST_REQUIRE(...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_REQUIRE(" #__VA_ARGS__ ")", "" \
+ ); \
+ if (not (__VA_ARGS__)) { \
+ m_f.type = ::rapid_cxx_test::failure_type::require; \
+ } \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ if (m_f.type != ::rapid_cxx_test::failure_type::none) { \
+ return; \
+ } \
+ } while (false)
+#
+
+# define TEST_ASSERT(...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_ASSERT(" #__VA_ARGS__ ")", "" \
+ ); \
+ if (not (__VA_ARGS__)) { \
+ m_f.type = ::rapid_cxx_test::failure_type::assert; \
+ } \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ if (m_f.type != ::rapid_cxx_test::failure_type::none) { \
+ std::abort(); \
+ } \
+ } while (false)
+#
+
+////////////////////////////////////////////////////////////////////////////////
+// TEST_CHECK_NO_THROW / TEST_CHECK_THROW
+////////////////////////////////////////////////////////////////////////////////
+#ifndef TEST_HAS_NO_EXCEPTIONS
+
+# define TEST_CHECK_NO_THROW(...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_CHECK_NO_THROW(" #__VA_ARGS__ ")", "" \
+ ); \
+ try { \
+ (static_cast<void>(__VA_ARGS__)); \
+ } catch (...) { \
+ m_f.type = ::rapid_cxx_test::failure_type::check; \
+ } \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ } while (false)
+#
+
+# define TEST_CHECK_THROW(Except, ...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_CHECK_THROW(" #Except "," #__VA_ARGS__ ")", "" \
+ ); \
+ try { \
+ (static_cast<void>(__VA_ARGS__)); \
+ m_f.type = ::rapid_cxx_test::failure_type::check; \
+ } catch (Except const &) {} \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ } while (false)
+#
+
+#else // TEST_HAS_NO_EXCEPTIONS
+
+# define TEST_CHECK_NO_THROW(...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_CHECK_NO_THROW(" #__VA_ARGS__ ")", "" \
+ ); \
+ (static_cast<void>(__VA_ARGS__)); \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ } while (false)
+#
+
+#define TEST_CHECK_THROW(Except, ...) ((void)0)
+
+#endif // TEST_HAS_NO_EXCEPTIONS
+
+
+////////////////////////////////////////////////////////////////////////////////
+// TEST_REQUIRE_NO_THROW / TEST_REQUIRE_THROWs
+////////////////////////////////////////////////////////////////////////////////
+#ifndef TEST_HAS_NO_EXCEPTIONS
+
+# define TEST_REQUIRE_NO_THROW(...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_REQUIRE_NO_THROW(" #__VA_ARGS__ ")", "" \
+ ); \
+ try { \
+ (static_cast<void>(__VA_ARGS__)); \
+ } catch (...) { \
+ m_f.type = ::rapid_cxx_test::failure_type::require; \
+ } \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ if (m_f.type != ::rapid_cxx_test::failure_type::none) { \
+ return; \
+ } \
+ } while (false)
+#
+
+# define TEST_REQUIRE_THROW(Except, ...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_REQUIRE_THROW(" #Except "," #__VA_ARGS__ ")", "" \
+ ); \
+ try { \
+ (static_cast<void>(__VA_ARGS__)); \
+ m_f.type = ::rapid_cxx_test::failure_type::require; \
+ } catch (Except const &) {} \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ if (m_f.type != ::rapid_cxx_test::failure_type::none) { \
+ return; \
+ } \
+ } while (false)
+#
+
+#else // TEST_HAS_NO_EXCEPTIONS
+
+# define TEST_REQUIRE_NO_THROW(...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_REQUIRE_NO_THROW(" #__VA_ARGS__ ")", "" \
+ ); \
+ (static_cast<void>(__VA_ARGS__)); \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ } while (false)
+#
+
+#define TEST_REQUIRE_THROW(Except, ...) ((void)0)
+
+#endif // TEST_HAS_NO_EXCEPTIONS
+
+////////////////////////////////////////////////////////////////////////////////
+// TEST_ASSERT_NO_THROW / TEST_ASSERT_THROW
+////////////////////////////////////////////////////////////////////////////////
+#ifndef TEST_HAS_NO_EXCEPTIONS
+
+# define TEST_ASSERT_NO_THROW(...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_ASSERT_NO_THROW(" #__VA_ARGS__ ")", "" \
+ ); \
+ try { \
+ (static_cast<void>(__VA_ARGS__)); \
+ } catch (...) { \
+ m_f.type = ::rapid_cxx_test::failure_type::assert; \
+ } \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ if (m_f.type != ::rapid_cxx_test::failure_type::none) { \
+ std::abort(); \
+ } \
+ } while (false)
+#
+
+# define TEST_ASSERT_THROW(Except, ...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_ASSERT_THROW(" #Except "," #__VA_ARGS__ ")", "" \
+ ); \
+ try { \
+ (static_cast<void>(__VA_ARGS__)); \
+ m_f.type = ::rapid_cxx_test::failure_type::assert; \
+ } catch (Except const &) {} \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ if (m_f.type != ::rapid_cxx_test::failure_type::none) { \
+ std::abort(); \
+ } \
+ } while (false)
+#
+
+#else // TEST_HAS_NO_EXCEPTIONS
+
+# define TEST_ASSERT_NO_THROW(...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_ASSERT_NO_THROW(" #__VA_ARGS__ ")", "" \
+ ); \
+ (static_cast<void>(__VA_ARGS__)); \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ } while (false)
+#
+
+#define TEST_ASSERT_THROW(Except, ...) ((void)0)
+
+#endif // TEST_HAS_NO_EXCEPTIONS
+
+////////////////////////////////////////////////////////////////////////////////
+//
+////////////////////////////////////////////////////////////////////////////////
+
+# define TEST_WARN_EQUAL_COLLECTIONS(...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_WARN_EQUAL_COLLECTIONS(" #__VA_ARGS__ ")", "" \
+ ); \
+ if (not ::rapid_cxx_test::detail::check_equal_collections_impl(__VA_ARGS__)) { \
+ m_f.type = ::rapid_cxx_test::failure_type::warn; \
+ } \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ } while (false)
+#
+
+# define TEST_CHECK_EQUAL_COLLECTIONS(...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_CHECK_EQUAL_COLLECTIONS(" #__VA_ARGS__ ")", "" \
+ ); \
+ if (not ::rapid_cxx_test::detail::check_equal_collections_impl(__VA_ARGS__)) { \
+ m_f.type = ::rapid_cxx_test::failure_type::check; \
+ } \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ } while (false)
+#
+
+# define TEST_REQUIRE_EQUAL_COLLECTIONS(...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_REQUIRE_EQUAL_COLLECTIONS(" #__VA_ARGS__ ")", "" \
+ ); \
+ if (not ::rapid_cxx_test::detail::check_equal_collections_impl(__VA_ARGS__)) { \
+ m_f.type = ::rapid_cxx_test::failure_type::require; \
+ } \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ if (m_f.type != ::rapid_cxx_test::failure_type::none) { \
+ return; \
+ } \
+ } while (false)
+#
+
+# define TEST_ASSERT_EQUAL_COLLECTIONS(...) \
+ do { \
+ TEST_SET_CHECKPOINT(); \
+ ::rapid_cxx_test::test_outcome m_f( \
+ ::rapid_cxx_test::failure_type::none, __FILE__, TEST_FUNC_NAME(), __LINE__ \
+ , "TEST_ASSERT_EQUAL_COLLECTIONS(" #__VA_ARGS__ ")", "" \
+ ); \
+ if (not ::rapid_cxx_test::detail::check_equal_collections_impl(__VA_ARGS__)) { \
+ m_f.type = ::rapid_cxx_test::failure_type::assert; \
+ } \
+ ::rapid_cxx_test::get_reporter().report(m_f); \
+ if (m_f.type != ::rapid_cxx_test::failure_type::none) { \
+ ::std::abort(); \
+ } \
+ } while (false)
+#
+
+namespace rapid_cxx_test
+{
+ typedef void (*invoker_t)();
+
+ ////////////////////////////////////////////////////////////////////////////
+ struct test_case
+ {
+ test_case()
+ : file(""), func(""), line(0), invoke(NULL)
+ {}
+
+ test_case(const char* file1, const char* func1, std::size_t line1,
+ invoker_t invoke1)
+ : file(file1), func(func1), line(line1), invoke(invoke1)
+ {}
+
+ const char *file;
+ const char *func;
+ std::size_t line;
+ invoker_t invoke;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+ struct failure_type
+ {
+ enum enum_type {
+ none,
+ unsupported,
+ warn,
+ check,
+ require,
+ assert,
+ uncaught_exception
+ };
+ };
+
+ typedef failure_type::enum_type failure_type_t;
+
+ ////////////////////////////////////////////////////////////////////////////
+ struct test_outcome
+ {
+ test_outcome()
+ : type(failure_type::none),
+ file(""), func(""), line(0),
+ expression(""), message("")
+ {}
+
+ test_outcome(failure_type_t type1, const char* file1, const char* func1,
+ std::size_t line1, const char* expression1,
+ const char* message1)
+ : type(type1), file(file1), func(func1), line(line1),
+ expression(expression1), message(message1)
+ {
+ trim_func_string();
+ }
+
+ failure_type_t type;
+ const char *file;
+ const char *func;
+ std::size_t line;
+ const char *expression;
+ const char *message;
+
+ private:
+ void trim_file_string() {
+ const char* f_start = file;
+ const char* prev_start = f_start;
+ const char* last_start = f_start;
+ char last;
+ while ((last = *f_start) != '\0') {
+ ++f_start;
+ if (last == '/' && *f_start) {
+ prev_start = last_start;
+ last_start = f_start;
+ }
+ }
+ file = prev_start;
+ }
+ void trim_func_string() {
+ const char* void_loc = ::strstr(func, "void ");
+ if (void_loc == func) {
+ func += strlen("void ");
+ }
+ const char* namespace_loc = ::strstr(func, "::");
+ if (namespace_loc) {
+ func = namespace_loc + 2;
+ }
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+ struct checkpoint
+ {
+ const char *file;
+ const char *func;
+ std::size_t line;
+ };
+
+ namespace detail
+ {
+ inline checkpoint & global_checkpoint()
+ {
+ static checkpoint cp = {"", "", 0};
+ return cp;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ inline void set_checkpoint(const char* file, const char* func, std::size_t line)
+ {
+ checkpoint& cp = detail::global_checkpoint();
+ cp.file = file;
+ cp.func = func;
+ cp.line = line;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ inline checkpoint const & get_checkpoint()
+ {
+ return detail::global_checkpoint();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ class test_suite
+ {
+ public:
+ typedef test_case const* iterator;
+ typedef iterator const_iterator;
+
+ public:
+ test_suite(const char *xname)
+ : m_name(xname), m_tests(), m_size(0)
+ {
+ assert(xname);
+ }
+
+ public:
+ const char *name() const { return m_name; }
+
+ std::size_t size() const { return m_size; }
+
+ test_case const & operator[](std::size_t i) const
+ {
+ assert(i < m_size);
+ return m_tests[i];
+ }
+
+ const_iterator begin() const
+ { return m_tests; }
+
+ const_iterator end() const
+ {
+ return m_tests + m_size;
+ }
+
+ public:
+ std::size_t register_test(test_case tc)
+ {
+ static std::size_t test_case_max = sizeof(m_tests) / sizeof(test_case);
+ assert(m_size < test_case_max);
+ m_tests[m_size] = tc;
+ return m_size++;
+ }
+
+ private:
+ test_suite(test_suite const &);
+ test_suite & operator=(test_suite const &);
+
+ private:
+ const char* m_name;
+ // Since fast compile times in a priority, we use simple containers
+ // with hard limits.
+ test_case m_tests[256];
+ std::size_t m_size;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+ class registrar
+ {
+ public:
+ registrar(test_suite & st, test_case tc)
+ {
+ st.register_test(tc);
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+ class test_reporter
+ {
+ public:
+ test_reporter()
+ : m_testcases(0), m_testcase_failures(0), m_unsupported(0),
+ m_assertions(0), m_warning_failures(0), m_check_failures(0),
+ m_require_failures(0), m_uncaught_exceptions(0), m_failure()
+ {
+ }
+
+ void test_case_begin()
+ {
+ ++m_testcases;
+ clear_failure();
+ }
+
+ void test_case_end()
+ {
+ if (m_failure.type != failure_type::none
+ && m_failure.type != failure_type::unsupported) {
+ ++m_testcase_failures;
+ }
+ }
+
+# if defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wswitch-default"
+# endif
+ // Each assertion and failure is reported through this function.
+ void report(test_outcome o)
+ {
+ ++m_assertions;
+ switch (o.type)
+ {
+ case failure_type::none:
+ break;
+ case failure_type::unsupported:
+ ++m_unsupported;
+ m_failure = o;
+ break;
+ case failure_type::warn:
+ ++m_warning_failures;
+ report_error(o);
+ break;
+ case failure_type::check:
+ ++m_check_failures;
+ report_error(o);
+ m_failure = o;
+ break;
+ case failure_type::require:
+ ++m_require_failures;
+ report_error(o);
+ m_failure = o;
+ break;
+ case failure_type::assert:
+ report_error(o);
+ break;
+ case failure_type::uncaught_exception:
+ ++m_uncaught_exceptions;
+ std::fprintf(stderr
+ , "Test case FAILED with uncaught exception:\n"
+ " last checkpoint near %s::%lu %s\n\n"
+ , o.file, o.line, o.func
+ );
+ m_failure = o;
+ break;
+ }
+ }
+# if defined(__GNUC__)
+# pragma GCC diagnostic pop
+# endif
+
+ test_outcome current_failure() const
+ {
+ return m_failure;
+ }
+
+ void clear_failure()
+ {
+ m_failure.type = failure_type::none;
+ m_failure.file = "";
+ m_failure.func = "";
+ m_failure.line = 0;
+ m_failure.expression = "";
+ m_failure.message = "";
+ }
+
+ std::size_t test_case_count() const
+ { return m_testcases; }
+
+ std::size_t test_case_failure_count() const
+ { return m_testcase_failures; }
+
+ std::size_t unsupported_count() const
+ { return m_unsupported; }
+
+ std::size_t assertion_count() const
+ { return m_assertions; }
+
+ std::size_t warning_failure_count() const
+ { return m_warning_failures; }
+
+ std::size_t check_failure_count() const
+ { return m_check_failures; }
+
+ std::size_t require_failure_count() const
+ { return m_require_failures; }
+
+ std::size_t failure_count() const
+ { return m_check_failures + m_require_failures + m_uncaught_exceptions; }
+
+ // Print a summary of what was run and the outcome.
+ void print_summary(const char* suitename) const
+ {
+ FILE* out = failure_count() ? stderr : stdout;
+ std::size_t testcases_run = m_testcases - m_unsupported;
+ std::fprintf(out, "Summary for testsuite %s:\n", suitename);
+ std::fprintf(out, " %lu of %lu test cases passed.\n", testcases_run - m_testcase_failures, testcases_run);
+ std::fprintf(out, " %lu of %lu assertions passed.\n", m_assertions - (m_warning_failures + m_check_failures + m_require_failures), m_assertions);
+ std::fprintf(out, " %lu unsupported test case%s.\n", m_unsupported, (m_unsupported != 1 ? "s" : ""));
+ }
+
+ private:
+ test_reporter(test_reporter const &);
+ test_reporter const & operator=(test_reporter const &);
+
+ void report_error(test_outcome o) const
+ {
+ std::fprintf(stderr, "In %s:%lu Assertion %s failed.\n in file: %s\n %s\n"
+ , o.func, o.line, o.expression, o.file, o.message ? o.message : ""
+ );
+ }
+
+ private:
+ // counts of testcases, failed testcases, and unsupported testcases.
+ std::size_t m_testcases;
+ std::size_t m_testcase_failures;
+ std::size_t m_unsupported;
+
+ // counts of assertions and assertion failures.
+ std::size_t m_assertions;
+ std::size_t m_warning_failures;
+ std::size_t m_check_failures;
+ std::size_t m_require_failures;
+ std::size_t m_uncaught_exceptions;
+
+ // The last failure. This is cleared between testcases.
+ test_outcome m_failure;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+ inline test_reporter & get_reporter()
+ {
+ static test_reporter o;
+ return o;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ class test_runner
+ {
+ public:
+ test_runner(test_suite & ts)
+ : m_ts(ts)
+ {}
+
+ public:
+ int run()
+ {
+ // for each testcase
+ for (test_suite::const_iterator b = m_ts.begin(), e = m_ts.end();
+ b != e; ++b)
+ {
+ test_case const& tc = *b;
+ set_checkpoint(tc.file, tc.func, tc.line);
+ get_reporter().test_case_begin();
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ try {
+#endif
+ tc.invoke();
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ } catch (...) {
+ test_outcome o;
+ o.type = failure_type::uncaught_exception;
+ o.file = get_checkpoint().file;
+ o.func = get_checkpoint().func;
+ o.line = get_checkpoint().line;
+ o.expression = "";
+ o.message = "";
+ get_reporter().report(o);
+ }
+#endif
+ get_reporter().test_case_end();
+ }
+ auto exit_code = get_reporter().failure_count() ? EXIT_FAILURE : EXIT_SUCCESS;
+ if (exit_code == EXIT_FAILURE)
+ get_reporter().print_summary(m_ts.name());
+ return exit_code;
+ }
+
+ private:
+ test_runner(test_runner const &);
+ test_runner operator=(test_runner const &);
+
+ test_suite & m_ts;
+ };
+
+ namespace detail
+ {
+ template <class Iter1, class Iter2>
+ bool check_equal_collections_impl(
+ Iter1 start1, Iter1 const end1
+ , Iter2 start2, Iter2 const end2
+ )
+ {
+ while (start1 != end1 && start2 != end2) {
+ if (*start1 != *start2) {
+ return false;
+ }
+ ++start1; ++start2;
+ }
+ return (start1 == end1 && start2 == end2);
+ }
+ } // namespace detail
+
+} // namespace rapid_cxx_test
+
+
+# if defined(__GNUC__)
+# pragma GCC diagnostic pop
+# endif
+
+#endif /* RAPID_CXX_TEST_HPP */
diff --git a/test/support/test.support/test_convertible_header.pass.cpp b/test/support/test.support/test_convertible_header.pass.cpp
new file mode 100644
index 0000000000000..a56b84b4739c5
--- /dev/null
+++ b/test/support/test.support/test_convertible_header.pass.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// "support/test_convertible.hpp"
+
+#include "test_convertible.hpp"
+
+struct ImplicitDefault {
+ ImplicitDefault() {}
+};
+static_assert(test_convertible<ImplicitDefault>(), "Must be convertible");
+
+struct ExplicitDefault {
+ explicit ExplicitDefault() {}
+};
+static_assert(!test_convertible<ExplicitDefault>(), "Must not be convertible");
+
+struct ImplicitInt {
+ ImplicitInt(int) {}
+};
+static_assert(test_convertible<ImplicitInt, int>(), "Must be convertible");
+
+struct ExplicitInt {
+ explicit ExplicitInt(int) {}
+};
+static_assert(!test_convertible<ExplicitInt, int>(), "Must not be convertible");
+
+struct ImplicitCopy {
+ ImplicitCopy(ImplicitCopy const&) {}
+};
+static_assert(test_convertible<ImplicitCopy, ImplicitCopy>(), "Must be convertible");
+
+struct ExplicitCopy {
+ explicit ExplicitCopy(ExplicitCopy const&) {}
+};
+static_assert(!test_convertible<ExplicitCopy, ExplicitCopy>(), "Must not be convertible");
+
+struct ImplicitMove {
+ ImplicitMove(ImplicitMove&&) {}
+};
+static_assert(test_convertible<ImplicitMove, ImplicitMove>(), "Must be convertible");
+
+struct ExplicitMove {
+ explicit ExplicitMove(ExplicitMove&&) {}
+};
+static_assert(!test_convertible<ExplicitMove, ExplicitMove>(), "Must not be convertible");
+
+struct ImplicitArgs {
+ ImplicitArgs(int, int, int) {}
+};
+static_assert(test_convertible<ImplicitArgs, int, int, int>(), "Must be convertible");
+
+struct ExplicitArgs {
+ explicit ExplicitArgs(int, int, int) {}
+};
+static_assert(!test_convertible<ExplicitArgs, int, int, int>(), "Must not be convertible");
+
+int main() {
+ // Nothing to do
+}
diff --git a/test/support/test.support/test_macros_header_exceptions.fail.cpp b/test/support/test.support/test_macros_header_exceptions.fail.cpp
new file mode 100644
index 0000000000000..ade2cd98fe08c
--- /dev/null
+++ b/test/support/test.support/test_macros_header_exceptions.fail.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// "support/test_macros.hpp"
+
+// #define TEST_HAS_NO_EXCEPTIONS
+
+#include "test_macros.h"
+
+int main() {
+#if defined(TEST_HAS_NO_EXCEPTIONS)
+ try { ((void)0); } catch (...) {} // expected-error {{exceptions disabled}}
+#else
+ try { ((void)0); } catch (...) {}
+#error exceptions enabled
+// expected-error@-1 {{exceptions enabled}}
+#endif
+}
diff --git a/test/support/test.support/test_macros_header_exceptions.pass.cpp b/test/support/test.support/test_macros_header_exceptions.pass.cpp
new file mode 100644
index 0000000000000..589e148a00320
--- /dev/null
+++ b/test/support/test.support/test_macros_header_exceptions.pass.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: libcpp-no-exceptions
+
+// "support/test_macros.hpp"
+
+// #define TEST_HAS_NO_EXCEPTIONS
+
+#include "test_macros.h"
+
+#if defined(TEST_HAS_NO_EXCEPTIONS)
+#error macro defined unexpectedly
+#endif
+
+int main() {
+ try { ((void)0); } catch (...) {}
+}
diff --git a/test/support/test.support/test_macros_header_rtti.fail.cpp b/test/support/test.support/test_macros_header_rtti.fail.cpp
new file mode 100644
index 0000000000000..851a6c6014164
--- /dev/null
+++ b/test/support/test.support/test_macros_header_rtti.fail.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// "support/test_macros.hpp"
+
+// #define TEST_HAS_NO_RTTI
+
+#include "test_macros.h"
+
+struct A { virtual ~A() {} };
+struct B : A {};
+
+int main() {
+#if defined(TEST_HAS_NO_RTTI)
+ A* ptr = new B;
+ (void)dynamic_cast<B*>(ptr); // expected-error{{cannot use dynamic_cast}}
+#else
+ A* ptr = new B;
+ (void)dynamic_cast<B*>(ptr);
+#error RTTI enabled
+// expected-error@-1{{RTTI enabled}}
+#endif
+}
diff --git a/test/support/test.support/test_macros_header_rtti.pass.cpp b/test/support/test.support/test_macros_header_rtti.pass.cpp
new file mode 100644
index 0000000000000..d189a0efc2fcb
--- /dev/null
+++ b/test/support/test.support/test_macros_header_rtti.pass.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: libcpp-no-rtti
+
+// "support/test_macros.hpp"
+
+// #define TEST_HAS_NO_RTTI
+
+#include "test_macros.h"
+
+#if defined(TEST_HAS_NO_RTTI)
+#error Macro defined unexpectedly
+#endif
+
+struct A { virtual ~A() {} };
+struct B : A {};
+
+int main() {
+ A* ptr = new B;
+ (void)dynamic_cast<B*>(ptr);
+}
diff --git a/test/support/test_allocator.h b/test/support/test_allocator.h
index 3ca672f89a9be..466c7fabc66d7 100644
--- a/test/support/test_allocator.h
+++ b/test/support/test_allocator.h
@@ -76,18 +76,22 @@ public:
++alloc_count;
return (pointer)::operator new(n * sizeof(T));
}
- void deallocate(pointer p, size_type n)
+ void deallocate(pointer p, size_type)
{assert(data_ >= 0); --alloc_count; ::operator delete((void*)p);}
size_type max_size() const throw()
{return UINT_MAX / sizeof(T);}
+#if TEST_STD_VER < 11
void construct(pointer p, const T& val)
- {::new(p) T(val);}
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
- void construct(pointer p, T&& val)
- {::new(p) T(std::move(val));}
-#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
- void destroy(pointer p) {p->~T();}
-
+ {::new(static_cast<void*>(p)) T(val);}
+#else
+ template <class U> void construct(pointer p, U&& val)
+ {::new(static_cast<void*>(p)) T(std::forward<U>(val));}
+#endif
+ void destroy(pointer p)
+ {
+ p->~T();
+ ((void)p); // Prevent MSVC's spurious unused warning
+ }
friend bool operator==(const test_allocator& x, const test_allocator& y)
{return x.data_ == y.data_;}
friend bool operator!=(const test_allocator& x, const test_allocator& y)
@@ -136,16 +140,17 @@ public:
++alloc_count;
return (pointer)::operator new (n * sizeof(T));
}
- void deallocate(pointer p, size_type n)
+ void deallocate(pointer p, size_type)
{assert(data_ >= 0); --alloc_count; ::operator delete((void*)p); }
size_type max_size() const throw()
{return UINT_MAX / sizeof(T);}
+#if TEST_STD_VER < 11
void construct(pointer p, const T& val)
- {::new(p) T(val);}
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
- void construct(pointer p, T&& val)
- {::new(p) T(std::move(val));}
-#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+ {::new(static_cast<void*>(p)) T(val);}
+#else
+ template <class U> void construct(pointer p, U&& val)
+ {::new(static_cast<void*>(p)) T(std::forward<U>(val));}
+#endif
void destroy(pointer p) {p->~T();}
friend bool operator==(const non_default_test_allocator& x, const non_default_test_allocator& y)
@@ -201,7 +206,7 @@ public:
: data_(a.data_) {}
T* allocate(std::size_t n)
{return (T*)::operator new(n * sizeof(T));}
- void deallocate(T* p, std::size_t n)
+ void deallocate(T* p, std::size_t)
{::operator delete((void*)p);}
other_allocator select_on_container_copy_construction() const
@@ -223,4 +228,82 @@ public:
};
+#if TEST_STD_VER >= 11
+
+struct Ctor_Tag {};
+
+template <typename T> class TaggingAllocator;
+
+struct Tag_X {
+ // All constructors must be passed the Tag type.
+
+ // DefaultInsertable into vector<X, TaggingAllocator<X>>,
+ Tag_X(Ctor_Tag) {}
+ // CopyInsertable into vector<X, TaggingAllocator<X>>,
+ Tag_X(Ctor_Tag, const Tag_X&) {}
+ // MoveInsertable into vector<X, TaggingAllocator<X>>, and
+ Tag_X(Ctor_Tag, Tag_X&&) {}
+
+ // EmplaceConstructible into vector<X, TaggingAllocator<X>> from args.
+ template<typename... Args>
+ Tag_X(Ctor_Tag, Args&&...) { }
+
+ // not DefaultConstructible, CopyConstructible or MoveConstructible.
+ Tag_X() = delete;
+ Tag_X(const Tag_X&) = delete;
+ Tag_X(Tag_X&&) = delete;
+
+ // CopyAssignable.
+ Tag_X& operator=(const Tag_X&) { return *this; }
+
+ // MoveAssignable.
+ Tag_X& operator=(Tag_X&&) { return *this; }
+
+private:
+ // Not Destructible.
+ ~Tag_X() { }
+
+ // Erasable from vector<X, TaggingAllocator<X>>.
+ friend class TaggingAllocator<Tag_X>;
+};
+
+
+template<typename T>
+class TaggingAllocator {
+public:
+ using value_type = T;
+ TaggingAllocator() = default;
+
+ template<typename U>
+ TaggingAllocator(const TaggingAllocator<U>&) { }
+
+ T* allocate(std::size_t n) { return std::allocator<T>{}.allocate(n); }
+
+ void deallocate(T* p, std::size_t n) { std::allocator<T>{}.deallocate(p, n); }
+
+ template<typename... Args>
+ void construct(Tag_X* p, Args&&... args)
+ { ::new((void*)p) Tag_X(Ctor_Tag{}, std::forward<Args>(args)...); }
+
+ template<typename U, typename... Args>
+ void construct(U* p, Args&&... args)
+ { ::new((void*)p) U(std::forward<Args>(args)...); }
+
+ template<typename U, typename... Args>
+ void destroy(U* p)
+ { p->~U(); }
+};
+
+template<typename T, typename U>
+bool
+operator==(const TaggingAllocator<T>&, const TaggingAllocator<U>&)
+{ return true; }
+
+template<typename T, typename U>
+bool
+operator!=(const TaggingAllocator<T>&, const TaggingAllocator<U>&)
+{ return false; }
+#endif
+
+
#endif // TEST_ALLOCATOR_H
diff --git a/test/support/test_convertible.hpp b/test/support/test_convertible.hpp
new file mode 100644
index 0000000000000..787cef6568f28
--- /dev/null
+++ b/test/support/test_convertible.hpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 SUPPORT_TEST_CONVERTIBLE_HPP
+#define SUPPORT_TEST_CONVERTIBLE_HPP
+
+// "test_convertible<Tp, Args...>()" is a metafunction used to check if 'Tp'
+// is implicitly convertible from 'Args...' for any number of arguments,
+// Unlike 'std::is_convertible' which only allows checking for single argument
+// conversions.
+
+#include <type_traits>
+
+#include "test_macros.h"
+
+#if TEST_STD_VER < 11
+#error test_convertible.hpp requires C++11 or newer
+#endif
+
+namespace detail {
+ template <class Tp> void eat_type(Tp);
+
+ template <class Tp, class ...Args>
+ constexpr auto test_convertible_imp(int)
+ -> decltype(eat_type<Tp>({std::declval<Args>()...}), true)
+ { return true; }
+
+ template <class Tp, class ...Args>
+ constexpr auto test_convertible_imp(long) -> bool { return false; }
+}
+
+template <class Tp, class ...Args>
+constexpr bool test_convertible()
+{ return detail::test_convertible_imp<Tp, Args...>(0); }
+
+#endif // SUPPORT_TEST_CONVERTIBLE_HPP \ No newline at end of file
diff --git a/test/support/test_iterators.h b/test/support/test_iterators.h
index d814879fa2727..d4a079971b15a 100644
--- a/test/support/test_iterators.h
+++ b/test/support/test_iterators.h
@@ -12,6 +12,7 @@
#include <iterator>
#include <stdexcept>
+#include <cstddef>
#include <cassert>
#include "test_macros.h"
@@ -335,116 +336,137 @@ struct ThrowingIterator {
typedef const T * pointer;
typedef const T & reference;
- enum ThrowingAction { TAIncrement, TADecrement, TADereference, TAAssignment, TAComparison };
-
-// Constructors
- ThrowingIterator ()
- : begin_(nullptr), end_(nullptr), current_(nullptr), action_(TADereference), index_(0) {}
- ThrowingIterator (const T *first, const T *last, size_t index = 0, ThrowingAction action = TADereference)
- : begin_(first), end_(last), current_(first), action_(action), index_(index) {}
- ThrowingIterator (const ThrowingIterator &rhs)
- : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_), action_(rhs.action_), index_(rhs.index_) {}
- ThrowingIterator & operator= (const ThrowingIterator &rhs)
- {
- if (action_ == TAAssignment)
- {
- if (index_ == 0)
- throw std::runtime_error ("throw from iterator assignment");
- else
- --index_;
- }
- begin_ = rhs.begin_;
- end_ = rhs.end_;
- current_ = rhs.current_;
- action_ = rhs.action_;
- index_ = rhs.index_;
- return *this;
- }
-
-// iterator operations
- reference operator*() const
- {
- if (action_ == TADereference)
- {
- if (index_ == 0)
- throw std::runtime_error ("throw from iterator dereference");
- else
- --index_;
- }
- return *current_;
- }
-
- ThrowingIterator & operator++()
- {
- if (action_ == TAIncrement)
- {
- if (index_ == 0)
- throw std::runtime_error ("throw from iterator increment");
- else
- --index_;
- }
- ++current_;
- return *this;
- }
-
- ThrowingIterator operator++(int)
- {
- ThrowingIterator temp = *this;
- ++(*this);
- return temp;
- }
-
- ThrowingIterator & operator--()
- {
- if (action_ == TADecrement)
- {
- if (index_ == 0)
- throw std::runtime_error ("throw from iterator decrement");
- else
- --index_;
- }
- --current_;
- return *this;
- }
-
- ThrowingIterator operator--(int) {
- ThrowingIterator temp = *this;
- --(*this);
- return temp;
- }
-
- bool operator== (const ThrowingIterator &rhs) const
- {
- if (action_ == TAComparison)
- {
- if (index_ == 0)
- throw std::runtime_error ("throw from iterator comparison");
- else
- --index_;
- }
- bool atEndL = current_ == end_;
- bool atEndR = rhs.current_ == rhs.end_;
- if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not.
- if (atEndL) return true; // both are at the end (or empty)
- return current_ == rhs.current_;
- }
+ enum ThrowingAction { TAIncrement, TADecrement, TADereference, TAAssignment, TAComparison };
+
+// Constructors
+ ThrowingIterator ()
+ : begin_(nullptr), end_(nullptr), current_(nullptr), action_(TADereference), index_(0) {}
+ ThrowingIterator (const T *first, const T *last, size_t index = 0, ThrowingAction action = TADereference)
+ : begin_(first), end_(last), current_(first), action_(action), index_(index) {}
+ ThrowingIterator (const ThrowingIterator &rhs)
+ : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_), action_(rhs.action_), index_(rhs.index_) {}
+ ThrowingIterator & operator= (const ThrowingIterator &rhs)
+ {
+ if (action_ == TAAssignment)
+ {
+ if (index_ == 0)
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ throw std::runtime_error ("throw from iterator assignment");
+#else
+ assert(false);
+#endif
+
+ else
+ --index_;
+ }
+ begin_ = rhs.begin_;
+ end_ = rhs.end_;
+ current_ = rhs.current_;
+ action_ = rhs.action_;
+ index_ = rhs.index_;
+ return *this;
+ }
+
+// iterator operations
+ reference operator*() const
+ {
+ if (action_ == TADereference)
+ {
+ if (index_ == 0)
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ throw std::runtime_error ("throw from iterator dereference");
+#else
+ assert(false);
+#endif
+ else
+ --index_;
+ }
+ return *current_;
+ }
+
+ ThrowingIterator & operator++()
+ {
+ if (action_ == TAIncrement)
+ {
+ if (index_ == 0)
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ throw std::runtime_error ("throw from iterator increment");
+#else
+ assert(false);
+#endif
+ else
+ --index_;
+ }
+ ++current_;
+ return *this;
+ }
+
+ ThrowingIterator operator++(int)
+ {
+ ThrowingIterator temp = *this;
+ ++(*this);
+ return temp;
+ }
+
+ ThrowingIterator & operator--()
+ {
+ if (action_ == TADecrement)
+ {
+ if (index_ == 0)
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ throw std::runtime_error ("throw from iterator decrement");
+#else
+ assert(false);
+#endif
+ else
+ --index_;
+ }
+ --current_;
+ return *this;
+ }
+
+ ThrowingIterator operator--(int) {
+ ThrowingIterator temp = *this;
+ --(*this);
+ return temp;
+ }
+
+ bool operator== (const ThrowingIterator &rhs) const
+ {
+ if (action_ == TAComparison)
+ {
+ if (index_ == 0)
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ throw std::runtime_error ("throw from iterator comparison");
+#else
+ assert(false);
+#endif
+ else
+ --index_;
+ }
+ bool atEndL = current_ == end_;
+ bool atEndR = rhs.current_ == rhs.end_;
+ if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not.
+ if (atEndL) return true; // both are at the end (or empty)
+ return current_ == rhs.current_;
+ }
private:
- const T* begin_;
- const T* end_;
- const T* current_;
- ThrowingAction action_;
- mutable size_t index_;
+ const T* begin_;
+ const T* end_;
+ const T* current_;
+ ThrowingAction action_;
+ mutable size_t index_;
};
template <typename T>
bool operator== (const ThrowingIterator<T>& a, const ThrowingIterator<T>& b)
-{ return a.operator==(b); }
+{ return a.operator==(b); }
template <typename T>
bool operator!= (const ThrowingIterator<T>& a, const ThrowingIterator<T>& b)
-{ return !a.operator==(b); }
-
+{ return !a.operator==(b); }
+
template <typename T>
struct NonThrowingIterator {
typedef std::bidirectional_iterator_tag iterator_category;
@@ -453,75 +475,75 @@ struct NonThrowingIterator {
typedef const T * pointer;
typedef const T & reference;
-// Constructors
- NonThrowingIterator ()
- : begin_(nullptr), end_(nullptr), current_(nullptr) {}
- NonThrowingIterator (const T *first, const T* last)
- : begin_(first), end_(last), current_(first) {}
- NonThrowingIterator (const NonThrowingIterator &rhs)
- : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_) {}
- NonThrowingIterator & operator= (const NonThrowingIterator &rhs) TEST_NOEXCEPT
- {
- begin_ = rhs.begin_;
- end_ = rhs.end_;
- current_ = rhs.current_;
- return *this;
- }
-
-// iterator operations
- reference operator*() const TEST_NOEXCEPT
- {
- return *current_;
- }
-
- NonThrowingIterator & operator++() TEST_NOEXCEPT
- {
- ++current_;
- return *this;
- }
-
- NonThrowingIterator operator++(int) TEST_NOEXCEPT
- {
- NonThrowingIterator temp = *this;
- ++(*this);
- return temp;
- }
-
- NonThrowingIterator & operator--() TEST_NOEXCEPT
- {
- --current_;
- return *this;
- }
-
- NonThrowingIterator operator--(int) TEST_NOEXCEPT
- {
- NonThrowingIterator temp = *this;
- --(*this);
- return temp;
- }
-
- bool operator== (const NonThrowingIterator &rhs) const TEST_NOEXCEPT
- {
- bool atEndL = current_ == end_;
- bool atEndR = rhs.current_ == rhs.end_;
- if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not.
- if (atEndL) return true; // both are at the end (or empty)
- return current_ == rhs.current_;
- }
+// Constructors
+ NonThrowingIterator ()
+ : begin_(nullptr), end_(nullptr), current_(nullptr) {}
+ NonThrowingIterator (const T *first, const T* last)
+ : begin_(first), end_(last), current_(first) {}
+ NonThrowingIterator (const NonThrowingIterator &rhs)
+ : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_) {}
+ NonThrowingIterator & operator= (const NonThrowingIterator &rhs) TEST_NOEXCEPT
+ {
+ begin_ = rhs.begin_;
+ end_ = rhs.end_;
+ current_ = rhs.current_;
+ return *this;
+ }
+
+// iterator operations
+ reference operator*() const TEST_NOEXCEPT
+ {
+ return *current_;
+ }
+
+ NonThrowingIterator & operator++() TEST_NOEXCEPT
+ {
+ ++current_;
+ return *this;
+ }
+
+ NonThrowingIterator operator++(int) TEST_NOEXCEPT
+ {
+ NonThrowingIterator temp = *this;
+ ++(*this);
+ return temp;
+ }
+
+ NonThrowingIterator & operator--() TEST_NOEXCEPT
+ {
+ --current_;
+ return *this;
+ }
+
+ NonThrowingIterator operator--(int) TEST_NOEXCEPT
+ {
+ NonThrowingIterator temp = *this;
+ --(*this);
+ return temp;
+ }
+
+ bool operator== (const NonThrowingIterator &rhs) const TEST_NOEXCEPT
+ {
+ bool atEndL = current_ == end_;
+ bool atEndR = rhs.current_ == rhs.end_;
+ if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not.
+ if (atEndL) return true; // both are at the end (or empty)
+ return current_ == rhs.current_;
+ }
private:
- const T* begin_;
- const T* end_;
- const T* current_;
+ const T* begin_;
+ const T* end_;
+ const T* current_;
};
template <typename T>
bool operator== (const NonThrowingIterator<T>& a, const NonThrowingIterator<T>& b) TEST_NOEXCEPT
-{ return a.operator==(b); }
+{ return a.operator==(b); }
template <typename T>
bool operator!= (const NonThrowingIterator<T>& a, const NonThrowingIterator<T>& b) TEST_NOEXCEPT
-{ return !a.operator==(b); }
+{ return !a.operator==(b); }
#undef DELETE_FUNCTION
diff --git a/test/support/test_macros.h b/test/support/test_macros.h
index c34e8cf7ef14f..a072e31b77b70 100644
--- a/test/support/test_macros.h
+++ b/test/support/test_macros.h
@@ -11,6 +11,8 @@
#ifndef SUPPORT_TEST_MACROS_HPP
#define SUPPORT_TEST_MACROS_HPP
+#include <ciso646> // Get STL specific macros like _LIBCPP_VERSION
+
#define TEST_CONCAT1(X, Y) X##Y
#define TEST_CONCAT(X, Y) TEST_CONCAT1(X, Y)
@@ -33,6 +35,7 @@
#endif
/* Make a nice name for the standard version */
+#ifndef TEST_STD_VER
#if __cplusplus <= 199711L
# define TEST_STD_VER 3
#elif __cplusplus <= 201103L
@@ -40,15 +43,8 @@
#elif __cplusplus <= 201402L
# define TEST_STD_VER 14
#else
-# define TEST_STD_VER 99 // greater than current standard
+# define TEST_STD_VER 16 // current year; greater than current standard
#endif
-
-/* Features that were introduced in C++11 */
-#if TEST_STD_VER >= 11
-#define TEST_HAS_RVALUE_REFERENCES
-#define TEST_HAS_VARIADIC_TEMPLATES
-#define TEST_HAS_INITIALIZER_LISTS
-#define TEST_HAS_BASIC_CONSTEXPR
#endif
/* Features that were introduced in C++14 */
@@ -61,44 +57,27 @@
#if TEST_STD_VER > 14
#endif
-#if TEST_HAS_EXTENSION(cxx_decltype) || TEST_STD_VER >= 11
-#define TEST_DECLTYPE(T) decltype(T)
-#else
-#define TEST_DECLTYPE(T) __typeof__(T)
-#endif
-
#if TEST_STD_VER >= 11
#define TEST_CONSTEXPR constexpr
#define TEST_NOEXCEPT noexcept
+# if TEST_STD_VER >= 14
+# define TEST_CONSTEXPR_CXX14 constexpr
+# else
+# define TEST_CONSTEXPR_CXX14
+# endif
#else
#define TEST_CONSTEXPR
+#define TEST_CONSTEXPR_CXX14
#define TEST_NOEXCEPT
#endif
-#if TEST_HAS_EXTENSION(cxx_static_assert) || TEST_STD_VER >= 11
-# define TEST_STATIC_ASSERT(Expr, Msg) static_assert(Expr, Msg)
-#else
-# define TEST_STATIC_ASSERT(Expr, Msg) \
- typedef ::test_detail::static_assert_check<sizeof( \
- ::test_detail::static_assert_incomplete_test<(Expr)>)> \
- TEST_CONCAT(test_assert, __LINE__)
-#
-#endif
-
-namespace test_detail {
-
-template <bool> struct static_assert_incomplete_test;
-template <> struct static_assert_incomplete_test<true> {};
-template <unsigned> struct static_assert_check {};
-
-} // end namespace test_detail
-
-
-#if !TEST_HAS_FEATURE(cxx_rtti) && !defined(__cxx_rtti)
+#if !TEST_HAS_FEATURE(cxx_rtti) && !defined(__cpp_rtti) \
+ && !defined(__GXX_RTTI)
#define TEST_HAS_NO_RTTI
#endif
-#if !TEST_HAS_FEATURE(cxx_exceptions) && !defined(__cxx_exceptions)
+#if !TEST_HAS_FEATURE(cxx_exceptions) && !defined(__cpp_exceptions) \
+ && !defined(__EXCEPTIONS)
#define TEST_HAS_NO_EXCEPTIONS
#endif
@@ -107,4 +86,36 @@ template <unsigned> struct static_assert_check {};
#define TEST_HAS_SANITIZERS
#endif
+#if defined(_LIBCPP_NORETURN)
+#define TEST_NORETURN _LIBCPP_NORETURN
+#else
+#define TEST_NORETURN [[noreturn]]
+#endif
+
+/* Macros for testing libc++ specific behavior and extensions */
+#if defined(_LIBCPP_VERSION)
+#define LIBCPP_ASSERT(...) assert(__VA_ARGS__)
+#define LIBCPP_STATIC_ASSERT(...) static_assert(__VA_ARGS__)
+#else
+#define LIBCPP_ASSERT(...) ((void)0)
+#define LIBCPP_STATIC_ASSERT(...) ((void)0)
+#endif
+
+#define ASSERT_NOEXCEPT(...) \
+ static_assert(noexcept(__VA_ARGS__), "Operation must be noexcept")
+
+#define ASSERT_NOT_NOEXCEPT(...) \
+ static_assert(!noexcept(__VA_ARGS__), "Operation must NOT be noexcept")
+
+namespace test_macros_detail {
+template <class T, class U>
+struct is_same { enum { value = 0};} ;
+template <class T>
+struct is_same<T, T> { enum {value = 1}; };
+} // namespace test_macros_detail
+
+#define ASSERT_SAME_TYPE(...) \
+ static_assert(test_macros_detail::is_same<__VA_ARGS__>::value, \
+ "Types differ uexpectedly")
+
#endif // SUPPORT_TEST_MACROS_HPP
diff --git a/test/support/test_memory_resource.hpp b/test/support/test_memory_resource.hpp
new file mode 100644
index 0000000000000..e7b067cf631d5
--- /dev/null
+++ b/test/support/test_memory_resource.hpp
@@ -0,0 +1,507 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 SUPPORT_TEST_MEMORY_RESOURCE_HPP
+#define SUPPORT_TEST_MEMORY_RESOURCE_HPP
+
+#include <experimental/memory_resource>
+#include <memory>
+#include <type_traits>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <cstdint>
+#include <cassert>
+#include "test_macros.h"
+
+struct AllocController;
+ // 'AllocController' is a concrete type that instruments and controls the
+ // behavior of of test allocators.
+
+template <class T>
+class CountingAllocator;
+ // 'CountingAllocator' is an basic implementation of the 'Allocator'
+ // requirements that use the 'AllocController' interface.
+
+template <class T>
+class MinAlignAllocator;
+ // 'MinAlignAllocator' is an instrumented test type which implements the
+ // 'Allocator' requirements. 'MinAlignAllocator' ensures that it *never*
+ // returns a pointer to over-aligned storage. For example
+ // 'MinAlignPointer<char>{}.allocate(...)' will never a 2-byte aligned
+ // pointer.
+
+template <class T>
+class NullAllocator;
+ // 'NullAllocator' is an instrumented test type which implements the
+ // 'Allocator' requirements except that 'allocator' and 'deallocate' are
+ // nops.
+
+
+#define DISALLOW_COPY(Type) \
+ Type(Type const&) = delete; \
+ Type& operator=(Type const&) = delete
+
+constexpr std::size_t MaxAlignV = alignof(std::max_align_t);
+
+struct TestException {};
+
+struct AllocController {
+ int copy_constructed = 0;
+ int move_constructed = 0;
+
+ int alive = 0;
+ int alloc_count = 0;
+ int dealloc_count = 0;
+ int is_equal_count = 0;
+
+ std::size_t alive_size;
+ std::size_t allocated_size;
+ std::size_t deallocated_size;
+
+ std::size_t last_size = 0;
+ std::size_t last_align = 0;
+ void * last_pointer = 0;
+
+ std::size_t last_alloc_size = 0;
+ std::size_t last_alloc_align = 0;
+ void * last_alloc_pointer = nullptr;
+
+ std::size_t last_dealloc_size = 0;
+ std::size_t last_dealloc_align = 0;
+ void * last_dealloc_pointer = nullptr;
+
+ bool throw_on_alloc = false;
+
+ AllocController() = default;
+
+ void countAlloc(void* p, size_t s, size_t a) {
+ ++alive;
+ ++alloc_count;
+ alive_size += s;
+ allocated_size += s;
+ last_pointer = last_alloc_pointer = p;
+ last_size = last_alloc_size = s;
+ last_align = last_alloc_align = a;
+ }
+
+ void countDealloc(void* p, size_t s, size_t a) {
+ --alive;
+ ++dealloc_count;
+ alive_size -= s;
+ deallocated_size += s;
+ last_pointer = last_dealloc_pointer = p;
+ last_size = last_dealloc_size = s;
+ last_align = last_dealloc_align = a;
+ }
+
+ void reset() { std::memset(this, 0, sizeof(*this)); }
+
+public:
+ bool checkAlloc(void* p, size_t s, size_t a) const {
+ return p == last_alloc_pointer &&
+ s == last_alloc_size &&
+ a == last_alloc_align;
+ }
+
+ bool checkAlloc(void* p, size_t s) const {
+ return p == last_alloc_pointer &&
+ s == last_alloc_size;
+ }
+
+ bool checkAllocAtLeast(void* p, size_t s, size_t a) const {
+ return p == last_alloc_pointer &&
+ s <= last_alloc_size &&
+ a <= last_alloc_align;
+ }
+
+ bool checkAllocAtLeast(void* p, size_t s) const {
+ return p == last_alloc_pointer &&
+ s <= last_alloc_size;
+ }
+
+ bool checkDealloc(void* p, size_t s, size_t a) const {
+ return p == last_dealloc_pointer &&
+ s == last_dealloc_size &&
+ a == last_dealloc_align;
+ }
+
+ bool checkDealloc(void* p, size_t s) const {
+ return p == last_dealloc_pointer &&
+ s == last_dealloc_size;
+ }
+
+ bool checkDeallocMatchesAlloc() const {
+ return last_dealloc_pointer == last_alloc_pointer &&
+ last_dealloc_size == last_alloc_size &&
+ last_dealloc_align == last_alloc_align;
+ }
+
+ void countIsEqual() {
+ ++is_equal_count;
+ }
+
+ bool checkIsEqualCalledEq(int n) const {
+ return is_equal_count == n;
+ }
+private:
+ DISALLOW_COPY(AllocController);
+};
+
+template <class T>
+class CountingAllocator
+{
+public:
+ typedef T value_type;
+ typedef T* pointer;
+ CountingAllocator() = delete;
+ explicit CountingAllocator(AllocController& PP) : P(&PP) {}
+
+ CountingAllocator(CountingAllocator const& other) : P(other.P) {
+ P->copy_constructed += 1;
+ }
+
+ CountingAllocator(CountingAllocator&& other) : P(other.P) {
+ P->move_constructed += 1;
+ }
+
+ template <class U>
+ CountingAllocator(CountingAllocator<U> const& other) TEST_NOEXCEPT : P(other.P) {
+ P->copy_constructed += 1;
+ }
+
+ template <class U>
+ CountingAllocator(CountingAllocator<U>&& other) TEST_NOEXCEPT : P(other.P) {
+ P->move_constructed += 1;
+ }
+
+ T* allocate(std::size_t n)
+ {
+ void* ret = ::operator new(n*sizeof(T));
+ P->countAlloc(ret, n*sizeof(T), alignof(T));
+ return static_cast<T*>(ret);
+ }
+
+ void deallocate(T* p, std::size_t n)
+ {
+ void* vp = static_cast<void*>(p);
+ P->countDealloc(vp, n*sizeof(T), alignof(T));
+ ::operator delete(vp);
+ }
+
+ AllocController& getController() const { return *P; }
+
+private:
+ template <class Tp> friend class CountingAllocator;
+ AllocController *P;
+};
+
+template <class T, class U>
+inline bool operator==(CountingAllocator<T> const& x,
+ CountingAllocator<U> const& y) {
+ return &x.getController() == &y.getController();
+}
+
+template <class T, class U>
+inline bool operator!=(CountingAllocator<T> const& x,
+ CountingAllocator<U> const& y) {
+ return !(x == y);
+}
+
+template <class T>
+class MinAlignedAllocator
+{
+public:
+ typedef T value_type;
+ typedef T* pointer;
+
+ MinAlignedAllocator() = delete;
+
+ explicit MinAlignedAllocator(AllocController& R) : P(&R) {}
+
+ MinAlignedAllocator(MinAlignedAllocator const& other) : P(other.P) {
+ P->copy_constructed += 1;
+ }
+
+ MinAlignedAllocator(MinAlignedAllocator&& other) : P(other.P) {
+ P->move_constructed += 1;
+ }
+
+ template <class U>
+ MinAlignedAllocator(MinAlignedAllocator<U> const& other) TEST_NOEXCEPT : P(other.P) {
+ P->copy_constructed += 1;
+ }
+
+ template <class U>
+ MinAlignedAllocator(MinAlignedAllocator<U>&& other) TEST_NOEXCEPT : P(other.P) {
+ P->move_constructed += 1;
+ }
+
+ T* allocate(std::size_t n) {
+ char* aligned_ptr = (char*)::operator new(alloc_size(n*sizeof(T)));
+ assert(is_max_aligned(aligned_ptr));
+
+ char* unaligned_ptr = aligned_ptr + alignof(T);
+ assert(is_min_aligned(unaligned_ptr));
+
+ P->countAlloc(unaligned_ptr, n * sizeof(T), alignof(T));
+
+ return ((T*)unaligned_ptr);
+ }
+
+ void deallocate(T* p, std::size_t n) {
+ assert(is_min_aligned(p));
+
+ char* aligned_ptr = ((char*)p) - alignof(T);
+ assert(is_max_aligned(aligned_ptr));
+
+ P->countDealloc(p, n*sizeof(T), alignof(T));
+
+ return ::operator delete(static_cast<void*>(aligned_ptr));
+ }
+
+ AllocController& getController() const { return *P; }
+
+private:
+ static const std::size_t BlockSize = alignof(std::max_align_t);
+
+ static std::size_t alloc_size(std::size_t s) {
+ std::size_t bytes = (s + BlockSize - 1) & ~(BlockSize - 1);
+ bytes += BlockSize;
+ assert(bytes % BlockSize == 0);
+ return bytes;
+ }
+
+ static bool is_max_aligned(void* p) {
+ return reinterpret_cast<std::uintptr_t>(p) % BlockSize == 0;
+ }
+
+ static bool is_min_aligned(void* p) {
+ if (alignof(T) == BlockSize) {
+ return is_max_aligned(p);
+ } else {
+ return reinterpret_cast<std::uintptr_t>(p) % BlockSize == alignof(T);
+ }
+ }
+
+ template <class Tp> friend class MinAlignedAllocator;
+ mutable AllocController *P;
+};
+
+
+template <class T, class U>
+inline bool operator==(MinAlignedAllocator<T> const& x,
+ MinAlignedAllocator<U> const& y) {
+ return &x.getController() == &y.getController();
+}
+
+template <class T, class U>
+inline bool operator!=(MinAlignedAllocator<T> const& x,
+ MinAlignedAllocator<U> const& y) {
+ return !(x == y);
+}
+
+template <class T>
+class NullAllocator
+{
+public:
+ typedef T value_type;
+ typedef T* pointer;
+ NullAllocator() = delete;
+ explicit NullAllocator(AllocController& PP) : P(&PP) {}
+
+ NullAllocator(NullAllocator const& other) : P(other.P) {
+ P->copy_constructed += 1;
+ }
+
+ NullAllocator(NullAllocator&& other) : P(other.P) {
+ P->move_constructed += 1;
+ }
+
+ template <class U>
+ NullAllocator(NullAllocator<U> const& other) TEST_NOEXCEPT : P(other.P) {
+ P->copy_constructed += 1;
+ }
+
+ template <class U>
+ NullAllocator(NullAllocator<U>&& other) TEST_NOEXCEPT : P(other.P) {
+ P->move_constructed += 1;
+ }
+
+ T* allocate(std::size_t n)
+ {
+ P->countAlloc(nullptr, n*sizeof(T), alignof(T));
+ return nullptr;
+ }
+
+ void deallocate(T* p, std::size_t n)
+ {
+ void* vp = static_cast<void*>(p);
+ P->countDealloc(vp, n*sizeof(T), alignof(T));
+ }
+
+ AllocController& getController() const { return *P; }
+
+private:
+ template <class Tp> friend class NullAllocator;
+ AllocController *P;
+};
+
+template <class T, class U>
+inline bool operator==(NullAllocator<T> const& x,
+ NullAllocator<U> const& y) {
+ return &x.getController() == &y.getController();
+}
+
+template <class T, class U>
+inline bool operator!=(NullAllocator<T> const& x,
+ NullAllocator<U> const& y) {
+ return !(x == y);
+}
+
+
+
+template <class ProviderT, int = 0>
+class TestResourceImp : public std::experimental::pmr::memory_resource
+{
+public:
+ static int resource_alive;
+ static int resource_constructed;
+ static int resource_destructed;
+
+ static void resetStatics() {
+ assert(resource_alive == 0);
+ resource_alive = 0;
+ resource_constructed = 0;
+ resource_destructed = 0;
+ }
+
+ using memory_resource = std::experimental::pmr::memory_resource;
+ using Provider = ProviderT;
+
+ int value;
+
+ explicit TestResourceImp(int val = 0) : value(val) {
+ ++resource_alive;
+ ++resource_constructed;
+ }
+
+ ~TestResourceImp() noexcept {
+ --resource_alive;
+ ++resource_destructed;
+ }
+
+ void reset() { C.reset(); P.reset(); }
+ AllocController& getController() { return C; }
+
+ bool checkAlloc(void* p, std::size_t s, std::size_t a) const
+ { return C.checkAlloc(p, s, a); }
+
+ bool checkDealloc(void* p, std::size_t s, std::size_t a) const
+ { return C.checkDealloc(p, s, a); }
+
+ bool checkIsEqualCalledEq(int n) const { return C.checkIsEqualCalledEq(n); }
+
+protected:
+ virtual void * do_allocate(std::size_t s, std::size_t a) {
+ if (C.throw_on_alloc) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ throw TestException{};
+#else
+ assert(false);
+#endif
+ }
+ void* ret = P.allocate(s, a);
+ C.countAlloc(ret, s, a);
+ return ret;
+ }
+
+ virtual void do_deallocate(void * p, std::size_t s, std::size_t a) {
+ C.countDealloc(p, s, a);
+ P.deallocate(p, s, a);
+ }
+
+ virtual bool do_is_equal(memory_resource const & other) const noexcept {
+ C.countIsEqual();
+ TestResourceImp const * o = dynamic_cast<TestResourceImp const *>(&other);
+ return o && o->value == value;
+ }
+private:
+ mutable AllocController C;
+ mutable Provider P;
+ DISALLOW_COPY(TestResourceImp);
+};
+
+template <class Provider, int N>
+int TestResourceImp<Provider, N>::resource_alive = 0;
+
+template <class Provider, int N>
+int TestResourceImp<Provider, N>::resource_constructed = 0;
+
+template <class Provider, int N>
+int TestResourceImp<Provider, N>::resource_destructed = 0;
+
+
+struct NullProvider {
+ NullProvider() {}
+ void* allocate(size_t, size_t) { return nullptr; }
+ void deallocate(void*, size_t, size_t) {}
+ void reset() {}
+private:
+ DISALLOW_COPY(NullProvider);
+};
+
+struct NewDeleteProvider {
+ NewDeleteProvider() {}
+ void* allocate(size_t s, size_t) { return ::operator new(s); }
+ void deallocate(void* p, size_t, size_t) { ::operator delete(p); }
+ void reset() {}
+private:
+ DISALLOW_COPY(NewDeleteProvider);
+};
+
+template <size_t Size = 4096 * 10> // 10 pages worth of memory.
+struct BufferProvider {
+ char buffer[Size];
+ void* next = &buffer;
+ size_t space = Size;
+
+ BufferProvider() {}
+
+ void* allocate(size_t s, size_t a) {
+ void* ret = std::align(s, a, next, space);
+ if (ret == nullptr) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ throw std::bad_alloc();
+#else
+ assert(false);
+#endif
+ }
+
+ return ret;
+ }
+
+ void deallocate(void*, size_t, size_t) {}
+
+ void reset() {
+ next = &buffer;
+ space = Size;
+ }
+private:
+ DISALLOW_COPY(BufferProvider);
+};
+
+using NullResource = TestResourceImp<NullProvider, 0>;
+using NewDeleteResource = TestResourceImp<NewDeleteProvider, 0>;
+using TestResource = TestResourceImp<BufferProvider<>, 0>;
+using TestResource1 = TestResourceImp<BufferProvider<>, 1>;
+using TestResource2 = TestResourceImp<BufferProvider<>, 2>;
+
+
+#endif /* SUPPORT_TEST_MEMORY_RESOURCE_HPP */
diff --git a/test/support/type_id.h b/test/support/type_id.h
new file mode 100644
index 0000000000000..309f0884e4a7b
--- /dev/null
+++ b/test/support/type_id.h
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 SUPPORT_TYPE_ID_H
+#define SUPPORT_TYPE_ID_H
+
+#include <functional>
+#include <cassert>
+
+#include "test_macros.h"
+
+#if TEST_STD_VER < 11
+#error This header requires C++11 or greater
+#endif
+
+// TypeID - Represent a unique identifier for a type. TypeID allows equality
+// comparisons between different types.
+struct TypeID {
+ friend bool operator==(TypeID const& LHS, TypeID const& RHS)
+ {return LHS.m_id == RHS.m_id; }
+ friend bool operator!=(TypeID const& LHS, TypeID const& RHS)
+ {return LHS.m_id != RHS.m_id; }
+private:
+ explicit constexpr TypeID(const int* xid) : m_id(xid) {}
+
+ TypeID(const TypeID&) = delete;
+ TypeID& operator=(TypeID const&) = delete;
+
+ const int* const m_id;
+ template <class T> friend TypeID const& makeTypeID();
+
+};
+
+// makeTypeID - Return the TypeID for the specified type 'T'.
+template <class T>
+inline TypeID const& makeTypeID() {
+ static int dummy;
+ static const TypeID id(&dummy);
+ return id;
+}
+
+template <class ...Args>
+struct ArgumentListID {};
+
+// makeArgumentID - Create and return a unique identifier for a given set
+// of arguments.
+template <class ...Args>
+inline TypeID const& makeArgumentID() {
+ return makeTypeID<ArgumentListID<Args...>>();
+}
+
+#endif // SUPPORT_TYPE_ID_H
diff --git a/test/support/uses_alloc_types.hpp b/test/support/uses_alloc_types.hpp
new file mode 100644
index 0000000000000..834e57729a7ae
--- /dev/null
+++ b/test/support/uses_alloc_types.hpp
@@ -0,0 +1,298 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 USES_ALLOC_TYPES_HPP
+#define USES_ALLOC_TYPES_HPP
+
+# include <experimental/memory_resource>
+# include <experimental/utility>
+# include <memory>
+# include <cassert>
+
+#include "test_memory_resource.hpp"
+#include "type_id.h"
+
+// There are two forms of uses-allocator construction:
+// (1) UA_AllocArg: 'T(allocator_arg_t, Alloc const&, Args&&...)'
+// (2) UA_AllocLast: 'T(Args&&..., Alloc const&)'
+// 'UA_None' represents non-uses allocator construction.
+enum class UsesAllocatorType {
+ UA_None = 0,
+ UA_AllocArg = 2,
+ UA_AllocLast = 4
+};
+constexpr UsesAllocatorType UA_None = UsesAllocatorType::UA_None;
+constexpr UsesAllocatorType UA_AllocArg = UsesAllocatorType::UA_AllocArg;
+constexpr UsesAllocatorType UA_AllocLast = UsesAllocatorType::UA_AllocLast;
+
+template <class Alloc, std::size_t N>
+class UsesAllocatorV1;
+ // Implements form (1) of uses-allocator construction from the specified
+ // 'Alloc' type and exactly 'N' additional arguments. It also provides
+ // non-uses allocator construction from 'N' arguments. This test type
+ // blows up when form (2) of uses-allocator is even considered.
+
+template <class Alloc, std::size_t N>
+class UsesAllocatorV2;
+ // Implements form (2) of uses-allocator construction from the specified
+ // 'Alloc' type and exactly 'N' additional arguments. It also provides
+ // non-uses allocator construction from 'N' arguments.
+
+template <class Alloc, std::size_t N>
+class UsesAllocatorV3;
+ // Implements both form (1) and (2) of uses-allocator construction from
+ // the specified 'Alloc' type and exactly 'N' additional arguments. It also
+ // provides non-uses allocator construction from 'N' arguments.
+
+template <class Alloc, std::size_t>
+class NotUsesAllocator;
+ // Implements both form (1) and (2) of uses-allocator construction from
+ // the specified 'Alloc' type and exactly 'N' additional arguments. It also
+ // provides non-uses allocator construction from 'N' arguments. However
+ // 'NotUsesAllocator' never provides a 'allocator_type' typedef so it is
+ // never automatically uses-allocator constructed.
+
+
+template <class ...ArgTypes, class TestType>
+bool checkConstruct(TestType& value, UsesAllocatorType form,
+ typename TestType::CtorAlloc const& alloc)
+ // Check that 'value' was constructed using the specified 'form' of
+ // construction and with the specified 'ArgTypes...'. Additionally
+ // check that 'value' was constructed using the specified 'alloc'.
+{
+ if (form == UA_None) {
+ return value.template checkConstruct<ArgTypes&&...>(form);
+ } else {
+ return value.template checkConstruct<ArgTypes&&...>(form, alloc);
+ }
+}
+
+
+template <class ...ArgTypes, class TestType>
+bool checkConstruct(TestType& value, UsesAllocatorType form) {
+ return value.template checkConstruct<ArgTypes&&...>(form);
+}
+
+template <class TestType>
+bool checkConstructionEquiv(TestType& T, TestType& U)
+ // check that 'T' and 'U' where initialized in the exact same manner.
+{
+ return T.checkConstructEquiv(U);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+namespace detail {
+
+template <bool IsZero, size_t N, class ArgList, class ...Args>
+struct TakeNImp;
+
+template <class ArgList, class ...Args>
+struct TakeNImp<true, 0, ArgList, Args...> {
+ typedef ArgList type;
+};
+
+template <size_t N, class ...A1, class F, class ...R>
+struct TakeNImp<false, N, ArgumentListID<A1...>, F, R...>
+ : TakeNImp<N-1 == 0, N - 1, ArgumentListID<A1..., F>, R...> {};
+
+template <size_t N, class ...Args>
+struct TakeNArgs : TakeNImp<N == 0, N, ArgumentListID<>, Args...> {};
+
+template <class T>
+struct Identity { typedef T type; };
+
+template <class T>
+using IdentityT = typename Identity<T>::type;
+
+template <bool Value>
+using EnableIfB = typename std::enable_if<Value, bool>::type;
+
+} // end namespace detail
+
+using detail::EnableIfB;
+
+struct AllocLastTag {};
+
+template <class Alloc>
+struct UsesAllocatorTestBase {
+public:
+ using CtorAlloc = typename std::conditional<
+ std::is_same<Alloc, std::experimental::erased_type>::value,
+ std::experimental::pmr::memory_resource*,
+ Alloc
+ >::type;
+
+ template <class ...ArgTypes>
+ bool checkConstruct(UsesAllocatorType expectType) const {
+ return expectType == constructor_called &&
+ makeArgumentID<ArgTypes...>() == *args_id;
+ }
+
+ template <class ...ArgTypes>
+ bool checkConstruct(UsesAllocatorType expectType,
+ CtorAlloc const& expectAlloc) const {
+ return expectType == constructor_called &&
+ makeArgumentID<ArgTypes...>() == *args_id &&
+ expectAlloc == allocator;
+ }
+
+ bool checkConstructEquiv(UsesAllocatorTestBase& O) const {
+ return constructor_called == O.constructor_called
+ && *args_id == *O.args_id
+ && allocator == O.allocator;
+ }
+
+protected:
+ explicit UsesAllocatorTestBase(const TypeID* aid)
+ : args_id(aid), constructor_called(UA_None), allocator()
+ {}
+
+ template <class ...Args>
+ UsesAllocatorTestBase(std::allocator_arg_t, CtorAlloc const& a, Args&&...)
+ : args_id(&makeArgumentID<Args&&...>()),
+ constructor_called(UA_AllocArg),
+ allocator(a)
+ {}
+
+ template <class ...Args, class ArgsIDL = detail::TakeNArgs<sizeof...(Args) - 1, Args&&...>>
+ UsesAllocatorTestBase(AllocLastTag, Args&&... args)
+ : args_id(&makeTypeID<typename ArgsIDL::type>()),
+ constructor_called(UA_AllocLast),
+ allocator(getAllocatorFromPack(
+ typename ArgsIDL::type{},
+ std::forward<Args>(args)...))
+ {
+ }
+
+private:
+ template <class ...LArgs, class ...Args>
+ static CtorAlloc getAllocatorFromPack(ArgumentListID<LArgs...>, Args&&... args) {
+ return getAllocatorFromPackImp<LArgs const&...>(args...);
+ }
+
+ template <class ...LArgs>
+ static CtorAlloc getAllocatorFromPackImp(
+ typename detail::Identity<LArgs>::type..., CtorAlloc const& alloc) {
+ return alloc;
+ }
+
+ const TypeID* args_id;
+ UsesAllocatorType constructor_called = UA_None;
+ CtorAlloc allocator;
+};
+
+template <class Alloc, size_t Arity>
+class UsesAllocatorV1 : public UsesAllocatorTestBase<Alloc>
+{
+public:
+ typedef Alloc allocator_type;
+
+ using Base = UsesAllocatorTestBase<Alloc>;
+ using CtorAlloc = typename Base::CtorAlloc;
+
+ UsesAllocatorV1() : Base(&makeArgumentID<>()) {}
+
+ // Non-Uses Allocator Ctor
+ template <class ...Args, EnableIfB<sizeof...(Args) == Arity> = false>
+ UsesAllocatorV1(Args&&... args) : Base(&makeArgumentID<Args&&...>()) {};
+
+ // Uses Allocator Arg Ctor
+ template <class ...Args>
+ UsesAllocatorV1(std::allocator_arg_t tag, CtorAlloc const & a, Args&&... args)
+ : Base(tag, a, std::forward<Args>(args)...)
+ { }
+
+ // BLOWS UP: Uses Allocator Last Ctor
+ template <class _First, class ...Args, EnableIfB<sizeof...(Args) == Arity> _Dummy = false>
+ constexpr UsesAllocatorV1(_First&& __first, Args&&... args)
+ {
+ static_assert(!std::is_same<_First, _First>::value, "");
+ }
+};
+
+
+template <class Alloc, size_t Arity>
+class UsesAllocatorV2 : public UsesAllocatorTestBase<Alloc>
+{
+public:
+ typedef Alloc allocator_type;
+
+ using Base = UsesAllocatorTestBase<Alloc>;
+ using CtorAlloc = typename Base::CtorAlloc;
+
+ UsesAllocatorV2() : Base(&makeArgumentID<>()) {}
+
+ // Non-Uses Allocator Ctor
+ template <class ...Args, EnableIfB<sizeof...(Args) == Arity> = false>
+ UsesAllocatorV2(Args&&... args) : Base(&makeArgumentID<Args&&...>()) {};
+
+ // Uses Allocator Last Ctor
+ template <class ...Args, EnableIfB<sizeof...(Args) == Arity + 1> = false>
+ UsesAllocatorV2(Args&&... args)
+ : Base(AllocLastTag{}, std::forward<Args>(args)...)
+ {}
+};
+
+template <class Alloc, size_t Arity>
+class UsesAllocatorV3 : public UsesAllocatorTestBase<Alloc>
+{
+public:
+ typedef Alloc allocator_type;
+
+ using Base = UsesAllocatorTestBase<Alloc>;
+ using CtorAlloc = typename Base::CtorAlloc;
+
+ UsesAllocatorV3() : Base(&makeArgumentID<>()) {}
+
+ // Non-Uses Allocator Ctor
+ template <class ...Args, EnableIfB<sizeof...(Args) == Arity> = false>
+ UsesAllocatorV3(Args&&... args) : Base(&makeArgumentID<Args&&...>()) {};
+
+ // Uses Allocator Arg Ctor
+ template <class ...Args>
+ UsesAllocatorV3(std::allocator_arg_t tag, CtorAlloc const& alloc, Args&&... args)
+ : Base(tag, alloc, std::forward<Args>(args)...)
+ {}
+
+ // Uses Allocator Last Ctor
+ template <class ...Args, EnableIfB<sizeof...(Args) == Arity + 1> = false>
+ UsesAllocatorV3(Args&&... args)
+ : Base(AllocLastTag{}, std::forward<Args>(args)...)
+ {}
+};
+
+template <class Alloc, size_t Arity>
+class NotUsesAllocator : public UsesAllocatorTestBase<Alloc>
+{
+public:
+ // no allocator_type typedef provided
+
+ using Base = UsesAllocatorTestBase<Alloc>;
+ using CtorAlloc = typename Base::CtorAlloc;
+
+ NotUsesAllocator() : Base(&makeArgumentID<>()) {}
+
+ // Non-Uses Allocator Ctor
+ template <class ...Args, EnableIfB<sizeof...(Args) == Arity> = false>
+ NotUsesAllocator(Args&&... args) : Base(&makeArgumentID<Args&&...>()) {};
+
+ // Uses Allocator Arg Ctor
+ template <class ...Args>
+ NotUsesAllocator(std::allocator_arg_t tag, CtorAlloc const& alloc, Args&&... args)
+ : Base(tag, alloc, std::forward<Args>(args)...)
+ {}
+
+ // Uses Allocator Last Ctor
+ template <class ...Args, EnableIfB<sizeof...(Args) == Arity + 1> = false>
+ NotUsesAllocator(Args&&... args)
+ : Base(AllocLastTag{}, std::forward<Args>(args)...)
+ {}
+};
+
+#endif /* USES_ALLOC_TYPES_HPP */