Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/mfbt/tests/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 46 kB image not shown  

Quelle  TestVariant.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */


#include <type_traits>

#include "mozilla/UniquePtr.h"
#include "mozilla/Variant.h"

#include <tuple>

using mozilla::MakeUnique;
using mozilla::UniquePtr;
using mozilla::Variant;

struct Destroyer {
  static int destroyedCount;
  ~Destroyer() { destroyedCount++; }
};

int Destroyer::destroyedCount = 0;

static void testDetails() {
  printf("testDetails\n");

  using mozilla::detail::Nth;

  // Test Nth with a list of 1 item.
  static_assert(std::is_same_v<typename Nth<0, int>::Type, int>,
                "Nth<0, int>::Type should be int");

  // Test Nth with a list of more than 1 item.
  static_assert(std::is_same_v<typename Nth<0, intchar>::Type, int>,
                "Nth<0, int, char>::Type should be int");
  static_assert(std::is_same_v<typename Nth<1, intchar>::Type, char>,
                "Nth<1, int, char>::Type should be char");

  using mozilla::detail::SelectVariantType;

  // SelectVariantType for zero items (shouldn't happen, but `count` should
  // still work ok.)
  static_assert(SelectVariantType<intchar>::count == 0,
                "SelectVariantType::count should be 0");

  // SelectVariantType for 1 type, for all combinations from/to T, const T,
  // const T&, T&&
  // - type to type
  static_assert(std::is_same_v<typename SelectVariantType<intint>::Type, int>,
                "SelectVariantType::Type should be int");
  static_assert(SelectVariantType<intint>::count == 1,
                "SelectVariantType::count should be 1");

  // - type to const type
  static_assert(std::is_same_v<typename SelectVariantType<intconst int>::Type,
                               const int>,
                "SelectVariantType::Type should be const int");
  static_assert(SelectVariantType<intconst int>::count == 1,
                "SelectVariantType::count should be 1");

  // - type to const type&
  static_assert(
      std::is_same_v<typename SelectVariantType<intconst int&>::Type,
                     const int&>,
      "SelectVariantType::Type should be const int&");
  static_assert(SelectVariantType<intconst int&>::count == 1,
                "SelectVariantType::count should be 1");

  // - type to type&&
  static_assert(
      std::is_same_v<typename SelectVariantType<intint&&>::Type, int&&>,
      "SelectVariantType::Type should be int&&");
  static_assert(SelectVariantType<intint&&>::count == 1,
                "SelectVariantType::count should be 1");

  // - const type to type
  static_assert(
      std::is_same_v<typename SelectVariantType<const intint>::Type, int>,
      "SelectVariantType::Type should be int");
  static_assert(SelectVariantType<const intint>::count == 1,
                "SelectVariantType::count should be 1");

  // - const type to const type
  static_assert(
      std::is_same_v<typename SelectVariantType<const intconst int>::Type,
                     const int>,
      "SelectVariantType::Type should be const int");
  static_assert(SelectVariantType<const intconst int>::count == 1,
                "SelectVariantType::count should be 1");

  // - const type to const type&
  static_assert(
      std::is_same_v<typename SelectVariantType<const intconst int&>::Type,
                     const int&>,
      "SelectVariantType::Type should be const int&");
  static_assert(SelectVariantType<const intconst int&>::count == 1,
                "SelectVariantType::count should be 1");

  // - const type to type&&
  static_assert(
      std::is_same_v<typename SelectVariantType<const intint&&>::Type, int&&>,
      "SelectVariantType::Type should be int&&");
  static_assert(SelectVariantType<const intint&&>::count == 1,
                "SelectVariantType::count should be 1");

  // - const type& to type
  static_assert(
      std::is_same_v<typename SelectVariantType<const int&, int>::Type, int>,
      "SelectVariantType::Type should be int");
  static_assert(SelectVariantType<const int&, int>::count == 1,
                "SelectVariantType::count should be 1");

  // - const type& to const type
  static_assert(
      std::is_same_v<typename SelectVariantType<const int&, const int>::Type,
                     const int>,
      "SelectVariantType::Type should be const int");
  static_assert(SelectVariantType<const int&, const int>::count == 1,
                "SelectVariantType::count should be 1");

  // - const type& to const type&
  static_assert(
      std::is_same_v<typename SelectVariantType<const int&, const int&>::Type,
                     const int&>,
      "SelectVariantType::Type should be const int&");
  static_assert(SelectVariantType<const int&, const int&>::count == 1,
                "SelectVariantType::count should be 1");

  // - const type& to type&&
  static_assert(
      std::is_same_v<typename SelectVariantType<const int&, int&&>::Type,
                     int&&>,
      "SelectVariantType::Type should be int&&");
  static_assert(SelectVariantType<const int&, int&&>::count == 1,
                "SelectVariantType::count should be 1");

  // - type&& to type
  static_assert(
      std::is_same_v<typename SelectVariantType<int&&, int>::Type, int>,
      "SelectVariantType::Type should be int");
  static_assert(SelectVariantType<int&&, int>::count == 1,
                "SelectVariantType::count should be 1");

  // - type&& to const type
  static_assert(
      std::is_same_v<typename SelectVariantType<int&&, const int>::Type,
                     const int>,
      "SelectVariantType::Type should be const int");
  static_assert(SelectVariantType<int&&, const int>::count == 1,
                "SelectVariantType::count should be 1");

  // - type&& to const type&
  static_assert(
      std::is_same_v<typename SelectVariantType<int&&, const int&>::Type,
                     const int&>,
      "SelectVariantType::Type should be const int&");
  static_assert(SelectVariantType<int&&, const int&>::count == 1,
                "SelectVariantType::count should be 1");

  // - type&& to type&&
  static_assert(
      std::is_same_v<typename SelectVariantType<int&&, int&&>::Type, int&&>,
      "SelectVariantType::Type should be int&&");
  static_assert(SelectVariantType<int&&, int&&>::count == 1,
                "SelectVariantType::count should be 1");

  // SelectVariantType for two different types.
  // (Don't test all combinations, trust that the above tests are sufficient.)
  static_assert(
      std::is_same_v<typename SelectVariantType<intintchar>::Type, int>,
      "SelectVariantType::Type should be int");
  static_assert(SelectVariantType<intintchar>::count == 1,
                "SelectVariantType::count should be 1");
  static_assert(
      std::is_same_v<typename SelectVariantType<charintchar>::Type, char>,
      "SelectVariantType::Type should be char");
  static_assert(SelectVariantType<charintchar>::count == 1,
                "SelectVariantType::count should be 1");

  // SelectVariantType for two identical types.
  static_assert(
      std::is_same_v<typename SelectVariantType<intintint>::Type, int>,
      "SelectVariantType::Type should be int");
  static_assert(SelectVariantType<intintint>::count == 2,
                "SelectVariantType::count should be 2");

  // SelectVariantType for two identical types, with others around.
  static_assert(
      std::is_same_v<typename SelectVariantType<intcharintint>::Type,
                     int>,
      "SelectVariantType::Type should be int");
  static_assert(SelectVariantType<intcharintint>::count == 2,
                "SelectVariantType::count should be 2");

  static_assert(
      std::is_same_v<typename SelectVariantType<intintcharint>::Type,
                     int>,
      "SelectVariantType::Type should be int");
  static_assert(SelectVariantType<intintcharint>::count == 2,
                "SelectVariantType::count should be 2");

  static_assert(
      std::is_same_v<typename SelectVariantType<intintintchar>::Type,
                     int>,
      "SelectVariantType::Type should be int");
  static_assert(SelectVariantType<intintintchar>::count == 2,
                "SelectVariantType::count should be 2");

  static_assert(
      std::is_same_v<
          typename SelectVariantType<intcharintcharintchar>::Type,
          int>,
      "SelectVariantType::Type should be int");
  static_assert(
      SelectVariantType<intcharintcharintchar>::count == 2,
      "SelectVariantType::count should be 2");

  // SelectVariantType for two identically-selectable types (first one wins!).
  static_assert(
      std::is_same_v<typename SelectVariantType<intintconst int>::Type,
                     int>,
      "SelectVariantType::Type should be int");
  static_assert(SelectVariantType<intintconst int>::count == 2,
                "SelectVariantType::count should be 2");
  static_assert(
      std::is_same_v<typename SelectVariantType<intconst intint>::Type,
                     const int>,
      "SelectVariantType::Type should be const int");
  static_assert(SelectVariantType<intconst intint>::count == 2,
                "SelectVariantType::count should be 2");
  static_assert(
      std::is_same_v<typename SelectVariantType<intconst intint&&>::Type,
                     const int>,
      "SelectVariantType::Type should be const int");
  static_assert(SelectVariantType<intconst intint&&>::count == 2,
                "SelectVariantType::count should be 2");
}

static void testSimple() {
  printf("testSimple\n");
  using V = Variant<uint32_t, uint64_t>;

  // Non-const lvalue.
  V v(uint64_t(1));
  MOZ_RELEASE_ASSERT(v.is<uint64_t>());
  MOZ_RELEASE_ASSERT(!v.is<uint32_t>());
  MOZ_RELEASE_ASSERT(v.as<uint64_t>() == 1);

  MOZ_RELEASE_ASSERT(v.is<1>());
  MOZ_RELEASE_ASSERT(!v.is<0>());
  static_assert(std::is_same_v<decltype(v.as<1>()), uint64_t&>,
                "v.as<1>() should return a uint64_t&");
  MOZ_RELEASE_ASSERT(v.as<1>() == 1);

  // Const lvalue.
  const V& cv = v;
  MOZ_RELEASE_ASSERT(cv.is<uint64_t>());
  MOZ_RELEASE_ASSERT(!cv.is<uint32_t>());
  MOZ_RELEASE_ASSERT(cv.as<uint64_t>() == 1);

  MOZ_RELEASE_ASSERT(cv.is<1>());
  MOZ_RELEASE_ASSERT(!cv.is<0>());
  static_assert(std::is_same_v<decltype(cv.as<1>()), const uint64_t&>,
                "cv.as<1>() should return a const uint64_t&");
  MOZ_RELEASE_ASSERT(cv.as<1>() == 1);

  // Non-const rvalue, using a function to create a temporary.
  auto MakeV = []() { return V(uint64_t(1)); };
  MOZ_RELEASE_ASSERT(MakeV().is<uint64_t>());
  MOZ_RELEASE_ASSERT(!MakeV().is<uint32_t>());
  MOZ_RELEASE_ASSERT(MakeV().as<uint64_t>() == 1);

  MOZ_RELEASE_ASSERT(MakeV().is<1>());
  MOZ_RELEASE_ASSERT(!MakeV().is<0>());
  static_assert(std::is_same_v<decltype(MakeV().as<1>()), uint64_t&&>,
                "MakeV().as<1>() should return a uint64_t&&");
  MOZ_RELEASE_ASSERT(MakeV().as<1>() == 1);

  // Const rvalue, using a function to create a temporary.
  auto MakeCV = []() -> const V { return V(uint64_t(1)); };
  MOZ_RELEASE_ASSERT(MakeCV().is<uint64_t>());
  MOZ_RELEASE_ASSERT(!MakeCV().is<uint32_t>());
  MOZ_RELEASE_ASSERT(MakeCV().as<uint64_t>() == 1);

  MOZ_RELEASE_ASSERT(MakeCV().is<1>());
  MOZ_RELEASE_ASSERT(!MakeCV().is<0>());
  static_assert(std::is_same_v<decltype(MakeCV().as<1>()), const uint64_t&&>,
                "MakeCV().as<1>() should return a const uint64_t&&");
  MOZ_RELEASE_ASSERT(MakeCV().as<1>() == 1);
}

static void testDuplicate() {
  printf("testDuplicate\n");
  Variant<uint32_t, uint64_t, uint32_t> v(uint64_t(1));
  MOZ_RELEASE_ASSERT(v.is<uint64_t>());
  MOZ_RELEASE_ASSERT(v.as<uint64_t>() == 1);
  // Note: uint32_t is not unique, so `v.is<uint32_t>()` is not allowed.

  MOZ_RELEASE_ASSERT(v.is<1>());
  MOZ_RELEASE_ASSERT(!v.is<0>());
  MOZ_RELEASE_ASSERT(!v.is<2>());
  static_assert(std::is_same_v<decltype(v.as<0>()), uint32_t&>,
                "as<0>() should return a uint64_t");
  static_assert(std::is_same_v<decltype(v.as<1>()), uint64_t&>,
                "as<1>() should return a uint64_t");
  static_assert(std::is_same_v<decltype(v.as<2>()), uint32_t&>,
                "as<2>() should return a uint64_t");
  MOZ_RELEASE_ASSERT(v.as<1>() == 1);
  MOZ_RELEASE_ASSERT(v.extract<1>() == 1);
}

static void testConstructionWithVariantType() {
  Variant<uint32_t, uint64_t, uint32_t> v(mozilla::VariantType<uint64_t>{}, 3);
  MOZ_RELEASE_ASSERT(v.is<uint64_t>());
  // MOZ_RELEASE_ASSERT(!v.is<uint32_t>()); // uint32_t is not unique!
  MOZ_RELEASE_ASSERT(v.as<uint64_t>() == 3);
}

static void testConstructionWithVariantIndex() {
  Variant<uint32_t, uint64_t, uint32_t> v(mozilla::VariantIndex<2>{}, 2);
  MOZ_RELEASE_ASSERT(!v.is<uint64_t>());
  // Note: uint32_t is not unique, so `v.is<uint32_t>()` is not allowed.

  MOZ_RELEASE_ASSERT(!v.is<1>());
  MOZ_RELEASE_ASSERT(!v.is<0>());
  MOZ_RELEASE_ASSERT(v.is<2>());
  MOZ_RELEASE_ASSERT(v.as<2>() == 2);
  MOZ_RELEASE_ASSERT(v.extract<2>() == 2);
}

static void testEmplaceWithType() {
  printf("testEmplaceWithType\n");
  Variant<uint32_t, uint64_t, uint32_t> v1(mozilla::VariantIndex<0>{}, 0);
  v1.emplace<uint64_t>(3);
  MOZ_RELEASE_ASSERT(v1.is<uint64_t>());
  MOZ_RELEASE_ASSERT(v1.as<uint64_t>() == 3);

  Variant<UniquePtr<int>, char> v2('a');
  v2.emplace<UniquePtr<int>>();
  MOZ_RELEASE_ASSERT(v2.is<UniquePtr<int>>());
  MOZ_RELEASE_ASSERT(!v2.as<UniquePtr<int>>().get());

  Variant<UniquePtr<int>, char> v3('a');
  v3.emplace<UniquePtr<int>>(MakeUnique<int>(4));
  MOZ_RELEASE_ASSERT(v3.is<UniquePtr<int>>());
  MOZ_RELEASE_ASSERT(*v3.as<UniquePtr<int>>().get() == 4);
}

static void testEmplaceWithIndex() {
  printf("testEmplaceWithIndex\n");
  Variant<uint32_t, uint64_t, uint32_t> v1(mozilla::VariantIndex<1>{}, 0);
  v1.emplace<2>(2);
  MOZ_RELEASE_ASSERT(!v1.is<uint64_t>());
  MOZ_RELEASE_ASSERT(!v1.is<1>());
  MOZ_RELEASE_ASSERT(!v1.is<0>());
  MOZ_RELEASE_ASSERT(v1.is<2>());
  MOZ_RELEASE_ASSERT(v1.as<2>() == 2);
  MOZ_RELEASE_ASSERT(v1.extract<2>() == 2);

  Variant<UniquePtr<int>, char> v2('a');
  v2.emplace<0>();
  MOZ_RELEASE_ASSERT(v2.is<UniquePtr<int>>());
  MOZ_RELEASE_ASSERT(!v2.is<1>());
  MOZ_RELEASE_ASSERT(v2.is<0>());
  MOZ_RELEASE_ASSERT(!v2.as<0>().get());
  MOZ_RELEASE_ASSERT(!v2.extract<0>().get());

  Variant<UniquePtr<int>, char> v3('a');
  v3.emplace<0>(MakeUnique<int>(4));
  MOZ_RELEASE_ASSERT(v3.is<UniquePtr<int>>());
  MOZ_RELEASE_ASSERT(!v3.is<1>());
  MOZ_RELEASE_ASSERT(v3.is<0>());
  MOZ_RELEASE_ASSERT(*v3.as<0>().get() == 4);
  MOZ_RELEASE_ASSERT(*v3.extract<0>().get() == 4);
}

static void testCopy() {
  printf("testCopy\n");
  Variant<uint32_t, uint64_t> v1(uint64_t(1));
  Variant<uint32_t, uint64_t> v2(v1);
  MOZ_RELEASE_ASSERT(v2.is<uint64_t>());
  MOZ_RELEASE_ASSERT(!v2.is<uint32_t>());
  MOZ_RELEASE_ASSERT(v2.as<uint64_t>() == 1);

  Variant<uint32_t, uint64_t> v3(uint32_t(10));
  v3 = v2;
  MOZ_RELEASE_ASSERT(v3.is<uint64_t>());
  MOZ_RELEASE_ASSERT(v3.as<uint64_t>() == 1);
}

static void testMove() {
  printf("testMove\n");
  Variant<UniquePtr<int>, char> v1(MakeUnique<int>(5));
  Variant<UniquePtr<int>, char> v2(std::move(v1));

  MOZ_RELEASE_ASSERT(v2.is<UniquePtr<int>>());
  MOZ_RELEASE_ASSERT(*v2.as<UniquePtr<int>>() == 5);

  MOZ_RELEASE_ASSERT(v1.is<UniquePtr<int>>());
  MOZ_RELEASE_ASSERT(v1.as<UniquePtr<int>>() == nullptr);

  Destroyer::destroyedCount = 0;
  {
    Variant<char, UniquePtr<Destroyer>> v3(MakeUnique<Destroyer>());
    Variant<char, UniquePtr<Destroyer>> v4(std::move(v3));

    Variant<char, UniquePtr<Destroyer>> v5('a');
    v5 = std::move(v4);

    auto ptr = v5.extract<UniquePtr<Destroyer>>();
    MOZ_RELEASE_ASSERT(Destroyer::destroyedCount == 0);
  }
  MOZ_RELEASE_ASSERT(Destroyer::destroyedCount == 1);
}

static void testDestructor() {
  printf("testDestructor\n");
  Destroyer::destroyedCount = 0;

  {
    Destroyer d;

    {
      Variant<char, UniquePtr<char[]>, Destroyer> v1(d);
      MOZ_RELEASE_ASSERT(Destroyer::destroyedCount ==
                         0);  // None destroyed yet.
    }

    MOZ_RELEASE_ASSERT(Destroyer::destroyedCount ==
                       1);  // v1's copy of d is destroyed.

    {
      Variant<char, UniquePtr<char[]>, Destroyer> v2(
          mozilla::VariantIndex<2>{});
      v2.emplace<Destroyer>(d);
      MOZ_RELEASE_ASSERT(Destroyer::destroyedCount ==
                         2);  // v2's initial value is destroyed.
    }

    MOZ_RELEASE_ASSERT(Destroyer::destroyedCount ==
                       3);  // v2's second value is destroyed.
  }

  MOZ_RELEASE_ASSERT(Destroyer::destroyedCount == 4);  // d is destroyed.
}

static void testEquality() {
  printf("testEquality\n");
  using V = Variant<charint>;

  V v0('a');
  V v1('b');
  V v2('b');
  V v3(42);
  V v4(27);
  V v5(27);
  V v6(int('b'));

  MOZ_RELEASE_ASSERT(v0 != v1);
  MOZ_RELEASE_ASSERT(v1 == v2);
  MOZ_RELEASE_ASSERT(v2 != v3);
  MOZ_RELEASE_ASSERT(v3 != v4);
  MOZ_RELEASE_ASSERT(v4 == v5);
  MOZ_RELEASE_ASSERT(v1 != v6);

  MOZ_RELEASE_ASSERT(v0 == v0);
  MOZ_RELEASE_ASSERT(v1 == v1);
  MOZ_RELEASE_ASSERT(v2 == v2);
  MOZ_RELEASE_ASSERT(v3 == v3);
  MOZ_RELEASE_ASSERT(v4 == v4);
  MOZ_RELEASE_ASSERT(v5 == v5);
  MOZ_RELEASE_ASSERT(v6 == v6);
}

// Matcher that returns a description of how its call-operator was invoked.
struct Describer {
  enum class ParameterSize { NA, U8, U32, U64 };
  enum class ParameterQualifier {
    NA,
    ParamLREF,
    ParamCLREF,
    ParamRREF,
    ParamCRREF
  };
  enum class ThisQualifier { NA, ThisLREF, ThisCLREF, ThisRREF, ThisCRREF };

  using Result =
      std::tuple<ParameterSize, ParameterQualifier, ThisQualifier, uint64_t>;

#define RESULT(SIZE, PQUAL, TQUAL, VALUE)                 \
  Describer::Result(Describer::ParameterSize::SIZE,       \
                    Describer::ParameterQualifier::PQUAL, \
                    Describer::ThisQualifier::TQUAL, VALUE)

#define CALL(TYPE, SIZE, PQUAL, TREF, TQUAL)   \
  Result operator()(TYPE aValue) TREF {        \
    return RESULT(SIZE, PQUAL, TQUAL, aValue); \
  }

  // All combinations of possible call operators:
  // Every line, the parameter integer type changes.
  // Every 3 lines, the parameter type changes constness.
  // Every 6 lines, the parameter changes reference l/r-valueness.
  // Every 12 lines, the member function qualifier changes constness.
  // After 24 lines, the member function qualifier changes ref l/r-valueness.
  CALL(uint8_t&, U8, ParamLREF, &, ThisLREF)
  CALL(uint32_t&, U32, ParamLREF, &, ThisLREF)
  CALL(uint64_t&, U64, ParamLREF, &, ThisLREF)

  CALL(const uint8_t&, U8, ParamCLREF, &, ThisLREF)
  CALL(const uint32_t&, U32, ParamCLREF, &, ThisLREF)
  CALL(const uint64_t&, U64, ParamCLREF, &, ThisLREF)

  CALL(uint8_t&&, U8, ParamRREF, &, ThisLREF)
  CALL(uint32_t&&, U32, ParamRREF, &, ThisLREF)
  CALL(uint64_t&&, U64, ParamRREF, &, ThisLREF)

  CALL(const uint8_t&&, U8, ParamCRREF, &, ThisLREF)
  CALL(const uint32_t&&, U32, ParamCRREF, &, ThisLREF)
  CALL(const uint64_t&&, U64, ParamCRREF, &, ThisLREF)

  CALL(uint8_t&, U8, ParamLREF, const&, ThisCLREF)
  CALL(uint32_t&, U32, ParamLREF, const&, ThisCLREF)
  CALL(uint64_t&, U64, ParamLREF, const&, ThisCLREF)

  CALL(const uint8_t&, U8, ParamCLREF, const&, ThisCLREF)
  CALL(const uint32_t&, U32, ParamCLREF, const&, ThisCLREF)
  CALL(const uint64_t&, U64, ParamCLREF, const&, ThisCLREF)

  CALL(uint8_t&&, U8, ParamRREF, const&, ThisCLREF)
  CALL(uint32_t&&, U32, ParamRREF, const&, ThisCLREF)
  CALL(uint64_t&&, U64, ParamRREF, const&, ThisCLREF)

  CALL(const uint8_t&&, U8, ParamCRREF, const&, ThisCLREF)
  CALL(const uint32_t&&, U32, ParamCRREF, const&, ThisCLREF)
  CALL(const uint64_t&&, U64, ParamCRREF, const&, ThisCLREF)

  CALL(uint8_t&, U8, ParamLREF, &&, ThisRREF)
  CALL(uint32_t&, U32, ParamLREF, &&, ThisRREF)
  CALL(uint64_t&, U64, ParamLREF, &&, ThisRREF)

  CALL(const uint8_t&, U8, ParamCLREF, &&, ThisRREF)
  CALL(const uint32_t&, U32, ParamCLREF, &&, ThisRREF)
  CALL(const uint64_t&, U64, ParamCLREF, &&, ThisRREF)

  CALL(uint8_t&&, U8, ParamRREF, &&, ThisRREF)
  CALL(uint32_t&&, U32, ParamRREF, &&, ThisRREF)
  CALL(uint64_t&&, U64, ParamRREF, &&, ThisRREF)

  CALL(const uint8_t&&, U8, ParamCRREF, &&, ThisRREF)
  CALL(const uint32_t&&, U32, ParamCRREF, &&, ThisRREF)
  CALL(const uint64_t&&, U64, ParamCRREF, &&, ThisRREF)

  CALL(uint8_t&, U8, ParamLREF, const&&, ThisCRREF)
  CALL(uint32_t&, U32, ParamLREF, const&&, ThisCRREF)
  CALL(uint64_t&, U64, ParamLREF, const&&, ThisCRREF)

  CALL(const uint8_t&, U8, ParamCLREF, const&&, ThisCRREF)
  CALL(const uint32_t&, U32, ParamCLREF, const&&, ThisCRREF)
  CALL(const uint64_t&, U64, ParamCLREF, const&&, ThisCRREF)

  CALL(uint8_t&&, U8, ParamRREF, const&&, ThisCRREF)
  CALL(uint32_t&&, U32, ParamRREF, const&&, ThisCRREF)
  CALL(uint64_t&&, U64, ParamRREF, const&&, ThisCRREF)

  CALL(const uint8_t&&, U8, ParamCRREF, const&&, ThisCRREF)
  CALL(const uint32_t&&, U32, ParamCRREF, const&&, ThisCRREF)
  CALL(const uint64_t&&, U64, ParamCRREF, const&&, ThisCRREF)

#undef CALL

  // Catch-all, to verify that there is no call with any type other than the
  // expected ones above.
  template <typename Other>
  Result operator()(const Other&) {
    MOZ_RELEASE_ASSERT(false);
    return RESULT(NA, NA, NA, 0);
  }
};

static void testMatching() {
  printf("testMatching\n");
  using V = Variant<uint8_t, uint32_t, uint64_t>;

  Describer desc;
  const Describer descConst;
  auto MakeDescriber = []() { return Describer(); };
  auto MakeConstDescriber = []() -> const Describer { return Describer(); };

  V v1(uint8_t(1));
  V v2(uint32_t(2));
  V v3(uint64_t(3));

  const V& constRef1 = v1;
  const V& constRef2 = v2;
  const V& constRef3 = v3;

  // Create a temporary variant by returning a copy of one.
  auto CopyV = [](const V& aV) { return aV; };

  // Create a temporary variant by returning a const copy of one.
  auto CopyConstV = [](const V& aV) -> const V { return aV; };

  // All combinations of possible calls:
  // Every line, the variant integer type changes.
  // Every 3 lines, the variant type changes constness.
  // Every 6 lines, the variant changes reference l/r-valueness.
  // Every 12 lines, the matcher changes constness.
  // After 24 lines, the matcher changes ref l/r-valueness.
  MOZ_RELEASE_ASSERT(v1.match(desc) == RESULT(U8, ParamLREF, ThisLREF, 1));
  MOZ_RELEASE_ASSERT(v2.match(desc) == RESULT(U32, ParamLREF, ThisLREF, 2));
  MOZ_RELEASE_ASSERT(v3.match(desc) == RESULT(U64, ParamLREF, ThisLREF, 3));

  MOZ_RELEASE_ASSERT(constRef1.match(desc) ==
                     RESULT(U8, ParamCLREF, ThisLREF, 1));
  MOZ_RELEASE_ASSERT(constRef2.match(desc) ==
                     RESULT(U32, ParamCLREF, ThisLREF, 2));
  MOZ_RELEASE_ASSERT(constRef3.match(desc) ==
                     RESULT(U64, ParamCLREF, ThisLREF, 3));

  MOZ_RELEASE_ASSERT(CopyV(v1).match(desc) ==
                     RESULT(U8, ParamRREF, ThisLREF, 1));
  MOZ_RELEASE_ASSERT(CopyV(v2).match(desc) ==
                     RESULT(U32, ParamRREF, ThisLREF, 2));
  MOZ_RELEASE_ASSERT(CopyV(v3).match(desc) ==
                     RESULT(U64, ParamRREF, ThisLREF, 3));

  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc) ==
                     RESULT(U8, ParamCRREF, ThisLREF, 1));
  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc) ==
                     RESULT(U32, ParamCRREF, ThisLREF, 2));
  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc) ==
                     RESULT(U64, ParamCRREF, ThisLREF, 3));

  MOZ_RELEASE_ASSERT(v1.match(descConst) ==
                     RESULT(U8, ParamLREF, ThisCLREF, 1));
  MOZ_RELEASE_ASSERT(v2.match(descConst) ==
                     RESULT(U32, ParamLREF, ThisCLREF, 2));
  MOZ_RELEASE_ASSERT(v3.match(descConst) ==
                     RESULT(U64, ParamLREF, ThisCLREF, 3));

  MOZ_RELEASE_ASSERT(constRef1.match(descConst) ==
                     RESULT(U8, ParamCLREF, ThisCLREF, 1));
  MOZ_RELEASE_ASSERT(constRef2.match(descConst) ==
                     RESULT(U32, ParamCLREF, ThisCLREF, 2));
  MOZ_RELEASE_ASSERT(constRef3.match(descConst) ==
                     RESULT(U64, ParamCLREF, ThisCLREF, 3));

  MOZ_RELEASE_ASSERT(CopyV(v1).match(descConst) ==
                     RESULT(U8, ParamRREF, ThisCLREF, 1));
  MOZ_RELEASE_ASSERT(CopyV(v2).match(descConst) ==
                     RESULT(U32, ParamRREF, ThisCLREF, 2));
  MOZ_RELEASE_ASSERT(CopyV(v3).match(descConst) ==
                     RESULT(U64, ParamRREF, ThisCLREF, 3));

  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(descConst) ==
                     RESULT(U8, ParamCRREF, ThisCLREF, 1));
  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(descConst) ==
                     RESULT(U32, ParamCRREF, ThisCLREF, 2));
  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(descConst) ==
                     RESULT(U64, ParamCRREF, ThisCLREF, 3));

  MOZ_RELEASE_ASSERT(v1.match(MakeDescriber()) ==
                     RESULT(U8, ParamLREF, ThisRREF, 1));
  MOZ_RELEASE_ASSERT(v2.match(MakeDescriber()) ==
                     RESULT(U32, ParamLREF, ThisRREF, 2));
  MOZ_RELEASE_ASSERT(v3.match(MakeDescriber()) ==
                     RESULT(U64, ParamLREF, ThisRREF, 3));

  MOZ_RELEASE_ASSERT(constRef1.match(MakeDescriber()) ==
                     RESULT(U8, ParamCLREF, ThisRREF, 1));
  MOZ_RELEASE_ASSERT(constRef2.match(MakeDescriber()) ==
                     RESULT(U32, ParamCLREF, ThisRREF, 2));
  MOZ_RELEASE_ASSERT(constRef3.match(MakeDescriber()) ==
                     RESULT(U64, ParamCLREF, ThisRREF, 3));

  MOZ_RELEASE_ASSERT(CopyV(v1).match(MakeDescriber()) ==
                     RESULT(U8, ParamRREF, ThisRREF, 1));
  MOZ_RELEASE_ASSERT(CopyV(v2).match(MakeDescriber()) ==
                     RESULT(U32, ParamRREF, ThisRREF, 2));
  MOZ_RELEASE_ASSERT(CopyV(v3).match(MakeDescriber()) ==
                     RESULT(U64, ParamRREF, ThisRREF, 3));

  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(MakeDescriber()) ==
                     RESULT(U8, ParamCRREF, ThisRREF, 1));
  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(MakeDescriber()) ==
                     RESULT(U32, ParamCRREF, ThisRREF, 2));
  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(MakeDescriber()) ==
                     RESULT(U64, ParamCRREF, ThisRREF, 3));

  MOZ_RELEASE_ASSERT(v1.match(MakeConstDescriber()) ==
                     RESULT(U8, ParamLREF, ThisCRREF, 1));
  MOZ_RELEASE_ASSERT(v2.match(MakeConstDescriber()) ==
                     RESULT(U32, ParamLREF, ThisCRREF, 2));
  MOZ_RELEASE_ASSERT(v3.match(MakeConstDescriber()) ==
                     RESULT(U64, ParamLREF, ThisCRREF, 3));

  MOZ_RELEASE_ASSERT(constRef1.match(MakeConstDescriber()) ==
                     RESULT(U8, ParamCLREF, ThisCRREF, 1));
  MOZ_RELEASE_ASSERT(constRef2.match(MakeConstDescriber()) ==
                     RESULT(U32, ParamCLREF, ThisCRREF, 2));
  MOZ_RELEASE_ASSERT(constRef3.match(MakeConstDescriber()) ==
                     RESULT(U64, ParamCLREF, ThisCRREF, 3));

  MOZ_RELEASE_ASSERT(CopyV(v1).match(MakeConstDescriber()) ==
                     RESULT(U8, ParamRREF, ThisCRREF, 1));
  MOZ_RELEASE_ASSERT(CopyV(v2).match(MakeConstDescriber()) ==
                     RESULT(U32, ParamRREF, ThisCRREF, 2));
  MOZ_RELEASE_ASSERT(CopyV(v3).match(MakeConstDescriber()) ==
                     RESULT(U64, ParamRREF, ThisCRREF, 3));

  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(MakeConstDescriber()) ==
                     RESULT(U8, ParamCRREF, ThisCRREF, 1));
  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(MakeConstDescriber()) ==
                     RESULT(U32, ParamCRREF, ThisCRREF, 2));
  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(MakeConstDescriber()) ==
                     RESULT(U64, ParamCRREF, ThisCRREF, 3));
}

static void testMatchingLambda() {
  printf("testMatchingLambda\n");
  using V = Variant<uint8_t, uint32_t, uint64_t>;

  // Note: Lambdas' call operators are const by default (unless the lambda is
  // declared `mutable`).
  // There is no need to test mutable lambdas, nor rvalue lambda, because there
  // would be no way to distinguish how each lambda is actually invoked because
  // there is only one choice of call operator in each overload set.
  auto desc = [](auto&& a) {
    if constexpr (std::is_same_v<decltype(a), uint8_t&>) {
      return RESULT(U8, ParamLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&>) {
      return RESULT(U8, ParamCLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint8_t&&>) {
      return RESULT(U8, ParamRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&&>) {
      return RESULT(U8, ParamCRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint32_t&>) {
      return RESULT(U32, ParamLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&>) {
      return RESULT(U32, ParamCLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint32_t&&>) {
      return RESULT(U32, ParamRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&&>) {
      return RESULT(U32, ParamCRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint64_t&>) {
      return RESULT(U64, ParamLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&>) {
      return RESULT(U64, ParamCLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint64_t&&>) {
      return RESULT(U64, ParamRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&&>) {
      return RESULT(U64, ParamCRREF, NA, a);
    } else {
      // We don't expect any other type.
      // Tech note: We can't just do `static_assert(false)` which would always
      // fail during the initial parsing. So we depend on the templated
      // parameter to delay computing `false` until actual instantiation.
      static_assert(sizeof(a) == size_t(-1));
      return RESULT(NA, NA, NA, 0);
    }
  };

  V v1(uint8_t(1));
  V v2(uint32_t(2));
  V v3(uint64_t(3));

  const V& constRef1 = v1;
  const V& constRef2 = v2;
  const V& constRef3 = v3;

  // Create a temporary variant by returning a copy of one.
  auto CopyV = [](const V& aV) { return aV; };

  // Create a temporary variant by returning a const copy of one.
  auto CopyConstV = [](const V& aV) -> const V { return aV; };

  MOZ_RELEASE_ASSERT(v1.match(desc) == RESULT(U8, ParamLREF, NA, 1));
  MOZ_RELEASE_ASSERT(v2.match(desc) == RESULT(U32, ParamLREF, NA, 2));
  MOZ_RELEASE_ASSERT(v3.match(desc) == RESULT(U64, ParamLREF, NA, 3));

  MOZ_RELEASE_ASSERT(constRef1.match(desc) == RESULT(U8, ParamCLREF, NA, 1));
  MOZ_RELEASE_ASSERT(constRef2.match(desc) == RESULT(U32, ParamCLREF, NA, 2));
  MOZ_RELEASE_ASSERT(constRef3.match(desc) == RESULT(U64, ParamCLREF, NA, 3));

  MOZ_RELEASE_ASSERT(CopyV(v1).match(desc) == RESULT(U8, ParamRREF, NA, 1));
  MOZ_RELEASE_ASSERT(CopyV(v2).match(desc) == RESULT(U32, ParamRREF, NA, 2));
  MOZ_RELEASE_ASSERT(CopyV(v3).match(desc) == RESULT(U64, ParamRREF, NA, 3));

  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc) ==
                     RESULT(U8, ParamCRREF, NA, 1));
  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc) ==
                     RESULT(U32, ParamCRREF, NA, 2));
  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc) ==
                     RESULT(U64, ParamCRREF, NA, 3));
}

static void testMatchingLambdaWithIndex() {
  printf("testMatchingLambdaWithIndex\n");
  using V = Variant<uint8_t, uint32_t, uint64_t>;

  // Note: Lambdas' call operators are const by default (unless the lambda is
  // declared `mutable`), hence the use of "...Const" strings below.
  // There is no need to test mutable lambdas, nor rvalue lambda, because there
  // would be no way to distinguish how each lambda is actually invoked because
  // there is only one choice of call operator in each overload set.
  auto desc = [](auto aIndex, auto&& a) {
    static_assert(
        std::is_same_v<decltype(aIndex), uint_fast8_t>,
        "Expected a uint_fast8_t index for a Variant with 3 alternatives");
    if constexpr (std::is_same_v<decltype(a), uint8_t&>) {
      MOZ_RELEASE_ASSERT(aIndex == 0);
      return RESULT(U8, ParamLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&>) {
      MOZ_RELEASE_ASSERT(aIndex == 0);
      return RESULT(U8, ParamCLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint8_t&&>) {
      MOZ_RELEASE_ASSERT(aIndex == 0);
      return RESULT(U8, ParamRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&&>) {
      MOZ_RELEASE_ASSERT(aIndex == 0);
      return RESULT(U8, ParamCRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint32_t&>) {
      MOZ_RELEASE_ASSERT(aIndex == 1);
      return RESULT(U32, ParamLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&>) {
      MOZ_RELEASE_ASSERT(aIndex == 1);
      return RESULT(U32, ParamCLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint32_t&&>) {
      MOZ_RELEASE_ASSERT(aIndex == 1);
      return RESULT(U32, ParamRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&&>) {
      MOZ_RELEASE_ASSERT(aIndex == 1);
      return RESULT(U32, ParamCRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint64_t&>) {
      MOZ_RELEASE_ASSERT(aIndex == 2);
      return RESULT(U64, ParamLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&>) {
      MOZ_RELEASE_ASSERT(aIndex == 2);
      return RESULT(U64, ParamCLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint64_t&&>) {
      MOZ_RELEASE_ASSERT(aIndex == 2);
      return RESULT(U64, ParamRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&&>) {
      MOZ_RELEASE_ASSERT(aIndex == 2);
      return RESULT(U64, ParamCRREF, NA, a);
    } else {
      // We don't expect any other type.
      // Tech note: We can't just do `static_assert(false)` which would always
      // fail during the initial parsing. So we depend on the templated
      // parameter to delay computing `false` until actual instantiation.
      static_assert(sizeof(a) == size_t(-1));
      return RESULT(NA, NA, NA, 0);
    }
  };

  V v1(uint8_t(1));
  V v2(uint32_t(2));
  V v3(uint64_t(3));

  const V& constRef1 = v1;
  const V& constRef2 = v2;
  const V& constRef3 = v3;

  // Create a temporary variant by returning a copy of one.
  auto CopyV = [](const V& aV) { return aV; };

  // Create a temporary variant by returning a const copy of one.
  auto CopyConstV = [](const V& aV) -> const V { return aV; };

  MOZ_RELEASE_ASSERT(v1.match(desc) == RESULT(U8, ParamLREF, NA, 1));
  MOZ_RELEASE_ASSERT(v2.match(desc) == RESULT(U32, ParamLREF, NA, 2));
  MOZ_RELEASE_ASSERT(v3.match(desc) == RESULT(U64, ParamLREF, NA, 3));

  MOZ_RELEASE_ASSERT(constRef1.match(desc) == RESULT(U8, ParamCLREF, NA, 1));
  MOZ_RELEASE_ASSERT(constRef2.match(desc) == RESULT(U32, ParamCLREF, NA, 2));
  MOZ_RELEASE_ASSERT(constRef3.match(desc) == RESULT(U64, ParamCLREF, NA, 3));

  MOZ_RELEASE_ASSERT(CopyV(v1).match(desc) == RESULT(U8, ParamRREF, NA, 1));
  MOZ_RELEASE_ASSERT(CopyV(v2).match(desc) == RESULT(U32, ParamRREF, NA, 2));
  MOZ_RELEASE_ASSERT(CopyV(v3).match(desc) == RESULT(U64, ParamRREF, NA, 3));

  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc) ==
                     RESULT(U8, ParamCRREF, NA, 1));
  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc) ==
                     RESULT(U32, ParamCRREF, NA, 2));
  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc) ==
                     RESULT(U64, ParamCRREF, NA, 3));
}

static void testMatchingLambdas() {
  printf("testMatchingLambdas\n");
  using V = Variant<uint8_t, uint32_t, uint64_t>;

  auto desc8 = [](auto&& a) {
    if constexpr (std::is_same_v<decltype(a), uint8_t&>) {
      return RESULT(U8, ParamLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&>) {
      return RESULT(U8, ParamCLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint8_t&&>) {
      return RESULT(U8, ParamRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&&>) {
      return RESULT(U8, ParamCRREF, NA, a);
    } else {
      // We don't expect any other type.
      // Tech note: We can't just do `static_assert(false)` which would always
      // fail during the initial parsing. So we depend on the templated
      // parameter to delay computing `false` until actual instantiation.
      static_assert(sizeof(a) == size_t(-1));
      return RESULT(NA, NA, NA, 0);
    }
  };
  auto desc32 = [](auto&& a) {
    if constexpr (std::is_same_v<decltype(a), uint32_t&>) {
      return RESULT(U32, ParamLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&>) {
      return RESULT(U32, ParamCLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint32_t&&>) {
      return RESULT(U32, ParamRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&&>) {
      return RESULT(U32, ParamCRREF, NA, a);
    } else {
      // We don't expect any other type.
      // Tech note: We can't just do `static_assert(false)` which would always
      // fail during the initial parsing. So we depend on the templated
      // parameter to delay computing `false` until actual instantiation.
      static_assert(sizeof(a) == size_t(-1));
      return RESULT(NA, NA, NA, 0);
    }
  };
  auto desc64 = [](auto&& a) {
    if constexpr (std::is_same_v<decltype(a), uint64_t&>) {
      return RESULT(U64, ParamLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&>) {
      return RESULT(U64, ParamCLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint64_t&&>) {
      return RESULT(U64, ParamRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&&>) {
      return RESULT(U64, ParamCRREF, NA, a);
    } else {
      // We don't expect any other type.
      // Tech note: We can't just do `static_assert(false)` which would always
      // fail during the initial parsing. So we depend on the templated
      // parameter to delay computing `false` until actual instantiation.
      static_assert(sizeof(a) == size_t(-1));
      return RESULT(NA, NA, NA, 0);
    }
  };

  V v1(uint8_t(1));
  V v2(uint32_t(2));
  V v3(uint64_t(3));

  const V& constRef1 = v1;
  const V& constRef2 = v2;
  const V& constRef3 = v3;

  // Create a temporary variant by returning a copy of one.
  auto CopyV = [](const V& aV) { return aV; };

  // Create a temporary variant by returning a const copy of one.
  auto CopyConstV = [](const V& aV) -> const V { return aV; };

  MOZ_RELEASE_ASSERT(v1.match(desc8, desc32, desc64) ==
                     RESULT(U8, ParamLREF, NA, 1));
  MOZ_RELEASE_ASSERT(v2.match(desc8, desc32, desc64) ==
                     RESULT(U32, ParamLREF, NA, 2));
  MOZ_RELEASE_ASSERT(v3.match(desc8, desc32, desc64) ==
                     RESULT(U64, ParamLREF, NA, 3));

  MOZ_RELEASE_ASSERT(constRef1.match(desc8, desc32, desc64) ==
                     RESULT(U8, ParamCLREF, NA, 1));
  MOZ_RELEASE_ASSERT(constRef2.match(desc8, desc32, desc64) ==
                     RESULT(U32, ParamCLREF, NA, 2));
  MOZ_RELEASE_ASSERT(constRef3.match(desc8, desc32, desc64) ==
                     RESULT(U64, ParamCLREF, NA, 3));

  MOZ_RELEASE_ASSERT(CopyV(v1).match(desc8, desc32, desc64) ==
                     RESULT(U8, ParamRREF, NA, 1));
  MOZ_RELEASE_ASSERT(CopyV(v2).match(desc8, desc32, desc64) ==
                     RESULT(U32, ParamRREF, NA, 2));
  MOZ_RELEASE_ASSERT(CopyV(v3).match(desc8, desc32, desc64) ==
                     RESULT(U64, ParamRREF, NA, 3));

  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc8, desc32, desc64) ==
                     RESULT(U8, ParamCRREF, NA, 1));
  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc8, desc32, desc64) ==
                     RESULT(U32, ParamCRREF, NA, 2));
  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc8, desc32, desc64) ==
                     RESULT(U64, ParamCRREF, NA, 3));
}

static void testMatchingLambdasWithIndex() {
  printf("testMatchingLambdasWithIndex\n");
  using V = Variant<uint8_t, uint32_t, uint64_t>;

  auto desc8 = [](size_t aIndex, auto&& a) {
    MOZ_RELEASE_ASSERT(aIndex == 0);
    if constexpr (std::is_same_v<decltype(a), uint8_t&>) {
      return RESULT(U8, ParamLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&>) {
      return RESULT(U8, ParamCLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint8_t&&>) {
      return RESULT(U8, ParamRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint8_t&&>) {
      return RESULT(U8, ParamCRREF, NA, a);
    } else {
      // We don't expect any other type.
      // Tech note: We can't just do `static_assert(false)` which would always
      // fail during the initial parsing. So we depend on the templated
      // parameter to delay computing `false` until actual instantiation.
      static_assert(sizeof(a) == size_t(-1));
      return RESULT(NA, NA, NA, 0);
    }
  };
  auto desc32 = [](size_t aIndex, auto&& a) {
    MOZ_RELEASE_ASSERT(aIndex == 1);
    if constexpr (std::is_same_v<decltype(a), uint32_t&>) {
      return RESULT(U32, ParamLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&>) {
      return RESULT(U32, ParamCLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint32_t&&>) {
      return RESULT(U32, ParamRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint32_t&&>) {
      return RESULT(U32, ParamCRREF, NA, a);
    } else {
      // We don't expect any other type.
      // Tech note: We can't just do `static_assert(false)` which would always
      // fail during the initial parsing. So we depend on the templated
      // parameter to delay computing `false` until actual instantiation.
      static_assert(sizeof(a) == size_t(-1));
      return RESULT(NA, NA, NA, 0);
    }
  };
  auto desc64 = [](size_t aIndex, auto&& a) {
    MOZ_RELEASE_ASSERT(aIndex == 2);
    if constexpr (std::is_same_v<decltype(a), uint64_t&>) {
      return RESULT(U64, ParamLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&>) {
      return RESULT(U64, ParamCLREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), uint64_t&&>) {
      return RESULT(U64, ParamRREF, NA, a);
    } else if constexpr (std::is_same_v<decltype(a), const uint64_t&&>) {
      return RESULT(U64, ParamCRREF, NA, a);
    } else {
      // We don't expect any other type.
      // Tech note: We can't just do `static_assert(false)` which would always
      // fail during the initial parsing. So we depend on the templated
      // parameter to delay computing `false` until actual instantiation.
      static_assert(sizeof(a) == size_t(-1));
      return RESULT(NA, NA, NA, 0);
    }
  };

  V v1(uint8_t(1));
  V v2(uint32_t(2));
  V v3(uint64_t(3));

  const V& constRef1 = v1;
  const V& constRef2 = v2;
  const V& constRef3 = v3;

  // Create a temporary variant by returning a copy of one.
  auto CopyV = [](const V& aV) { return aV; };

  // Create a temporary variant by returning a const copy of one.
  auto CopyConstV = [](const V& aV) -> const V { return aV; };

  MOZ_RELEASE_ASSERT(v1.match(desc8, desc32, desc64) ==
                     RESULT(U8, ParamLREF, NA, 1));
  MOZ_RELEASE_ASSERT(v2.match(desc8, desc32, desc64) ==
                     RESULT(U32, ParamLREF, NA, 2));
  MOZ_RELEASE_ASSERT(v3.match(desc8, desc32, desc64) ==
                     RESULT(U64, ParamLREF, NA, 3));

  MOZ_RELEASE_ASSERT(constRef1.match(desc8, desc32, desc64) ==
                     RESULT(U8, ParamCLREF, NA, 1));
  MOZ_RELEASE_ASSERT(constRef2.match(desc8, desc32, desc64) ==
                     RESULT(U32, ParamCLREF, NA, 2));
  MOZ_RELEASE_ASSERT(constRef3.match(desc8, desc32, desc64) ==
                     RESULT(U64, ParamCLREF, NA, 3));

  MOZ_RELEASE_ASSERT(CopyV(v1).match(desc8, desc32, desc64) ==
                     RESULT(U8, ParamRREF, NA, 1));
  MOZ_RELEASE_ASSERT(CopyV(v2).match(desc8, desc32, desc64) ==
                     RESULT(U32, ParamRREF, NA, 2));
  MOZ_RELEASE_ASSERT(CopyV(v3).match(desc8, desc32, desc64) ==
                     RESULT(U64, ParamRREF, NA, 3));

  MOZ_RELEASE_ASSERT(CopyConstV(v1).match(desc8, desc32, desc64) ==
                     RESULT(U8, ParamCRREF, NA, 1));
  MOZ_RELEASE_ASSERT(CopyConstV(v2).match(desc8, desc32, desc64) ==
                     RESULT(U32, ParamCRREF, NA, 2));
  MOZ_RELEASE_ASSERT(CopyConstV(v3).match(desc8, desc32, desc64) ==
                     RESULT(U64, ParamCRREF, NA, 3));
}

#undef RESULT

static void testAddTagToHash() {
  printf("testAddToHash\n");
  using V = Variant<uint8_t, uint16_t, uint32_t, uint64_t>;

  // We don't know what our hash function is, and these are certainly not all
  // true under all hash functions. But they are probably true under almost any
  // decent hash function, and our aim is simply to establish that the tag
  // *does* influence the hash value.
  {
    mozilla::HashNumber h8 = V(uint8_t(1)).addTagToHash(0);
    mozilla::HashNumber h16 = V(uint16_t(1)).addTagToHash(0);
    mozilla::HashNumber h32 = V(uint32_t(1)).addTagToHash(0);
    mozilla::HashNumber h64 = V(uint64_t(1)).addTagToHash(0);

    MOZ_RELEASE_ASSERT(h8 != h16 && h8 != h32 && h8 != h64);
    MOZ_RELEASE_ASSERT(h16 != h32 && h16 != h64);
    MOZ_RELEASE_ASSERT(h32 != h64);
  }

  {
    mozilla::HashNumber h8 = V(uint8_t(1)).addTagToHash(0x124356);
    mozilla::HashNumber h16 = V(uint16_t(1)).addTagToHash(0x124356);
    mozilla::HashNumber h32 = V(uint32_t(1)).addTagToHash(0x124356);
    mozilla::HashNumber h64 = V(uint64_t(1)).addTagToHash(0x124356);

    MOZ_RELEASE_ASSERT(h8 != h16 && h8 != h32 && h8 != h64);
    MOZ_RELEASE_ASSERT(h16 != h32 && h16 != h64);
    MOZ_RELEASE_ASSERT(h32 != h64);
  }
}

int main() {
  testDetails();
  testSimple();
  testDuplicate();
  testConstructionWithVariantType();
  testConstructionWithVariantIndex();
  testEmplaceWithType();
  testEmplaceWithIndex();
  testCopy();
  testMove();
  testDestructor();
  testEquality();
  testMatching();
  testMatchingLambda();
  testMatchingLambdaWithIndex();
  testMatchingLambdas();
  testMatchingLambdasWithIndex();
  testAddTagToHash();

  printf("TestVariant OK!\n");
  return 0;
}

100%


¤ Dauer der Verarbeitung: 0.27 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.