1 //
2 // Tests for
3 //  explicit bounded_ptr(T* pointer, T const* begin, T const* end);
4 //
5 
6 #include <libkern/c++/bounded_ptr.h>
7 #include <array>
8 #include <darwintest.h>
9 #include <darwintest_utils.h>
10 #include "test_utils.h"
11 
12 #define _assert(...) T_ASSERT_TRUE((__VA_ARGS__), # __VA_ARGS__)
13 
14 struct T {
15 	int i;
16 	friend constexpr bool
17 	operator==(T const volatile& a, T const& b)
18 	{
19 		return a.i == b.i;
20 	}
21 };
22 
23 template <typename T, typename QualT>
24 static void
25 tests()
26 {
27 	std::array<T, 5> array = {T{0}, T{1}, T{2}, T{3}, T{4}};
28 	{
29 		test_bounded_ptr<QualT> p(array.begin() + 0, array.begin(), array.end());
30 		_assert(*p == T{0});
31 	}
32 	{
33 		test_bounded_ptr<QualT> p(array.begin() + 1, array.begin(), array.end());
34 		_assert(*p == T{1});
35 	}
36 	{
37 		test_bounded_ptr<QualT> p(array.begin() + 2, array.begin(), array.end());
38 		_assert(*p == T{2});
39 	}
40 	{
41 		test_bounded_ptr<QualT> p(array.begin() + 3, array.begin(), array.end());
42 		_assert(*p == T{3});
43 	}
44 	{
45 		test_bounded_ptr<QualT> p(array.begin() + 4, array.begin(), array.end());
46 		_assert(*p == T{4});
47 	}
48 
49 	// It must be valid to construct out-of-bounds pointers, but we obviously
50 	// can't dereference them.
51 	{
52 		// T{0}     T{1}     T{2}     T{3}     T{4}     <one-past-last>
53 		//            ^                 ^                     ^
54 		//            |                 |                     |
55 		//           ptr              begin                  end
56 		test_bounded_ptr<QualT> p(array.begin() + 1, array.begin() + 3, array.end());
57 		_assert(p.unsafe_discard_bounds() == array.begin() + 1);
58 	}
59 	{
60 		// T{0}     T{1}     T{2}     T{3}     T{4}     <one-past-last>
61 		//   ^                          ^        ^
62 		//   |                          |        |
63 		// begin                       end      ptr
64 		test_bounded_ptr<QualT> p(array.begin() + 4, array.begin(), array.begin() + 3);
65 		_assert(p.unsafe_discard_bounds() == array.begin() + 4);
66 	}
67 	{
68 		// T{0}     T{1}     T{2}     T{3}     T{4}     <one-past-last>
69 		//   ^                                                ^
70 		//   |                                                |
71 		// begin                                             end,ptr
72 		test_bounded_ptr<QualT> p(array.end(), array.begin(), array.end());
73 		_assert(p.unsafe_discard_bounds() == array.end());
74 	}
75 
76 	// Test creating a bounded_ptr from a null pointer.
77 	{
78 		test_bounded_ptr<QualT> p(nullptr, nullptr, nullptr);
79 		_assert(p.unsafe_discard_bounds() == nullptr);
80 	}
81 }
82 
83 struct Base { };
84 struct Derived : Base { };
85 
86 T_DECL(ctor_begin_end, "bounded_ptr.ctor.begin_end") {
87 	tests<T, T>();
88 	tests<T, T const>();
89 	tests<T, T volatile>();
90 	tests<T, T const volatile>();
91 
92 	// Make sure we can construct a `bounded_ptr<Base>` from `Derived*` pointers
93 	{
94 		std::array<Derived, 5> array = {};
95 		test_bounded_ptr<Base> p(static_cast<Derived*>(array.begin()),
96 		    static_cast<Derived*>(array.begin()),
97 		    static_cast<Derived*>(array.end()));
98 	}
99 }
100