summaryrefslogtreecommitdiffstats
path: root/js/src/jsapi-tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:43:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:43:14 +0000
commit8dd16259287f58f9273002717ec4d27e97127719 (patch)
tree3863e62a53829a84037444beab3abd4ed9dfc7d0 /js/src/jsapi-tests
parentReleasing progress-linux version 126.0.1-1~progress7.99u1. (diff)
downloadfirefox-8dd16259287f58f9273002717ec4d27e97127719.tar.xz
firefox-8dd16259287f58f9273002717ec4d27e97127719.zip
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jsapi-tests')
-rw-r--r--js/src/jsapi-tests/moz.build2
-rw-r--r--js/src/jsapi-tests/testFractionToDouble.cpp181
-rw-r--r--js/src/jsapi-tests/testFrontendJSON.cpp23
-rw-r--r--js/src/jsapi-tests/testInt128.cpp576
4 files changed, 782 insertions, 0 deletions
diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build
index f6cc3b3f70..ac9afbe814 100644
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -50,6 +50,7 @@ UNIFIED_SOURCES += [
"testForceLexicalInitialization.cpp",
"testForOfIterator.cpp",
"testForwardSetProperty.cpp",
+ "testFractionToDouble.cpp",
"testFreshGlobalEvalRedefinition.cpp",
"testFrontendCompileStencil.cpp",
"testFrontendErrors.cpp",
@@ -74,6 +75,7 @@ UNIFIED_SOURCES += [
"testHashTable.cpp",
"testIndexToString.cpp",
"testInformalValueTypeName.cpp",
+ "testInt128.cpp",
"testIntern.cpp",
"testIntlAvailableLocales.cpp",
"testIntString.cpp",
diff --git a/js/src/jsapi-tests/testFractionToDouble.cpp b/js/src/jsapi-tests/testFractionToDouble.cpp
new file mode 100644
index 0000000000..c3e6842863
--- /dev/null
+++ b/js/src/jsapi-tests/testFractionToDouble.cpp
@@ -0,0 +1,181 @@
+/* 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/. */
+
+#ifdef JS_HAS_TEMPORAL_API
+
+# include <cmath>
+# include <stdint.h>
+
+# include "builtin/temporal/Int128.h"
+# include "builtin/temporal/Temporal.h"
+# include "jsapi-tests/tests.h"
+
+using namespace js::temporal;
+
+// Simple test using numerators and denominators where the result can be
+// computed through standard double division.
+BEGIN_TEST(testFraction_simple) {
+ int64_t numerators[] = {
+ 0, 1, 2, 10, 100, INT32_MIN, INT32_MAX,
+ };
+
+ int64_t denominators[] = {
+ 1, 2, 3, 10, 100, 1000,
+ };
+
+ for (auto numerator : numerators) {
+ for (auto denominator : denominators) {
+ double result = double(numerator) / double(denominator);
+
+ CHECK_EQUAL(FractionToDouble(numerator, denominator), result);
+ CHECK_EQUAL(FractionToDouble(Int128{numerator}, Int128{denominator}),
+ result);
+
+ CHECK_EQUAL(FractionToDouble(-numerator, denominator),
+ std::copysign(result, -numerator));
+ CHECK_EQUAL(FractionToDouble(-Int128{numerator}, Int128{denominator}),
+ std::copysign(result, -numerator));
+ }
+ }
+
+ return true;
+}
+END_TEST(testFraction_simple)
+
+// Complex test with values exceeding Number.MAX_SAFE_INTEGER.
+BEGIN_TEST(testFraction_complex) {
+ struct {
+ int64_t numerator;
+ int64_t denominator;
+ double result;
+ } values[] = {
+ // Number.MAX_SAFE_INTEGER
+ {9007199254740991, 2, 4503599627370495.5},
+ {9007199254740992, 2, 4503599627370496},
+ {9007199254740993, 2, 4503599627370496.5},
+
+ {INT64_MAX, 2, 4611686018427387903.5},
+ {INT64_MIN, 2, -4611686018427387904.0},
+ };
+
+ for (auto [numerator, denominator, result] : values) {
+ CHECK_EQUAL(FractionToDouble(numerator, denominator), result);
+ CHECK_EQUAL(FractionToDouble(Int128{numerator}, Int128{denominator}),
+ result);
+ }
+
+ return true;
+}
+END_TEST(testFraction_complex)
+
+// Complex test with Int128 values exceeding Number.MAX_SAFE_INTEGER.
+BEGIN_TEST(testFraction_complex_int128) {
+ struct {
+ Int128 numerator;
+ Int128 denominator;
+ double result;
+ } values[] = {
+ // Divide 1 by a growing divisor.
+ {Int128{1}, Int128{1'000}, 0.001},
+ {Int128{1}, Int128{1'000'000}, 0.000'001},
+ {Int128{1}, Int128{1'000'000'000}, 0.000'000'001},
+ {Int128{1}, Int128{1'000'000'000'000}, 0.000'000'000'001},
+ {Int128{1}, Int128{1'000'000'000'000'000}, 0.000'000'000'000'001},
+ {Int128{1}, Int128{1'000'000'000'000'000'000}, 0.000'000'000'000'000'001},
+ {Int128{1}, Int128{1'000'000'000'000'000'000} * Int128{1'000},
+ 0.000'000'000'000'000'000'001},
+ {Int128{1}, Int128{1'000'000'000'000'000'000} * Int128{1'000'000},
+ 0.000'000'000'000'000'000'000'001},
+ {Int128{1}, Int128{1'000'000'000'000'000'000} * Int128{1'000'000'000},
+ 0.000'000'000'000'000'000'000'000'001},
+ {Int128{1}, Int128{1'000'000'000'000'000'000} * Int128{1'000'000'000'000},
+ 0.000'000'000'000'000'000'000'000'000'001},
+ {Int128{1},
+ Int128{1'000'000'000'000'000'000} * Int128{1'000'000'000'000'000},
+ 0.000'000'000'000'000'000'000'000'000'000'001},
+ {Int128{1},
+ Int128{1'000'000'000'000'000'000} * Int128{1'000'000'000'000'000'000},
+ 0.000'000'000'000'000'000'000'000'000'000'000'001},
+
+ // Divide a number not representable as an int64.
+ {Int128{0x8000'0000} << 64, Int128{1'000},
+ 39614081257132168796771975.1680},
+ {Int128{0x8000'0000} << 64, Int128{1'000'000},
+ 39614081257132168796771.9751680},
+ {Int128{0x8000'0000} << 64, Int128{1'000'000'000},
+ 39614081257132168796.7719751680},
+ {Int128{0x8000'0000} << 64, Int128{1'000'000'000'000},
+ 39614081257132168.7967719751680},
+ {Int128{0x8000'0000} << 64, Int128{1'000'000'000'000'000},
+ 39614081257132.1687967719751680},
+ {Int128{0x8000'0000} << 64, Int128{1'000'000'000'000'000'000},
+ 39614081257.1321687967719751680},
+ {Int128{0x8000'0000} << 64,
+ Int128{1'000'000'000'000'000'000} * Int128{1'000},
+ 39614081.2571321687967719751680},
+ {Int128{0x8000'0000} << 64,
+ Int128{1'000'000'000'000'000'000} * Int128{1'000'000},
+ 39614.0812571321687967719751680},
+ {Int128{0x8000'0000} << 64,
+ Int128{1'000'000'000'000'000'000} * Int128{1'000'000'000},
+ 39.6140812571321687967719751680},
+ {Int128{0x8000'0000} << 64,
+ Int128{1'000'000'000'000'000'000} * Int128{1'000'000'000'000},
+ 0.0396140812571321687967719751680},
+ {Int128{0x8000'0000} << 64,
+ Int128{1'000'000'000'000'000'000} * Int128{1'000'000'000'000'000},
+ 0.0000396140812571321687967719751680},
+ {Int128{0x8000'0000} << 64,
+ Int128{1'000'000'000'000'000'000} * Int128{1'000'000'000'000'000'000},
+ 0.0000000396140812571321687967719751680},
+
+ // Test divisor which isn't a multiple of ten.
+ {Int128{0x8000'0000} << 64, Int128{2}, 19807040628566084398385987584.0},
+ {Int128{0x8000'0000} << 64, Int128{3}, 13204693752377389598923991722.666},
+ {Int128{0x8000'0000} << 64, Int128{3'333},
+ 11885412918431493788410433.5937},
+ {Int128{0x8000'0000} << 64, Int128{3'333'333},
+ 11884225565562207195252.3120756},
+ {Int128{0x8000'0000} << 64, Int128{3'333'333'333},
+ 11884224378328073076.864399858},
+ {Int128{0x8000'0000} << 64, Int128{3'333'333'333'333},
+ 11884224377140839.0614693066343},
+ {Int128{0x8000'0000} << 64, Int128{3'333'333'333'333'333},
+ 11884224377139.6518274540302643},
+ {Int128{0x8000'0000} << 64, Int128{3'333'333'333'333'333'333},
+ 11884224377.1396506402200149881},
+ {Int128{0x8000'0000} << 64,
+ (Int128{3'333'333'333'333'333'333} * Int128{1'000}) + Int128{333},
+ 11884224.3771396506390327809728},
+ {Int128{0x8000'0000} << 64,
+ (Int128{3'333'333'333'333'333'333} * Int128{1'000'000}) +
+ Int128{333'333},
+ 11884.2243771396506390315937388},
+ {Int128{0x8000'0000} << 64,
+ (Int128{3'333'333'333'333'333'333} * Int128{1'000'000'000}) +
+ Int128{333'333'333},
+ 11.884224377139650639031592551588422437713965063903159255158842243},
+ {Int128{0x8000'0000} << 64,
+ (Int128{3'333'333'333'333'333'333} * Int128{1'000'000'000'000}) +
+ Int128{333'333'333'333},
+ 0.0118842243771396506390315925504},
+ {Int128{0x8000'0000} << 64,
+ (Int128{3'333'333'333'333'333'333} * Int128{1'000'000'000'000'000}) +
+ Int128{333'333'333'333'333},
+ 0.0000118842243771396506390315925504},
+ {Int128{0x8000'0000} << 64,
+ (Int128{3'333'333'333'333'333'333} * Int128{1'000'000'000'000'000'000}) +
+ Int128{333'333'333'333'333'333},
+ 0.0000000118842243771396506390315925504},
+ };
+
+ for (auto [numerator, denominator, result] : values) {
+ CHECK_EQUAL(FractionToDouble(numerator, denominator), result);
+ }
+
+ return true;
+}
+END_TEST(testFraction_complex_int128)
+
+#endif
diff --git a/js/src/jsapi-tests/testFrontendJSON.cpp b/js/src/jsapi-tests/testFrontendJSON.cpp
index b5315e6084..0960a8025a 100644
--- a/js/src/jsapi-tests/testFrontendJSON.cpp
+++ b/js/src/jsapi-tests/testFrontendJSON.cpp
@@ -472,6 +472,29 @@ BEGIN_FRONTEND_TEST(testParseJSONWithHandler) {
checkedLast = true;
}
+ {
+ const size_t failAt = 1;
+ MyHandler handler;
+ const char16_t* source;
+
+#define IMMEDIATE_FAIL(json) \
+ handler.failAt.emplace(failAt); \
+ source = json; \
+ CHECK(!JS::ParseJSONWithHandler( \
+ source, std::char_traits<char16_t>::length(source), &handler)); \
+ CHECK(handler.events.length() == failAt); \
+ handler.events.clear();
+
+ IMMEDIATE_FAIL(u"{");
+ IMMEDIATE_FAIL(u"[");
+ IMMEDIATE_FAIL(u"\"string\"");
+ IMMEDIATE_FAIL(u"1");
+ IMMEDIATE_FAIL(u"true");
+ IMMEDIATE_FAIL(u"null");
+
+#undef IMMEDIATE_FAIL
+ }
+
return true;
}
diff --git a/js/src/jsapi-tests/testInt128.cpp b/js/src/jsapi-tests/testInt128.cpp
new file mode 100644
index 0000000000..134d2ab684
--- /dev/null
+++ b/js/src/jsapi-tests/testInt128.cpp
@@ -0,0 +1,576 @@
+/* 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/. */
+
+#ifdef JS_HAS_TEMPORAL_API
+
+# include "mozilla/TextUtils.h"
+
+# include <array>
+# include <climits>
+# include <limits>
+# include <optional>
+# include <stdint.h>
+# include <utility>
+
+# include "builtin/temporal/Int128.h"
+# include "jsapi-tests/tests.h"
+
+using Int128 = js::temporal::Int128;
+using Uint128 = js::temporal::Uint128;
+
+// Simple Uint128 parser.
+template <char... DIGITS>
+constexpr Uint128 operator""_u128() {
+ static_assert(sizeof...(DIGITS) > 0);
+
+ constexpr auto digits = std::array{DIGITS...};
+
+ constexpr auto isBinaryDigit = [](auto c) {
+ return (c >= '0' && c <= '1') || c == '\'';
+ };
+
+ constexpr auto isOctalDigit = [](auto c) {
+ return (c >= '0' && c <= '7') || c == '\'';
+ };
+
+ constexpr auto isDigit = [](auto c) {
+ return mozilla::IsAsciiDigit(c) || c == '\'';
+ };
+
+ constexpr auto isHexDigit = [](auto c) {
+ return mozilla::IsAsciiHexDigit(c) || c == '\'';
+ };
+
+ constexpr auto isBinary = [isBinaryDigit](auto zero, auto prefix,
+ auto... rest) {
+ return zero == '0' && (prefix == 'b' || prefix == 'B') &&
+ (isBinaryDigit(rest) && ...);
+ };
+
+ constexpr auto isHex = [isHexDigit](auto zero, auto prefix, auto... rest) {
+ return zero == '0' && (prefix == 'x' || prefix == 'X') &&
+ (isHexDigit(rest) && ...);
+ };
+
+ constexpr auto binary = [digits]() -> std::optional<Uint128> {
+ auto value = Uint128{};
+ for (size_t i = 2; i < digits.size(); ++i) {
+ auto digit = digits[i];
+ if (digit == '\'') {
+ continue;
+ }
+
+ // Detect overflow.
+ if (((value << 1) >> 1) != value) {
+ return std::nullopt;
+ }
+ value = (value << 1) | Uint128{uint64_t(digit - '0')};
+ }
+ return value;
+ };
+
+ constexpr auto octal = [digits]() -> std::optional<Uint128> {
+ auto value = Uint128{};
+ for (size_t i = 1; i < digits.size(); ++i) {
+ auto digit = digits[i];
+ if (digit == '\'') {
+ continue;
+ }
+
+ // Detect overflow.
+ if (((value << 3) >> 3) != value) {
+ return std::nullopt;
+ }
+ value = (value << 3) | Uint128{uint64_t(digit - '0')};
+ }
+ return value;
+ };
+
+ constexpr auto decimal = [digits]() -> std::optional<Uint128> {
+ auto value = Uint128{};
+ for (size_t i = 0; i < digits.size(); ++i) {
+ auto digit = digits[i];
+ if (digit == '\'') {
+ continue;
+ }
+
+ // NB: Overflow check not implemented.
+ value = (value * Uint128{10}) + Uint128{uint64_t(digit - '0')};
+ }
+ return value;
+ };
+
+ constexpr auto hexadecimal = [digits]() -> std::optional<Uint128> {
+ auto value = Uint128{};
+ for (size_t i = 2; i < digits.size(); ++i) {
+ auto digit = digits[i];
+ if (digit == '\'') {
+ continue;
+ }
+
+ // Detect overflow.
+ if (((value << 4) >> 4) != value) {
+ return std::nullopt;
+ }
+ value =
+ (value << 4) | Uint128{uint64_t(digit >= 'a' ? (digit - 'a') + 10
+ : digit >= 'A' ? (digit - 'A') + 10
+ : digit - '0')};
+ }
+ return value;
+ };
+
+ if constexpr (digits.size() > 2 && digits[0] == '0' &&
+ !mozilla::IsAsciiDigit(digits[1])) {
+ if constexpr (isBinary(DIGITS...)) {
+ if constexpr (constexpr auto value = binary()) {
+ return *value;
+ } else {
+ static_assert(false, "binary literal too large");
+ }
+ } else if constexpr (isHex(DIGITS...)) {
+ if constexpr (constexpr auto value = hexadecimal()) {
+ return *value;
+ } else {
+ static_assert(false, "hexadecimal literal too large");
+ }
+ } else {
+ static_assert(false, "invalid prefix literal");
+ }
+ } else if constexpr (digits.size() > 1 && digits[0] == '0') {
+ if constexpr ((isOctalDigit(DIGITS) && ...)) {
+ if constexpr (constexpr auto value = octal()) {
+ return *value;
+ } else {
+ static_assert(false, "octal literal too large");
+ }
+ } else {
+ static_assert(false, "invalid octal literal");
+ }
+ } else if constexpr ((isDigit(DIGITS) && ...)) {
+ if constexpr (constexpr auto value = decimal()) {
+ return *value;
+ } else {
+ static_assert(false, "decimal literal too large");
+ }
+ } else {
+ static_assert(false, "invalid literal");
+ }
+}
+
+template <char... DIGITS>
+constexpr Int128 operator""_i128() {
+ return Int128{operator""_u128 < DIGITS... > ()};
+}
+
+template <typename T, size_t N, size_t... ISeq>
+static constexpr auto to_array_impl(const T (&elements)[N],
+ std::index_sequence<ISeq...>) {
+ return std::array<T, N>{{elements[ISeq]...}};
+}
+
+// No std::to_array because we don't yet compile with C++20.
+template <typename T, size_t N>
+static constexpr auto to_array(const T (&elements)[N]) {
+ return to_array_impl(elements, std::make_index_sequence<N>{});
+}
+
+class ConversionFixture : public JSAPIRuntimeTest {
+ public:
+ virtual ~ConversionFixture() = default;
+
+ template <typename T, typename U, size_t N>
+ bool testConversion(const std::array<U, N>& values);
+};
+
+template <typename T, typename U, size_t N>
+bool ConversionFixture::testConversion(const std::array<U, N>& values) {
+ for (auto v : values) {
+ // Conversion to signed int.
+ CHECK_EQUAL(int64_t(T{v}), int64_t(v));
+ CHECK_EQUAL(int32_t(T{v}), int32_t(v));
+ CHECK_EQUAL(int16_t(T{v}), int16_t(v));
+ CHECK_EQUAL(int8_t(T{v}), int8_t(v));
+
+ // Conversion to unsigned int.
+ CHECK_EQUAL(uint64_t(T{v}), uint64_t(v));
+ CHECK_EQUAL(uint32_t(T{v}), uint32_t(v));
+ CHECK_EQUAL(uint16_t(T{v}), uint16_t(v));
+ CHECK_EQUAL(uint8_t(T{v}), uint8_t(v));
+
+ // Conversion to double.
+ CHECK_EQUAL(double(T{v}), double(v));
+
+ // Conversion to bool.
+ CHECK_EQUAL(bool(T{v}), bool(v));
+ }
+ return true;
+}
+
+BEGIN_FIXTURE_TEST(ConversionFixture, testInt128_conversion) {
+ auto values = to_array<int64_t>({
+ INT64_MIN,
+ INT64_MIN + 1,
+ int64_t(INT32_MIN) - 1,
+ INT32_MIN,
+ INT32_MIN + 1,
+ -1,
+ 0,
+ 1,
+ INT32_MAX - 1,
+ INT32_MAX,
+ int64_t(INT32_MAX) + 1,
+ INT64_MAX - 1,
+ INT64_MAX,
+ });
+
+ CHECK(testConversion<Int128>(values));
+
+ return true;
+}
+END_FIXTURE_TEST(ConversionFixture, testInt128_conversion)
+
+BEGIN_FIXTURE_TEST(ConversionFixture, testUint128_conversion) {
+ auto values = to_array<uint64_t>({
+ 0,
+ 1,
+ UINT32_MAX - 1,
+ UINT32_MAX,
+ uint64_t(UINT32_MAX) + 1,
+ UINT64_MAX - 1,
+ UINT64_MAX,
+ });
+
+ CHECK(testConversion<Uint128>(values));
+
+ return true;
+}
+END_FIXTURE_TEST(ConversionFixture, testUint128_conversion)
+
+class OperatorFixture : public JSAPIRuntimeTest {
+ public:
+ virtual ~OperatorFixture() = default;
+
+ template <typename T, typename U, size_t N>
+ bool testOperator(const std::array<U, N>& values);
+};
+
+template <typename T, typename U, size_t N>
+bool OperatorFixture::testOperator(const std::array<U, N>& values) {
+ // Unary operators.
+ for (auto x : values) {
+ // Sign operators.
+ CHECK_EQUAL(U(+T{x}), +x);
+ CHECK_EQUAL(U(-T{x}), -x);
+
+ // Bitwise operators.
+ CHECK_EQUAL(U(~T{x}), ~x);
+
+ // Increment/Decrement operators.
+ auto y = T{x};
+ CHECK_EQUAL(U(++y), x + 1);
+ CHECK_EQUAL(U(y), x + 1);
+
+ y = T{x};
+ CHECK_EQUAL(U(y++), x);
+ CHECK_EQUAL(U(y), x + 1);
+
+ y = T{x};
+ CHECK_EQUAL(U(--y), x - 1);
+ CHECK_EQUAL(U(y), x - 1);
+
+ y = T{x};
+ CHECK_EQUAL(U(y--), x);
+ CHECK_EQUAL(U(y), x - 1);
+ }
+
+ // Binary operators.
+ for (auto x : values) {
+ for (auto y : values) {
+ // Comparison operators.
+ CHECK_EQUAL((T{x} == T{y}), (x == y));
+ CHECK_EQUAL((T{x} != T{y}), (x != y));
+ CHECK_EQUAL((T{x} < T{y}), (x < y));
+ CHECK_EQUAL((T{x} <= T{y}), (x <= y));
+ CHECK_EQUAL((T{x} > T{y}), (x > y));
+ CHECK_EQUAL((T{x} >= T{y}), (x >= y));
+
+ // Add/Sub/Mul operators.
+ CHECK_EQUAL(U(T{x} + T{y}), (x + y));
+ CHECK_EQUAL(U(T{x} - T{y}), (x - y));
+ CHECK_EQUAL(U(T{x} * T{y}), (x * y));
+
+ // Division operators.
+ if (y != 0) {
+ CHECK_EQUAL(U(T{x} / T{y}), (x / y));
+ CHECK_EQUAL(U(T{x} % T{y}), (x % y));
+ }
+
+ // Shift operators.
+ if (y >= 0) {
+ CHECK_EQUAL(U(T{x} << y), (x << y));
+ CHECK_EQUAL(U(T{x} >> y), (x >> y));
+ }
+
+ // Bitwise operators.
+ CHECK_EQUAL(U(T{x} & T{y}), (x & y));
+ CHECK_EQUAL(U(T{x} | T{y}), (x | y));
+ CHECK_EQUAL(U(T{x} ^ T{y}), (x ^ y));
+ }
+ }
+
+ // Compound assignment operators.
+ for (auto x : values) {
+ for (auto y : values) {
+ auto z = T{x};
+ z += T{y};
+ CHECK_EQUAL(U(z), x + y);
+
+ z = T{x};
+ z -= T{y};
+ CHECK_EQUAL(U(z), x - y);
+
+ z = T{x};
+ z *= T{y};
+ CHECK_EQUAL(U(z), x * y);
+
+ if (y != 0) {
+ z = T{x};
+ z /= T{y};
+ CHECK_EQUAL(U(z), x / y);
+
+ z = T{x};
+ z %= T{y};
+ CHECK_EQUAL(U(z), x % y);
+ }
+
+ if (y >= 0) {
+ z = T{x};
+ z <<= y;
+ CHECK_EQUAL(U(z), x << y);
+
+ z = T{x};
+ z >>= y;
+ CHECK_EQUAL(U(z), x >> y);
+ }
+
+ z = T{x};
+ z &= T{y};
+ CHECK_EQUAL(U(z), x & y);
+
+ z = T{x};
+ z |= T{y};
+ CHECK_EQUAL(U(z), x | y);
+
+ z = T{x};
+ z ^= T{y};
+ CHECK_EQUAL(U(z), x ^ y);
+ }
+ }
+ return true;
+}
+
+BEGIN_FIXTURE_TEST(OperatorFixture, testInt128_operator) {
+ auto values = to_array<int64_t>({
+ -3,
+ -2,
+ -1,
+ 0,
+ 1,
+ 2,
+ 3,
+ 63,
+ });
+
+ CHECK(testOperator<Int128>(values));
+
+ // Values larger than INT64_MAX.
+ CHECK((Int128{INT64_MAX} * Int128{2}) ==
+ (Int128{INT64_MAX} + Int128{INT64_MAX}));
+ CHECK((Int128{INT64_MAX} * Int128{3}) ==
+ (Int128{INT64_MAX} * Int128{4} - Int128{INT64_MAX}));
+ CHECK((Int128{INT64_MAX} * Int128{2}) == (Int128{INT64_MAX} << 1));
+ CHECK((Int128{INT64_MAX} * Int128{8}) == (Int128{INT64_MAX} << 3));
+ CHECK((Int128{INT64_MAX} * Int128{8} / Int128{2}) ==
+ (Int128{INT64_MAX} << 2));
+ CHECK((Int128{INT64_MAX} * Int128{23} % Int128{13}) == (Int128{5}));
+
+ // Values smaller than INT64_MIN.
+ CHECK((Int128{INT64_MIN} * Int128{2}) ==
+ (Int128{INT64_MIN} + Int128{INT64_MIN}));
+ CHECK((Int128{INT64_MIN} * Int128{3}) ==
+ (Int128{INT64_MIN} * Int128{4} - Int128{INT64_MIN}));
+ CHECK((Int128{INT64_MIN} * Int128{2}) == (Int128{INT64_MIN} << 1));
+ CHECK((Int128{INT64_MIN} * Int128{8}) == (Int128{INT64_MIN} << 3));
+ CHECK((Int128{INT64_MIN} * Int128{8} / Int128{2}) ==
+ (Int128{INT64_MIN} << 2));
+ CHECK((Int128{INT64_MIN} * Int128{23} % Int128{13}) == (Int128{-2}));
+
+ return true;
+}
+END_FIXTURE_TEST(OperatorFixture, testInt128_operator)
+
+BEGIN_FIXTURE_TEST(OperatorFixture, testUint128_operator) {
+ auto values = to_array<uint64_t>({
+ 0,
+ 1,
+ 2,
+ 3,
+ 5,
+ 63,
+ });
+
+ CHECK(testOperator<Uint128>(values));
+
+ // Values larger than UINT64_MAX.
+ CHECK((Uint128{UINT64_MAX} * Uint128{2}) ==
+ (Uint128{UINT64_MAX} + Uint128{UINT64_MAX}));
+ CHECK((Uint128{UINT64_MAX} * Uint128{3}) ==
+ (Uint128{UINT64_MAX} * Uint128{4} - Uint128{UINT64_MAX}));
+ CHECK((Uint128{UINT64_MAX} * Uint128{2}) == (Uint128{UINT64_MAX} << 1));
+ CHECK((Uint128{UINT64_MAX} * Uint128{8}) == (Uint128{UINT64_MAX} << 3));
+ CHECK((Uint128{UINT64_MAX} * Uint128{8} / Uint128{2}) ==
+ (Uint128{UINT64_MAX} << 2));
+ CHECK((Uint128{UINT64_MAX} * Uint128{23} % Uint128{13}) == (Uint128{7}));
+
+ return true;
+}
+END_FIXTURE_TEST(OperatorFixture, testUint128_operator)
+
+BEGIN_TEST(testInt128_literal) {
+ CHECK_EQUAL(int64_t(0x7fff'ffff'ffff'ffff_i128), INT64_MAX);
+ CHECK_EQUAL(int64_t(-0x8000'0000'0000'0000_i128), INT64_MIN);
+
+ CHECK(std::numeric_limits<Int128>::max() ==
+ 0x7fff'ffff'ffff'ffff'ffff'ffff'ffff'ffff_i128);
+ CHECK(std::numeric_limits<Int128>::min() ==
+ -0x8000'0000'0000'0000'0000'0000'0000'0000_i128);
+
+ auto x = (Int128{INT64_MAX} + Int128{1}) * Int128{3};
+ CHECK(x == 27670116110564327424_i128);
+ CHECK(x == 0x1'8000'0000'0000'0000_i128);
+
+ auto y = Int128{0} - (Int128{5} * Int128{INT64_MAX});
+ CHECK(y == -46116860184273879035_i128);
+ CHECK(y == -0x2'7fff'ffff'ffff'fffb_i128);
+
+ // NB: This shift expression overflows.
+ auto z = Int128{0x1122'3344} << 100;
+ CHECK(z == 0x1223'3440'0000'0000'0000'0000'0000'0000_i128);
+ CHECK(z == 0221063210000000000000000000000000000000000_i128);
+ CHECK(z == 24108894070078995479046745700448600064_i128);
+ CHECK(
+ z ==
+ 0b10010001000110011010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_i128);
+
+ z >>= 80;
+ CHECK(z == 0X1223'3440'0000_i128);
+ CHECK(z == 0442146420000000_i128);
+ CHECK(z == 19942409764864_i128);
+ CHECK(z == 0B100100010001100110100010000000000000000000000_i128);
+
+ auto v = Int128{INT64_MAX} * Int128{INT64_MAX};
+ CHECK(v == 0x3fff'ffff'ffff'ffff'0000'0000'0000'0001_i128);
+ CHECK((v + v) == 0x7fff'ffff'ffff'fffe'0000'0000'0000'0002_i128);
+ CHECK((v * v) == 0x7fff'ffff'ffff'fffe'0000'0000'0000'0001_i128);
+ CHECK((v * -v) == -0x7fff'ffff'ffff'fffe'0000'0000'0000'0001_i128);
+ CHECK((-v * v) == -0x7fff'ffff'ffff'fffe'0000'0000'0000'0001_i128);
+ CHECK((-v * -v) == 0x7fff'ffff'ffff'fffe'0000'0000'0000'0001_i128);
+
+ auto w = Int128{INT64_MIN} * Int128{INT64_MIN};
+ CHECK(w == 0x4000'0000'0000'0000'0000'0000'0000'0000_i128);
+ CHECK((w + w) == -0x8000'0000'0000'0000'0000'0000'0000'0000_i128);
+ CHECK((w * w) == 0_i128);
+
+ CHECK((Int128{1} << 120) == 0x100'0000'0000'0000'0000'0000'0000'0000_i128);
+
+ return true;
+}
+END_TEST(testInt128_literal)
+
+BEGIN_TEST(testUint128_literal) {
+ CHECK_EQUAL(uint64_t(0xffff'ffff'ffff'ffff_u128), UINT64_MAX);
+
+ CHECK(std::numeric_limits<Uint128>::max() ==
+ 0xffff'ffff'ffff'ffff'ffff'ffff'ffff'ffff_u128);
+
+ auto x = (Uint128{UINT64_MAX} + Uint128{3}) * Uint128{3};
+ CHECK(x == 55340232221128654854_u128);
+ CHECK(x == 0x3'0000'0000'0000'0006_u128);
+
+ // NB: This shift expression overflows.
+ auto z = Uint128{0x1122'3344} << 100;
+ CHECK(z == 0x1223'3440'0000'0000'0000'0000'0000'0000_u128);
+ CHECK(z == 0221063210000000000000000000000000000000000_u128);
+ CHECK(z == 24108894070078995479046745700448600064_u128);
+ CHECK(
+ z ==
+ 0b10010001000110011010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_u128);
+
+ z >>= 80;
+ CHECK(z == 0X1223'3440'0000_u128);
+ CHECK(z == 0442146420000000_u128);
+ CHECK(z == 19942409764864_u128);
+ CHECK(z == 0B100100010001100110100010000000000000000000000_u128);
+
+ auto v = Uint128{UINT64_MAX} * Uint128{UINT64_MAX};
+ CHECK(v == 0xffff'ffff'ffff'fffe'0000'0000'0000'0001_u128);
+ CHECK((v + v) == 0xffff'ffff'ffff'fffc'0000'0000'0000'0002_u128);
+ CHECK((v * v) == 0xffff'ffff'ffff'fffc'0000'0000'0000'0001_u128);
+ CHECK((v * -v) == 0x3'ffff'ffff'ffff'ffff_u128);
+ CHECK((-v * v) == 0x3'ffff'ffff'ffff'ffff_u128);
+ CHECK((-v * -v) == 0xffff'ffff'ffff'fffc'0000'0000'0000'0001_u128);
+
+ CHECK((Uint128{1} << 120) == 0x100'0000'0000'0000'0000'0000'0000'0000_u128);
+
+ return true;
+}
+END_TEST(testUint128_literal)
+
+BEGIN_TEST(testInt128_division) {
+ auto x = Int128{INT64_MAX} * Int128{4};
+ CHECK((x / Int128{2}) == 0xffff'ffff'ffff'fffe_i128);
+ CHECK((x / Int128{2}) == (x >> 1));
+
+ auto y = Int128{INT64_MAX} * Int128{16};
+ CHECK((y / Int128{2}) == 0x3'ffff'ffff'ffff'fff8_i128);
+ CHECK((y / Int128{2}) == (y >> 1));
+
+ CHECK((0x1122'3344'5566'7788'aabb'ccdd'ff12'3456_i128 / 7_i128) ==
+ 0x272'999c'0c33'35a5'cf3f'6668'db4b'be55_i128);
+ CHECK((0x1122'3344'5566'7788'aabb'ccdd'ff12'3456_i128 /
+ 0x1'2345'6789'abcd'ef11'abcd'ef11_i128) == 0xf0f0f0f_i128);
+ CHECK((7_i128 / 0x1122'3344'5566'7788'aabb'ccdd'ff12'3456_i128) == 0_i128);
+
+ CHECK((0x1122'3344'5566'7788'aabb'ccdd'ff12'3456_i128 % 7_i128) == 3_i128);
+ CHECK((0x1122'3344'5566'7788'aabb'ccdd'ff12'3456_i128 %
+ 0x1'2345'6789'abcd'ef11'abcd'ef11_i128) ==
+ 0x1122'3353'7d8e'9fb0'dc00'3357_i128);
+ CHECK((7_i128 % 0x1122'3344'5566'7788'aabb'ccdd'ff12'3456_i128) == 7_i128);
+
+ return true;
+}
+END_TEST(testInt128_division)
+
+BEGIN_TEST(testInt128_abs) {
+ CHECK((0_i128).abs() == 0_u128);
+
+ CHECK((0x1122'3344_i128).abs() == 0x1122'3344_u128);
+ CHECK((-0x1122'3344_i128).abs() == 0x1122'3344_u128);
+
+ CHECK((0x1111'2222'3333'4444'5555'6666'7777'8888_i128).abs() ==
+ 0x1111'2222'3333'4444'5555'6666'7777'8888_u128);
+ CHECK((-0x1111'2222'3333'4444'5555'6666'7777'8888_i128).abs() ==
+ 0x1111'2222'3333'4444'5555'6666'7777'8888_u128);
+
+ CHECK(std::numeric_limits<Int128>::min().abs() ==
+ 0x8000'0000'0000'0000'0000'0000'0000'0000_u128);
+ CHECK(std::numeric_limits<Int128>::max().abs() ==
+ 0x7fff'ffff'ffff'ffff'ffff'ffff'ffff'ffff_u128);
+
+ return true;
+}
+END_TEST(testInt128_abs)
+
+#endif