tor-browser

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

TestVector.cpp (22954B)


      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 <utility>
      8 
      9 #include "mozilla/IntegerRange.h"
     10 #include "mozilla/UniquePtr.h"
     11 #include "mozilla/Vector.h"
     12 
     13 using mozilla::IntegerRange;
     14 using mozilla::MakeUnique;
     15 using mozilla::UniquePtr;
     16 using mozilla::Vector;
     17 using mozilla::detail::VectorTesting;
     18 
     19 struct mozilla::detail::VectorTesting {
     20  static void testReserved();
     21  static void testConstRange();
     22  static void testEmplaceBack();
     23  static void testReverse();
     24  static void testExtractRawBuffer();
     25  static void testExtractOrCopyRawBuffer();
     26  static void testReplaceRawBuffer();
     27  static void testInsert();
     28  static void testErase();
     29  static void testShrinkStorageToFit();
     30  static void testAppend();
     31 };
     32 
     33 void mozilla::detail::VectorTesting::testReserved() {
     34 #ifdef DEBUG
     35  Vector<bool> bv;
     36  MOZ_RELEASE_ASSERT(bv.reserved() == 0);
     37 
     38  MOZ_RELEASE_ASSERT(bv.append(true));
     39  MOZ_RELEASE_ASSERT(bv.reserved() == 1);
     40 
     41  Vector<bool> otherbv;
     42  MOZ_RELEASE_ASSERT(otherbv.append(false));
     43  MOZ_RELEASE_ASSERT(otherbv.append(true));
     44  MOZ_RELEASE_ASSERT(bv.appendAll(otherbv));
     45  MOZ_RELEASE_ASSERT(bv.reserved() == 3);
     46 
     47  MOZ_RELEASE_ASSERT(bv.reserve(5));
     48  MOZ_RELEASE_ASSERT(bv.reserved() == 5);
     49 
     50  MOZ_RELEASE_ASSERT(bv.reserve(1));
     51  MOZ_RELEASE_ASSERT(bv.reserved() == 5);
     52 
     53  Vector<bool> bv2(std::move(bv));
     54  MOZ_RELEASE_ASSERT(bv.reserved() == 0);
     55  MOZ_RELEASE_ASSERT(bv2.reserved() == 5);
     56 
     57  bv2.clearAndFree();
     58  MOZ_RELEASE_ASSERT(bv2.reserved() == 0);
     59 
     60  Vector<int, 42> iv;
     61  MOZ_RELEASE_ASSERT(iv.reserved() == 0);
     62 
     63  MOZ_RELEASE_ASSERT(iv.append(17));
     64  MOZ_RELEASE_ASSERT(iv.reserved() == 1);
     65 
     66  Vector<int, 42> otheriv;
     67  MOZ_RELEASE_ASSERT(otheriv.append(42));
     68  MOZ_RELEASE_ASSERT(otheriv.append(37));
     69  MOZ_RELEASE_ASSERT(iv.appendAll(otheriv));
     70  MOZ_RELEASE_ASSERT(iv.reserved() == 3);
     71 
     72  MOZ_RELEASE_ASSERT(iv.reserve(5));
     73  MOZ_RELEASE_ASSERT(iv.reserved() == 5);
     74 
     75  MOZ_RELEASE_ASSERT(iv.reserve(1));
     76  MOZ_RELEASE_ASSERT(iv.reserved() == 5);
     77 
     78  MOZ_RELEASE_ASSERT(iv.reserve(55));
     79  MOZ_RELEASE_ASSERT(iv.reserved() == 55);
     80 
     81  Vector<int, 42> iv2(std::move(iv));
     82  MOZ_RELEASE_ASSERT(iv.reserved() == 0);
     83  MOZ_RELEASE_ASSERT(iv2.reserved() == 55);
     84 
     85  iv2.clearAndFree();
     86  MOZ_RELEASE_ASSERT(iv2.reserved() == 0);
     87 #endif
     88 }
     89 
     90 void mozilla::detail::VectorTesting::testConstRange() {
     91 #ifdef DEBUG
     92  Vector<int> vec;
     93 
     94  for (int i = 0; i < 10; i++) {
     95    MOZ_RELEASE_ASSERT(vec.append(i));
     96  }
     97 
     98  const auto& vecRef = vec;
     99 
    100  Vector<int>::ConstRange range = vecRef.all();
    101  for (int i = 0; i < 10; i++) {
    102    MOZ_RELEASE_ASSERT(!range.empty());
    103    MOZ_RELEASE_ASSERT(range.front() == i);
    104    range.popFront();
    105  }
    106 #endif
    107 }
    108 
    109 namespace {
    110 
    111 struct S {
    112  size_t j;
    113  UniquePtr<size_t> k;
    114 
    115  static size_t constructCount;
    116  static size_t moveCount;
    117  static size_t destructCount;
    118 
    119  static void resetCounts() {
    120    constructCount = 0;
    121    moveCount = 0;
    122    destructCount = 0;
    123  }
    124 
    125  S(size_t j, size_t k) : j(j), k(MakeUnique<size_t>(k)) { constructCount++; }
    126 
    127  S(S&& rhs) : j(rhs.j), k(std::move(rhs.k)) {
    128    rhs.j = 0;
    129    rhs.k.reset(0);
    130    moveCount++;
    131  }
    132 
    133  ~S() { destructCount++; }
    134 
    135  S& operator=(S&& rhs) {
    136    j = rhs.j;
    137    rhs.j = 0;
    138    k = std::move(rhs.k);
    139    rhs.k.reset();
    140    moveCount++;
    141    return *this;
    142  }
    143 
    144  bool operator==(const S& rhs) const { return j == rhs.j && *k == *rhs.k; }
    145 
    146  S(const S&) = delete;
    147  S& operator=(const S&) = delete;
    148 };
    149 
    150 size_t S::constructCount = 0;
    151 size_t S::moveCount = 0;
    152 size_t S::destructCount = 0;
    153 
    154 }  // namespace
    155 
    156 void mozilla::detail::VectorTesting::testEmplaceBack() {
    157  S::resetCounts();
    158 
    159  Vector<S> vec;
    160  MOZ_RELEASE_ASSERT(vec.reserve(20));
    161 
    162  for (size_t i = 0; i < 10; i++) {
    163    S s(i, i * i);
    164    MOZ_RELEASE_ASSERT(vec.append(std::move(s)));
    165  }
    166 
    167  MOZ_RELEASE_ASSERT(vec.length() == 10);
    168  MOZ_RELEASE_ASSERT(S::constructCount == 10);
    169  MOZ_RELEASE_ASSERT(S::moveCount == 10);
    170 
    171  for (size_t i = 10; i < 20; i++) {
    172    MOZ_RELEASE_ASSERT(vec.emplaceBack(i, i * i));
    173  }
    174 
    175  MOZ_RELEASE_ASSERT(vec.length() == 20);
    176  MOZ_RELEASE_ASSERT(S::constructCount == 20);
    177  MOZ_RELEASE_ASSERT(S::moveCount == 10);
    178 
    179  for (size_t i = 0; i < 20; i++) {
    180    MOZ_RELEASE_ASSERT(vec[i].j == i);
    181    MOZ_RELEASE_ASSERT(*vec[i].k == i * i);
    182  }
    183 }
    184 
    185 void mozilla::detail::VectorTesting::testReverse() {
    186  // Use UniquePtr to make sure that reverse() can handler move-only types.
    187  Vector<UniquePtr<uint8_t>, 0> vec;
    188 
    189  // Reverse an odd number of elements.
    190 
    191  for (uint8_t i = 0; i < 5; i++) {
    192    auto p = MakeUnique<uint8_t>(i);
    193    MOZ_RELEASE_ASSERT(p);
    194    MOZ_RELEASE_ASSERT(vec.append(std::move(p)));
    195  }
    196 
    197  vec.reverse();
    198 
    199  MOZ_RELEASE_ASSERT(*vec[0] == 4);
    200  MOZ_RELEASE_ASSERT(*vec[1] == 3);
    201  MOZ_RELEASE_ASSERT(*vec[2] == 2);
    202  MOZ_RELEASE_ASSERT(*vec[3] == 1);
    203  MOZ_RELEASE_ASSERT(*vec[4] == 0);
    204 
    205  // Reverse an even number of elements.
    206 
    207  vec.popBack();
    208  vec.reverse();
    209 
    210  MOZ_RELEASE_ASSERT(*vec[0] == 1);
    211  MOZ_RELEASE_ASSERT(*vec[1] == 2);
    212  MOZ_RELEASE_ASSERT(*vec[2] == 3);
    213  MOZ_RELEASE_ASSERT(*vec[3] == 4);
    214 
    215  // Reverse an empty vector.
    216 
    217  vec.clear();
    218  MOZ_RELEASE_ASSERT(vec.length() == 0);
    219  vec.reverse();
    220  MOZ_RELEASE_ASSERT(vec.length() == 0);
    221 
    222  // Reverse a vector using only inline storage.
    223 
    224  Vector<UniquePtr<uint8_t>, 5> vec2;
    225  for (uint8_t i = 0; i < 5; i++) {
    226    auto p = MakeUnique<uint8_t>(i);
    227    MOZ_RELEASE_ASSERT(p);
    228    MOZ_RELEASE_ASSERT(vec2.append(std::move(p)));
    229  }
    230 
    231  vec2.reverse();
    232 
    233  MOZ_RELEASE_ASSERT(*vec2[0] == 4);
    234  MOZ_RELEASE_ASSERT(*vec2[1] == 3);
    235  MOZ_RELEASE_ASSERT(*vec2[2] == 2);
    236  MOZ_RELEASE_ASSERT(*vec2[3] == 1);
    237  MOZ_RELEASE_ASSERT(*vec2[4] == 0);
    238 }
    239 
    240 void mozilla::detail::VectorTesting::testExtractRawBuffer() {
    241  S::resetCounts();
    242 
    243  Vector<S, 5> vec;
    244  MOZ_RELEASE_ASSERT(vec.reserve(5));
    245  for (size_t i = 0; i < 5; i++) {
    246    vec.infallibleEmplaceBack(i, i * i);
    247  }
    248  MOZ_RELEASE_ASSERT(vec.length() == 5);
    249  MOZ_ASSERT(vec.reserved() == 5);
    250  MOZ_RELEASE_ASSERT(S::constructCount == 5);
    251  MOZ_RELEASE_ASSERT(S::moveCount == 0);
    252  MOZ_RELEASE_ASSERT(S::destructCount == 0);
    253 
    254  S* buf = vec.extractRawBuffer();
    255  MOZ_RELEASE_ASSERT(!buf);
    256  MOZ_RELEASE_ASSERT(vec.length() == 5);
    257  MOZ_ASSERT(vec.reserved() == 5);
    258  MOZ_RELEASE_ASSERT(S::constructCount == 5);
    259  MOZ_RELEASE_ASSERT(S::moveCount == 0);
    260  MOZ_RELEASE_ASSERT(S::destructCount == 0);
    261 
    262  MOZ_RELEASE_ASSERT(vec.reserve(10));
    263  for (size_t i = 5; i < 10; i++) {
    264    vec.infallibleEmplaceBack(i, i * i);
    265  }
    266  MOZ_RELEASE_ASSERT(vec.length() == 10);
    267  MOZ_ASSERT(vec.reserved() == 10);
    268  MOZ_RELEASE_ASSERT(S::constructCount == 10);
    269  MOZ_RELEASE_ASSERT(S::moveCount == 5);
    270  MOZ_RELEASE_ASSERT(S::destructCount == 5);
    271 
    272  buf = vec.extractRawBuffer();
    273  MOZ_RELEASE_ASSERT(buf);
    274  MOZ_RELEASE_ASSERT(vec.length() == 0);
    275  MOZ_ASSERT(vec.reserved() == 0);
    276  MOZ_RELEASE_ASSERT(S::constructCount == 10);
    277  MOZ_RELEASE_ASSERT(S::moveCount == 5);
    278  MOZ_RELEASE_ASSERT(S::destructCount == 5);
    279 
    280  for (size_t i = 0; i < 10; i++) {
    281    MOZ_RELEASE_ASSERT(buf[i].j == i);
    282    MOZ_RELEASE_ASSERT(*buf[i].k == i * i);
    283  }
    284 
    285  free(buf);
    286 }
    287 
    288 void mozilla::detail::VectorTesting::testExtractOrCopyRawBuffer() {
    289  S::resetCounts();
    290 
    291  Vector<S, 5> vec;
    292  MOZ_RELEASE_ASSERT(vec.reserve(5));
    293  for (size_t i = 0; i < 5; i++) {
    294    vec.infallibleEmplaceBack(i, i * i);
    295  }
    296  MOZ_RELEASE_ASSERT(vec.length() == 5);
    297  MOZ_ASSERT(vec.reserved() == 5);
    298  MOZ_RELEASE_ASSERT(S::constructCount == 5);
    299  MOZ_RELEASE_ASSERT(S::moveCount == 0);
    300  MOZ_RELEASE_ASSERT(S::destructCount == 0);
    301 
    302  S* buf = vec.extractOrCopyRawBuffer();
    303  MOZ_RELEASE_ASSERT(buf);
    304  MOZ_RELEASE_ASSERT(vec.length() == 0);
    305  MOZ_ASSERT(vec.reserved() == 0);
    306  MOZ_RELEASE_ASSERT(S::constructCount == 5);
    307  MOZ_RELEASE_ASSERT(S::moveCount == 5);
    308  MOZ_RELEASE_ASSERT(S::destructCount == 5);
    309 
    310  for (size_t i = 0; i < 5; i++) {
    311    MOZ_RELEASE_ASSERT(buf[i].j == i);
    312    MOZ_RELEASE_ASSERT(*buf[i].k == i * i);
    313  }
    314 
    315  S::resetCounts();
    316 
    317  MOZ_RELEASE_ASSERT(vec.reserve(10));
    318  for (size_t i = 0; i < 10; i++) {
    319    vec.infallibleEmplaceBack(i, i * i);
    320  }
    321  MOZ_RELEASE_ASSERT(vec.length() == 10);
    322  MOZ_ASSERT(vec.reserved() == 10);
    323  MOZ_RELEASE_ASSERT(S::constructCount == 10);
    324  MOZ_RELEASE_ASSERT(S::moveCount == 0);
    325  MOZ_RELEASE_ASSERT(S::destructCount == 0);
    326 
    327  buf = vec.extractOrCopyRawBuffer();
    328  MOZ_RELEASE_ASSERT(buf);
    329  MOZ_RELEASE_ASSERT(vec.length() == 0);
    330  MOZ_ASSERT(vec.reserved() == 0);
    331  MOZ_RELEASE_ASSERT(S::constructCount == 10);
    332  MOZ_RELEASE_ASSERT(S::moveCount == 0);
    333  MOZ_RELEASE_ASSERT(S::destructCount == 0);
    334 
    335  for (size_t i = 0; i < 10; i++) {
    336    MOZ_RELEASE_ASSERT(buf[i].j == i);
    337    MOZ_RELEASE_ASSERT(*buf[i].k == i * i);
    338  }
    339 
    340  free(buf);
    341 }
    342 
    343 void mozilla::detail::VectorTesting::testReplaceRawBuffer() {
    344  S::resetCounts();
    345 
    346  S* s = nullptr;
    347 
    348  {
    349    Vector<S> v;
    350    MOZ_RELEASE_ASSERT(v.reserve(4));
    351    v.infallibleEmplaceBack(1, 2);
    352    v.infallibleEmplaceBack(3, 4);
    353    MOZ_RELEASE_ASSERT(S::constructCount == 2);
    354    s = v.extractRawBuffer();
    355  }
    356 
    357  MOZ_RELEASE_ASSERT(S::constructCount == 2);
    358  MOZ_RELEASE_ASSERT(S::moveCount == 0);
    359  MOZ_RELEASE_ASSERT(S::destructCount == 0);
    360 
    361  {
    362    Vector<S, 10> v;
    363    v.replaceRawBuffer(s, 2);
    364    MOZ_ASSERT(v.reserved() == 2);
    365    MOZ_RELEASE_ASSERT(v.length() == 2);
    366    MOZ_RELEASE_ASSERT(v.capacity() == 10);
    367    MOZ_RELEASE_ASSERT(v[0].j == 1);
    368    MOZ_RELEASE_ASSERT(v[1].j == 3);
    369    MOZ_RELEASE_ASSERT(S::destructCount == 2);
    370  }
    371 
    372  MOZ_RELEASE_ASSERT(S::constructCount == 2);
    373  MOZ_RELEASE_ASSERT(S::moveCount == 2);
    374  MOZ_RELEASE_ASSERT(S::destructCount == 4);
    375 
    376  S::resetCounts();
    377 
    378  {
    379    Vector<S, 2> v;
    380    MOZ_RELEASE_ASSERT(v.reserve(4));
    381    v.infallibleEmplaceBack(9, 10);
    382    MOZ_RELEASE_ASSERT(S::constructCount == 1);
    383    s = v.extractRawBuffer();
    384    MOZ_RELEASE_ASSERT(S::constructCount == 1);
    385    MOZ_RELEASE_ASSERT(S::moveCount == 0);
    386  }
    387 
    388  MOZ_RELEASE_ASSERT(S::destructCount == 0);
    389 
    390  {
    391    Vector<S> v;
    392    v.replaceRawBuffer(s, 1, 4);
    393    MOZ_ASSERT(v.reserved() == 4);
    394    MOZ_RELEASE_ASSERT(v.length() == 1);
    395    MOZ_RELEASE_ASSERT(v.capacity() == 4);
    396    MOZ_RELEASE_ASSERT(v[0].j == 9);
    397    for (size_t i = 0; i < 5; i++) MOZ_RELEASE_ASSERT(v.emplaceBack(i, i));
    398    MOZ_ASSERT(v.reserved() == 6);
    399    MOZ_RELEASE_ASSERT(v.length() == 6);
    400    MOZ_RELEASE_ASSERT(S::constructCount == 6);
    401    MOZ_RELEASE_ASSERT(S::moveCount == 4);
    402    MOZ_RELEASE_ASSERT(S::destructCount == 4);
    403  }
    404 
    405  MOZ_RELEASE_ASSERT(S::destructCount == 10);
    406 }
    407 
    408 void mozilla::detail::VectorTesting::testInsert() {
    409  S::resetCounts();
    410 
    411  Vector<S, 8> vec;
    412  MOZ_RELEASE_ASSERT(vec.reserve(8));
    413  for (size_t i = 0; i < 7; i++) {
    414    vec.infallibleEmplaceBack(i, i * i);
    415  }
    416 
    417  MOZ_RELEASE_ASSERT(vec.length() == 7);
    418  MOZ_ASSERT(vec.reserved() == 8);
    419  MOZ_RELEASE_ASSERT(S::constructCount == 7);
    420  MOZ_RELEASE_ASSERT(S::moveCount == 0);
    421  MOZ_RELEASE_ASSERT(S::destructCount == 0);
    422 
    423  S s(42, 43);
    424  MOZ_RELEASE_ASSERT(vec.insert(vec.begin() + 4, std::move(s)));
    425 
    426  for (size_t i = 0; i < vec.length(); i++) {
    427    const S& s = vec[i];
    428    MOZ_RELEASE_ASSERT(s.k);
    429    if (i < 4) {
    430      MOZ_RELEASE_ASSERT(s.j == i && *s.k == i * i);
    431    } else if (i == 4) {
    432      MOZ_RELEASE_ASSERT(s.j == 42 && *s.k == 43);
    433    } else {
    434      MOZ_RELEASE_ASSERT(s.j == i - 1 && *s.k == (i - 1) * (i - 1));
    435    }
    436  }
    437 
    438  MOZ_RELEASE_ASSERT(vec.length() == 8);
    439  MOZ_ASSERT(vec.reserved() == 8);
    440  MOZ_RELEASE_ASSERT(S::constructCount == 8);
    441  MOZ_RELEASE_ASSERT(S::moveCount == 1 /* move in insert() call */ +
    442                                         1 /* move the back() element */ +
    443                                         3 /* elements to shift */);
    444  MOZ_RELEASE_ASSERT(S::destructCount == 1);
    445 }
    446 
    447 void mozilla::detail::VectorTesting::testErase() {
    448  S::resetCounts();
    449 
    450  Vector<S, 8> vec;
    451  MOZ_RELEASE_ASSERT(vec.reserve(8));
    452  for (size_t i = 0; i < 7; i++) {
    453    vec.infallibleEmplaceBack(i, i * i);
    454  }
    455 
    456  // vec: [0, 1, 2, 3, 4, 5, 6]
    457  MOZ_RELEASE_ASSERT(vec.length() == 7);
    458  MOZ_ASSERT(vec.reserved() == 8);
    459  MOZ_RELEASE_ASSERT(S::constructCount == 7);
    460  MOZ_RELEASE_ASSERT(S::moveCount == 0);
    461  MOZ_RELEASE_ASSERT(S::destructCount == 0);
    462  S::resetCounts();
    463 
    464  vec.erase(&vec[4]);
    465  // vec: [0, 1, 2, 3, 5, 6]
    466  MOZ_RELEASE_ASSERT(vec.length() == 6);
    467  MOZ_ASSERT(vec.reserved() == 8);
    468  MOZ_RELEASE_ASSERT(S::constructCount == 0);
    469  // 5 and 6 should have been moved into 4 and 5.
    470  MOZ_RELEASE_ASSERT(S::moveCount == 2);
    471  MOZ_RELEASE_ASSERT(S::destructCount == 1);
    472  MOZ_RELEASE_ASSERT(vec[4] == S(5, 5 * 5));
    473  MOZ_RELEASE_ASSERT(vec[5] == S(6, 6 * 6));
    474  S::resetCounts();
    475 
    476  vec.erase(&vec[3], &vec[5]);
    477  // vec: [0, 1, 2, 6]
    478  MOZ_RELEASE_ASSERT(vec.length() == 4);
    479  MOZ_ASSERT(vec.reserved() == 8);
    480  MOZ_RELEASE_ASSERT(S::constructCount == 0);
    481  // 6 should have been moved into 3.
    482  MOZ_RELEASE_ASSERT(S::moveCount == 1);
    483  MOZ_RELEASE_ASSERT(S::destructCount == 2);
    484  MOZ_RELEASE_ASSERT(vec[3] == S(6, 6 * 6));
    485 
    486  S s2(2, 2 * 2);
    487  S::resetCounts();
    488 
    489  vec.eraseIfEqual(s2);
    490  // vec: [0, 1, 6]
    491  MOZ_RELEASE_ASSERT(vec.length() == 3);
    492  MOZ_ASSERT(vec.reserved() == 8);
    493  MOZ_RELEASE_ASSERT(S::constructCount == 0);
    494  // 6 should have been moved into 2.
    495  MOZ_RELEASE_ASSERT(S::moveCount == 1);
    496  MOZ_RELEASE_ASSERT(S::destructCount == 1);
    497  MOZ_RELEASE_ASSERT(vec[2] == S(6, 6 * 6));
    498  S::resetCounts();
    499 
    500  // Predicate to find one element.
    501  vec.eraseIf([](const S& s) { return s.j == 1; });
    502  // vec: [0, 6]
    503  MOZ_RELEASE_ASSERT(vec.length() == 2);
    504  MOZ_ASSERT(vec.reserved() == 8);
    505  MOZ_RELEASE_ASSERT(S::constructCount == 0);
    506  // 6 should have been moved into 1.
    507  MOZ_RELEASE_ASSERT(S::moveCount == 1);
    508  MOZ_RELEASE_ASSERT(S::destructCount == 1);
    509  MOZ_RELEASE_ASSERT(vec[1] == S(6, 6 * 6));
    510  S::resetCounts();
    511 
    512  // Generic predicate that flags everything.
    513  vec.eraseIf([](auto&&) { return true; });
    514  // vec: []
    515  MOZ_RELEASE_ASSERT(vec.length() == 0);
    516  MOZ_ASSERT(vec.reserved() == 8);
    517  MOZ_RELEASE_ASSERT(S::constructCount == 0);
    518  MOZ_RELEASE_ASSERT(S::moveCount == 0);
    519  MOZ_RELEASE_ASSERT(S::destructCount == 2);
    520 
    521  for (size_t i = 0; i < 7; i++) {
    522    vec.infallibleEmplaceBack(i, i * i);
    523  }
    524  // vec: [0, 1, 2, 3, 4, 5, 6]
    525  MOZ_RELEASE_ASSERT(vec.length() == 7);
    526  S::resetCounts();
    527 
    528  // Predicate that flags all even numbers.
    529  vec.eraseIf([](const S& s) { return s.j % 2 == 0; });
    530  // vec: [1 (was 0), 3 (was 1), 5 (was 2)]
    531  MOZ_RELEASE_ASSERT(vec.length() == 3);
    532  MOZ_ASSERT(vec.reserved() == 8);
    533  MOZ_RELEASE_ASSERT(S::constructCount == 0);
    534  MOZ_RELEASE_ASSERT(S::moveCount == 3);
    535  MOZ_RELEASE_ASSERT(S::destructCount == 4);
    536 }
    537 
    538 void mozilla::detail::VectorTesting::testShrinkStorageToFit() {
    539  // Vectors not using inline storage realloc capacity to exact length.
    540  {
    541    Vector<int, 0> v1;
    542    MOZ_RELEASE_ASSERT(v1.reserve(10));
    543    v1.infallibleAppend(1);
    544    MOZ_ASSERT(v1.reserved() == 10);
    545    MOZ_RELEASE_ASSERT(v1.length() == 1);
    546    MOZ_RELEASE_ASSERT(v1.capacity() >= 10);
    547    v1.shrinkStorageToFit();
    548    MOZ_ASSERT(v1.reserved() == 1);
    549    MOZ_RELEASE_ASSERT(v1.length() == 1);
    550    MOZ_RELEASE_ASSERT(v1.capacity() == 1);
    551  }
    552 
    553  // Vectors using inline storage do nothing.
    554  {
    555    Vector<int, 2> v2;
    556    MOZ_RELEASE_ASSERT(v2.reserve(2));
    557    v2.infallibleAppend(1);
    558    MOZ_ASSERT(v2.reserved() == 2);
    559    MOZ_RELEASE_ASSERT(v2.length() == 1);
    560    MOZ_RELEASE_ASSERT(v2.capacity() == 2);
    561    v2.shrinkStorageToFit();
    562    MOZ_ASSERT(v2.reserved() == 2);
    563    MOZ_RELEASE_ASSERT(v2.length() == 1);
    564    MOZ_RELEASE_ASSERT(v2.capacity() == 2);
    565  }
    566 
    567  // shrinkStorageToFit uses inline storage if possible.
    568  {
    569    Vector<int, 2> v;
    570    MOZ_RELEASE_ASSERT(v.reserve(4));
    571    v.infallibleAppend(1);
    572    MOZ_ASSERT(v.reserved() == 4);
    573    MOZ_RELEASE_ASSERT(v.length() == 1);
    574    MOZ_RELEASE_ASSERT(v.capacity() >= 4);
    575    v.shrinkStorageToFit();
    576    MOZ_ASSERT(v.reserved() == 1);
    577    MOZ_RELEASE_ASSERT(v.length() == 1);
    578    MOZ_RELEASE_ASSERT(v.capacity() == 2);
    579  }
    580 
    581  // Non-pod shrinking to non-inline storage.
    582  {
    583    static size_t sConstructCounter = 0;
    584    static size_t sCopyCounter = 0;
    585    static size_t sMoveCounter = 0;
    586    static size_t sDestroyCounter = 0;
    587    struct NonPod {
    588      int mSomething = 10;
    589 
    590      NonPod() { sConstructCounter++; }
    591 
    592      NonPod(const NonPod& aOther) : mSomething(aOther.mSomething) {
    593        sCopyCounter++;
    594      }
    595      NonPod(NonPod&& aOther) : mSomething(aOther.mSomething) {
    596        sMoveCounter++;
    597      }
    598      ~NonPod() { sDestroyCounter++; }
    599    };
    600 
    601    Vector<NonPod, 5> v;
    602    MOZ_RELEASE_ASSERT(v.reserve(10));
    603    for (size_t i = 0; i < 8; ++i) {
    604      v.infallibleEmplaceBack();
    605    }
    606    MOZ_RELEASE_ASSERT(sConstructCounter == 8);
    607    MOZ_RELEASE_ASSERT(sCopyCounter == 0);
    608    MOZ_RELEASE_ASSERT(sMoveCounter == 0);
    609    MOZ_RELEASE_ASSERT(sDestroyCounter == 0);
    610    MOZ_RELEASE_ASSERT(v.length() == 8);
    611    MOZ_ASSERT(v.reserved() == 10);
    612    MOZ_RELEASE_ASSERT(v.capacity() >= 10);
    613    MOZ_RELEASE_ASSERT(v.shrinkStorageToFit());
    614 
    615    MOZ_RELEASE_ASSERT(sConstructCounter == 8);
    616    MOZ_RELEASE_ASSERT(sCopyCounter == 0);
    617    MOZ_RELEASE_ASSERT(sMoveCounter == 8);
    618    MOZ_RELEASE_ASSERT(sDestroyCounter == 8);
    619    MOZ_RELEASE_ASSERT(v.length() == 8);
    620    MOZ_ASSERT(v.reserved() == 8);
    621    MOZ_RELEASE_ASSERT(v.capacity() == 8);
    622  }
    623 
    624  // Non-POD shrinking to inline storage.
    625  {
    626    static size_t sConstructCounter = 0;
    627    static size_t sCopyCounter = 0;
    628    static size_t sMoveCounter = 0;
    629    static size_t sDestroyCounter = 0;
    630    struct NonPod {
    631      int mSomething = 10;
    632 
    633      NonPod() { sConstructCounter++; }
    634 
    635      NonPod(const NonPod& aOther) : mSomething(aOther.mSomething) {
    636        sCopyCounter++;
    637      }
    638      NonPod(NonPod&& aOther) : mSomething(aOther.mSomething) {
    639        sMoveCounter++;
    640      }
    641      ~NonPod() { sDestroyCounter++; }
    642    };
    643 
    644    Vector<NonPod, 5> v;
    645    MOZ_RELEASE_ASSERT(v.reserve(10));
    646    for (size_t i = 0; i < 3; ++i) {
    647      v.infallibleEmplaceBack();
    648    }
    649    MOZ_RELEASE_ASSERT(sConstructCounter == 3);
    650    MOZ_RELEASE_ASSERT(sCopyCounter == 0);
    651    MOZ_RELEASE_ASSERT(sMoveCounter == 0);
    652    MOZ_RELEASE_ASSERT(sDestroyCounter == 0);
    653    MOZ_RELEASE_ASSERT(v.length() == 3);
    654    MOZ_ASSERT(v.reserved() == 10);
    655    MOZ_RELEASE_ASSERT(v.capacity() >= 10);
    656    MOZ_RELEASE_ASSERT(v.shrinkStorageToFit());
    657 
    658    MOZ_RELEASE_ASSERT(sConstructCounter == 3);
    659    MOZ_RELEASE_ASSERT(sCopyCounter == 0);
    660    MOZ_RELEASE_ASSERT(sMoveCounter == 3);
    661    MOZ_RELEASE_ASSERT(sDestroyCounter == 3);
    662    MOZ_RELEASE_ASSERT(v.length() == 3);
    663    MOZ_ASSERT(v.reserved() == 3);
    664    MOZ_RELEASE_ASSERT(v.capacity() == 5);
    665  }
    666 }
    667 
    668 void mozilla::detail::VectorTesting::testAppend() {
    669  // Test moving append/appendAll with a move-only type
    670  Vector<UniquePtr<int>> bv;
    671  for (const int val : IntegerRange<int>(0, 3)) {
    672    MOZ_RELEASE_ASSERT(bv.append(MakeUnique<int>(val)));
    673  }
    674 
    675  Vector<UniquePtr<int>> otherbv;
    676  for (const int val : IntegerRange<int>(3, 8)) {
    677    MOZ_RELEASE_ASSERT(otherbv.append(MakeUnique<int>(val)));
    678  }
    679  MOZ_RELEASE_ASSERT(bv.appendAll(std::move(otherbv)));
    680 
    681  MOZ_RELEASE_ASSERT(otherbv.length() == 0);
    682  MOZ_RELEASE_ASSERT(bv.length() == 8);
    683  for (const int val : IntegerRange<int>(0, 8)) {
    684    MOZ_RELEASE_ASSERT(*bv[val] == val);
    685  }
    686 }
    687 
    688 // Vector with no inline storage should occupy the absolute minimum space in
    689 // non-debug builds.  (Debug adds a laundry list of other constraints, none
    690 // directly relevant to shipping builds, that aren't worth precisely modeling.)
    691 #ifndef DEBUG
    692 
    693 template <typename T>
    694 struct NoInlineStorageLayout {
    695  T* mBegin;
    696  size_t mLength;
    697  struct CRAndStorage {
    698    size_t mCapacity;
    699  } mTail;
    700 };
    701 
    702 // Only one of these should be necessary, but test a few of them for good
    703 // measure.
    704 static_assert(sizeof(Vector<int, 0>) == sizeof(NoInlineStorageLayout<int>),
    705              "Vector of int without inline storage shouldn't occupy dead "
    706              "space for that absence of storage");
    707 
    708 static_assert(sizeof(Vector<bool, 0>) == sizeof(NoInlineStorageLayout<bool>),
    709              "Vector of bool without inline storage shouldn't occupy dead "
    710              "space for that absence of storage");
    711 
    712 static_assert(sizeof(Vector<S, 0>) == sizeof(NoInlineStorageLayout<S>),
    713              "Vector of S without inline storage shouldn't occupy dead "
    714              "space for that absence of storage");
    715 
    716 #endif  // DEBUG
    717 
    718 static void TestVectorBeginNonNull() {
    719  // Vector::begin() should never return nullptr, to accommodate callers that
    720  // (either for hygiene, or for semantic reasons) need a non-null pointer even
    721  // for zero elements.
    722 
    723  Vector<bool, 0> bvec0;
    724  MOZ_RELEASE_ASSERT(bvec0.length() == 0);
    725  MOZ_RELEASE_ASSERT(bvec0.begin() != nullptr);
    726 
    727  Vector<bool, 1> bvec1;
    728  MOZ_RELEASE_ASSERT(bvec1.length() == 0);
    729  MOZ_RELEASE_ASSERT(bvec1.begin() != nullptr);
    730 
    731  Vector<bool, 64> bvec64;
    732  MOZ_RELEASE_ASSERT(bvec64.length() == 0);
    733  MOZ_RELEASE_ASSERT(bvec64.begin() != nullptr);
    734 
    735  Vector<int, 0> ivec0;
    736  MOZ_RELEASE_ASSERT(ivec0.length() == 0);
    737  MOZ_RELEASE_ASSERT(ivec0.begin() != nullptr);
    738 
    739  Vector<int, 1> ivec1;
    740  MOZ_RELEASE_ASSERT(ivec1.length() == 0);
    741  MOZ_RELEASE_ASSERT(ivec1.begin() != nullptr);
    742 
    743  Vector<int, 64> ivec64;
    744  MOZ_RELEASE_ASSERT(ivec64.length() == 0);
    745  MOZ_RELEASE_ASSERT(ivec64.begin() != nullptr);
    746 
    747  Vector<long, 0> lvec0;
    748  MOZ_RELEASE_ASSERT(lvec0.length() == 0);
    749  MOZ_RELEASE_ASSERT(lvec0.begin() != nullptr);
    750 
    751  Vector<long, 1> lvec1;
    752  MOZ_RELEASE_ASSERT(lvec1.length() == 0);
    753  MOZ_RELEASE_ASSERT(lvec1.begin() != nullptr);
    754 
    755  Vector<long, 64> lvec64;
    756  MOZ_RELEASE_ASSERT(lvec64.length() == 0);
    757  MOZ_RELEASE_ASSERT(lvec64.begin() != nullptr);
    758 
    759  // Vector<T, N> doesn't guarantee N inline elements -- the actual count is
    760  // capped so that any Vector fits in a not-crazy amount of space -- so the
    761  // code below won't overflow stacks or anything crazy.
    762  struct VeryBig {
    763    int array[16 * 1024 * 1024];
    764  };
    765 
    766  Vector<VeryBig, 0> vbvec0;
    767  MOZ_RELEASE_ASSERT(vbvec0.length() == 0);
    768  MOZ_RELEASE_ASSERT(vbvec0.begin() != nullptr);
    769 
    770  Vector<VeryBig, 1> vbvec1;
    771  MOZ_RELEASE_ASSERT(vbvec1.length() == 0);
    772  MOZ_RELEASE_ASSERT(vbvec1.begin() != nullptr);
    773 
    774  Vector<VeryBig, 64> vbvec64;
    775  MOZ_RELEASE_ASSERT(vbvec64.length() == 0);
    776  MOZ_RELEASE_ASSERT(vbvec64.begin() != nullptr);
    777 }
    778 
    779 int main() {
    780  VectorTesting::testReserved();
    781  VectorTesting::testConstRange();
    782  VectorTesting::testEmplaceBack();
    783  VectorTesting::testReverse();
    784  VectorTesting::testExtractRawBuffer();
    785  VectorTesting::testExtractOrCopyRawBuffer();
    786  VectorTesting::testReplaceRawBuffer();
    787  VectorTesting::testInsert();
    788  VectorTesting::testErase();
    789  VectorTesting::testShrinkStorageToFit();
    790  VectorTesting::testAppend();
    791  TestVectorBeginNonNull();
    792 }