summaryrefslogtreecommitdiffstats
path: root/mfbt/tests/TestTuple.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mfbt/tests/TestTuple.cpp')
-rw-r--r--mfbt/tests/TestTuple.cpp362
1 files changed, 362 insertions, 0 deletions
diff --git a/mfbt/tests/TestTuple.cpp b/mfbt/tests/TestTuple.cpp
new file mode 100644
index 0000000000..4e20101972
--- /dev/null
+++ b/mfbt/tests/TestTuple.cpp
@@ -0,0 +1,362 @@
+/* -*- 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 <utility>
+
+#include "mozilla/Assertions.h"
+#include "mozilla/CompactPair.h"
+#include "mozilla/Tuple.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Unused.h"
+
+using mozilla::CompactPair;
+using mozilla::Get;
+using mozilla::MakeTuple;
+using mozilla::MakeUnique;
+using mozilla::Tie;
+using mozilla::Tuple;
+using mozilla::UniquePtr;
+using mozilla::Unused;
+using std::pair;
+
+#define CHECK(c) \
+ do { \
+ bool cond = !!(c); \
+ MOZ_RELEASE_ASSERT(cond, "Failed assertion: " #c); \
+ } while (false)
+
+// The second argument is the expected type. It's variadic to allow the
+// type to contain commas.
+#define CHECK_TYPE(expression, ...) \
+ static_assert(std::is_same_v<decltype(expression), __VA_ARGS__>, \
+ "Type mismatch!")
+
+struct ConvertibleToInt {
+ operator int() const { return 42; }
+};
+
+static void TestConstruction() {
+ // Default construction
+ Tuple<> a;
+ Unused << a;
+ Tuple<int> b;
+ Unused << b;
+
+ // Construction from elements
+ int x = 1, y = 1;
+ Tuple<int, int> c{x, y};
+ Tuple<int&, const int&> d{x, y};
+ x = 42;
+ y = 42;
+ CHECK(Get<0>(c) == 1);
+ CHECK(Get<1>(c) == 1);
+ CHECK(Get<0>(d) == 42);
+ CHECK(Get<1>(d) == 42);
+
+ // Construction from objects convertible to the element types
+ Tuple<int, int> e{1.0, ConvertibleToInt{}};
+
+ // Copy construction
+ Tuple<int> x1;
+ Tuple<int> x2{x1};
+
+ Tuple<int, int> f(c);
+ CHECK(Get<0>(f) == 1);
+ CHECK(Get<0>(f) == 1);
+
+ // Move construction
+ Tuple<UniquePtr<int>> g{MakeUnique<int>(42)};
+ Tuple<UniquePtr<int>> h{std::move(g)};
+ CHECK(Get<0>(g) == nullptr);
+ CHECK(*Get<0>(h) == 42);
+}
+
+static void TestConstructionFromMozPair() {
+ // Construction from elements
+ int x = 1, y = 1;
+ CompactPair<int, int> a{x, y};
+ CompactPair<int&, const int&> b{x, y};
+ Tuple<int, int> c(a);
+ Tuple<int&, const int&> d(b);
+ x = 42;
+ y = 42;
+ CHECK(Get<0>(c) == 1);
+ CHECK(Get<1>(c) == 1);
+ CHECK(Get<0>(d) == 42);
+ CHECK(Get<1>(d) == 42);
+}
+
+static void TestConstructionFromStdPair() {
+ // Construction from elements
+ int x = 1, y = 1;
+ pair<int, int> a{x, y};
+ pair<int&, const int&> b{x, y};
+ Tuple<int, int> c(a);
+ Tuple<int&, const int&> d(b);
+ x = 42;
+ y = 42;
+ CHECK(Get<0>(c) == 1);
+ CHECK(Get<1>(c) == 1);
+ CHECK(Get<0>(d) == 42);
+ CHECK(Get<1>(d) == 42);
+}
+
+static void TestAssignment() {
+ // Copy assignment
+ Tuple<int> a{0};
+ Tuple<int> b{42};
+ a = b;
+ CHECK(Get<0>(a) == 42);
+
+ // Assignment to reference member
+ int i = 0;
+ int j = 42;
+ Tuple<int&> c{i};
+ Tuple<int&> d{j};
+ c = d;
+ CHECK(i == 42);
+
+ // Move assignment
+ Tuple<UniquePtr<int>> e{MakeUnique<int>(0)};
+ Tuple<UniquePtr<int>> f{MakeUnique<int>(42)};
+ e = std::move(f);
+ CHECK(*Get<0>(e) == 42);
+ CHECK(Get<0>(f) == nullptr);
+}
+
+static void TestAssignmentFromMozPair() {
+ // Copy assignment
+ Tuple<int, int> a{0, 0};
+ CompactPair<int, int> b{42, 42};
+ a = b;
+ CHECK(Get<0>(a) == 42);
+ CHECK(Get<1>(a) == 42);
+
+ // Assignment to reference member
+ int i = 0;
+ int j = 0;
+ int k = 42;
+ Tuple<int&, int&> c{i, j};
+ CompactPair<int&, int&> d{k, k};
+ c = d;
+ CHECK(i == 42);
+ CHECK(j == 42);
+
+ // Move assignment
+ Tuple<UniquePtr<int>, UniquePtr<int>> e{MakeUnique<int>(0),
+ MakeUnique<int>(0)};
+ CompactPair<UniquePtr<int>, UniquePtr<int>> f{MakeUnique<int>(42),
+ MakeUnique<int>(42)};
+ e = std::move(f);
+ CHECK(*Get<0>(e) == 42);
+ CHECK(*Get<1>(e) == 42);
+ CHECK(f.first() == nullptr);
+ CHECK(f.second() == nullptr);
+}
+
+static void TestAssignmentFromStdPair() {
+ // Copy assignment
+ Tuple<int, int> a{0, 0};
+ pair<int, int> b{42, 42};
+ a = b;
+ CHECK(Get<0>(a) == 42);
+ CHECK(Get<1>(a) == 42);
+
+ // Assignment to reference member
+ int i = 0;
+ int j = 0;
+ int k = 42;
+ Tuple<int&, int&> c{i, j};
+ pair<int&, int&> d{k, k};
+ c = d;
+ CHECK(i == 42);
+ CHECK(j == 42);
+
+ // Move assignment.
+ Tuple<UniquePtr<int>, UniquePtr<int>> e{MakeUnique<int>(0),
+ MakeUnique<int>(0)};
+ // XXX: On some platforms std::pair doesn't support move constructor.
+ pair<UniquePtr<int>, UniquePtr<int>> f;
+ f.first = MakeUnique<int>(42);
+ f.second = MakeUnique<int>(42);
+
+ e = std::move(f);
+ CHECK(*Get<0>(e) == 42);
+ CHECK(*Get<1>(e) == 42);
+ CHECK(f.first == nullptr);
+ CHECK(f.second == nullptr);
+}
+
+static void TestGet() {
+ int x = 1;
+ int y = 2;
+ int z = 3;
+ Tuple<int, int&, const int&> tuple(x, y, z);
+
+ // Using Get<>() to read elements
+ CHECK(Get<0>(tuple) == 1);
+ CHECK(Get<1>(tuple) == 2);
+ CHECK(Get<2>(tuple) == 3);
+
+ // Using Get<>() to write to elements
+ Get<0>(tuple) = 41;
+ CHECK(Get<0>(tuple) == 41);
+
+ // Writing through reference elements
+ Get<1>(tuple) = 42;
+ CHECK(Get<1>(tuple) == 42);
+ CHECK(y == 42);
+}
+
+static void TestMakeTuple() {
+ auto tuple = MakeTuple(42, 0.5f, 'c');
+ CHECK_TYPE(tuple, Tuple<int, float, char>);
+ CHECK(Get<0>(tuple) == 42);
+ CHECK(Get<1>(tuple) == 0.5f);
+ CHECK(Get<2>(tuple) == 'c');
+
+ // Make sure we don't infer the type to be Tuple<int&>.
+ int x = 1;
+ auto tuple2 = MakeTuple(x);
+ CHECK_TYPE(tuple2, Tuple<int>);
+ x = 2;
+ CHECK(Get<0>(tuple2) == 1);
+}
+
+static bool TestTieMozPair() {
+ int i;
+ float f;
+ char c;
+ Tuple<int, float, char> rhs1(42, 0.5f, 'c');
+ Tie(i, f, c) = rhs1;
+ CHECK(i == Get<0>(rhs1));
+ CHECK(f == Get<1>(rhs1));
+ CHECK(c == Get<2>(rhs1));
+ // Test conversions
+ Tuple<ConvertibleToInt, double, unsigned char> rhs2(ConvertibleToInt(), 0.7f,
+ 'd');
+ Tie(i, f, c) = rhs2;
+ CHECK(i == Get<0>(rhs2));
+ CHECK(f == Get<1>(rhs2));
+ CHECK(c == Get<2>(rhs2));
+
+ // Test Pair
+ CompactPair<int, float> rhs3(42, 1.5f);
+ Tie(i, f) = rhs3;
+ CHECK(i == rhs3.first());
+ CHECK(f == rhs3.second());
+
+ return true;
+}
+
+static bool TestTie() {
+ int i;
+ float f;
+ char c;
+ Tuple<int, float, char> rhs1(42, 0.5f, 'c');
+ Tie(i, f, c) = rhs1;
+ CHECK(i == Get<0>(rhs1));
+ CHECK(f == Get<1>(rhs1));
+ CHECK(c == Get<2>(rhs1));
+ // Test conversions
+ Tuple<ConvertibleToInt, double, unsigned char> rhs2(ConvertibleToInt(), 0.7f,
+ 'd');
+ Tie(i, f, c) = rhs2;
+ CHECK(i == Get<0>(rhs2));
+ CHECK(f == Get<1>(rhs2));
+ CHECK(c == Get<2>(rhs2));
+
+ // Test Pair
+ pair<int, float> rhs3(42, 1.5f);
+ Tie(i, f) = rhs3;
+ CHECK(i == rhs3.first);
+ CHECK(f == rhs3.second);
+
+ return true;
+}
+
+static bool TestTieIgnore() {
+ int i;
+ char c;
+ Tuple<int, float, char> rhs1(42, 0.5f, 'c');
+
+ Tie(i, mozilla::Ignore, c) = rhs1;
+
+ CHECK(i == Get<0>(rhs1));
+ CHECK(c == Get<2>(rhs1));
+
+ return true;
+}
+
+template <typename... Elements, typename F>
+static void CheckForEachCall(const Tuple<Elements...>& aTuple,
+ F&& CallForEach) {
+ constexpr std::size_t tupleSize = sizeof...(Elements);
+
+ Tuple<Elements...> checkResult;
+ std::size_t i = 0;
+ auto createResult = [&](auto& aElem) {
+ static_assert(tupleSize == 3,
+ "Need to deal with more/less cases in the switch below");
+
+ CHECK(i < tupleSize);
+ switch (i) {
+ case 0:
+ Get<0>(checkResult) = aElem;
+ break;
+ case 1:
+ Get<1>(checkResult) = aElem;
+ break;
+ case 2:
+ Get<2>(checkResult) = aElem;
+ break;
+ }
+ ++i;
+ };
+
+ CallForEach(aTuple, createResult);
+
+ CHECK(checkResult == aTuple);
+}
+
+static bool TestForEach() {
+ Tuple<int, float, char> tuple = MakeTuple(42, 0.5f, 'c');
+
+ CheckForEachCall(
+ tuple, [](auto& aTuple, auto&& aLambda) { aTuple.ForEach(aLambda); });
+
+ CheckForEachCall(
+ tuple, [](auto& aTuple, auto&& aLambda) { ForEach(aTuple, aLambda); });
+
+ CheckForEachCall(tuple, [](auto& aTuple, auto&& aLambda) {
+ const decltype(aTuple)& constTuple = aTuple;
+ constTuple.ForEach(aLambda);
+ });
+
+ CheckForEachCall(tuple, [](auto& aTuple, auto&& aLambda) {
+ const decltype(aTuple)& constTuple = aTuple;
+ ForEach(constTuple, aLambda);
+ });
+
+ return true;
+}
+
+int main() {
+ TestConstruction();
+ TestConstructionFromMozPair();
+ TestConstructionFromStdPair();
+ TestAssignment();
+ TestAssignmentFromMozPair();
+ TestAssignmentFromStdPair();
+ TestGet();
+ TestMakeTuple();
+ TestTie();
+ TestTieIgnore();
+ TestTieMozPair();
+ TestForEach();
+ return 0;
+}