diff --git a/mfbt/MathAlgorithms.h b/mfbt/MathAlgorithms.h index 927f008b213..ee36aca5082 100644 --- a/mfbt/MathAlgorithms.h +++ b/mfbt/MathAlgorithms.h @@ -414,13 +414,14 @@ FloorLog2Size(size_t n) } /* - * Round x up to the nearest power of 2. This function assumes that the most - * significant bit of x is not set, which would lead to overflow. + * Compute the smallest power of 2 greater than or equal to |x|. |x| must not + * be so great that the computed value would overflow |size_t|. */ inline size_t RoundUpPow2(size_t x) { - MOZ_ASSERT(~x > x, "can't round up -- will overflow!"); + MOZ_ASSERT(x <= (size_t(1) << (sizeof(size_t) * CHAR_BIT - 1)), + "can't round up -- will overflow!"); return size_t(1) << CeilingLog2(x); } diff --git a/mfbt/tests/TestCeilingFloor.cpp b/mfbt/tests/TestCeilingFloor.cpp index fc697e230cf..8ac2fda4de9 100644 --- a/mfbt/tests/TestCeilingFloor.cpp +++ b/mfbt/tests/TestCeilingFloor.cpp @@ -7,6 +7,7 @@ using mozilla::CeilingLog2; using mozilla::FloorLog2; +using mozilla::RoundUpPow2; static void TestCeiling() @@ -46,9 +47,39 @@ TestFloor() MOZ_ASSERT(FloorLog2(i) == 4); } +static void +TestRoundUpPow2() +{ + MOZ_ASSERT(RoundUpPow2(0) == 1); + MOZ_ASSERT(RoundUpPow2(1) == 1); + MOZ_ASSERT(RoundUpPow2(2) == 2); + MOZ_ASSERT(RoundUpPow2(3) == 4); + MOZ_ASSERT(RoundUpPow2(4) == 4); + MOZ_ASSERT(RoundUpPow2(5) == 8); + MOZ_ASSERT(RoundUpPow2(6) == 8); + MOZ_ASSERT(RoundUpPow2(7) == 8); + MOZ_ASSERT(RoundUpPow2(8) == 8); + MOZ_ASSERT(RoundUpPow2(9) == 16); + + MOZ_ASSERT(RoundUpPow2(15) == 16); + MOZ_ASSERT(RoundUpPow2(16) == 16); + MOZ_ASSERT(RoundUpPow2(17) == 32); + + MOZ_ASSERT(RoundUpPow2(31) == 32); + MOZ_ASSERT(RoundUpPow2(32) == 32); + MOZ_ASSERT(RoundUpPow2(33) == 64); + + size_t MaxPow2 = size_t(1) << (sizeof(size_t) * CHAR_BIT - 1); + MOZ_ASSERT(RoundUpPow2(MaxPow2 - 1) == MaxPow2); + MOZ_ASSERT(RoundUpPow2(MaxPow2) == MaxPow2); + // not valid to round up when past the max power of two +} + int main() { TestCeiling(); TestFloor(); + + TestRoundUpPow2(); return 0; }