|
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 |
}
|