1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2015 Microsoft Corporation. All rights reserved.
4 //
5 // This code is licensed under the MIT License (MIT).
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
13 // THE SOFTWARE.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16
17 #include <catch/catch.hpp>
18
19 #include <gsl/gsl>
20
21 #include <memory>
22 #include <string>
23 #include <vector>
24
25 using namespace gsl;
26
27 struct MyBase
28 {
29 };
30 struct MyDerived : public MyBase
31 {
32 };
33 struct Unrelated
34 {
35 };
36
37 // stand-in for a user-defined ref-counted class
38 template <typename T>
39 struct RefCounted
40 {
RefCountedRefCounted41 RefCounted(T* p) : p_(p) {}
operator T*RefCounted42 operator T*() { return p_; }
43 T* p_;
44 };
45
46 // user defined smart pointer with comparison operators returning non bool value
47 template <typename T>
48 struct CustomPtr
49 {
CustomPtrCustomPtr50 CustomPtr(T* p) : p_(p) {}
operator T*CustomPtr51 operator T*() { return p_; }
operator !=CustomPtr52 bool operator!=(std::nullptr_t) const { return p_ != nullptr; }
53 T* p_ = nullptr;
54 };
55
56 template <typename T, typename U>
operator ==(CustomPtr<T> const & lhs,CustomPtr<U> const & rhs)57 std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
58 {
59 return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true"
60 : "false";
61 }
62
63 template <typename T, typename U>
operator !=(CustomPtr<T> const & lhs,CustomPtr<U> const & rhs)64 std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
65 {
66 return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true"
67 : "false";
68 }
69
70 template <typename T, typename U>
operator <(CustomPtr<T> const & lhs,CustomPtr<U> const & rhs)71 std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
72 {
73 return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true"
74 : "false";
75 }
76
77 template <typename T, typename U>
operator >(CustomPtr<T> const & lhs,CustomPtr<U> const & rhs)78 std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
79 {
80 return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true"
81 : "false";
82 }
83
84 template <typename T, typename U>
operator <=(CustomPtr<T> const & lhs,CustomPtr<U> const & rhs)85 std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
86 {
87 return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true"
88 : "false";
89 }
90
91 template <typename T, typename U>
operator >=(CustomPtr<T> const & lhs,CustomPtr<U> const & rhs)92 std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
93 {
94 return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true"
95 : "false";
96 }
97
98 struct NonCopyableNonMovable
99 {
100 NonCopyableNonMovable() = default;
101 NonCopyableNonMovable(const NonCopyableNonMovable&) = delete;
102 NonCopyableNonMovable& operator=(const NonCopyableNonMovable&) = delete;
103 NonCopyableNonMovable(NonCopyableNonMovable&&) = delete;
104 NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete;
105 };
106
helper(not_null<int * > p)107 bool helper(not_null<int*> p) { return *p == 12; }
108
109 TEST_CASE("TestNotNullConstructors")
110 {
111 #ifdef CONFIRM_COMPILATION_ERRORS
112 not_null<int*> p = nullptr; // yay...does not compile!
113 not_null<std::vector<char>*> p = 0; // yay...does not compile!
114 not_null<int*> p; // yay...does not compile!
115 std::unique_ptr<int> up = std::make_unique<int>(120);
116 not_null<int*> p = up;
117
118 // Forbid non-nullptr assignable types
119 not_null<std::vector<int>> f(std::vector<int>{1});
120 not_null<int> z(10);
121 not_null<std::vector<int>> y({1, 2});
122 #endif
123 int i = 12;
124 auto rp = RefCounted<int>(&i);
125 not_null<int*> p(rp);
126 CHECK(p.get() == &i);
127
128 not_null<std::shared_ptr<int>> x(
129 std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
130 }
131
132 TEST_CASE("TestNotNullCasting")
133 {
134 MyBase base;
135 MyDerived derived;
136 Unrelated unrelated;
137 not_null<Unrelated*> u = &unrelated;
138 (void) u;
139 not_null<MyDerived*> p = &derived;
140 not_null<MyBase*> q = &base;
141 q = p; // allowed with heterogeneous copy ctor
142 CHECK(q == p);
143
144 #ifdef CONFIRM_COMPILATION_ERRORS
145 q = u; // no viable conversion possible between MyBase* and Unrelated*
146 p = q; // not possible to implicitly convert MyBase* to MyDerived*
147
148 not_null<Unrelated*> r = p;
149 not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
150 #endif
151 not_null<Unrelated*> t = reinterpret_cast<Unrelated*>(p.get());
152 CHECK(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get()));
153 }
154
155 TEST_CASE("TestNotNullAssignment")
156 {
157 int i = 12;
158 not_null<int*> p = &i;
159 CHECK(helper(p));
160
161 int* q = nullptr;
162 CHECK_THROWS_AS(p = q, fail_fast);
163 }
164
165 TEST_CASE("TestNotNullRawPointerComparison")
166 {
167 int ints[2] = {42, 43};
168 int* p1 = &ints[0];
169 const int* p2 = &ints[1];
170
171 using NotNull1 = not_null<decltype(p1)>;
172 using NotNull2 = not_null<decltype(p2)>;
173
174 CHECK((NotNull1(p1) == NotNull1(p1)) == true);
175 CHECK((NotNull1(p1) == NotNull2(p2)) == false);
176
177 CHECK((NotNull1(p1) != NotNull1(p1)) == false);
178 CHECK((NotNull1(p1) != NotNull2(p2)) == true);
179
180 CHECK((NotNull1(p1) < NotNull1(p1)) == false);
181 CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2));
182 CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1));
183
184 CHECK((NotNull1(p1) > NotNull1(p1)) == false);
185 CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2));
186 CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1));
187
188 CHECK((NotNull1(p1) <= NotNull1(p1)) == true);
189 CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2));
190 CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1));
191
192 }
193
194 TEST_CASE("TestNotNullDereferenceOperator")
195 {
196 {
197 auto sp1 = std::make_shared<NonCopyableNonMovable>();
198
199 using NotNullSp1 = not_null<decltype(sp1)>;
200 CHECK(typeid(*sp1) == typeid(*NotNullSp1(sp1)));
201 CHECK(std::addressof(*NotNullSp1(sp1)) == std::addressof(*sp1));
202 }
203
204 {
205 int ints[1] = { 42 };
206 CustomPtr<int> p1(&ints[0]);
207
208 using NotNull1 = not_null<decltype(p1)>;
209 CHECK(typeid(*NotNull1(p1)) == typeid(*p1));
210 CHECK(*NotNull1(p1) == 42);
211 *NotNull1(p1) = 43;
212 CHECK(ints[0] == 43);
213 }
214
215 {
216 int v = 42;
217 gsl::not_null<int*> p(&v);
218 CHECK(typeid(*p) == typeid(*(&v)));
219 *p = 43;
220 CHECK(v == 43);
221 }
222 }
223
224 TEST_CASE("TestNotNullSharedPtrComparison")
225 {
226 auto sp1 = std::make_shared<int>(42);
227 auto sp2 = std::make_shared<const int>(43);
228
229 using NotNullSp1 = not_null<decltype(sp1)>;
230 using NotNullSp2 = not_null<decltype(sp2)>;
231
232 CHECK((NotNullSp1(sp1) == NotNullSp1(sp1)) == true);
233 CHECK((NotNullSp1(sp1) == NotNullSp2(sp2)) == false);
234
235 CHECK((NotNullSp1(sp1) != NotNullSp1(sp1)) == false);
236 CHECK((NotNullSp1(sp1) != NotNullSp2(sp2)) == true);
237
238 CHECK((NotNullSp1(sp1) < NotNullSp1(sp1)) == false);
239 CHECK((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2));
240 CHECK((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1));
241
242 CHECK((NotNullSp1(sp1) > NotNullSp1(sp1)) == false);
243 CHECK((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2));
244 CHECK((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1));
245
246 CHECK((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true);
247 CHECK((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2));
248 CHECK((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1));
249
250 CHECK((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true);
251 CHECK((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2));
252 CHECK((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1));
253 }
254
255 TEST_CASE("TestNotNullCustomPtrComparison")
256 {
257 int ints[2] = {42, 43};
258 CustomPtr<int> p1(&ints[0]);
259 CustomPtr<const int> p2(&ints[1]);
260
261 using NotNull1 = not_null<decltype(p1)>;
262 using NotNull2 = not_null<decltype(p2)>;
263
264 CHECK((NotNull1(p1) == NotNull1(p1)) == "true");
265 CHECK((NotNull1(p1) == NotNull2(p2)) == "false");
266
267 CHECK((NotNull1(p1) != NotNull1(p1)) == "false");
268 CHECK((NotNull1(p1) != NotNull2(p2)) == "true");
269
270 CHECK((NotNull1(p1) < NotNull1(p1)) == "false");
271 CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2));
272 CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1));
273
274 CHECK((NotNull1(p1) > NotNull1(p1)) == "false");
275 CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2));
276 CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1));
277
278 CHECK((NotNull1(p1) <= NotNull1(p1)) == "true");
279 CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2));
280 CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1));
281
282 CHECK((NotNull1(p1) >= NotNull1(p1)) == "true");
283 CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2));
284 CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1));
285 }
286