TestNotNull.cpp (12945B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include <type_traits> 8 9 #include "mozilla/NotNull.h" 10 #include "mozilla/RefPtr.h" 11 #include "mozilla/UniquePtr.h" 12 13 using mozilla::MakeNotNull; 14 using mozilla::NotNull; 15 using mozilla::UniquePtr; 16 using mozilla::WrapNotNull; 17 18 #define CHECK MOZ_RELEASE_ASSERT 19 20 class Blah { 21 public: 22 Blah() : mX(0) {} 23 void blah() {}; 24 int mX; 25 }; 26 27 // A simple smart pointer that implicity converts to and from T*. 28 template <typename T> 29 class MyPtr { 30 T* mRawPtr; 31 32 public: 33 MyPtr() : mRawPtr(nullptr) {} 34 MOZ_IMPLICIT MyPtr(T* aRawPtr) : mRawPtr(aRawPtr) {} 35 36 T* get() const { return mRawPtr; } 37 operator T*() const { return get(); } 38 39 T* operator->() const { return get(); } 40 }; 41 42 // A simple class that works with RefPtr. It keeps track of the maximum 43 // refcount value for testing purposes. 44 class MyRefType { 45 int mExpectedMaxRefCnt; 46 int mMaxRefCnt; 47 int mRefCnt; 48 49 public: 50 explicit MyRefType(int aExpectedMaxRefCnt) 51 : mExpectedMaxRefCnt(aExpectedMaxRefCnt), mMaxRefCnt(0), mRefCnt(0) {} 52 53 ~MyRefType() { CHECK(mMaxRefCnt == mExpectedMaxRefCnt); } 54 55 uint32_t AddRef() { 56 mRefCnt++; 57 if (mRefCnt > mMaxRefCnt) { 58 mMaxRefCnt = mRefCnt; 59 } 60 return mRefCnt; 61 } 62 63 uint32_t Release() { 64 CHECK(mRefCnt > 0); 65 mRefCnt--; 66 if (mRefCnt == 0) { 67 delete this; 68 return 0; 69 } 70 return mRefCnt; 71 } 72 }; 73 74 void f_i(int* aPtr) {} 75 void f_my(MyPtr<int> aPtr) {} 76 77 void f_nni(NotNull<int*> aPtr) {} 78 void f_nnmy(NotNull<MyPtr<int>> aPtr) {} 79 80 void TestNotNullWithMyPtr() { 81 int i4 = 4; 82 int i5 = 5; 83 84 MyPtr<int> my4 = &i4; 85 MyPtr<int> my5 = &i5; 86 87 NotNull<int*> nni4 = WrapNotNull(&i4); 88 NotNull<int*> nni5 = WrapNotNull(&i5); 89 NotNull<MyPtr<int>> nnmy4 = WrapNotNull(my4); 90 91 // WrapNotNull(nullptr); // no wrapping from nullptr 92 // WrapNotNull(0); // no wrapping from zero 93 94 // NotNull<int*> construction combinations 95 // NotNull<int*> nni4a; // no default 96 // NotNull<int*> nni4a(nullptr); // no nullptr 97 // NotNull<int*> nni4a(0); // no zero 98 // NotNull<int*> nni4a(&i4); // no int* 99 // NotNull<int*> nni4a(my4); // no MyPtr<int> 100 NotNull<int*> nni4b(WrapNotNull(&i4)); // WrapNotNull(int*) 101 NotNull<int*> nni4c(WrapNotNull(my4)); // WrapNotNull(MyPtr<int>) 102 NotNull<int*> nni4d(nni4); // NotNull<int*> 103 NotNull<int*> nni4e(nnmy4); // NotNull<MyPtr<int>> 104 CHECK(*nni4b == 4); 105 CHECK(*nni4c == 4); 106 CHECK(*nni4d == 4); 107 CHECK(*nni4e == 4); 108 109 // NotNull<MyPtr<int>> construction combinations 110 // NotNull<MyPtr<int>> nnmy4a; // no default 111 // NotNull<MyPtr<int>> nnmy4a(nullptr); // no nullptr 112 // NotNull<MyPtr<int>> nnmy4a(0); // no zero 113 // NotNull<MyPtr<int>> nnmy4a(&i4); // no int* 114 // NotNull<MyPtr<int>> nnmy4a(my4); // no MyPtr<int> 115 NotNull<MyPtr<int>> nnmy4b(WrapNotNull(&i4)); // WrapNotNull(int*) 116 NotNull<MyPtr<int>> nnmy4c(WrapNotNull(my4)); // WrapNotNull(MyPtr<int>) 117 NotNull<MyPtr<int>> nnmy4d(nni4); // NotNull<int*> 118 NotNull<MyPtr<int>> nnmy4e(nnmy4); // NotNull<MyPtr<int>> 119 CHECK(*nnmy4b == 4); 120 CHECK(*nnmy4c == 4); 121 CHECK(*nnmy4d == 4); 122 CHECK(*nnmy4e == 4); 123 124 // NotNull<int*> assignment combinations 125 // nni4b = nullptr; // no nullptr 126 // nni4b = 0; // no zero 127 // nni4a = &i4; // no int* 128 // nni4a = my4; // no MyPtr<int> 129 nni4b = WrapNotNull(&i4); // WrapNotNull(int*) 130 nni4c = WrapNotNull(my4); // WrapNotNull(MyPtr<int>) 131 nni4d = nni4; // NotNull<int*> 132 nni4e = nnmy4; // NotNull<MyPtr<int>> 133 CHECK(*nni4b == 4); 134 CHECK(*nni4c == 4); 135 CHECK(*nni4d == 4); 136 CHECK(*nni4e == 4); 137 138 // NotNull<MyPtr<int>> assignment combinations 139 // nnmy4a = nullptr; // no nullptr 140 // nnmy4a = 0; // no zero 141 // nnmy4a = &i4; // no int* 142 // nnmy4a = my4; // no MyPtr<int> 143 nnmy4b = WrapNotNull(&i4); // WrapNotNull(int*) 144 nnmy4c = WrapNotNull(my4); // WrapNotNull(MyPtr<int>) 145 nnmy4d = nni4; // NotNull<int*> 146 nnmy4e = nnmy4; // NotNull<MyPtr<int>> 147 CHECK(*nnmy4b == 4); 148 CHECK(*nnmy4c == 4); 149 CHECK(*nnmy4d == 4); 150 CHECK(*nnmy4e == 4); 151 152 NotNull<MyPtr<int>> nnmy5 = WrapNotNull(&i5); 153 CHECK(*nnmy5 == 5); 154 CHECK(nnmy5 == &i5); // NotNull<MyPtr<int>> == int* 155 CHECK(nnmy5 == my5); // NotNull<MyPtr<int>> == MyPtr<int> 156 CHECK(nnmy5 == nni5); // NotNull<MyPtr<int>> == NotNull<int*> 157 CHECK(nnmy5 == nnmy5); // NotNull<MyPtr<int>> == NotNull<MyPtr<int>> 158 CHECK(&i5 == nnmy5); // int* == NotNull<MyPtr<int>> 159 CHECK(my5 == nnmy5); // MyPtr<int> == NotNull<MyPtr<int>> 160 CHECK(nni5 == nnmy5); // NotNull<int*> == NotNull<MyPtr<int>> 161 CHECK(nnmy5 == nnmy5); // NotNull<MyPtr<int>> == NotNull<MyPtr<int>> 162 // CHECK(nni5 == nullptr); // no comparisons with nullptr 163 // CHECK(nullptr == nni5); // no comparisons with nullptr 164 // CHECK(nni5 == 0); // no comparisons with zero 165 // CHECK(0 == nni5); // no comparisons with zero 166 167 CHECK(*nnmy5 == 5); 168 CHECK(nnmy5 != &i4); // NotNull<MyPtr<int>> != int* 169 CHECK(nnmy5 != my4); // NotNull<MyPtr<int>> != MyPtr<int> 170 CHECK(nnmy5 != nni4); // NotNull<MyPtr<int>> != NotNull<int*> 171 CHECK(nnmy5 != nnmy4); // NotNull<MyPtr<int>> != NotNull<MyPtr<int>> 172 CHECK(&i4 != nnmy5); // int* != NotNull<MyPtr<int>> 173 CHECK(my4 != nnmy5); // MyPtr<int> != NotNull<MyPtr<int>> 174 CHECK(nni4 != nnmy5); // NotNull<int*> != NotNull<MyPtr<int>> 175 CHECK(nnmy4 != nnmy5); // NotNull<MyPtr<int>> != NotNull<MyPtr<int>> 176 // CHECK(nni4 != nullptr); // no comparisons with nullptr 177 // CHECK(nullptr != nni4); // no comparisons with nullptr 178 // CHECK(nni4 != 0); // no comparisons with zero 179 // CHECK(0 != nni4); // no comparisons with zero 180 181 // int* parameter 182 f_i(&i4); // identity int* --> int* 183 f_i(my4); // implicit MyPtr<int> --> int* 184 f_i(my4.get()); // explicit MyPtr<int> --> int* 185 f_i(nni4); // implicit NotNull<int*> --> int* 186 f_i(nni4.get()); // explicit NotNull<int*> --> int* 187 // f_i(nnmy4); // no implicit NotNull<MyPtr<int>> --> int* 188 f_i(nnmy4.get()); // explicit NotNull<MyPtr<int>> --> int* 189 f_i(nnmy4.get().get()); // doubly-explicit NotNull<MyPtr<int>> --> int* 190 191 // MyPtr<int> parameter 192 f_my(&i4); // implicit int* --> MyPtr<int> 193 f_my(my4); // identity MyPtr<int> --> MyPtr<int> 194 f_my(my4.get()); // explicit MyPtr<int> --> MyPtr<int> 195 // f_my(nni4); // no implicit NotNull<int*> --> MyPtr<int> 196 f_my(nni4.get()); // explicit NotNull<int*> --> MyPtr<int> 197 f_my(nnmy4); // implicit NotNull<MyPtr<int>> --> MyPtr<int> 198 f_my(nnmy4.get()); // explicit NotNull<MyPtr<int>> --> MyPtr<int> 199 f_my( 200 nnmy4.get().get()); // doubly-explicit NotNull<MyPtr<int>> --> MyPtr<int> 201 202 // NotNull<int*> parameter 203 f_nni(nni4); // identity NotNull<int*> --> NotNull<int*> 204 f_nni(nnmy4); // implicit NotNull<MyPtr<int>> --> NotNull<int*> 205 206 // NotNull<MyPtr<int>> parameter 207 f_nnmy(nni4); // implicit NotNull<int*> --> NotNull<MyPtr<int>> 208 f_nnmy(nnmy4); // identity NotNull<MyPtr<int>> --> NotNull<MyPtr<int>> 209 210 // CHECK(nni4); // disallow boolean conversion / unary expression usage 211 // CHECK(nnmy4); // ditto 212 213 // '->' dereferencing. 214 Blah blah; 215 MyPtr<Blah> myblah = &blah; 216 NotNull<Blah*> nnblah = WrapNotNull(&blah); 217 NotNull<MyPtr<Blah>> nnmyblah = WrapNotNull(myblah); 218 (&blah)->blah(); // int* 219 myblah->blah(); // MyPtr<int> 220 nnblah->blah(); // NotNull<int*> 221 nnmyblah->blah(); // NotNull<MyPtr<int>> 222 223 (&blah)->mX = 1; 224 CHECK((&blah)->mX == 1); 225 myblah->mX = 2; 226 CHECK(myblah->mX == 2); 227 nnblah->mX = 3; 228 CHECK(nnblah->mX == 3); 229 nnmyblah->mX = 4; 230 CHECK(nnmyblah->mX == 4); 231 232 // '*' dereferencing (lvalues and rvalues) 233 *(&i4) = 7; // int* 234 CHECK(*(&i4) == 7); 235 *my4 = 6; // MyPtr<int> 236 CHECK(*my4 == 6); 237 *nni4 = 5; // NotNull<int*> 238 CHECK(*nni4 == 5); 239 *nnmy4 = 4; // NotNull<MyPtr<int>> 240 CHECK(*nnmy4 == 4); 241 242 // Non-null arrays. 243 static const int N = 20; 244 int a[N]; 245 NotNull<int*> nna = WrapNotNull(a); 246 for (int i = 0; i < N; i++) { 247 nna[i] = i; 248 } 249 for (int i = 0; i < N; i++) { 250 nna[i] *= 2; 251 } 252 for (int i = 0; i < N; i++) { 253 CHECK(nna[i] == i * 2); 254 } 255 } 256 257 void f_ref(NotNull<MyRefType*> aR) { NotNull<RefPtr<MyRefType>> r = aR; } 258 259 void TestNotNullWithRefPtr() { 260 // This MyRefType object will have a maximum refcount of 5. 261 NotNull<RefPtr<MyRefType>> r1 = WrapNotNull(new MyRefType(5)); 262 263 // At this point the refcount is 1. 264 265 NotNull<RefPtr<MyRefType>> r2 = r1; 266 267 // At this point the refcount is 2. 268 269 NotNull<MyRefType*> r3 = r2; 270 (void)r3; 271 272 // At this point the refcount is still 2. 273 274 RefPtr<MyRefType> r4 = r2; 275 (void)r4; 276 277 // At this point the refcount is 3. 278 279 RefPtr<MyRefType> r5 = r3.get(); 280 (void)r5; 281 282 // At this point the refcount is 4. 283 284 // No change to the refcount occurs because of the argument passing. Within 285 // f_ref() the refcount temporarily hits 5, due to the local RefPtr. 286 f_ref(r2); 287 288 // At this point the refcount is 4. 289 290 NotNull<RefPtr<MyRefType>> r6 = std::move(r2); 291 (void)r6; 292 293 CHECK(r2.get()); 294 CHECK(r6.get()); 295 296 // At this point the refcount is 5 again, since NotNull is not movable. 297 298 // At function's end all RefPtrs are destroyed and the refcount drops to 0 299 // and the MyRefType is destroyed. 300 } 301 302 // Create a derived object and store its base pointer. 303 struct Base { 304 virtual ~Base() = default; 305 virtual bool IsDerived() const { return false; } 306 }; 307 struct Derived : Base { 308 bool IsDerived() const override { return true; } 309 }; 310 311 void TestMakeNotNull() { 312 // Raw pointer. 313 auto nni = MakeNotNull<int*>(11); 314 static_assert(std::is_same_v<NotNull<int*>, decltype(nni)>, 315 "MakeNotNull<int*> should return NotNull<int*>"); 316 CHECK(*nni == 11); 317 delete nni; 318 319 // Raw pointer to const. 320 auto nnci = MakeNotNull<const int*>(12); 321 static_assert(std::is_same_v<NotNull<const int*>, decltype(nnci)>, 322 "MakeNotNull<const int*> should return NotNull<const int*>"); 323 CHECK(*nnci == 12); 324 delete nnci; 325 326 auto nnd = MakeNotNull<Derived*>(); 327 static_assert(std::is_same_v<NotNull<Derived*>, decltype(nnd)>, 328 "MakeNotNull<Derived*> should return NotNull<Derived*>"); 329 CHECK(nnd->IsDerived()); 330 delete nnd; 331 NotNull<Base*> nnb = MakeNotNull<Derived*>(); 332 static_assert(std::is_same_v<NotNull<Base*>, decltype(nnb)>, 333 "MakeNotNull<Derived*> should be assignable to NotNull<Base*>"); 334 // Check that we have really built a Derived object. 335 CHECK(nnb->IsDerived()); 336 delete nnb; 337 338 // Allow smart pointers. 339 auto nnmi = MakeNotNull<MyPtr<int>>(23); 340 static_assert(std::is_same_v<NotNull<MyPtr<int>>, decltype(nnmi)>, 341 "MakeNotNull<MyPtr<int>> should return NotNull<MyPtr<int>>"); 342 CHECK(*nnmi == 23); 343 delete nnmi.get().get(); 344 345 auto nnui = MakeNotNull<UniquePtr<int>>(24); 346 static_assert( 347 std::is_same_v<NotNull<UniquePtr<int>>, decltype(nnui)>, 348 "MakeNotNull<UniquePtr<int>> should return NotNull<UniquePtr<int>>"); 349 CHECK(*nnui == 24); 350 351 // Expect only 1 RefCnt (from construction). 352 auto nnr = MakeNotNull<RefPtr<MyRefType>>(1); 353 static_assert(std::is_same_v<NotNull<RefPtr<MyRefType>>, decltype(nnr)>, 354 "MakeNotNull<RefPtr<MyRefType>> should return " 355 "NotNull<RefPtr<MyRefType>>"); 356 (void)nnr; 357 } 358 359 mozilla::MovingNotNull<UniquePtr<int>> CreateNotNullUniquePtr() { 360 return mozilla::WrapMovingNotNull(mozilla::MakeUnique<int>(42)); 361 } 362 363 void TestMovingNotNull() { 364 UniquePtr<int> x1 = CreateNotNullUniquePtr(); 365 CHECK(x1); 366 CHECK(42 == *x1); 367 368 NotNull<UniquePtr<int>> x2 = CreateNotNullUniquePtr(); 369 CHECK(42 == *x2); 370 371 NotNull<UniquePtr<Base>> x3 = 372 mozilla::WrapMovingNotNull(mozilla::MakeUnique<Derived>()); 373 374 // Must not compile: 375 // auto y = CreateNotNullUniquePtr(); 376 } 377 378 int main() { 379 TestNotNullWithMyPtr(); 380 TestNotNullWithRefPtr(); 381 TestMakeNotNull(); 382 TestMovingNotNull(); 383 384 return 0; 385 }