/* -*- 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 #include #include using mozilla::detail::Saturate; #define A(a) MOZ_RELEASE_ASSERT(a, "Test \'" #a "\' failed.") static const unsigned long sNumOps = 32; template static T StartValue() { // Specialize |StartValue| for the given type. A(false); } template <> int8_t StartValue() { return 0; } template <> int16_t StartValue() { return 0; } template <> int32_t StartValue() { return 0; } template <> uint8_t StartValue() { // Picking a value near middle of uint8_t's range. return static_cast(std::numeric_limits::max()); } template <> uint16_t StartValue() { // Picking a value near middle of uint16_t's range. return static_cast(std::numeric_limits::max()); } template <> uint32_t StartValue() { // Picking a value near middle of uint32_t's range. return static_cast(std::numeric_limits::max()); } // Add // template static void TestPrefixIncr() { T value = StartValue(); Saturate satValue(value); for (T i = 0; i < static_cast(sNumOps); ++i) { A(++value == ++satValue); } } template static void TestPostfixIncr() { T value = StartValue(); Saturate satValue(value); for (T i = 0; i < static_cast(sNumOps); ++i) { A(value++ == satValue++); } } template static void TestAdd() { T value = StartValue(); Saturate satValue(value); for (T i = 0; i < static_cast(sNumOps); ++i) { A((value + i) == (satValue + i)); } } // Subtract // template static void TestPrefixDecr() { T value = StartValue(); Saturate satValue(value); for (T i = 0; i < static_cast(sNumOps); ++i) { A(--value == --satValue); } } template static void TestPostfixDecr() { T value = StartValue(); Saturate satValue(value); for (T i = 0; i < static_cast(sNumOps); ++i) { A(value-- == satValue--); } } template static void TestSub() { T value = StartValue(); Saturate satValue(value); for (T i = 0; i < static_cast(sNumOps); ++i) { A((value - i) == (satValue - i)); } } // Corner cases near bounds // template static void TestUpperBound() { Saturate satValue(std::numeric_limits::max()); A(--satValue == (std::numeric_limits::max() - 1)); A(++satValue == (std::numeric_limits::max())); A(++satValue == (std::numeric_limits::max())); // don't overflow here A(++satValue == (std::numeric_limits::max())); // don't overflow here A(--satValue == (std::numeric_limits::max() - 1)); // back at (max - 1) A(--satValue == (std::numeric_limits::max() - 2)); } template static void TestLowerBound() { Saturate satValue(std::numeric_limits::min()); A(++satValue == (std::numeric_limits::min() + 1)); A(--satValue == (std::numeric_limits::min())); A(--satValue == (std::numeric_limits::min())); // don't overflow here A(--satValue == (std::numeric_limits::min())); // don't overflow here A(++satValue == (std::numeric_limits::min() + 1)); // back at (max + 1) A(++satValue == (std::numeric_limits::min() + 2)); } // Framework // template static void TestAll() { // Assert that we don't accidently hit type's range limits in tests. const T value = StartValue(); A(std::numeric_limits::min() + static_cast(sNumOps) <= value); A(std::numeric_limits::max() - static_cast(sNumOps) >= value); TestPrefixIncr(); TestPostfixIncr(); TestAdd(); TestPrefixDecr(); TestPostfixDecr(); TestSub(); TestUpperBound(); TestLowerBound(); } int main() { TestAll(); TestAll(); TestAll(); TestAll(); TestAll(); TestAll(); return 0; }