tor-browser

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

TestVariant.cpp (47614B)


      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/UniquePtr.h"
     10 #include "mozilla/Variant.h"
     11 
     12 #include <tuple>
     13 
     14 using mozilla::MakeUnique;
     15 using mozilla::UniquePtr;
     16 using mozilla::Variant;
     17 
     18 struct Destroyer {
     19  static int destroyedCount;
     20  ~Destroyer() { destroyedCount++; }
     21 };
     22 
     23 int Destroyer::destroyedCount = 0;
     24 
     25 static void testDetails() {
     26  printf("testDetails\n");
     27 
     28  using mozilla::detail::Nth;
     29 
     30  // Test Nth with a list of 1 item.
     31  static_assert(std::is_same_v<typename Nth<0, int>::Type, int>,
     32                "Nth<0, int>::Type should be int");
     33 
     34  // Test Nth with a list of more than 1 item.
     35  static_assert(std::is_same_v<typename Nth<0, int, char>::Type, int>,
     36                "Nth<0, int, char>::Type should be int");
     37  static_assert(std::is_same_v<typename Nth<1, int, char>::Type, char>,
     38                "Nth<1, int, char>::Type should be char");
     39 
     40  using mozilla::detail::SelectVariantType;
     41 
     42  // SelectVariantType for zero items (shouldn't happen, but `count` should
     43  // still work ok.)
     44  static_assert(SelectVariantType<int, char>::count == 0,
     45                "SelectVariantType<int, char>::count should be 0");
     46 
     47  // SelectVariantType for 1 type, for all combinations from/to T, const T,
     48  // const T&, T&&
     49  // - type to type
     50  static_assert(std::is_same_v<typename SelectVariantType<int, int>::Type, int>,
     51                "SelectVariantType<int, int>::Type should be int");
     52  static_assert(SelectVariantType<int, int>::count == 1,
     53                "SelectVariantType<int, int>::count should be 1");
     54 
     55  // - type to const type
     56  static_assert(std::is_same_v<typename SelectVariantType<int, const int>::Type,
     57                               const int>,
     58                "SelectVariantType<int, const int>::Type should be const int");
     59  static_assert(SelectVariantType<int, const int>::count == 1,
     60                "SelectVariantType<int, const int>::count should be 1");
     61 
     62  // - type to const type&
     63  static_assert(
     64      std::is_same_v<typename SelectVariantType<int, const int&>::Type,
     65                     const int&>,
     66      "SelectVariantType<int, const int&>::Type should be const int&");
     67  static_assert(SelectVariantType<int, const int&>::count == 1,
     68                "SelectVariantType<int, const int&>::count should be 1");
     69 
     70  // - type to type&&
     71  static_assert(
     72      std::is_same_v<typename SelectVariantType<int, int&&>::Type, int&&>,
     73      "SelectVariantType<int, int&&>::Type should be int&&");
     74  static_assert(SelectVariantType<int, int&&>::count == 1,
     75                "SelectVariantType<int, int&&>::count should be 1");
     76 
     77  // - const type to type
     78  static_assert(
     79      std::is_same_v<typename SelectVariantType<const int, int>::Type, int>,
     80      "SelectVariantType<const int, int>::Type should be int");
     81  static_assert(SelectVariantType<const int, int>::count == 1,
     82                "SelectVariantType<const int, int>::count should be 1");
     83 
     84  // - const type to const type
     85  static_assert(
     86      std::is_same_v<typename SelectVariantType<const int, const int>::Type,
     87                     const int>,
     88      "SelectVariantType<const int, const int>::Type should be const int");
     89  static_assert(SelectVariantType<const int, const int>::count == 1,
     90                "SelectVariantType<const int, const int>::count should be 1");
     91 
     92  // - const type to const type&
     93  static_assert(
     94      std::is_same_v<typename SelectVariantType<const int, const int&>::Type,
     95                     const int&>,
     96      "SelectVariantType<const int, const int&>::Type should be const int&");
     97  static_assert(SelectVariantType<const int, const int&>::count == 1,
     98                "SelectVariantType<const int, const int&>::count should be 1");
     99 
    100  // - const type to type&&
    101  static_assert(
    102      std::is_same_v<typename SelectVariantType<const int, int&&>::Type, int&&>,
    103      "SelectVariantType<const int, int&&>::Type should be int&&");
    104  static_assert(SelectVariantType<const int, int&&>::count == 1,
    105                "SelectVariantType<const int, int&&>::count should be 1");
    106 
    107  // - const type& to type
    108  static_assert(
    109      std::is_same_v<typename SelectVariantType<const int&, int>::Type, int>,
    110      "SelectVariantType<const int&, int>::Type should be int");
    111  static_assert(SelectVariantType<const int&, int>::count == 1,
    112                "SelectVariantType<const int&, int>::count should be 1");
    113 
    114  // - const type& to const type
    115  static_assert(
    116      std::is_same_v<typename SelectVariantType<const int&, const int>::Type,
    117                     const int>,
    118      "SelectVariantType<const int&, const int>::Type should be const int");
    119  static_assert(SelectVariantType<const int&, const int>::count == 1,
    120                "SelectVariantType<const int&, const int>::count should be 1");
    121 
    122  // - const type& to const type&
    123  static_assert(
    124      std::is_same_v<typename SelectVariantType<const int&, const int&>::Type,
    125                     const int&>,
    126      "SelectVariantType<const int&, const int&>::Type should be const int&");
    127  static_assert(SelectVariantType<const int&, const int&>::count == 1,
    128                "SelectVariantType<const int&, const int&>::count should be 1");
    129 
    130  // - const type& to type&&
    131  static_assert(
    132      std::is_same_v<typename SelectVariantType<const int&, int&&>::Type,
    133                     int&&>,
    134      "SelectVariantType<const int&, int&&>::Type should be int&&");
    135  static_assert(SelectVariantType<const int&, int&&>::count == 1,
    136                "SelectVariantType<const int&, int&&>::count should be 1");
    137 
    138  // - type&& to type
    139  static_assert(
    140      std::is_same_v<typename SelectVariantType<int&&, int>::Type, int>,
    141      "SelectVariantType<int&&, int>::Type should be int");
    142  static_assert(SelectVariantType<int&&, int>::count == 1,
    143                "SelectVariantType<int&&, int>::count should be 1");
    144 
    145  // - type&& to const type
    146  static_assert(
    147      std::is_same_v<typename SelectVariantType<int&&, const int>::Type,
    148                     const int>,
    149      "SelectVariantType<int&&, const int>::Type should be const int");
    150  static_assert(SelectVariantType<int&&, const int>::count == 1,
    151                "SelectVariantType<int&&, const int>::count should be 1");
    152 
    153  // - type&& to const type&
    154  static_assert(
    155      std::is_same_v<typename SelectVariantType<int&&, const int&>::Type,
    156                     const int&>,
    157      "SelectVariantType<int&&, const int&>::Type should be const int&");
    158  static_assert(SelectVariantType<int&&, const int&>::count == 1,
    159                "SelectVariantType<int&&, const int&>::count should be 1");
    160 
    161  // - type&& to type&&
    162  static_assert(
    163      std::is_same_v<typename SelectVariantType<int&&, int&&>::Type, int&&>,
    164      "SelectVariantType<int&&, int&&>::Type should be int&&");
    165  static_assert(SelectVariantType<int&&, int&&>::count == 1,
    166                "SelectVariantType<int&&, int&&>::count should be 1");
    167 
    168  // SelectVariantType for two different types.
    169  // (Don't test all combinations, trust that the above tests are sufficient.)
    170  static_assert(
    171      std::is_same_v<typename SelectVariantType<int, int, char>::Type, int>,
    172      "SelectVariantType<int, int, char>::Type should be int");
    173  static_assert(SelectVariantType<int, int, char>::count == 1,
    174                "SelectVariantType<int, int, char>::count should be 1");
    175  static_assert(
    176      std::is_same_v<typename SelectVariantType<char, int, char>::Type, char>,
    177      "SelectVariantType<char, int, char>::Type should be char");
    178  static_assert(SelectVariantType<char, int, char>::count == 1,
    179                "SelectVariantType<char, int, char>::count should be 1");
    180 
    181  // SelectVariantType for two identical types.
    182  static_assert(
    183      std::is_same_v<typename SelectVariantType<int, int, int>::Type, int>,
    184      "SelectVariantType<int, int, int>::Type should be int");
    185  static_assert(SelectVariantType<int, int, int>::count == 2,
    186                "SelectVariantType<int, int, int>::count should be 2");
    187 
    188  // SelectVariantType for two identical types, with others around.
    189  static_assert(
    190      std::is_same_v<typename SelectVariantType<int, char, int, int>::Type,
    191                     int>,
    192      "SelectVariantType<int, char, int, int>::Type should be int");
    193  static_assert(SelectVariantType<int, char, int, int>::count == 2,
    194                "SelectVariantType<int, char, int, int>::count should be 2");
    195 
    196  static_assert(
    197      std::is_same_v<typename SelectVariantType<int, int, char, int>::Type,
    198                     int>,
    199      "SelectVariantType<int, int, char, int>::Type should be int");
    200  static_assert(SelectVariantType<int, int, char, int>::count == 2,
    201                "SelectVariantType<int, int, char, int>::count should be 2");
    202 
    203  static_assert(
    204      std::is_same_v<typename SelectVariantType<int, int, int, char>::Type,
    205                     int>,
    206      "SelectVariantType<int, int, int, char>::Type should be int");
    207  static_assert(SelectVariantType<int, int, int, char>::count == 2,
    208                "SelectVariantType<int, int, int, char>::count should be 2");
    209 
    210  static_assert(
    211      std::is_same_v<
    212          typename SelectVariantType<int, char, int, char, int, char>::Type,
    213          int>,
    214      "SelectVariantType<int, char, int, char, int, char>::Type should be int");
    215  static_assert(
    216      SelectVariantType<int, char, int, char, int, char>::count == 2,
    217      "SelectVariantType<int, char, int, char, int, char>::count should be 2");
    218 
    219  // SelectVariantType for two identically-selectable types (first one wins!).
    220  static_assert(
    221      std::is_same_v<typename SelectVariantType<int, int, const int>::Type,
    222                     int>,
    223      "SelectVariantType<int, int, const int>::Type should be int");
    224  static_assert(SelectVariantType<int, int, const int>::count == 2,
    225                "SelectVariantType<int, int, const int>::count should be 2");
    226  static_assert(
    227      std::is_same_v<typename SelectVariantType<int, const int, int>::Type,
    228                     const int>,
    229      "SelectVariantType<int, const int, int>::Type should be const int");
    230  static_assert(SelectVariantType<int, const int, int>::count == 2,
    231                "SelectVariantType<int, const int, int>::count should be 2");
    232  static_assert(
    233      std::is_same_v<typename SelectVariantType<int, const int, int&&>::Type,
    234                     const int>,
    235      "SelectVariantType<int, const int, int&&>::Type should be const int");
    236  static_assert(SelectVariantType<int, const int, int&&>::count == 2,
    237                "SelectVariantType<int, const int, int&&>::count should be 2");
    238 }
    239 
    240 static void testSimple() {
    241  printf("testSimple\n");
    242  using V = Variant<uint32_t, uint64_t>;
    243 
    244  // Non-const lvalue.
    245  V v(uint64_t(1));
    246  MOZ_RELEASE_ASSERT(v.is<uint64_t>());
    247  MOZ_RELEASE_ASSERT(!v.is<uint32_t>());
    248  MOZ_RELEASE_ASSERT(v.as<uint64_t>() == 1);
    249 
    250  MOZ_RELEASE_ASSERT(v.is<1>());
    251  MOZ_RELEASE_ASSERT(!v.is<0>());
    252  static_assert(std::is_same_v<decltype(v.as<1>()), uint64_t&>,
    253                "v.as<1>() should return a uint64_t&");
    254  MOZ_RELEASE_ASSERT(v.as<1>() == 1);
    255 
    256  // Const lvalue.
    257  const V& cv = v;
    258  MOZ_RELEASE_ASSERT(cv.is<uint64_t>());
    259  MOZ_RELEASE_ASSERT(!cv.is<uint32_t>());
    260  MOZ_RELEASE_ASSERT(cv.as<uint64_t>() == 1);
    261 
    262  MOZ_RELEASE_ASSERT(cv.is<1>());
    263  MOZ_RELEASE_ASSERT(!cv.is<0>());
    264  static_assert(std::is_same_v<decltype(cv.as<1>()), const uint64_t&>,
    265                "cv.as<1>() should return a const uint64_t&");
    266  MOZ_RELEASE_ASSERT(cv.as<1>() == 1);
    267 
    268  // Non-const rvalue, using a function to create a temporary.
    269  auto MakeV = []() { return V(uint64_t(1)); };
    270  MOZ_RELEASE_ASSERT(MakeV().is<uint64_t>());
    271  MOZ_RELEASE_ASSERT(!MakeV().is<uint32_t>());
    272  MOZ_RELEASE_ASSERT(MakeV().as<uint64_t>() == 1);
    273 
    274  MOZ_RELEASE_ASSERT(MakeV().is<1>());
    275  MOZ_RELEASE_ASSERT(!MakeV().is<0>());
    276  static_assert(std::is_same_v<decltype(MakeV().as<1>()), uint64_t&&>,
    277                "MakeV().as<1>() should return a uint64_t&&");
    278  MOZ_RELEASE_ASSERT(MakeV().as<1>() == 1);
    279 
    280  // Const rvalue, using a function to create a temporary.
    281  auto MakeCV = []() -> const V { return V(uint64_t(1)); };
    282  MOZ_RELEASE_ASSERT(MakeCV().is<uint64_t>());
    283  MOZ_RELEASE_ASSERT(!MakeCV().is<uint32_t>());
    284  MOZ_RELEASE_ASSERT(MakeCV().as<uint64_t>() == 1);
    285 
    286  MOZ_RELEASE_ASSERT(MakeCV().is<1>());
    287  MOZ_RELEASE_ASSERT(!MakeCV().is<0>());
    288  static_assert(std::is_same_v<decltype(MakeCV().as<1>()), const uint64_t&&>,
    289                "MakeCV().as<1>() should return a const uint64_t&&");
    290  MOZ_RELEASE_ASSERT(MakeCV().as<1>() == 1);
    291 }
    292 
    293 static void testDuplicate() {
    294  printf("testDuplicate\n");
    295  Variant<uint32_t, uint64_t, uint32_t> v(uint64_t(1));
    296  MOZ_RELEASE_ASSERT(v.is<uint64_t>());
    297  MOZ_RELEASE_ASSERT(v.as<uint64_t>() == 1);
    298  // Note: uint32_t is not unique, so `v.is<uint32_t>()` is not allowed.
    299 
    300  MOZ_RELEASE_ASSERT(v.is<1>());
    301  MOZ_RELEASE_ASSERT(!v.is<0>());
    302  MOZ_RELEASE_ASSERT(!v.is<2>());
    303  static_assert(std::is_same_v<decltype(v.as<0>()), uint32_t&>,
    304                "as<0>() should return a uint64_t");
    305  static_assert(std::is_same_v<decltype(v.as<1>()), uint64_t&>,
    306                "as<1>() should return a uint64_t");
    307  static_assert(std::is_same_v<decltype(v.as<2>()), uint32_t&>,
    308                "as<2>() should return a uint64_t");
    309  MOZ_RELEASE_ASSERT(v.as<1>() == 1);
    310  MOZ_RELEASE_ASSERT(v.extract<1>() == 1);
    311 }
    312 
    313 static void testConstructionWithVariantType() {
    314  Variant<uint32_t, uint64_t, uint32_t> v(mozilla::VariantType<uint64_t>{}, 3);
    315  MOZ_RELEASE_ASSERT(v.is<uint64_t>());
    316  // MOZ_RELEASE_ASSERT(!v.is<uint32_t>()); // uint32_t is not unique!
    317  MOZ_RELEASE_ASSERT(v.as<uint64_t>() == 3);
    318 }
    319 
    320 static void testConstructionWithVariantIndex() {
    321  Variant<uint32_t, uint64_t, uint32_t> v(mozilla::VariantIndex<2>{}, 2);
    322  MOZ_RELEASE_ASSERT(!v.is<uint64_t>());
    323  // Note: uint32_t is not unique, so `v.is<uint32_t>()` is not allowed.
    324 
    325  MOZ_RELEASE_ASSERT(!v.is<1>());
    326  MOZ_RELEASE_ASSERT(!v.is<0>());
    327  MOZ_RELEASE_ASSERT(v.is<2>());
    328  MOZ_RELEASE_ASSERT(v.as<2>() == 2);
    329  MOZ_RELEASE_ASSERT(v.extract<2>() == 2);
    330 }
    331 
    332 static void testEmplaceWithType() {
    333  printf("testEmplaceWithType\n");
    334  Variant<uint32_t, uint64_t, uint32_t> v1(mozilla::VariantIndex<0>{}, 0);
    335  v1.emplace<uint64_t>(3);
    336  MOZ_RELEASE_ASSERT(v1.is<uint64_t>());
    337  MOZ_RELEASE_ASSERT(v1.as<uint64_t>() == 3);
    338 
    339  Variant<UniquePtr<int>, char> v2('a');
    340  v2.emplace<UniquePtr<int>>();
    341  MOZ_RELEASE_ASSERT(v2.is<UniquePtr<int>>());
    342  MOZ_RELEASE_ASSERT(!v2.as<UniquePtr<int>>().get());
    343 
    344  Variant<UniquePtr<int>, char> v3('a');
    345  v3.emplace<UniquePtr<int>>(MakeUnique<int>(4));
    346  MOZ_RELEASE_ASSERT(v3.is<UniquePtr<int>>());
    347  MOZ_RELEASE_ASSERT(*v3.as<UniquePtr<int>>().get() == 4);
    348 }
    349 
    350 static void testEmplaceWithIndex() {
    351  printf("testEmplaceWithIndex\n");
    352  Variant<uint32_t, uint64_t, uint32_t> v1(mozilla::VariantIndex<1>{}, 0);
    353  v1.emplace<2>(2);
    354  MOZ_RELEASE_ASSERT(!v1.is<uint64_t>());
    355  MOZ_RELEASE_ASSERT(!v1.is<1>());
    356  MOZ_RELEASE_ASSERT(!v1.is<0>());
    357  MOZ_RELEASE_ASSERT(v1.is<2>());
    358  MOZ_RELEASE_ASSERT(v1.as<2>() == 2);
    359  MOZ_RELEASE_ASSERT(v1.extract<2>() == 2);
    360 
    361  Variant<UniquePtr<int>, char> v2('a');
    362  v2.emplace<0>();
    363  MOZ_RELEASE_ASSERT(v2.is<UniquePtr<int>>());
    364  MOZ_RELEASE_ASSERT(!v2.is<1>());
    365  MOZ_RELEASE_ASSERT(v2.is<0>());
    366  MOZ_RELEASE_ASSERT(!v2.as<0>().get());
    367  MOZ_RELEASE_ASSERT(!v2.extract<0>().get());
    368 
    369  Variant<UniquePtr<int>, char> v3('a');
    370  v3.emplace<0>(MakeUnique<int>(4));
    371  MOZ_RELEASE_ASSERT(v3.is<UniquePtr<int>>());
    372  MOZ_RELEASE_ASSERT(!v3.is<1>());
    373  MOZ_RELEASE_ASSERT(v3.is<0>());
    374  MOZ_RELEASE_ASSERT(*v3.as<0>().get() == 4);
    375  MOZ_RELEASE_ASSERT(*v3.extract<0>().get() == 4);
    376 }
    377 
    378 static void testCopy() {
    379  printf("testCopy\n");
    380  Variant<uint32_t, uint64_t> v1(uint64_t(1));
    381  Variant<uint32_t, uint64_t> v2(v1);
    382  MOZ_RELEASE_ASSERT(v2.is<uint64_t>());
    383  MOZ_RELEASE_ASSERT(!v2.is<uint32_t>());
    384  MOZ_RELEASE_ASSERT(v2.as<uint64_t>() == 1);
    385 
    386  Variant<uint32_t, uint64_t> v3(uint32_t(10));
    387  v3 = v2;
    388  MOZ_RELEASE_ASSERT(v3.is<uint64_t>());
    389  MOZ_RELEASE_ASSERT(v3.as<uint64_t>() == 1);
    390 }
    391 
    392 static void testMove() {
    393  printf("testMove\n");
    394  Variant<UniquePtr<int>, char> v1(MakeUnique<int>(5));
    395  Variant<UniquePtr<int>, char> v2(std::move(v1));
    396 
    397  MOZ_RELEASE_ASSERT(v2.is<UniquePtr<int>>());
    398  MOZ_RELEASE_ASSERT(*v2.as<UniquePtr<int>>() == 5);
    399 
    400  MOZ_RELEASE_ASSERT(v1.is<UniquePtr<int>>());
    401  MOZ_RELEASE_ASSERT(v1.as<UniquePtr<int>>() == nullptr);
    402 
    403  Destroyer::destroyedCount = 0;
    404  {
    405    Variant<char, UniquePtr<Destroyer>> v3(MakeUnique<Destroyer>());
    406    Variant<char, UniquePtr<Destroyer>> v4(std::move(v3));
    407 
    408    Variant<char, UniquePtr<Destroyer>> v5('a');
    409    v5 = std::move(v4);
    410 
    411    auto ptr = v5.extract<UniquePtr<Destroyer>>();
    412    MOZ_RELEASE_ASSERT(Destroyer::destroyedCount == 0);
    413  }
    414  MOZ_RELEASE_ASSERT(Destroyer::destroyedCount == 1);
    415 }
    416 
    417 static void testDestructor() {
    418  printf("testDestructor\n");
    419  Destroyer::destroyedCount = 0;
    420 
    421  {
    422    Destroyer d;
    423 
    424    {
    425      Variant<char, UniquePtr<char[]>, Destroyer> v1(d);
    426      MOZ_RELEASE_ASSERT(Destroyer::destroyedCount ==
    427                         0);  // None destroyed yet.
    428    }
    429 
    430    MOZ_RELEASE_ASSERT(Destroyer::destroyedCount ==
    431                       1);  // v1's copy of d is destroyed.
    432 
    433    {
    434      Variant<char, UniquePtr<char[]>, Destroyer> v2(
    435          mozilla::VariantIndex<2>{});
    436      v2.emplace<Destroyer>(d);
    437      MOZ_RELEASE_ASSERT(Destroyer::destroyedCount ==
    438                         2);  // v2's initial value is destroyed.
    439    }
    440 
    441    MOZ_RELEASE_ASSERT(Destroyer::destroyedCount ==
    442                       3);  // v2's second value is destroyed.
    443  }
    444 
    445  MOZ_RELEASE_ASSERT(Destroyer::destroyedCount == 4);  // d is destroyed.
    446 }
    447 
    448 static void testEquality() {
    449  printf("testEquality\n");
    450  using V = Variant<char, int>;
    451 
    452  V v0('a');
    453  V v1('b');
    454  V v2('b');
    455  V v3(42);
    456  V v4(27);
    457  V v5(27);
    458  V v6(int('b'));
    459 
    460  MOZ_RELEASE_ASSERT(v0 != v1);
    461  MOZ_RELEASE_ASSERT(v1 == v2);
    462  MOZ_RELEASE_ASSERT(v2 != v3);
    463  MOZ_RELEASE_ASSERT(v3 != v4);
    464  MOZ_RELEASE_ASSERT(v4 == v5);
    465  MOZ_RELEASE_ASSERT(v1 != v6);
    466 
    467  MOZ_RELEASE_ASSERT(v0 == v0);
    468  MOZ_RELEASE_ASSERT(v1 == v1);
    469  MOZ_RELEASE_ASSERT(v2 == v2);
    470  MOZ_RELEASE_ASSERT(v3 == v3);
    471  MOZ_RELEASE_ASSERT(v4 == v4);
    472  MOZ_RELEASE_ASSERT(v5 == v5);
    473  MOZ_RELEASE_ASSERT(v6 == v6);
    474 }
    475 
    476 // Matcher that returns a description of how its call-operator was invoked.
    477 struct Describer {
    478  enum class ParameterSize { NA, U8, U32, U64 };
    479  enum class ParameterQualifier {
    480    NA,
    481    ParamLREF,
    482    ParamCLREF,
    483    ParamRREF,
    484    ParamCRREF
    485  };
    486  enum class ThisQualifier { NA, ThisLREF, ThisCLREF, ThisRREF, ThisCRREF };
    487 
    488  using Result =
    489      std::tuple<ParameterSize, ParameterQualifier, ThisQualifier, uint64_t>;
    490 
    491 #define RESULT(SIZE, PQUAL, TQUAL, VALUE)                 \
    492  Describer::Result(Describer::ParameterSize::SIZE,       \
    493                    Describer::ParameterQualifier::PQUAL, \
    494                    Describer::ThisQualifier::TQUAL, VALUE)
    495 
    496 #define CALL(TYPE, SIZE, PQUAL, TREF, TQUAL)   \
    497  Result operator()(TYPE aValue) TREF {        \
    498    return RESULT(SIZE, PQUAL, TQUAL, aValue); \
    499  }
    500 
    501  // All combinations of possible call operators:
    502  // Every line, the parameter integer type changes.
    503  // Every 3 lines, the parameter type changes constness.
    504  // Every 6 lines, the parameter changes reference l/r-valueness.
    505  // Every 12 lines, the member function qualifier changes constness.
    506  // After 24 lines, the member function qualifier changes ref l/r-valueness.
    507  CALL(uint8_t&, U8, ParamLREF, &, ThisLREF)
    508  CALL(uint32_t&, U32, ParamLREF, &, ThisLREF)
    509  CALL(uint64_t&, U64, ParamLREF, &, ThisLREF)
    510 
    511  CALL(const uint8_t&, U8, ParamCLREF, &, ThisLREF)
    512  CALL(const uint32_t&, U32, ParamCLREF, &, ThisLREF)
    513  CALL(const uint64_t&, U64, ParamCLREF, &, ThisLREF)
    514 
    515  CALL(uint8_t&&, U8, ParamRREF, &, ThisLREF)
    516  CALL(uint32_t&&, U32, ParamRREF, &, ThisLREF)
    517  CALL(uint64_t&&, U64, ParamRREF, &, ThisLREF)
    518 
    519  CALL(const uint8_t&&, U8, ParamCRREF, &, ThisLREF)
    520  CALL(const uint32_t&&, U32, ParamCRREF, &, ThisLREF)
    521  CALL(const uint64_t&&, U64, ParamCRREF, &, ThisLREF)
    522 
    523  CALL(uint8_t&, U8, ParamLREF, const&, ThisCLREF)
    524  CALL(uint32_t&, U32, ParamLREF, const&, ThisCLREF)
    525  CALL(uint64_t&, U64, ParamLREF, const&, ThisCLREF)
    526 
    527  CALL(const uint8_t&, U8, ParamCLREF, const&, ThisCLREF)
    528  CALL(const uint32_t&, U32, ParamCLREF, const&, ThisCLREF)
    529  CALL(const uint64_t&, U64, ParamCLREF, const&, ThisCLREF)
    530 
    531  CALL(uint8_t&&, U8, ParamRREF, const&, ThisCLREF)
    532  CALL(uint32_t&&, U32, ParamRREF, const&, ThisCLREF)
    533  CALL(uint64_t&&, U64, ParamRREF, const&, ThisCLREF)
    534 
    535  CALL(const uint8_t&&, U8, ParamCRREF, const&, ThisCLREF)
    536  CALL(const uint32_t&&, U32, ParamCRREF, const&, ThisCLREF)
    537  CALL(const uint64_t&&, U64, ParamCRREF, const&, ThisCLREF)
    538 
    539  CALL(uint8_t&, U8, ParamLREF, &&, ThisRREF)
    540  CALL(uint32_t&, U32, ParamLREF, &&, ThisRREF)
    541  CALL(uint64_t&, U64, ParamLREF, &&, ThisRREF)
    542 
    543  CALL(const uint8_t&, U8, ParamCLREF, &&, ThisRREF)
    544  CALL(const uint32_t&, U32, ParamCLREF, &&, ThisRREF)
    545  CALL(const uint64_t&, U64, ParamCLREF, &&, ThisRREF)
    546 
    547  CALL(uint8_t&&, U8, ParamRREF, &&, ThisRREF)
    548  CALL(uint32_t&&, U32, ParamRREF, &&, ThisRREF)
    549  CALL(uint64_t&&, U64, ParamRREF, &&, ThisRREF)
    550 
    551  CALL(const uint8_t&&, U8, ParamCRREF, &&, ThisRREF)
    552  CALL(const uint32_t&&, U32, ParamCRREF, &&, ThisRREF)
    553  CALL(const uint64_t&&, U64, ParamCRREF, &&, ThisRREF)
    554 
    555  CALL(uint8_t&, U8, ParamLREF, const&&, ThisCRREF)
    556  CALL(uint32_t&, U32, ParamLREF, const&&, ThisCRREF)
    557  CALL(uint64_t&, U64, ParamLREF, const&&, ThisCRREF)
    558 
    559  CALL(const uint8_t&, U8, ParamCLREF, const&&, ThisCRREF)
    560  CALL(const uint32_t&, U32, ParamCLREF, const&&, ThisCRREF)
    561  CALL(const uint64_t&, U64, ParamCLREF, const&&, ThisCRREF)
    562 
    563  CALL(uint8_t&&, U8, ParamRREF, const&&, ThisCRREF)
    564  CALL(uint32_t&&, U32, ParamRREF, const&&, ThisCRREF)
    565  CALL(uint64_t&&, U64, ParamRREF, const&&, ThisCRREF)
    566 
    567  CALL(const uint8_t&&, U8, ParamCRREF, const&&, ThisCRREF)
    568  CALL(const uint32_t&&, U32, ParamCRREF, const&&, ThisCRREF)
    569  CALL(const uint64_t&&, U64, ParamCRREF, const&&, ThisCRREF)
    570 
    571 #undef CALL
    572 
    573  // Catch-all, to verify that there is no call with any type other than the
    574  // expected ones above.
    575  template <typename Other>
    576  Result operator()(const Other&) {
    577    MOZ_RELEASE_ASSERT(false);
    578    return RESULT(NA, NA, NA, 0);
    579  }
    580 };
    581 
    582 static void testMatching() {
    583  printf("testMatching\n");
    584  using V = Variant<uint8_t, uint32_t, uint64_t>;
    585 
    586  Describer desc;
    587  const Describer descConst;
    588  auto MakeDescriber = []() { return Describer(); };
    589  auto MakeConstDescriber = []() -> const Describer { return Describer(); };
    590 
    591  V v1(uint8_t(1));
    592  V v2(uint32_t(2));
    593  V v3(uint64_t(3));
    594 
    595  const V& constRef1 = v1;
    596  const V& constRef2 = v2;
    597  const V& constRef3 = v3;
    598 
    599  // Create a temporary variant by returning a copy of one.
    600  auto CopyV = [](const V& aV) { return aV; };
    601 
    602  // Create a temporary variant by returning a const copy of one.
    603  auto CopyConstV = [](const V& aV) -> const V { return aV; };
    604 
    605  // All combinations of possible calls:
    606  // Every line, the variant integer type changes.
    607  // Every 3 lines, the variant type changes constness.
    608  // Every 6 lines, the variant changes reference l/r-valueness.
    609  // Every 12 lines, the matcher changes constness.
    610  // After 24 lines, the matcher changes ref l/r-valueness.
    611  MOZ_RELEASE_ASSERT(v1.match(desc) == RESULT(U8, ParamLREF, ThisLREF, 1));
    612  MOZ_RELEASE_ASSERT(v2.match(desc) == RESULT(U32, ParamLREF, ThisLREF, 2));
    613  MOZ_RELEASE_ASSERT(v3.match(desc) == RESULT(U64, ParamLREF, ThisLREF, 3));
    614 
    615  MOZ_RELEASE_ASSERT(constRef1.match(desc) ==
    616                     RESULT(U8, ParamCLREF, ThisLREF, 1));
    617  MOZ_RELEASE_ASSERT(constRef2.match(desc) ==
    618                     RESULT(U32, ParamCLREF, ThisLREF, 2));
    619  MOZ_RELEASE_ASSERT(constRef3.match(desc) ==
    620                     RESULT(U64, ParamCLREF, ThisLREF, 3));
    621 
    622  MOZ_RELEASE_ASSERT(CopyV(v1).match(desc) ==
    623                     RESULT(U8, ParamRREF, ThisLREF, 1));
    624  MOZ_RELEASE_ASSERT(CopyV(v2).match(desc) ==
    625                     RESULT(U32, ParamRREF, ThisLREF, 2));
    626  MOZ_RELEASE_ASSERT(CopyV(v3).match(desc) ==
    627                     RESULT(U64, ParamRREF, ThisLREF, 3));
    628 
    629  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc) ==
    630                     RESULT(U8, ParamCRREF, ThisLREF, 1));
    631  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc) ==
    632                     RESULT(U32, ParamCRREF, ThisLREF, 2));
    633  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc) ==
    634                     RESULT(U64, ParamCRREF, ThisLREF, 3));
    635 
    636  MOZ_RELEASE_ASSERT(v1.match(descConst) ==
    637                     RESULT(U8, ParamLREF, ThisCLREF, 1));
    638  MOZ_RELEASE_ASSERT(v2.match(descConst) ==
    639                     RESULT(U32, ParamLREF, ThisCLREF, 2));
    640  MOZ_RELEASE_ASSERT(v3.match(descConst) ==
    641                     RESULT(U64, ParamLREF, ThisCLREF, 3));
    642 
    643  MOZ_RELEASE_ASSERT(constRef1.match(descConst) ==
    644                     RESULT(U8, ParamCLREF, ThisCLREF, 1));
    645  MOZ_RELEASE_ASSERT(constRef2.match(descConst) ==
    646                     RESULT(U32, ParamCLREF, ThisCLREF, 2));
    647  MOZ_RELEASE_ASSERT(constRef3.match(descConst) ==
    648                     RESULT(U64, ParamCLREF, ThisCLREF, 3));
    649 
    650  MOZ_RELEASE_ASSERT(CopyV(v1).match(descConst) ==
    651                     RESULT(U8, ParamRREF, ThisCLREF, 1));
    652  MOZ_RELEASE_ASSERT(CopyV(v2).match(descConst) ==
    653                     RESULT(U32, ParamRREF, ThisCLREF, 2));
    654  MOZ_RELEASE_ASSERT(CopyV(v3).match(descConst) ==
    655                     RESULT(U64, ParamRREF, ThisCLREF, 3));
    656 
    657  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(descConst) ==
    658                     RESULT(U8, ParamCRREF, ThisCLREF, 1));
    659  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(descConst) ==
    660                     RESULT(U32, ParamCRREF, ThisCLREF, 2));
    661  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(descConst) ==
    662                     RESULT(U64, ParamCRREF, ThisCLREF, 3));
    663 
    664  MOZ_RELEASE_ASSERT(v1.match(MakeDescriber()) ==
    665                     RESULT(U8, ParamLREF, ThisRREF, 1));
    666  MOZ_RELEASE_ASSERT(v2.match(MakeDescriber()) ==
    667                     RESULT(U32, ParamLREF, ThisRREF, 2));
    668  MOZ_RELEASE_ASSERT(v3.match(MakeDescriber()) ==
    669                     RESULT(U64, ParamLREF, ThisRREF, 3));
    670 
    671  MOZ_RELEASE_ASSERT(constRef1.match(MakeDescriber()) ==
    672                     RESULT(U8, ParamCLREF, ThisRREF, 1));
    673  MOZ_RELEASE_ASSERT(constRef2.match(MakeDescriber()) ==
    674                     RESULT(U32, ParamCLREF, ThisRREF, 2));
    675  MOZ_RELEASE_ASSERT(constRef3.match(MakeDescriber()) ==
    676                     RESULT(U64, ParamCLREF, ThisRREF, 3));
    677 
    678  MOZ_RELEASE_ASSERT(CopyV(v1).match(MakeDescriber()) ==
    679                     RESULT(U8, ParamRREF, ThisRREF, 1));
    680  MOZ_RELEASE_ASSERT(CopyV(v2).match(MakeDescriber()) ==
    681                     RESULT(U32, ParamRREF, ThisRREF, 2));
    682  MOZ_RELEASE_ASSERT(CopyV(v3).match(MakeDescriber()) ==
    683                     RESULT(U64, ParamRREF, ThisRREF, 3));
    684 
    685  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(MakeDescriber()) ==
    686                     RESULT(U8, ParamCRREF, ThisRREF, 1));
    687  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(MakeDescriber()) ==
    688                     RESULT(U32, ParamCRREF, ThisRREF, 2));
    689  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(MakeDescriber()) ==
    690                     RESULT(U64, ParamCRREF, ThisRREF, 3));
    691 
    692  MOZ_RELEASE_ASSERT(v1.match(MakeConstDescriber()) ==
    693                     RESULT(U8, ParamLREF, ThisCRREF, 1));
    694  MOZ_RELEASE_ASSERT(v2.match(MakeConstDescriber()) ==
    695                     RESULT(U32, ParamLREF, ThisCRREF, 2));
    696  MOZ_RELEASE_ASSERT(v3.match(MakeConstDescriber()) ==
    697                     RESULT(U64, ParamLREF, ThisCRREF, 3));
    698 
    699  MOZ_RELEASE_ASSERT(constRef1.match(MakeConstDescriber()) ==
    700                     RESULT(U8, ParamCLREF, ThisCRREF, 1));
    701  MOZ_RELEASE_ASSERT(constRef2.match(MakeConstDescriber()) ==
    702                     RESULT(U32, ParamCLREF, ThisCRREF, 2));
    703  MOZ_RELEASE_ASSERT(constRef3.match(MakeConstDescriber()) ==
    704                     RESULT(U64, ParamCLREF, ThisCRREF, 3));
    705 
    706  MOZ_RELEASE_ASSERT(CopyV(v1).match(MakeConstDescriber()) ==
    707                     RESULT(U8, ParamRREF, ThisCRREF, 1));
    708  MOZ_RELEASE_ASSERT(CopyV(v2).match(MakeConstDescriber()) ==
    709                     RESULT(U32, ParamRREF, ThisCRREF, 2));
    710  MOZ_RELEASE_ASSERT(CopyV(v3).match(MakeConstDescriber()) ==
    711                     RESULT(U64, ParamRREF, ThisCRREF, 3));
    712 
    713  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(MakeConstDescriber()) ==
    714                     RESULT(U8, ParamCRREF, ThisCRREF, 1));
    715  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(MakeConstDescriber()) ==
    716                     RESULT(U32, ParamCRREF, ThisCRREF, 2));
    717  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(MakeConstDescriber()) ==
    718                     RESULT(U64, ParamCRREF, ThisCRREF, 3));
    719 }
    720 
    721 static void testMatchingLambda() {
    722  printf("testMatchingLambda\n");
    723  using V = Variant<uint8_t, uint32_t, uint64_t>;
    724 
    725  // Note: Lambdas' call operators are const by default (unless the lambda is
    726  // declared `mutable`).
    727  // There is no need to test mutable lambdas, nor rvalue lambda, because there
    728  // would be no way to distinguish how each lambda is actually invoked because
    729  // there is only one choice of call operator in each overload set.
    730  auto desc = [](auto&& a) {
    731    if constexpr (std::is_same_v<decltype(a), uint8_t&>) {
    732      return RESULT(U8, ParamLREF, NA, a);
    733    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&>) {
    734      return RESULT(U8, ParamCLREF, NA, a);
    735    } else if constexpr (std::is_same_v<decltype(a), uint8_t&&>) {
    736      return RESULT(U8, ParamRREF, NA, a);
    737    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&&>) {
    738      return RESULT(U8, ParamCRREF, NA, a);
    739    } else if constexpr (std::is_same_v<decltype(a), uint32_t&>) {
    740      return RESULT(U32, ParamLREF, NA, a);
    741    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&>) {
    742      return RESULT(U32, ParamCLREF, NA, a);
    743    } else if constexpr (std::is_same_v<decltype(a), uint32_t&&>) {
    744      return RESULT(U32, ParamRREF, NA, a);
    745    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&&>) {
    746      return RESULT(U32, ParamCRREF, NA, a);
    747    } else if constexpr (std::is_same_v<decltype(a), uint64_t&>) {
    748      return RESULT(U64, ParamLREF, NA, a);
    749    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&>) {
    750      return RESULT(U64, ParamCLREF, NA, a);
    751    } else if constexpr (std::is_same_v<decltype(a), uint64_t&&>) {
    752      return RESULT(U64, ParamRREF, NA, a);
    753    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&&>) {
    754      return RESULT(U64, ParamCRREF, NA, a);
    755    } else {
    756      // We don't expect any other type.
    757      // Tech note: We can't just do `static_assert(false)` which would always
    758      // fail during the initial parsing. So we depend on the templated
    759      // parameter to delay computing `false` until actual instantiation.
    760      static_assert(sizeof(a) == size_t(-1));
    761      return RESULT(NA, NA, NA, 0);
    762    }
    763  };
    764 
    765  V v1(uint8_t(1));
    766  V v2(uint32_t(2));
    767  V v3(uint64_t(3));
    768 
    769  const V& constRef1 = v1;
    770  const V& constRef2 = v2;
    771  const V& constRef3 = v3;
    772 
    773  // Create a temporary variant by returning a copy of one.
    774  auto CopyV = [](const V& aV) { return aV; };
    775 
    776  // Create a temporary variant by returning a const copy of one.
    777  auto CopyConstV = [](const V& aV) -> const V { return aV; };
    778 
    779  MOZ_RELEASE_ASSERT(v1.match(desc) == RESULT(U8, ParamLREF, NA, 1));
    780  MOZ_RELEASE_ASSERT(v2.match(desc) == RESULT(U32, ParamLREF, NA, 2));
    781  MOZ_RELEASE_ASSERT(v3.match(desc) == RESULT(U64, ParamLREF, NA, 3));
    782 
    783  MOZ_RELEASE_ASSERT(constRef1.match(desc) == RESULT(U8, ParamCLREF, NA, 1));
    784  MOZ_RELEASE_ASSERT(constRef2.match(desc) == RESULT(U32, ParamCLREF, NA, 2));
    785  MOZ_RELEASE_ASSERT(constRef3.match(desc) == RESULT(U64, ParamCLREF, NA, 3));
    786 
    787  MOZ_RELEASE_ASSERT(CopyV(v1).match(desc) == RESULT(U8, ParamRREF, NA, 1));
    788  MOZ_RELEASE_ASSERT(CopyV(v2).match(desc) == RESULT(U32, ParamRREF, NA, 2));
    789  MOZ_RELEASE_ASSERT(CopyV(v3).match(desc) == RESULT(U64, ParamRREF, NA, 3));
    790 
    791  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc) ==
    792                     RESULT(U8, ParamCRREF, NA, 1));
    793  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc) ==
    794                     RESULT(U32, ParamCRREF, NA, 2));
    795  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc) ==
    796                     RESULT(U64, ParamCRREF, NA, 3));
    797 }
    798 
    799 static void testMatchingLambdaWithIndex() {
    800  printf("testMatchingLambdaWithIndex\n");
    801  using V = Variant<uint8_t, uint32_t, uint64_t>;
    802 
    803  // Note: Lambdas' call operators are const by default (unless the lambda is
    804  // declared `mutable`), hence the use of "...Const" strings below.
    805  // There is no need to test mutable lambdas, nor rvalue lambda, because there
    806  // would be no way to distinguish how each lambda is actually invoked because
    807  // there is only one choice of call operator in each overload set.
    808  auto desc = [](auto aIndex, auto&& a) {
    809    static_assert(
    810        std::is_same_v<decltype(aIndex), uint_fast8_t>,
    811        "Expected a uint_fast8_t index for a Variant with 3 alternatives");
    812    if constexpr (std::is_same_v<decltype(a), uint8_t&>) {
    813      MOZ_RELEASE_ASSERT(aIndex == 0);
    814      return RESULT(U8, ParamLREF, NA, a);
    815    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&>) {
    816      MOZ_RELEASE_ASSERT(aIndex == 0);
    817      return RESULT(U8, ParamCLREF, NA, a);
    818    } else if constexpr (std::is_same_v<decltype(a), uint8_t&&>) {
    819      MOZ_RELEASE_ASSERT(aIndex == 0);
    820      return RESULT(U8, ParamRREF, NA, a);
    821    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&&>) {
    822      MOZ_RELEASE_ASSERT(aIndex == 0);
    823      return RESULT(U8, ParamCRREF, NA, a);
    824    } else if constexpr (std::is_same_v<decltype(a), uint32_t&>) {
    825      MOZ_RELEASE_ASSERT(aIndex == 1);
    826      return RESULT(U32, ParamLREF, NA, a);
    827    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&>) {
    828      MOZ_RELEASE_ASSERT(aIndex == 1);
    829      return RESULT(U32, ParamCLREF, NA, a);
    830    } else if constexpr (std::is_same_v<decltype(a), uint32_t&&>) {
    831      MOZ_RELEASE_ASSERT(aIndex == 1);
    832      return RESULT(U32, ParamRREF, NA, a);
    833    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&&>) {
    834      MOZ_RELEASE_ASSERT(aIndex == 1);
    835      return RESULT(U32, ParamCRREF, NA, a);
    836    } else if constexpr (std::is_same_v<decltype(a), uint64_t&>) {
    837      MOZ_RELEASE_ASSERT(aIndex == 2);
    838      return RESULT(U64, ParamLREF, NA, a);
    839    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&>) {
    840      MOZ_RELEASE_ASSERT(aIndex == 2);
    841      return RESULT(U64, ParamCLREF, NA, a);
    842    } else if constexpr (std::is_same_v<decltype(a), uint64_t&&>) {
    843      MOZ_RELEASE_ASSERT(aIndex == 2);
    844      return RESULT(U64, ParamRREF, NA, a);
    845    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&&>) {
    846      MOZ_RELEASE_ASSERT(aIndex == 2);
    847      return RESULT(U64, ParamCRREF, NA, a);
    848    } else {
    849      // We don't expect any other type.
    850      // Tech note: We can't just do `static_assert(false)` which would always
    851      // fail during the initial parsing. So we depend on the templated
    852      // parameter to delay computing `false` until actual instantiation.
    853      static_assert(sizeof(a) == size_t(-1));
    854      return RESULT(NA, NA, NA, 0);
    855    }
    856  };
    857 
    858  V v1(uint8_t(1));
    859  V v2(uint32_t(2));
    860  V v3(uint64_t(3));
    861 
    862  const V& constRef1 = v1;
    863  const V& constRef2 = v2;
    864  const V& constRef3 = v3;
    865 
    866  // Create a temporary variant by returning a copy of one.
    867  auto CopyV = [](const V& aV) { return aV; };
    868 
    869  // Create a temporary variant by returning a const copy of one.
    870  auto CopyConstV = [](const V& aV) -> const V { return aV; };
    871 
    872  MOZ_RELEASE_ASSERT(v1.match(desc) == RESULT(U8, ParamLREF, NA, 1));
    873  MOZ_RELEASE_ASSERT(v2.match(desc) == RESULT(U32, ParamLREF, NA, 2));
    874  MOZ_RELEASE_ASSERT(v3.match(desc) == RESULT(U64, ParamLREF, NA, 3));
    875 
    876  MOZ_RELEASE_ASSERT(constRef1.match(desc) == RESULT(U8, ParamCLREF, NA, 1));
    877  MOZ_RELEASE_ASSERT(constRef2.match(desc) == RESULT(U32, ParamCLREF, NA, 2));
    878  MOZ_RELEASE_ASSERT(constRef3.match(desc) == RESULT(U64, ParamCLREF, NA, 3));
    879 
    880  MOZ_RELEASE_ASSERT(CopyV(v1).match(desc) == RESULT(U8, ParamRREF, NA, 1));
    881  MOZ_RELEASE_ASSERT(CopyV(v2).match(desc) == RESULT(U32, ParamRREF, NA, 2));
    882  MOZ_RELEASE_ASSERT(CopyV(v3).match(desc) == RESULT(U64, ParamRREF, NA, 3));
    883 
    884  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc) ==
    885                     RESULT(U8, ParamCRREF, NA, 1));
    886  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc) ==
    887                     RESULT(U32, ParamCRREF, NA, 2));
    888  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc) ==
    889                     RESULT(U64, ParamCRREF, NA, 3));
    890 }
    891 
    892 static void testMatchingLambdas() {
    893  printf("testMatchingLambdas\n");
    894  using V = Variant<uint8_t, uint32_t, uint64_t>;
    895 
    896  auto desc8 = [](auto&& a) {
    897    if constexpr (std::is_same_v<decltype(a), uint8_t&>) {
    898      return RESULT(U8, ParamLREF, NA, a);
    899    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&>) {
    900      return RESULT(U8, ParamCLREF, NA, a);
    901    } else if constexpr (std::is_same_v<decltype(a), uint8_t&&>) {
    902      return RESULT(U8, ParamRREF, NA, a);
    903    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&&>) {
    904      return RESULT(U8, ParamCRREF, NA, a);
    905    } else {
    906      // We don't expect any other type.
    907      // Tech note: We can't just do `static_assert(false)` which would always
    908      // fail during the initial parsing. So we depend on the templated
    909      // parameter to delay computing `false` until actual instantiation.
    910      static_assert(sizeof(a) == size_t(-1));
    911      return RESULT(NA, NA, NA, 0);
    912    }
    913  };
    914  auto desc32 = [](auto&& a) {
    915    if constexpr (std::is_same_v<decltype(a), uint32_t&>) {
    916      return RESULT(U32, ParamLREF, NA, a);
    917    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&>) {
    918      return RESULT(U32, ParamCLREF, NA, a);
    919    } else if constexpr (std::is_same_v<decltype(a), uint32_t&&>) {
    920      return RESULT(U32, ParamRREF, NA, a);
    921    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&&>) {
    922      return RESULT(U32, ParamCRREF, NA, a);
    923    } else {
    924      // We don't expect any other type.
    925      // Tech note: We can't just do `static_assert(false)` which would always
    926      // fail during the initial parsing. So we depend on the templated
    927      // parameter to delay computing `false` until actual instantiation.
    928      static_assert(sizeof(a) == size_t(-1));
    929      return RESULT(NA, NA, NA, 0);
    930    }
    931  };
    932  auto desc64 = [](auto&& a) {
    933    if constexpr (std::is_same_v<decltype(a), uint64_t&>) {
    934      return RESULT(U64, ParamLREF, NA, a);
    935    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&>) {
    936      return RESULT(U64, ParamCLREF, NA, a);
    937    } else if constexpr (std::is_same_v<decltype(a), uint64_t&&>) {
    938      return RESULT(U64, ParamRREF, NA, a);
    939    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&&>) {
    940      return RESULT(U64, ParamCRREF, NA, a);
    941    } else {
    942      // We don't expect any other type.
    943      // Tech note: We can't just do `static_assert(false)` which would always
    944      // fail during the initial parsing. So we depend on the templated
    945      // parameter to delay computing `false` until actual instantiation.
    946      static_assert(sizeof(a) == size_t(-1));
    947      return RESULT(NA, NA, NA, 0);
    948    }
    949  };
    950 
    951  V v1(uint8_t(1));
    952  V v2(uint32_t(2));
    953  V v3(uint64_t(3));
    954 
    955  const V& constRef1 = v1;
    956  const V& constRef2 = v2;
    957  const V& constRef3 = v3;
    958 
    959  // Create a temporary variant by returning a copy of one.
    960  auto CopyV = [](const V& aV) { return aV; };
    961 
    962  // Create a temporary variant by returning a const copy of one.
    963  auto CopyConstV = [](const V& aV) -> const V { return aV; };
    964 
    965  MOZ_RELEASE_ASSERT(v1.match(desc8, desc32, desc64) ==
    966                     RESULT(U8, ParamLREF, NA, 1));
    967  MOZ_RELEASE_ASSERT(v2.match(desc8, desc32, desc64) ==
    968                     RESULT(U32, ParamLREF, NA, 2));
    969  MOZ_RELEASE_ASSERT(v3.match(desc8, desc32, desc64) ==
    970                     RESULT(U64, ParamLREF, NA, 3));
    971 
    972  MOZ_RELEASE_ASSERT(constRef1.match(desc8, desc32, desc64) ==
    973                     RESULT(U8, ParamCLREF, NA, 1));
    974  MOZ_RELEASE_ASSERT(constRef2.match(desc8, desc32, desc64) ==
    975                     RESULT(U32, ParamCLREF, NA, 2));
    976  MOZ_RELEASE_ASSERT(constRef3.match(desc8, desc32, desc64) ==
    977                     RESULT(U64, ParamCLREF, NA, 3));
    978 
    979  MOZ_RELEASE_ASSERT(CopyV(v1).match(desc8, desc32, desc64) ==
    980                     RESULT(U8, ParamRREF, NA, 1));
    981  MOZ_RELEASE_ASSERT(CopyV(v2).match(desc8, desc32, desc64) ==
    982                     RESULT(U32, ParamRREF, NA, 2));
    983  MOZ_RELEASE_ASSERT(CopyV(v3).match(desc8, desc32, desc64) ==
    984                     RESULT(U64, ParamRREF, NA, 3));
    985 
    986  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc8, desc32, desc64) ==
    987                     RESULT(U8, ParamCRREF, NA, 1));
    988  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc8, desc32, desc64) ==
    989                     RESULT(U32, ParamCRREF, NA, 2));
    990  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc8, desc32, desc64) ==
    991                     RESULT(U64, ParamCRREF, NA, 3));
    992 }
    993 
    994 static void testMatchingLambdasWithIndex() {
    995  printf("testMatchingLambdasWithIndex\n");
    996  using V = Variant<uint8_t, uint32_t, uint64_t>;
    997 
    998  auto desc8 = [](size_t aIndex, auto&& a) {
    999    MOZ_RELEASE_ASSERT(aIndex == 0);
   1000    if constexpr (std::is_same_v<decltype(a), uint8_t&>) {
   1001      return RESULT(U8, ParamLREF, NA, a);
   1002    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&>) {
   1003      return RESULT(U8, ParamCLREF, NA, a);
   1004    } else if constexpr (std::is_same_v<decltype(a), uint8_t&&>) {
   1005      return RESULT(U8, ParamRREF, NA, a);
   1006    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&&>) {
   1007      return RESULT(U8, ParamCRREF, NA, a);
   1008    } else {
   1009      // We don't expect any other type.
   1010      // Tech note: We can't just do `static_assert(false)` which would always
   1011      // fail during the initial parsing. So we depend on the templated
   1012      // parameter to delay computing `false` until actual instantiation.
   1013      static_assert(sizeof(a) == size_t(-1));
   1014      return RESULT(NA, NA, NA, 0);
   1015    }
   1016  };
   1017  auto desc32 = [](size_t aIndex, auto&& a) {
   1018    MOZ_RELEASE_ASSERT(aIndex == 1);
   1019    if constexpr (std::is_same_v<decltype(a), uint32_t&>) {
   1020      return RESULT(U32, ParamLREF, NA, a);
   1021    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&>) {
   1022      return RESULT(U32, ParamCLREF, NA, a);
   1023    } else if constexpr (std::is_same_v<decltype(a), uint32_t&&>) {
   1024      return RESULT(U32, ParamRREF, NA, a);
   1025    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&&>) {
   1026      return RESULT(U32, ParamCRREF, NA, a);
   1027    } else {
   1028      // We don't expect any other type.
   1029      // Tech note: We can't just do `static_assert(false)` which would always
   1030      // fail during the initial parsing. So we depend on the templated
   1031      // parameter to delay computing `false` until actual instantiation.
   1032      static_assert(sizeof(a) == size_t(-1));
   1033      return RESULT(NA, NA, NA, 0);
   1034    }
   1035  };
   1036  auto desc64 = [](size_t aIndex, auto&& a) {
   1037    MOZ_RELEASE_ASSERT(aIndex == 2);
   1038    if constexpr (std::is_same_v<decltype(a), uint64_t&>) {
   1039      return RESULT(U64, ParamLREF, NA, a);
   1040    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&>) {
   1041      return RESULT(U64, ParamCLREF, NA, a);
   1042    } else if constexpr (std::is_same_v<decltype(a), uint64_t&&>) {
   1043      return RESULT(U64, ParamRREF, NA, a);
   1044    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&&>) {
   1045      return RESULT(U64, ParamCRREF, NA, a);
   1046    } else {
   1047      // We don't expect any other type.
   1048      // Tech note: We can't just do `static_assert(false)` which would always
   1049      // fail during the initial parsing. So we depend on the templated
   1050      // parameter to delay computing `false` until actual instantiation.
   1051      static_assert(sizeof(a) == size_t(-1));
   1052      return RESULT(NA, NA, NA, 0);
   1053    }
   1054  };
   1055 
   1056  V v1(uint8_t(1));
   1057  V v2(uint32_t(2));
   1058  V v3(uint64_t(3));
   1059 
   1060  const V& constRef1 = v1;
   1061  const V& constRef2 = v2;
   1062  const V& constRef3 = v3;
   1063 
   1064  // Create a temporary variant by returning a copy of one.
   1065  auto CopyV = [](const V& aV) { return aV; };
   1066 
   1067  // Create a temporary variant by returning a const copy of one.
   1068  auto CopyConstV = [](const V& aV) -> const V { return aV; };
   1069 
   1070  MOZ_RELEASE_ASSERT(v1.match(desc8, desc32, desc64) ==
   1071                     RESULT(U8, ParamLREF, NA, 1));
   1072  MOZ_RELEASE_ASSERT(v2.match(desc8, desc32, desc64) ==
   1073                     RESULT(U32, ParamLREF, NA, 2));
   1074  MOZ_RELEASE_ASSERT(v3.match(desc8, desc32, desc64) ==
   1075                     RESULT(U64, ParamLREF, NA, 3));
   1076 
   1077  MOZ_RELEASE_ASSERT(constRef1.match(desc8, desc32, desc64) ==
   1078                     RESULT(U8, ParamCLREF, NA, 1));
   1079  MOZ_RELEASE_ASSERT(constRef2.match(desc8, desc32, desc64) ==
   1080                     RESULT(U32, ParamCLREF, NA, 2));
   1081  MOZ_RELEASE_ASSERT(constRef3.match(desc8, desc32, desc64) ==
   1082                     RESULT(U64, ParamCLREF, NA, 3));
   1083 
   1084  MOZ_RELEASE_ASSERT(CopyV(v1).match(desc8, desc32, desc64) ==
   1085                     RESULT(U8, ParamRREF, NA, 1));
   1086  MOZ_RELEASE_ASSERT(CopyV(v2).match(desc8, desc32, desc64) ==
   1087                     RESULT(U32, ParamRREF, NA, 2));
   1088  MOZ_RELEASE_ASSERT(CopyV(v3).match(desc8, desc32, desc64) ==
   1089                     RESULT(U64, ParamRREF, NA, 3));
   1090 
   1091  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc8, desc32, desc64) ==
   1092                     RESULT(U8, ParamCRREF, NA, 1));
   1093  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc8, desc32, desc64) ==
   1094                     RESULT(U32, ParamCRREF, NA, 2));
   1095  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc8, desc32, desc64) ==
   1096                     RESULT(U64, ParamCRREF, NA, 3));
   1097 }
   1098 
   1099 #undef RESULT
   1100 
   1101 static void testAddTagToHash() {
   1102  printf("testAddToHash\n");
   1103  using V = Variant<uint8_t, uint16_t, uint32_t, uint64_t>;
   1104 
   1105  // We don't know what our hash function is, and these are certainly not all
   1106  // true under all hash functions. But they are probably true under almost any
   1107  // decent hash function, and our aim is simply to establish that the tag
   1108  // *does* influence the hash value.
   1109  {
   1110    mozilla::HashNumber h8 = V(uint8_t(1)).addTagToHash(0);
   1111    mozilla::HashNumber h16 = V(uint16_t(1)).addTagToHash(0);
   1112    mozilla::HashNumber h32 = V(uint32_t(1)).addTagToHash(0);
   1113    mozilla::HashNumber h64 = V(uint64_t(1)).addTagToHash(0);
   1114 
   1115    MOZ_RELEASE_ASSERT(h8 != h16 && h8 != h32 && h8 != h64);
   1116    MOZ_RELEASE_ASSERT(h16 != h32 && h16 != h64);
   1117    MOZ_RELEASE_ASSERT(h32 != h64);
   1118  }
   1119 
   1120  {
   1121    mozilla::HashNumber h8 = V(uint8_t(1)).addTagToHash(0x124356);
   1122    mozilla::HashNumber h16 = V(uint16_t(1)).addTagToHash(0x124356);
   1123    mozilla::HashNumber h32 = V(uint32_t(1)).addTagToHash(0x124356);
   1124    mozilla::HashNumber h64 = V(uint64_t(1)).addTagToHash(0x124356);
   1125 
   1126    MOZ_RELEASE_ASSERT(h8 != h16 && h8 != h32 && h8 != h64);
   1127    MOZ_RELEASE_ASSERT(h16 != h32 && h16 != h64);
   1128    MOZ_RELEASE_ASSERT(h32 != h64);
   1129  }
   1130 }
   1131 
   1132 int main() {
   1133  testDetails();
   1134  testSimple();
   1135  testDuplicate();
   1136  testConstructionWithVariantType();
   1137  testConstructionWithVariantIndex();
   1138  testEmplaceWithType();
   1139  testEmplaceWithIndex();
   1140  testCopy();
   1141  testMove();
   1142  testDestructor();
   1143  testEquality();
   1144  testMatching();
   1145  testMatchingLambda();
   1146  testMatchingLambdaWithIndex();
   1147  testMatchingLambdas();
   1148  testMatchingLambdasWithIndex();
   1149  testAddTagToHash();
   1150 
   1151  printf("TestVariant OK!\n");
   1152  return 0;
   1153 }