tor-browser

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

TestDoublyLinkedList.cpp (7687B)


      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/DoublyLinkedList.h"
      9 
     10 using mozilla::DoublyLinkedList;
     11 using mozilla::DoublyLinkedListElement;
     12 
     13 struct SomeClass : public DoublyLinkedListElement<SomeClass> {
     14  unsigned int mValue;
     15  explicit SomeClass(int aValue) : mValue(aValue) {}
     16  void incr() { ++mValue; }
     17  bool operator==(const SomeClass& other) const {
     18    return mValue == other.mValue;
     19  }
     20 };
     21 
     22 template <typename ListType, size_t N>
     23 static void CheckListValues(ListType& list, unsigned int (&values)[N]) {
     24  size_t count = 0;
     25  for (auto& x : list) {
     26    MOZ_RELEASE_ASSERT(x.mValue == values[count]);
     27    ++count;
     28  }
     29  MOZ_RELEASE_ASSERT(count == N);
     30 }
     31 
     32 static void TestDoublyLinkedList() {
     33  DoublyLinkedList<SomeClass> list;
     34 
     35  SomeClass one(1), two(2), three(3);
     36 
     37  MOZ_RELEASE_ASSERT(list.isEmpty());
     38  MOZ_RELEASE_ASSERT(!list.begin());
     39  MOZ_RELEASE_ASSERT(!list.end());
     40 
     41  for (SomeClass& x : list) {
     42    MOZ_RELEASE_ASSERT(x.mValue);
     43    MOZ_RELEASE_ASSERT(false);
     44  }
     45 
     46  list.pushFront(&one);
     47  {
     48    unsigned int check[]{1};
     49    CheckListValues(list, check);
     50  }
     51 
     52  MOZ_RELEASE_ASSERT(list.contains(one));
     53  MOZ_RELEASE_ASSERT(!list.contains(two));
     54  MOZ_RELEASE_ASSERT(!list.contains(three));
     55 
     56  MOZ_RELEASE_ASSERT(!list.isEmpty());
     57  MOZ_RELEASE_ASSERT(list.begin()->mValue == 1);
     58  MOZ_RELEASE_ASSERT(!list.end());
     59 
     60  list.pushFront(&two);
     61  {
     62    unsigned int check[]{2, 1};
     63    CheckListValues(list, check);
     64  }
     65 
     66  MOZ_RELEASE_ASSERT(list.begin()->mValue == 2);
     67  MOZ_RELEASE_ASSERT(!list.end());
     68  MOZ_RELEASE_ASSERT(!list.contains(three));
     69 
     70  list.pushBack(&three);
     71  {
     72    unsigned int check[]{2, 1, 3};
     73    CheckListValues(list, check);
     74  }
     75 
     76  MOZ_RELEASE_ASSERT(list.begin()->mValue == 2);
     77  MOZ_RELEASE_ASSERT(!list.end());
     78 
     79  list.remove(&one);
     80  {
     81    unsigned int check[]{2, 3};
     82    CheckListValues(list, check);
     83  }
     84 
     85  list.insertBefore(list.find(three), &one);
     86  {
     87    unsigned int check[]{2, 1, 3};
     88    CheckListValues(list, check);
     89  }
     90 
     91  list.remove(&three);
     92  {
     93    unsigned int check[]{2, 1};
     94    CheckListValues(list, check);
     95  }
     96 
     97  list.insertBefore(list.find(two), &three);
     98  {
     99    unsigned int check[]{3, 2, 1};
    100    CheckListValues(list, check);
    101  }
    102 
    103  list.remove(&three);
    104  {
    105    unsigned int check[]{2, 1};
    106    CheckListValues(list, check);
    107  }
    108 
    109  list.insertBefore(++list.find(two), &three);
    110  {
    111    unsigned int check[]{2, 3, 1};
    112    CheckListValues(list, check);
    113  }
    114 
    115  list.remove(&one);
    116  {
    117    unsigned int check[]{2, 3};
    118    CheckListValues(list, check);
    119  }
    120 
    121  list.remove(&two);
    122  {
    123    unsigned int check[]{3};
    124    CheckListValues(list, check);
    125  }
    126 
    127  list.insertBefore(list.find(three), &two);
    128  {
    129    unsigned int check[]{2, 3};
    130    CheckListValues(list, check);
    131  }
    132 
    133  list.remove(&three);
    134  {
    135    unsigned int check[]{2};
    136    CheckListValues(list, check);
    137  }
    138 
    139  list.remove(&two);
    140  MOZ_RELEASE_ASSERT(list.isEmpty());
    141 
    142  list.pushBack(&three);
    143  {
    144    unsigned int check[]{3};
    145    CheckListValues(list, check);
    146  }
    147 
    148  list.pushFront(&two);
    149  {
    150    unsigned int check[]{2, 3};
    151    CheckListValues(list, check);
    152  }
    153 
    154  // This should modify the values of |two| and |three| as pointers to them are
    155  // stored in the list, not copies.
    156  for (SomeClass& x : list) {
    157    x.incr();
    158  }
    159 
    160  MOZ_RELEASE_ASSERT(*list.begin() == two);
    161  MOZ_RELEASE_ASSERT(*++list.begin() == three);
    162 
    163  SomeClass four(4);
    164  MOZ_RELEASE_ASSERT(++list.begin() == list.find(four));
    165 }
    166 
    167 struct InTwoLists {
    168  explicit InTwoLists(unsigned int aValue) : mValue(aValue) {}
    169  DoublyLinkedListElement<InTwoLists> mListOne;
    170  DoublyLinkedListElement<InTwoLists> mListTwo;
    171  unsigned int mValue;
    172 
    173  struct GetListOneTrait {
    174    static DoublyLinkedListElement<InTwoLists>& Get(InTwoLists* aThis) {
    175      return aThis->mListOne;
    176    }
    177    static const DoublyLinkedListElement<InTwoLists>& Get(
    178        const InTwoLists* aThis) {
    179      return aThis->mListOne;
    180    }
    181  };
    182 };
    183 
    184 namespace mozilla {
    185 
    186 template <>
    187 struct GetDoublyLinkedListElement<InTwoLists> {
    188  static DoublyLinkedListElement<InTwoLists>& Get(InTwoLists* aThis) {
    189    return aThis->mListTwo;
    190  }
    191  static const DoublyLinkedListElement<InTwoLists>& Get(
    192      const InTwoLists* aThis) {
    193    return aThis->mListTwo;
    194  }
    195 };
    196 
    197 }  // namespace mozilla
    198 
    199 static void TestCustomAccessor() {
    200  DoublyLinkedList<InTwoLists, InTwoLists::GetListOneTrait> listOne;
    201  DoublyLinkedList<InTwoLists> listTwo;
    202 
    203  InTwoLists one(1);
    204  InTwoLists two(2);
    205 
    206  listOne.pushBack(&one);
    207  listOne.pushBack(&two);
    208  {
    209    unsigned int check[]{1, 2};
    210    CheckListValues(listOne, check);
    211  }
    212 
    213  listTwo.pushBack(&one);
    214  listTwo.pushBack(&two);
    215  {
    216    unsigned int check[]{1, 2};
    217    CheckListValues(listOne, check);
    218  }
    219  {
    220    unsigned int check[]{1, 2};
    221    CheckListValues(listTwo, check);
    222  }
    223 
    224  (void)listTwo.popBack();
    225  {
    226    unsigned int check[]{1, 2};
    227    CheckListValues(listOne, check);
    228  }
    229  {
    230    unsigned int check[]{1};
    231    CheckListValues(listTwo, check);
    232  }
    233 
    234  (void)listOne.popBack();
    235  {
    236    unsigned int check[]{1};
    237    CheckListValues(listOne, check);
    238  }
    239  {
    240    unsigned int check[]{1};
    241    CheckListValues(listTwo, check);
    242  }
    243 }
    244 
    245 static void TestSafeDoubleLinkedList() {
    246  mozilla::SafeDoublyLinkedList<SomeClass> list;
    247  auto* elt1 = new SomeClass(0);
    248  auto* elt2 = new SomeClass(0);
    249  auto* elt3 = new SomeClass(0);
    250  auto* elt4 = new SomeClass(0);
    251  list.pushBack(elt1);
    252  list.pushBack(elt2);
    253  list.pushBack(elt3);
    254  auto iter = list.begin();
    255 
    256  // basic tests for iterator validity
    257  MOZ_RELEASE_ASSERT(
    258      &*iter == elt1,
    259      "iterator returned by begin() must point to the first element!");
    260  MOZ_RELEASE_ASSERT(
    261      &*(iter.next()) == elt2,
    262      "iterator returned by begin() must have the second element as 'next'!");
    263  list.remove(elt2);
    264  MOZ_RELEASE_ASSERT(
    265      &*(iter.next()) == elt3,
    266      "After removal of the 2nd element 'next' must point to the 3rd element!");
    267  ++iter;
    268  MOZ_RELEASE_ASSERT(
    269      &*iter == elt3,
    270      "After advancing one step the current element must be the 3rd one!");
    271  MOZ_RELEASE_ASSERT(!iter.next(), "This is the last element of the list!");
    272  list.pushBack(elt4);
    273  MOZ_RELEASE_ASSERT(&*(iter.next()) == elt4,
    274                     "After adding an element at the end of the list the "
    275                     "iterator must be updated!");
    276 
    277  // advance to last element, then remove last element
    278  ++iter;
    279  list.popBack();
    280  MOZ_RELEASE_ASSERT(bool(iter) == false,
    281                     "After removing the last element, the iterator pointing "
    282                     "to the last element must be empty!");
    283 
    284  // iterate the whole remaining list, increment values
    285  for (auto& el : list) {
    286    el.incr();
    287  }
    288  MOZ_RELEASE_ASSERT(elt1->mValue == 1);
    289  MOZ_RELEASE_ASSERT(elt2->mValue == 0);
    290  MOZ_RELEASE_ASSERT(elt3->mValue == 1);
    291  MOZ_RELEASE_ASSERT(elt4->mValue == 0);
    292 
    293  // Removing the first element of the list while iterating must empty the
    294  // iterator
    295  for (auto it = list.begin(); it != list.end(); ++it) {
    296    MOZ_RELEASE_ASSERT(bool(it) == true, "The iterator must contain a value!");
    297    list.popFront();
    298    MOZ_RELEASE_ASSERT(
    299        bool(it) == false,
    300        "After removing the first element, the iterator must be empty!");
    301  }
    302 
    303  delete elt1;
    304  delete elt2;
    305  delete elt3;
    306  delete elt4;
    307 }
    308 
    309 int main() {
    310  TestDoublyLinkedList();
    311  TestCustomAccessor();
    312  TestSafeDoubleLinkedList();
    313  return 0;
    314 }