Blame mfbt/tests/TestWrappingOperations.cpp

Packit f0b94e
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
Packit f0b94e
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
Packit f0b94e
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
Packit f0b94e
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
Packit f0b94e
#include "mozilla/Assertions.h"
Packit f0b94e
#include "mozilla/WrappingOperations.h"
Packit f0b94e
Packit f0b94e
#include <stdint.h>
Packit f0b94e
Packit f0b94e
using mozilla::WrappingMultiply;
Packit f0b94e
using mozilla::WrapToSigned;
Packit f0b94e
Packit f0b94e
// NOTE: In places below |-FOO_MAX - 1| is used instead of |-FOO_MIN| because
Packit f0b94e
//       in C++ numeric literals are full expressions -- the |-| in a negative
Packit f0b94e
//       number is technically separate.  So with most compilers that limit
Packit f0b94e
//       |int| to the signed 32-bit range, something like |-2147483648| is
Packit f0b94e
//       operator-() applied to an *unsigned* expression.  And MSVC, at least,
Packit f0b94e
//       warns when you do that.  (The operation is well-defined, but it likely
Packit f0b94e
//       doesn't do what was intended.)  So we do the usual workaround for this
Packit f0b94e
//       (see your local copy of <stdint.h> for a likely demo of this), writing
Packit f0b94e
//       it out by negating the max value and subtracting 1.
Packit f0b94e
Packit f0b94e
static_assert(WrapToSigned(uint8_t(17)) == 17,
Packit f0b94e
              "no wraparound should work, 8-bit");
Packit f0b94e
static_assert(WrapToSigned(uint8_t(128)) == -128,
Packit f0b94e
              "works for 8-bit numbers, wraparound low end");
Packit f0b94e
static_assert(WrapToSigned(uint8_t(128 + 7)) == -128 + 7,
Packit f0b94e
              "works for 8-bit numbers, wraparound mid");
Packit f0b94e
static_assert(WrapToSigned(uint8_t(128 + 127)) == -128 + 127,
Packit f0b94e
              "works for 8-bit numbers, wraparound high end");
Packit f0b94e
Packit f0b94e
static_assert(WrapToSigned(uint16_t(12345)) == 12345,
Packit f0b94e
              "no wraparound should work, 16-bit");
Packit f0b94e
static_assert(WrapToSigned(uint16_t(32768)) == -32768,
Packit f0b94e
              "works for 16-bit numbers, wraparound low end");
Packit f0b94e
static_assert(WrapToSigned(uint16_t(32768 + 42)) == -32768 + 42,
Packit f0b94e
              "works for 16-bit numbers, wraparound mid");
Packit f0b94e
static_assert(WrapToSigned(uint16_t(32768 + 32767)) == -32768 + 32767,
Packit f0b94e
              "works for 16-bit numbers, wraparound high end");
Packit f0b94e
Packit f0b94e
static_assert(WrapToSigned(uint32_t(8675309)) == 8675309,
Packit f0b94e
              "no wraparound should work, 32-bit");
Packit f0b94e
static_assert(WrapToSigned(uint32_t(2147483648)) == -2147483647 - 1,
Packit f0b94e
              "works for 32-bit numbers, wraparound low end");
Packit f0b94e
static_assert(WrapToSigned(uint32_t(2147483648 + 42)) == -2147483647 - 1 + 42,
Packit f0b94e
              "works for 32-bit numbers, wraparound mid");
Packit f0b94e
static_assert(WrapToSigned(uint32_t(2147483648 + 2147483647)) ==
Packit f0b94e
                -2147483647 - 1 + 2147483647,
Packit f0b94e
              "works for 32-bit numbers, wraparound high end");
Packit f0b94e
Packit f0b94e
static_assert(WrapToSigned(uint64_t(4152739164)) == 4152739164,
Packit f0b94e
              "no wraparound should work, 64-bit");
Packit f0b94e
static_assert(WrapToSigned(uint64_t(9223372036854775808ULL)) == -9223372036854775807LL - 1,
Packit f0b94e
              "works for 64-bit numbers, wraparound low end");
Packit f0b94e
static_assert(WrapToSigned(uint64_t(9223372036854775808ULL + 8005552368LL)) ==
Packit f0b94e
                -9223372036854775807LL - 1 + 8005552368LL,
Packit f0b94e
              "works for 64-bit numbers, wraparound mid");
Packit f0b94e
static_assert(WrapToSigned(uint64_t(9223372036854775808ULL + 9223372036854775807ULL)) ==
Packit f0b94e
                -9223372036854775807LL - 1 + 9223372036854775807LL,
Packit f0b94e
              "works for 64-bit numbers, wraparound high end");
Packit f0b94e
Packit f0b94e
template<typename T>
Packit f0b94e
inline constexpr bool
Packit f0b94e
TestEqual(T aX, T aY)
Packit f0b94e
{
Packit f0b94e
  return aX == aY;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static void
Packit f0b94e
TestWrappingMultiply8()
Packit f0b94e
{
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint8_t(0), uint8_t(128)),
Packit f0b94e
                               uint8_t(0)),
Packit f0b94e
                     "zero times anything is zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint8_t(128), uint8_t(1)),
Packit f0b94e
                               uint8_t(128)),
Packit f0b94e
                     "1 times anything is anything");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint8_t(2), uint8_t(128)),
Packit f0b94e
                               uint8_t(0)),
Packit f0b94e
                     "2 times high bit overflows, produces zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint8_t(8), uint8_t(16)),
Packit f0b94e
                               uint8_t(128)),
Packit f0b94e
                     "multiply that populates the high bit produces that value");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint8_t(127), uint8_t(127)),
Packit f0b94e
                               uint8_t(1)),
Packit f0b94e
                     "multiplying signed maxvals overflows all the way to 1");
Packit f0b94e
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int8_t(0), int8_t(-128)),
Packit f0b94e
                               int8_t(0)),
Packit f0b94e
                     "zero times anything is zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int8_t(-128), int8_t(1)),
Packit f0b94e
                               int8_t(-128)),
Packit f0b94e
                     "1 times anything is anything");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int8_t(2), int8_t(-128)),
Packit f0b94e
                               int8_t(0)),
Packit f0b94e
                     "2 times min overflows, produces zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int8_t(16), int8_t(24)),
Packit f0b94e
                               int8_t(-128)),
Packit f0b94e
                     "multiply that populates the sign bit produces minval");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int8_t(8), int8_t(16)),
Packit f0b94e
                               int8_t(-128)),
Packit f0b94e
                     "multiply that populates the sign bit produces minval");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int8_t(127), int8_t(127)),
Packit f0b94e
                               int8_t(1)),
Packit f0b94e
                     "multiplying maxvals overflows all the way to 1");
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static void
Packit f0b94e
TestWrappingMultiply16()
Packit f0b94e
{
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint16_t(0), uint16_t(32768)),
Packit f0b94e
                               uint16_t(0)),
Packit f0b94e
                     "zero times anything is zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint16_t(32768), uint16_t(1)),
Packit f0b94e
                               uint16_t(32768)),
Packit f0b94e
                     "1 times anything is anything");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint16_t(2), uint16_t(32768)),
Packit f0b94e
                               uint16_t(0)),
Packit f0b94e
                     "2 times high bit overflows, produces zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint16_t(3), uint16_t(32768)),
Packit f0b94e
                               uint16_t(-32768)),
Packit f0b94e
                     "3 * 32768 - 65536 is 32768");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint16_t(64), uint16_t(512)),
Packit f0b94e
                               uint16_t(32768)),
Packit f0b94e
                     "multiply that populates the high bit produces that value");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint16_t(32767), uint16_t(32767)),
Packit f0b94e
                               uint16_t(1)),
Packit f0b94e
                    "multiplying signed maxvals overflows all the way to 1");
Packit f0b94e
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int16_t(0), int16_t(-32768)),
Packit f0b94e
                               int16_t(0)),
Packit f0b94e
                     "zero times anything is zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int16_t(-32768), int16_t(1)),
Packit f0b94e
                               int16_t(-32768)),
Packit f0b94e
                     "1 times anything is anything");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int16_t(-456), int16_t(123)),
Packit f0b94e
                               int16_t(9448)),
Packit f0b94e
                     "multiply opposite signs, then add 2**16 for the result");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int16_t(2), int16_t(-32768)),
Packit f0b94e
                               int16_t(0)),
Packit f0b94e
                     "2 times min overflows, produces zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int16_t(64), int16_t(512)),
Packit f0b94e
                               int16_t(-32768)),
Packit f0b94e
                     "multiply that populates the sign bit produces minval");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int16_t(32767), int16_t(32767)),
Packit f0b94e
                               int16_t(1)),
Packit f0b94e
                     "multiplying maxvals overflows all the way to 1");
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static void
Packit f0b94e
TestWrappingMultiply32()
Packit f0b94e
{
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint32_t(0), uint32_t(2147483648)),
Packit f0b94e
                               uint32_t(0)),
Packit f0b94e
                    "zero times anything is zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint32_t(42), uint32_t(17)),
Packit f0b94e
                               uint32_t(714)),
Packit f0b94e
                     "42 * 17 is 714 without wraparound");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint32_t(2147483648), uint32_t(1)),
Packit f0b94e
                               uint32_t(2147483648)),
Packit f0b94e
                     "1 times anything is anything");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint32_t(2), uint32_t(2147483648)),
Packit f0b94e
                               uint32_t(0)),
Packit f0b94e
                     "2 times high bit overflows, produces zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint32_t(8192), uint32_t(262144)),
Packit f0b94e
                               uint32_t(2147483648)),
Packit f0b94e
                     "multiply that populates the high bit produces that value");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint32_t(2147483647),
Packit f0b94e
                                                uint32_t(2147483647)),
Packit f0b94e
                               uint32_t(1)),
Packit f0b94e
                     "multiplying signed maxvals overflows all the way to 1");
Packit f0b94e
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int32_t(0), int32_t(-2147483647 - 1)),
Packit f0b94e
                               int32_t(0)),
Packit f0b94e
                     "zero times anything is zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int32_t(-2147483647 - 1), int32_t(1)),
Packit f0b94e
                               int32_t(-2147483647 - 1)),
Packit f0b94e
                     "1 times anything is anything");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int32_t(2), int32_t(-2147483647 - 1)),
Packit f0b94e
                               int32_t(0)),
Packit f0b94e
                     "2 times min overflows, produces zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int32_t(-7), int32_t(-9)),
Packit f0b94e
                               int32_t(63)),
Packit f0b94e
                     "-7 * -9 is 63, no wraparound needed");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int32_t(8192), int32_t(262144)),
Packit f0b94e
                               int32_t(-2147483647 - 1)),
Packit f0b94e
                     "multiply that populates the sign bit produces minval");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int32_t(2147483647), int32_t(2147483647)),
Packit f0b94e
                               int32_t(1)),
Packit f0b94e
                     "multiplying maxvals overflows all the way to 1");
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static void
Packit f0b94e
TestWrappingMultiply64()
Packit f0b94e
{
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint64_t(0),
Packit f0b94e
                                                uint64_t(9223372036854775808ULL)),
Packit f0b94e
                               uint64_t(0)),
Packit f0b94e
                     "zero times anything is zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint64_t(9223372036854775808ULL),
Packit f0b94e
                                                uint64_t(1)),
Packit f0b94e
                               uint64_t(9223372036854775808ULL)),
Packit f0b94e
                     "1 times anything is anything");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint64_t(2),
Packit f0b94e
                                                uint64_t(9223372036854775808ULL)),
Packit f0b94e
                               uint64_t(0)),
Packit f0b94e
                     "2 times high bit overflows, produces zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint64_t(131072),
Packit f0b94e
                                                uint64_t(70368744177664)),
Packit f0b94e
                               uint64_t(9223372036854775808ULL)),
Packit f0b94e
                     "multiply that populates the high bit produces that value");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(uint64_t(9223372036854775807),
Packit f0b94e
                                                uint64_t(9223372036854775807)),
Packit f0b94e
                               uint64_t(1)),
Packit f0b94e
                     "multiplying signed maxvals overflows all the way to 1");
Packit f0b94e
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int64_t(0), int64_t(-9223372036854775807 - 1)),
Packit f0b94e
                               int64_t(0)),
Packit f0b94e
                     "zero times anything is zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int64_t(-9223372036854775807 - 1),
Packit f0b94e
                                                int64_t(1)),
Packit f0b94e
                               int64_t(-9223372036854775807 - 1)),
Packit f0b94e
                     "1 times anything is anything");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int64_t(2),
Packit f0b94e
                                                int64_t(-9223372036854775807 - 1)),
Packit f0b94e
                               int64_t(0)),
Packit f0b94e
                     "2 times min overflows, produces zero");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int64_t(131072),
Packit f0b94e
                                                int64_t(70368744177664)),
Packit f0b94e
                               int64_t(-9223372036854775807 - 1)),
Packit f0b94e
                     "multiply that populates the sign bit produces minval");
Packit f0b94e
  MOZ_RELEASE_ASSERT(TestEqual(WrappingMultiply(int64_t(9223372036854775807),
Packit f0b94e
                                                int64_t(9223372036854775807)),
Packit f0b94e
                               int64_t(1)),
Packit f0b94e
                     "multiplying maxvals overflows all the way to 1");
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
int
Packit f0b94e
main()
Packit f0b94e
{
Packit f0b94e
  TestWrappingMultiply8();
Packit f0b94e
  TestWrappingMultiply16();
Packit f0b94e
  TestWrappingMultiply32();
Packit f0b94e
  TestWrappingMultiply64();
Packit f0b94e
  return 0;
Packit f0b94e
}