tor-browser

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

TestLinkedList.cpp (9709B)


      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 "mozilla/Assertions.h"
      8 #include "mozilla/LinkedList.h"
      9 
     10 using mozilla::AutoCleanLinkedList;
     11 using mozilla::LinkedList;
     12 using mozilla::LinkedListElement;
     13 
     14 struct SomeClass : public LinkedListElement<SomeClass> {
     15  unsigned int mValue;
     16  explicit SomeClass(int aValue = 0) : mValue(aValue) {}
     17  SomeClass(SomeClass&&) = default;
     18  SomeClass& operator=(SomeClass&&) = default;
     19  void incr() { ++mValue; }
     20 };
     21 
     22 template <size_t N>
     23 static void CheckListValues(LinkedList<SomeClass>& list,
     24                            unsigned int (&values)[N]) {
     25  size_t count = 0;
     26  for (SomeClass* x : list) {
     27    MOZ_RELEASE_ASSERT(x->mValue == values[count]);
     28    ++count;
     29  }
     30  MOZ_RELEASE_ASSERT(count == N);
     31 }
     32 
     33 static void TestList() {
     34  LinkedList<SomeClass> list;
     35 
     36  SomeClass one(1), two(2), three(3);
     37 
     38  MOZ_RELEASE_ASSERT(list.isEmpty());
     39  MOZ_RELEASE_ASSERT(list.length() == 0);
     40  MOZ_RELEASE_ASSERT(!list.getFirst());
     41  MOZ_RELEASE_ASSERT(!list.getLast());
     42  MOZ_RELEASE_ASSERT(!list.popFirst());
     43  MOZ_RELEASE_ASSERT(!list.popLast());
     44 
     45  for (SomeClass* x : list) {
     46    MOZ_RELEASE_ASSERT(x);
     47    MOZ_RELEASE_ASSERT(false);
     48  }
     49 
     50  list.insertFront(&one);
     51  {
     52    unsigned int check[]{1};
     53    CheckListValues(list, check);
     54  }
     55 
     56  MOZ_RELEASE_ASSERT(one.isInList());
     57  MOZ_RELEASE_ASSERT(!two.isInList());
     58  MOZ_RELEASE_ASSERT(!three.isInList());
     59 
     60  MOZ_RELEASE_ASSERT(list.contains(&one));
     61  MOZ_RELEASE_ASSERT(!list.contains(&two));
     62  MOZ_RELEASE_ASSERT(!list.contains(&three));
     63 
     64  MOZ_RELEASE_ASSERT(!list.isEmpty());
     65  MOZ_RELEASE_ASSERT(list.length() == 1);
     66  MOZ_RELEASE_ASSERT(list.getFirst()->mValue == 1);
     67  MOZ_RELEASE_ASSERT(list.getLast()->mValue == 1);
     68 
     69  list.insertFront(&two);
     70  {
     71    unsigned int check[]{2, 1};
     72    CheckListValues(list, check);
     73  }
     74 
     75  MOZ_RELEASE_ASSERT(list.length() == 2);
     76  MOZ_RELEASE_ASSERT(list.getFirst()->mValue == 2);
     77  MOZ_RELEASE_ASSERT(list.getLast()->mValue == 1);
     78 
     79  list.insertBack(&three);
     80  {
     81    unsigned int check[]{2, 1, 3};
     82    CheckListValues(list, check);
     83  }
     84 
     85  MOZ_RELEASE_ASSERT(list.length() == 3);
     86  MOZ_RELEASE_ASSERT(list.getFirst()->mValue == 2);
     87  MOZ_RELEASE_ASSERT(list.getLast()->mValue == 3);
     88 
     89  one.removeFrom(list);
     90  {
     91    unsigned int check[]{2, 3};
     92    CheckListValues(list, check);
     93  }
     94 
     95  three.setPrevious(&one);
     96  {
     97    unsigned int check[]{2, 1, 3};
     98    CheckListValues(list, check);
     99  }
    100 
    101  three.removeFrom(list);
    102  {
    103    unsigned int check[]{2, 1};
    104    CheckListValues(list, check);
    105  }
    106 
    107  two.setPrevious(&three);
    108  {
    109    unsigned int check[]{3, 2, 1};
    110    CheckListValues(list, check);
    111  }
    112 
    113  three.removeFrom(list);
    114  {
    115    unsigned int check[]{2, 1};
    116    CheckListValues(list, check);
    117  }
    118 
    119  two.setNext(&three);
    120  {
    121    unsigned int check[]{2, 3, 1};
    122    CheckListValues(list, check);
    123  }
    124 
    125  one.remove();
    126  {
    127    unsigned int check[]{2, 3};
    128    CheckListValues(list, check);
    129  }
    130 
    131  two.remove();
    132  {
    133    unsigned int check[]{3};
    134    CheckListValues(list, check);
    135  }
    136 
    137  three.setPrevious(&two);
    138  {
    139    unsigned int check[]{2, 3};
    140    CheckListValues(list, check);
    141  }
    142 
    143  three.remove();
    144  {
    145    unsigned int check[]{2};
    146    CheckListValues(list, check);
    147  }
    148 
    149  two.remove();
    150 
    151  list.insertBack(&three);
    152  {
    153    unsigned int check[]{3};
    154    CheckListValues(list, check);
    155  }
    156 
    157  list.insertFront(&two);
    158  {
    159    unsigned int check[]{2, 3};
    160    CheckListValues(list, check);
    161  }
    162 
    163  for (SomeClass* x : list) {
    164    x->incr();
    165  }
    166 
    167  MOZ_RELEASE_ASSERT(list.length() == 2);
    168  MOZ_RELEASE_ASSERT(list.getFirst() == &two);
    169  MOZ_RELEASE_ASSERT(list.getLast() == &three);
    170  MOZ_RELEASE_ASSERT(list.getFirst()->mValue == 3);
    171  MOZ_RELEASE_ASSERT(list.getLast()->mValue == 4);
    172 
    173  const LinkedList<SomeClass>& constList = list;
    174  for (const SomeClass* x : constList) {
    175    MOZ_RELEASE_ASSERT(x);
    176  }
    177 }
    178 
    179 static void TestExtendLists() {
    180  AutoCleanLinkedList<SomeClass> list1, list2;
    181 
    182  constexpr unsigned int N = 5;
    183  for (unsigned int i = 0; i < N; ++i) {
    184    list1.insertBack(new SomeClass(static_cast<int>(i)));
    185 
    186    AutoCleanLinkedList<SomeClass> singleItemList;
    187    singleItemList.insertFront(new SomeClass(static_cast<int>(i + N)));
    188    list2.extendBack(std::move(singleItemList));
    189  }
    190  // list1 = { 0, 1, 2, 3, 4 }
    191  // list2 = { 5, 6, 7, 8, 9 }
    192 
    193  list1.extendBack(AutoCleanLinkedList<SomeClass>());
    194  list1.extendBack(std::move(list2));
    195 
    196  // Make sure the line above has properly emptied |list2|.
    197  MOZ_RELEASE_ASSERT(list2.isEmpty());  // NOLINT(bugprone-use-after-move)
    198 
    199  size_t i = 0;
    200  for (SomeClass* x : list1) {
    201    MOZ_RELEASE_ASSERT(x->mValue == i++);
    202  }
    203  MOZ_RELEASE_ASSERT(i == N * 2);
    204 }
    205 
    206 void TestSplice() {
    207  AutoCleanLinkedList<SomeClass> list1, list2;
    208  for (unsigned int i = 1; i <= 5; ++i) {
    209    list1.insertBack(new SomeClass(static_cast<int>(i)));
    210 
    211    AutoCleanLinkedList<SomeClass> singleItemList;
    212    singleItemList.insertFront(new SomeClass(static_cast<int>(i * 10)));
    213    list2.extendBack(std::move(singleItemList));
    214  }
    215  // list1 = { 1, 2, 3, 4, 5 }
    216  // list2 = { 10, 20, 30, 40, 50 }
    217 
    218  list1.splice(2, list2, 0, 5);
    219 
    220  MOZ_RELEASE_ASSERT(list2.isEmpty());
    221  unsigned int kExpected1[]{1, 2, 10, 20, 30, 40, 50, 3, 4, 5};
    222  CheckListValues(list1, kExpected1);
    223 
    224  // Since aSourceLen=100 exceeds list1's end, the function transfers
    225  // three items [3, 4, 5].
    226  list2.splice(0, list1, 7, 100);
    227 
    228  unsigned int kExpected2[]{1, 2, 10, 20, 30, 40, 50};
    229  unsigned int kExpected3[]{3, 4, 5};
    230  CheckListValues(list1, kExpected2);
    231  CheckListValues(list2, kExpected3);
    232 
    233  // Since aDestinationPos=100 exceeds list2's end, the function transfers
    234  // items to list2's end.
    235  list2.splice(100, list1, 1, 1);
    236 
    237  unsigned int kExpected4[]{1, 10, 20, 30, 40, 50};
    238  unsigned int kExpected5[]{3, 4, 5, 2};
    239  CheckListValues(list1, kExpected4);
    240  CheckListValues(list2, kExpected5);
    241 }
    242 
    243 static void TestMove() {
    244  auto MakeSomeClass = [](unsigned int aValue) -> SomeClass {
    245    return SomeClass(aValue);
    246  };
    247 
    248  LinkedList<SomeClass> list1;
    249 
    250  // Test move constructor for LinkedListElement.
    251  SomeClass c1(MakeSomeClass(1));
    252  list1.insertBack(&c1);
    253 
    254  // Test move assignment for LinkedListElement from an element not in a
    255  // list.
    256  SomeClass c2;
    257  c2 = MakeSomeClass(2);
    258  list1.insertBack(&c2);
    259 
    260  // Test move assignment of LinkedListElement from an element already in a
    261  // list.
    262  SomeClass c3;
    263  c3 = std::move(c2);
    264  MOZ_RELEASE_ASSERT(!c2.isInList());
    265  MOZ_RELEASE_ASSERT(c3.isInList());
    266 
    267  // Test move constructor for LinkedList.
    268  LinkedList<SomeClass> list2(std::move(list1));
    269  {
    270    unsigned int check[]{1, 2};
    271    CheckListValues(list2, check);
    272  }
    273  MOZ_RELEASE_ASSERT(list1.isEmpty());
    274 
    275  // Test move assignment for LinkedList.
    276  LinkedList<SomeClass> list3;
    277  list3 = std::move(list2);
    278  {
    279    unsigned int check[]{1, 2};
    280    CheckListValues(list3, check);
    281  }
    282  MOZ_RELEASE_ASSERT(list2.isEmpty());
    283 
    284  list3.clear();
    285 }
    286 
    287 static void TestRemoveAndGet() {
    288  LinkedList<SomeClass> list;
    289 
    290  SomeClass one(1), two(2), three(3);
    291  list.insertBack(&one);
    292  list.insertBack(&two);
    293  list.insertBack(&three);
    294  {
    295    unsigned int check[]{1, 2, 3};
    296    CheckListValues(list, check);
    297  }
    298 
    299  MOZ_RELEASE_ASSERT(two.removeAndGetNext() == &three);
    300  {
    301    unsigned int check[]{1, 3};
    302    CheckListValues(list, check);
    303  }
    304 
    305  MOZ_RELEASE_ASSERT(three.removeAndGetPrevious() == &one);
    306  {
    307    unsigned int check[]{1};
    308    CheckListValues(list, check);
    309  }
    310 }
    311 
    312 struct PrivateClass : private LinkedListElement<PrivateClass> {
    313  friend class mozilla::LinkedList<PrivateClass>;
    314  friend class mozilla::LinkedListElement<PrivateClass>;
    315 };
    316 
    317 static void TestPrivate() {
    318  LinkedList<PrivateClass> list;
    319  PrivateClass one, two;
    320  list.insertBack(&one);
    321  list.insertBack(&two);
    322 
    323  size_t count = 0;
    324  for (PrivateClass* p : list) {
    325    MOZ_RELEASE_ASSERT(p, "cannot have null elements in list");
    326    count++;
    327  }
    328  MOZ_RELEASE_ASSERT(count == 2);
    329 }
    330 
    331 struct CountedClass : public LinkedListElement<RefPtr<CountedClass>> {
    332  int mCount;
    333  void AddRef() { mCount++; }
    334  void Release() { mCount--; }
    335 
    336  CountedClass() : mCount(0) {}
    337  ~CountedClass() { MOZ_RELEASE_ASSERT(mCount == 0); }
    338 };
    339 
    340 static void TestRefPtrList() {
    341  LinkedList<RefPtr<CountedClass>> list;
    342  CountedClass* elt1 = new CountedClass;
    343  CountedClass* elt2 = new CountedClass;
    344 
    345  list.insertBack(elt1);
    346  list.insertBack(elt2);
    347 
    348  MOZ_RELEASE_ASSERT(elt1->mCount == 1);
    349  MOZ_RELEASE_ASSERT(elt2->mCount == 1);
    350 
    351  for (RefPtr<CountedClass> p : list) {
    352    MOZ_RELEASE_ASSERT(p->mCount == 2);
    353  }
    354 
    355  RefPtr<CountedClass> ptr = list.getFirst();
    356  while (ptr) {
    357    MOZ_RELEASE_ASSERT(ptr->mCount == 2);
    358    RefPtr<CountedClass> next = ptr->getNext();
    359    ptr->remove();
    360    ptr = std::move(next);
    361  }
    362  ptr = nullptr;
    363 
    364  MOZ_RELEASE_ASSERT(elt1->mCount == 0);
    365  MOZ_RELEASE_ASSERT(elt2->mCount == 0);
    366 
    367  list.insertBack(elt1);
    368  elt1->setNext(elt2);
    369 
    370  MOZ_RELEASE_ASSERT(elt1->mCount == 1);
    371  MOZ_RELEASE_ASSERT(elt2->mCount == 1);
    372 
    373  RefPtr<CountedClass> first = list.popFirst();
    374 
    375  MOZ_RELEASE_ASSERT(elt1->mCount == 1);
    376  MOZ_RELEASE_ASSERT(elt2->mCount == 1);
    377 
    378  RefPtr<CountedClass> second = list.popFirst();
    379 
    380  MOZ_RELEASE_ASSERT(elt1->mCount == 1);
    381  MOZ_RELEASE_ASSERT(elt2->mCount == 1);
    382 
    383  first = second = nullptr;
    384 
    385  delete elt1;
    386  delete elt2;
    387 }
    388 
    389 int main() {
    390  TestList();
    391  TestExtendLists();
    392  TestSplice();
    393  TestPrivate();
    394  TestMove();
    395  TestRemoveAndGet();
    396  TestRefPtrList();
    397  return 0;
    398 }