no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / mfbt / tests / TestCasting.cpp
blob9b040956c73bd32819017c6b2675115632b54d5b
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/. */
7 #include "mozilla/Casting.h"
8 #include "mozilla/ThreadSafety.h"
10 #include <stdint.h>
11 #include <cstdint>
12 #include <limits>
13 #include <type_traits>
15 using mozilla::AssertedCast;
16 using mozilla::BitwiseCast;
17 using mozilla::detail::IsInBounds;
19 static const uint8_t floatMantissaBitsPlusOne = 24;
20 static const uint8_t doubleMantissaBitsPlusOne = 53;
22 template <typename Uint, typename Ulong, bool = (sizeof(Uint) == sizeof(Ulong))>
23 struct UintUlongBitwiseCast;
25 template <typename Uint, typename Ulong>
26 struct UintUlongBitwiseCast<Uint, Ulong, true> {
27 static void test() {
28 MOZ_RELEASE_ASSERT(BitwiseCast<Ulong>(Uint(8675309)) == Ulong(8675309));
32 template <typename Uint, typename Ulong>
33 struct UintUlongBitwiseCast<Uint, Ulong, false> {
34 static void test() {}
37 static void TestBitwiseCast() {
38 MOZ_RELEASE_ASSERT(BitwiseCast<int>(int(8675309)) == int(8675309));
39 UintUlongBitwiseCast<unsigned int, unsigned long>::test();
42 static void TestSameSize() {
43 MOZ_RELEASE_ASSERT((IsInBounds<int16_t, int16_t>(int16_t(0))));
44 MOZ_RELEASE_ASSERT((IsInBounds<int16_t, int16_t>(int16_t(INT16_MIN))));
45 MOZ_RELEASE_ASSERT((IsInBounds<int16_t, int16_t>(int16_t(INT16_MAX))));
46 MOZ_RELEASE_ASSERT((IsInBounds<uint16_t, uint16_t>(uint16_t(UINT16_MAX))));
47 MOZ_RELEASE_ASSERT((IsInBounds<uint16_t, int16_t>(uint16_t(0))));
48 MOZ_RELEASE_ASSERT((!IsInBounds<uint16_t, int16_t>(uint16_t(-1))));
49 MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, uint16_t>(int16_t(-1))));
50 MOZ_RELEASE_ASSERT((IsInBounds<int16_t, uint16_t>(int16_t(INT16_MAX))));
51 MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, uint16_t>(int16_t(INT16_MIN))));
52 MOZ_RELEASE_ASSERT((IsInBounds<int32_t, uint32_t>(int32_t(INT32_MAX))));
53 MOZ_RELEASE_ASSERT((!IsInBounds<int32_t, uint32_t>(int32_t(INT32_MIN))));
56 static void TestToBiggerSize() {
57 MOZ_RELEASE_ASSERT((IsInBounds<int16_t, int32_t>(int16_t(0))));
58 MOZ_RELEASE_ASSERT((IsInBounds<int16_t, int32_t>(int16_t(INT16_MIN))));
59 MOZ_RELEASE_ASSERT((IsInBounds<int16_t, int32_t>(int16_t(INT16_MAX))));
60 MOZ_RELEASE_ASSERT((IsInBounds<uint16_t, uint32_t>(uint16_t(UINT16_MAX))));
61 MOZ_RELEASE_ASSERT((IsInBounds<uint16_t, int32_t>(uint16_t(0))));
62 MOZ_RELEASE_ASSERT((IsInBounds<uint16_t, int32_t>(uint16_t(-1))));
63 MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, uint32_t>(int16_t(-1))));
64 MOZ_RELEASE_ASSERT((IsInBounds<int16_t, uint32_t>(int16_t(INT16_MAX))));
65 MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, uint32_t>(int16_t(INT16_MIN))));
66 MOZ_RELEASE_ASSERT((IsInBounds<int32_t, uint64_t>(int32_t(INT32_MAX))));
67 MOZ_RELEASE_ASSERT((!IsInBounds<int32_t, uint64_t>(int32_t(INT32_MIN))));
70 static void TestToSmallerSize() {
71 MOZ_RELEASE_ASSERT((IsInBounds<int16_t, int8_t>(int16_t(0))));
72 MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, int8_t>(int16_t(INT16_MIN))));
73 MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, int8_t>(int16_t(INT16_MAX))));
74 MOZ_RELEASE_ASSERT((!IsInBounds<uint16_t, uint8_t>(uint16_t(UINT16_MAX))));
75 MOZ_RELEASE_ASSERT((IsInBounds<uint16_t, int8_t>(uint16_t(0))));
76 MOZ_RELEASE_ASSERT((!IsInBounds<uint16_t, int8_t>(uint16_t(-1))));
77 MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, uint8_t>(int16_t(-1))));
78 MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, uint8_t>(int16_t(INT16_MAX))));
79 MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, uint8_t>(int16_t(INT16_MIN))));
80 MOZ_RELEASE_ASSERT((!IsInBounds<int32_t, uint16_t>(int32_t(INT32_MAX))));
81 MOZ_RELEASE_ASSERT((!IsInBounds<int32_t, uint16_t>(int32_t(INT32_MIN))));
83 // Boundary cases
84 MOZ_RELEASE_ASSERT((!IsInBounds<int64_t, int32_t>(int64_t(INT32_MIN) - 1)));
85 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MIN))));
86 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MIN) + 1)));
87 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MAX) - 1)));
88 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MAX))));
89 MOZ_RELEASE_ASSERT((!IsInBounds<int64_t, int32_t>(int64_t(INT32_MAX) + 1)));
91 MOZ_RELEASE_ASSERT((!IsInBounds<int64_t, uint32_t>(int64_t(-1))));
92 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(0))));
93 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(1))));
94 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(UINT32_MAX) - 1)));
95 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(UINT32_MAX))));
96 MOZ_RELEASE_ASSERT((!IsInBounds<int64_t, uint32_t>(int64_t(UINT32_MAX) + 1)));
99 template <typename In, typename Out>
100 void checkBoundariesFloating(In aEpsilon = {}, Out aIntegerOffset = {}) {
101 // Check the max value of the input float can't be represented as an integer.
102 // This is true for all floating point and integer width.
103 MOZ_RELEASE_ASSERT((!IsInBounds<In, Out>(std::numeric_limits<In>::max())));
104 // Check that the max value of the integer, as a float, minus an offset that
105 // depends on the magnitude, can be represented as an integer.
106 MOZ_RELEASE_ASSERT((IsInBounds<In, Out>(
107 static_cast<In>(std::numeric_limits<Out>::max() - aIntegerOffset))));
108 // Check that the max value of the integer, plus a number that depends on the
109 // magnitude of the number, can't be represented as this integer (because it
110 // becomes too big).
111 MOZ_RELEASE_ASSERT((!IsInBounds<In, Out>(
112 aEpsilon + static_cast<In>(std::numeric_limits<Out>::max()))));
113 if constexpr (std::is_signed_v<In>) {
114 // Same for negative numbers.
115 MOZ_RELEASE_ASSERT(
116 (!IsInBounds<In, Out>(std::numeric_limits<In>::lowest())));
117 MOZ_RELEASE_ASSERT((IsInBounds<In, Out>(
118 static_cast<In>(std::numeric_limits<Out>::lowest()))));
119 MOZ_RELEASE_ASSERT((!IsInBounds<In, Out>(
120 static_cast<In>(std::numeric_limits<Out>::lowest()) - aEpsilon)));
121 } else {
122 // Check for negative floats and unsigned integer types.
123 MOZ_RELEASE_ASSERT((!IsInBounds<In, Out>(static_cast<In>(-1))));
127 void TestFloatConversion() {
128 MOZ_RELEASE_ASSERT((!IsInBounds<uint64_t, float>(UINT64_MAX)));
129 MOZ_RELEASE_ASSERT((!IsInBounds<uint32_t, float>(UINT32_MAX)));
130 MOZ_RELEASE_ASSERT((IsInBounds<uint16_t, float>(UINT16_MAX)));
131 MOZ_RELEASE_ASSERT((IsInBounds<uint8_t, float>(UINT8_MAX)));
133 MOZ_RELEASE_ASSERT((!IsInBounds<int64_t, float>(INT64_MAX)));
134 MOZ_RELEASE_ASSERT((!IsInBounds<int64_t, float>(INT64_MIN)));
135 MOZ_RELEASE_ASSERT((!IsInBounds<int32_t, float>(INT32_MAX)));
136 MOZ_RELEASE_ASSERT((!IsInBounds<int32_t, float>(INT32_MIN)));
137 MOZ_RELEASE_ASSERT((IsInBounds<int16_t, float>(INT16_MAX)));
138 MOZ_RELEASE_ASSERT((IsInBounds<int16_t, float>(INT16_MIN)));
139 MOZ_RELEASE_ASSERT((IsInBounds<int8_t, float>(INT8_MAX)));
140 MOZ_RELEASE_ASSERT((IsInBounds<int8_t, float>(INT8_MIN)));
142 MOZ_RELEASE_ASSERT((!IsInBounds<uint64_t, double>(UINT64_MAX)));
143 MOZ_RELEASE_ASSERT((IsInBounds<uint32_t, double>(UINT32_MAX)));
144 MOZ_RELEASE_ASSERT((IsInBounds<uint16_t, double>(UINT16_MAX)));
145 MOZ_RELEASE_ASSERT((IsInBounds<uint8_t, double>(UINT8_MAX)));
147 MOZ_RELEASE_ASSERT((!IsInBounds<int64_t, double>(INT64_MAX)));
148 MOZ_RELEASE_ASSERT((!IsInBounds<int64_t, double>(INT64_MIN)));
149 MOZ_RELEASE_ASSERT((IsInBounds<int32_t, double>(INT32_MAX)));
150 MOZ_RELEASE_ASSERT((IsInBounds<int32_t, double>(INT32_MIN)));
151 MOZ_RELEASE_ASSERT((IsInBounds<int16_t, double>(INT16_MAX)));
152 MOZ_RELEASE_ASSERT((IsInBounds<int16_t, double>(INT16_MIN)));
153 MOZ_RELEASE_ASSERT((IsInBounds<int8_t, double>(INT8_MAX)));
154 MOZ_RELEASE_ASSERT((IsInBounds<int8_t, double>(INT8_MIN)));
156 // Floor check
157 MOZ_RELEASE_ASSERT((IsInBounds<float, uint64_t>(4.3)));
158 MOZ_RELEASE_ASSERT((AssertedCast<uint64_t>(4.3f) == 4u));
159 MOZ_RELEASE_ASSERT((IsInBounds<float, uint32_t>(4.3)));
160 MOZ_RELEASE_ASSERT((AssertedCast<uint32_t>(4.3f) == 4u));
161 MOZ_RELEASE_ASSERT((IsInBounds<float, uint16_t>(4.3)));
162 MOZ_RELEASE_ASSERT((AssertedCast<uint16_t>(4.3f) == 4u));
163 MOZ_RELEASE_ASSERT((IsInBounds<float, uint8_t>(4.3)));
164 MOZ_RELEASE_ASSERT((AssertedCast<uint8_t>(4.3f) == 4u));
166 MOZ_RELEASE_ASSERT((IsInBounds<float, int64_t>(4.3)));
167 MOZ_RELEASE_ASSERT((AssertedCast<int64_t>(4.3f) == 4u));
168 MOZ_RELEASE_ASSERT((IsInBounds<float, int32_t>(4.3)));
169 MOZ_RELEASE_ASSERT((AssertedCast<int32_t>(4.3f) == 4u));
170 MOZ_RELEASE_ASSERT((IsInBounds<float, int16_t>(4.3)));
171 MOZ_RELEASE_ASSERT((AssertedCast<int16_t>(4.3f) == 4u));
172 MOZ_RELEASE_ASSERT((IsInBounds<float, int8_t>(4.3)));
173 MOZ_RELEASE_ASSERT((AssertedCast<int8_t>(4.3f) == 4u));
175 MOZ_RELEASE_ASSERT((IsInBounds<float, int64_t>(-4.3)));
176 MOZ_RELEASE_ASSERT((AssertedCast<int64_t>(-4.3f) == -4));
177 MOZ_RELEASE_ASSERT((IsInBounds<float, int32_t>(-4.3)));
178 MOZ_RELEASE_ASSERT((AssertedCast<int32_t>(-4.3f) == -4));
179 MOZ_RELEASE_ASSERT((IsInBounds<float, int16_t>(-4.3)));
180 MOZ_RELEASE_ASSERT((AssertedCast<int16_t>(-4.3f) == -4));
181 MOZ_RELEASE_ASSERT((IsInBounds<float, int8_t>(-4.3)));
182 MOZ_RELEASE_ASSERT((AssertedCast<int8_t>(-4.3f) == -4));
184 // Bound check for float to unsigned integer conversion. The parameters are
185 // espilons and offsets allowing to check boundaries, that depend on the
186 // magnitude of the numbers.
187 checkBoundariesFloating<double, uint64_t>(2049.);
188 checkBoundariesFloating<double, uint32_t>(1.);
189 checkBoundariesFloating<double, uint16_t>(1.);
190 checkBoundariesFloating<double, uint8_t>(1.);
191 // Large number because of the lack of precision of floats at this magnitude
192 checkBoundariesFloating<float, uint64_t>(1.1e12f);
193 checkBoundariesFloating<float, uint32_t>(1.f, 128u);
194 checkBoundariesFloating<float, uint16_t>(1.f);
195 checkBoundariesFloating<float, uint8_t>(1.f);
197 checkBoundariesFloating<double, int64_t>(1025.);
198 checkBoundariesFloating<double, int32_t>(1.);
199 checkBoundariesFloating<double, int16_t>(1.);
200 checkBoundariesFloating<double, int8_t>(1.);
201 // Large number because of the lack of precision of floats at this magnitude
202 checkBoundariesFloating<float, int64_t>(1.1e12f);
203 checkBoundariesFloating<float, int32_t>(256.f, 64u);
204 checkBoundariesFloating<float, int16_t>(1.f);
205 checkBoundariesFloating<float, int8_t>(1.f);
207 // Integer to floating point, boundary cases
208 MOZ_RELEASE_ASSERT(!(IsInBounds<int64_t, float>(
209 int64_t(std::pow(2, floatMantissaBitsPlusOne)) + 1)));
210 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, float>(
211 int64_t(std::pow(2, floatMantissaBitsPlusOne)))));
212 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, float>(
213 int64_t(std::pow(2, floatMantissaBitsPlusOne)) - 1)));
215 MOZ_RELEASE_ASSERT(!(IsInBounds<int64_t, float>(
216 int64_t(-std::pow(2, floatMantissaBitsPlusOne)) - 1)));
217 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, float>(
218 int64_t(-std::pow(2, floatMantissaBitsPlusOne)))));
219 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, float>(
220 int64_t(-std::pow(2, floatMantissaBitsPlusOne)) + 1)));
222 MOZ_RELEASE_ASSERT(!(IsInBounds<int64_t, double>(
223 uint64_t(std::pow(2, doubleMantissaBitsPlusOne)) + 1)));
224 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, double>(
225 uint64_t(std::pow(2, doubleMantissaBitsPlusOne)))));
226 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, double>(
227 uint64_t(std::pow(2, doubleMantissaBitsPlusOne)) - 1)));
229 MOZ_RELEASE_ASSERT(!(IsInBounds<int64_t, double>(
230 int64_t(-std::pow(2, doubleMantissaBitsPlusOne)) - 1)));
231 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, double>(
232 int64_t(-std::pow(2, doubleMantissaBitsPlusOne)))));
233 MOZ_RELEASE_ASSERT((IsInBounds<int64_t, double>(
234 int64_t(-std::pow(2, doubleMantissaBitsPlusOne)) + 1)));
236 MOZ_RELEASE_ASSERT(!(IsInBounds<uint64_t, double>(UINT64_MAX)));
237 MOZ_RELEASE_ASSERT(!(IsInBounds<int64_t, double>(INT64_MAX)));
238 MOZ_RELEASE_ASSERT(!(IsInBounds<int64_t, double>(INT64_MIN)));
240 MOZ_RELEASE_ASSERT(
241 !(IsInBounds<double, float>(std::numeric_limits<double>::max())));
242 MOZ_RELEASE_ASSERT(
243 !(IsInBounds<double, float>(-std::numeric_limits<double>::max())));
246 int main() {
247 TestBitwiseCast();
249 TestSameSize();
250 TestToBiggerSize();
251 TestToSmallerSize();
252 TestFloatConversion();
254 return 0;