diff --git a/lib/std/core/dstring.c3 b/lib/std/core/dstring.c3 index fec99bf33..df4035453 100644 --- a/lib/std/core/dstring.c3 +++ b/lib/std/core/dstring.c3 @@ -1,5 +1,5 @@ module std::core::dstring; -import std::io; +import std::io, std::math; <* The DString offers a dynamic string builder. @@ -648,7 +648,7 @@ fn void DString.reserve(&self, usz addition) if (data.capacity >= len) return; usz new_capacity = data.capacity * 2; if (new_capacity < MIN_CAPACITY) new_capacity = MIN_CAPACITY; - while (new_capacity < len) new_capacity *= 2; + if (new_capacity < len) new_capacity = math::next_power_of_2(len); data.capacity = new_capacity; *self = (DString)allocator::realloc(data.allocator, data, StringData.sizeof + new_capacity); } diff --git a/lib/std/math/math.c3 b/lib/std/math/math.c3 index 7c7cf1cc9..f39628262 100644 --- a/lib/std/math/math.c3 +++ b/lib/std/math/math.c3 @@ -997,11 +997,29 @@ macro bool is_power_of_2(x) return x != 0 && (x & (x - 1)) == 0; } +<* + Returns the next power of two that is greater than or equal to x. + + @require types::is_int($typeof(x)) : "Input must be an integer type" + @require x >= 0 : "Input must be non-negative" +*> macro next_power_of_2(x) { - $typeof(x) y = 1; - while (y < x) y += y; - return y; + if (x <= 1) return 1; + if (x == 2) return 2; + + $typeof(x) v = x - 1; + + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + + $if ($sizeof(x) >= 2): v |= v >> 8; $endif; + $if ($sizeof(x) >= 4): v |= v >> 16; $endif; + $if ($sizeof(x) >= 8): v |= v >> 32; $endif; + $if ($sizeof(x) >= 16): v |= v >> 64; $endif; + + return v + 1; } macro equals_vec(v1, v2) @private