1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include <mozilla/Saturate.h> 8 9 #include <mozilla/Assertions.h> 10 11 #include <limits> 12 13 using mozilla::detail::Saturate; 14 15 #define A(a) MOZ_RELEASE_ASSERT(a, "Test \'" #a "\' failed.") 16 17 static const unsigned long sNumOps = 32; 18 19 template <typename T> StartValue()20static T StartValue() { 21 // Specialize |StartValue| for the given type. 22 A(false); 23 } 24 25 template <> StartValue()26int8_t StartValue<int8_t>() { 27 return 0; 28 } 29 30 template <> StartValue()31int16_t StartValue<int16_t>() { 32 return 0; 33 } 34 35 template <> StartValue()36int32_t StartValue<int32_t>() { 37 return 0; 38 } 39 40 template <> StartValue()41uint8_t StartValue<uint8_t>() { 42 // Picking a value near middle of uint8_t's range. 43 return static_cast<uint8_t>(std::numeric_limits<int8_t>::max()); 44 } 45 46 template <> StartValue()47uint16_t StartValue<uint16_t>() { 48 // Picking a value near middle of uint16_t's range. 49 return static_cast<uint8_t>(std::numeric_limits<int16_t>::max()); 50 } 51 52 template <> StartValue()53uint32_t StartValue<uint32_t>() { 54 // Picking a value near middle of uint32_t's range. 55 return static_cast<uint8_t>(std::numeric_limits<int32_t>::max()); 56 } 57 58 // Add 59 // 60 61 template <typename T> TestPrefixIncr()62static void TestPrefixIncr() { 63 T value = StartValue<T>(); 64 Saturate<T> satValue(value); 65 66 for (T i = 0; i < static_cast<T>(sNumOps); ++i) { 67 A(++value == ++satValue); 68 } 69 } 70 71 template <typename T> TestPostfixIncr()72static void TestPostfixIncr() { 73 T value = StartValue<T>(); 74 Saturate<T> satValue(value); 75 76 for (T i = 0; i < static_cast<T>(sNumOps); ++i) { 77 A(value++ == satValue++); 78 } 79 } 80 81 template <typename T> TestAdd()82static void TestAdd() { 83 T value = StartValue<T>(); 84 Saturate<T> satValue(value); 85 86 for (T i = 0; i < static_cast<T>(sNumOps); ++i) { 87 A((value + i) == (satValue + i)); 88 } 89 } 90 91 // Subtract 92 // 93 94 template <typename T> TestPrefixDecr()95static void TestPrefixDecr() { 96 T value = StartValue<T>(); 97 Saturate<T> satValue(value); 98 99 for (T i = 0; i < static_cast<T>(sNumOps); ++i) { 100 A(--value == --satValue); 101 } 102 } 103 104 template <typename T> TestPostfixDecr()105static void TestPostfixDecr() { 106 T value = StartValue<T>(); 107 Saturate<T> satValue(value); 108 109 for (T i = 0; i < static_cast<T>(sNumOps); ++i) { 110 A(value-- == satValue--); 111 } 112 } 113 114 template <typename T> TestSub()115static void TestSub() { 116 T value = StartValue<T>(); 117 Saturate<T> satValue(value); 118 119 for (T i = 0; i < static_cast<T>(sNumOps); ++i) { 120 A((value - i) == (satValue - i)); 121 } 122 } 123 124 // Corner cases near bounds 125 // 126 127 template <typename T> TestUpperBound()128static void TestUpperBound() { 129 Saturate<T> satValue(std::numeric_limits<T>::max()); 130 131 A(--satValue == (std::numeric_limits<T>::max() - 1)); 132 A(++satValue == (std::numeric_limits<T>::max())); 133 A(++satValue == (std::numeric_limits<T>::max())); // don't overflow here 134 A(++satValue == (std::numeric_limits<T>::max())); // don't overflow here 135 A(--satValue == (std::numeric_limits<T>::max() - 1)); // back at (max - 1) 136 A(--satValue == (std::numeric_limits<T>::max() - 2)); 137 } 138 139 template <typename T> TestLowerBound()140static void TestLowerBound() { 141 Saturate<T> satValue(std::numeric_limits<T>::min()); 142 143 A(++satValue == (std::numeric_limits<T>::min() + 1)); 144 A(--satValue == (std::numeric_limits<T>::min())); 145 A(--satValue == (std::numeric_limits<T>::min())); // don't overflow here 146 A(--satValue == (std::numeric_limits<T>::min())); // don't overflow here 147 A(++satValue == (std::numeric_limits<T>::min() + 1)); // back at (max + 1) 148 A(++satValue == (std::numeric_limits<T>::min() + 2)); 149 } 150 151 // Framework 152 // 153 154 template <typename T> TestAll()155static void TestAll() { 156 // Assert that we don't accidently hit type's range limits in tests. 157 const T value = StartValue<T>(); 158 A(std::numeric_limits<T>::min() + static_cast<T>(sNumOps) <= value); 159 A(std::numeric_limits<T>::max() - static_cast<T>(sNumOps) >= value); 160 161 TestPrefixIncr<T>(); 162 TestPostfixIncr<T>(); 163 TestAdd<T>(); 164 165 TestPrefixDecr<T>(); 166 TestPostfixDecr<T>(); 167 TestSub<T>(); 168 169 TestUpperBound<T>(); 170 TestLowerBound<T>(); 171 } 172 main()173int main() { 174 TestAll<int8_t>(); 175 TestAll<int16_t>(); 176 TestAll<int32_t>(); 177 TestAll<uint8_t>(); 178 TestAll<uint16_t>(); 179 TestAll<uint32_t>(); 180 return 0; 181 } 182