tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }