// // Tests for // explicit bounded_ptr(T* pointer, T const* begin, T const* end); // #include #include #include #include #include "test_utils.h" #define _assert(...) T_ASSERT_TRUE((__VA_ARGS__), # __VA_ARGS__) struct T { int i; friend constexpr bool operator==(T const volatile& a, T const& b) { return a.i == b.i; } }; template static void tests() { std::array array = {T{0}, T{1}, T{2}, T{3}, T{4}}; { test_bounded_ptr p(array.begin() + 0, array.begin(), array.end()); _assert(*p == T{0}); } { test_bounded_ptr p(array.begin() + 1, array.begin(), array.end()); _assert(*p == T{1}); } { test_bounded_ptr p(array.begin() + 2, array.begin(), array.end()); _assert(*p == T{2}); } { test_bounded_ptr p(array.begin() + 3, array.begin(), array.end()); _assert(*p == T{3}); } { test_bounded_ptr p(array.begin() + 4, array.begin(), array.end()); _assert(*p == T{4}); } // It must be valid to construct out-of-bounds pointers, but we obviously // can't dereference them. { // T{0} T{1} T{2} T{3} T{4} // ^ ^ ^ // | | | // ptr begin end test_bounded_ptr p(array.begin() + 1, array.begin() + 3, array.end()); _assert(p.unsafe_discard_bounds() == array.begin() + 1); } { // T{0} T{1} T{2} T{3} T{4} // ^ ^ ^ // | | | // begin end ptr test_bounded_ptr p(array.begin() + 4, array.begin(), array.begin() + 3); _assert(p.unsafe_discard_bounds() == array.begin() + 4); } { // T{0} T{1} T{2} T{3} T{4} // ^ ^ // | | // begin end,ptr test_bounded_ptr p(array.end(), array.begin(), array.end()); _assert(p.unsafe_discard_bounds() == array.end()); } // Test creating a bounded_ptr from a null pointer. { test_bounded_ptr p(nullptr, nullptr, nullptr); _assert(p.unsafe_discard_bounds() == nullptr); } } struct Base { }; struct Derived : Base { }; T_DECL(ctor_begin_end, "bounded_ptr.ctor.begin_end", T_META_TAG_VM_PREFERRED) { tests(); tests(); tests(); tests(); // Make sure we can construct a `bounded_ptr` from `Derived*` pointers { std::array array = {}; test_bounded_ptr p(static_cast(array.begin()), static_cast(array.begin()), static_cast(array.end())); } }