| ... | @@ -696,6 +696,78 @@ test "math.floorPowerOfTwo" { | ... | @@ -696,6 +696,78 @@ test "math.floorPowerOfTwo" { |
| 696 | comptime testFloorPowerOfTwo(); | 696 | comptime testFloorPowerOfTwo(); |
| 697 | } | 697 | } |
| 698 | | 698 | |
| | 699 | fn testFloorPowerOfTwo() void { |
| | 700 | testing.expect(floorPowerOfTwo(u32, 63) == 32); |
| | 701 | testing.expect(floorPowerOfTwo(u32, 64) == 64); |
| | 702 | testing.expect(floorPowerOfTwo(u32, 65) == 64); |
| | 703 | testing.expect(floorPowerOfTwo(u4, 7) == 4); |
| | 704 | testing.expect(floorPowerOfTwo(u4, 8) == 8); |
| | 705 | testing.expect(floorPowerOfTwo(u4, 9) == 8); |
| | 706 | } |
| | 707 | |
| | 708 | /// Returns the next power of two (if the value is not already a power of two). |
| | 709 | /// Result is a type with 1 more bit than the input type. |
| | 710 | pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) @IntType(T.is_signed, T.bit_count + 1) { |
| | 711 | if (T.is_signed) { |
| | 712 | @compileError("signed integers not supported"); |
| | 713 | } |
| | 714 | comptime const promotedType = @IntType(T.is_signed, T.bit_count + 1); |
| | 715 | comptime const shiftType = std.math.Log2Int(promotedType); |
| | 716 | if (value == 0) return promotedType(0); |
| | 717 | return promotedType(1) << @intCast(shiftType, T.bit_count - @clz(T, value - 1)); |
| | 718 | } |
| | 719 | |
| | 720 | /// Returns the next power of two (if the value is not already a power of two). |
| | 721 | /// If the value doesn't fit, returns an error. |
| | 722 | pub fn ceilPowerOfTwo(comptime T: type, value: T) (error{Overflow}!T) { |
| | 723 | if (T.is_signed) { |
| | 724 | @compileError("signed integers not supported"); |
| | 725 | } |
| | 726 | comptime const promotedType = @IntType(T.is_signed, T.bit_count + 1); |
| | 727 | comptime const overflowBit = promotedType(1) << T.bit_count; |
| | 728 | var x = ceilPowerOfTwoPromote(T, value); |
| | 729 | if (overflowBit & x != 0) { |
| | 730 | return error.Overflow; |
| | 731 | } |
| | 732 | return @intCast(T, x); |
| | 733 | } |
| | 734 | |
| | 735 | test "math.ceilPowerOfTwoPromote" { |
| | 736 | testCeilPowerOfTwoPromote(); |
| | 737 | comptime testCeilPowerOfTwoPromote(); |
| | 738 | } |
| | 739 | |
| | 740 | fn testCeilPowerOfTwoPromote() void { |
| | 741 | testing.expectEqual(u33(0), ceilPowerOfTwoPromote(u32, 0)); |
| | 742 | testing.expectEqual(u33(1), ceilPowerOfTwoPromote(u32, 1)); |
| | 743 | testing.expectEqual(u33(2), ceilPowerOfTwoPromote(u32, 2)); |
| | 744 | testing.expectEqual(u33(64), ceilPowerOfTwoPromote(u32, 63)); |
| | 745 | testing.expectEqual(u33(64), ceilPowerOfTwoPromote(u32, 64)); |
| | 746 | testing.expectEqual(u33(128), ceilPowerOfTwoPromote(u32, 65)); |
| | 747 | testing.expectEqual(u6(8), ceilPowerOfTwoPromote(u5, 7)); |
| | 748 | testing.expectEqual(u6(8), ceilPowerOfTwoPromote(u5, 8)); |
| | 749 | testing.expectEqual(u6(16), ceilPowerOfTwoPromote(u5, 9)); |
| | 750 | testing.expectEqual(u5(16), ceilPowerOfTwoPromote(u4, 9)); |
| | 751 | } |
| | 752 | |
| | 753 | test "math.ceilPowerOfTwo" { |
| | 754 | try testCeilPowerOfTwo(); |
| | 755 | comptime try testCeilPowerOfTwo(); |
| | 756 | } |
| | 757 | |
| | 758 | fn testCeilPowerOfTwo() !void { |
| | 759 | testing.expectEqual(u32(0), try ceilPowerOfTwo(u32, 0)); |
| | 760 | testing.expectEqual(u32(1), try ceilPowerOfTwo(u32, 1)); |
| | 761 | testing.expectEqual(u32(2), try ceilPowerOfTwo(u32, 2)); |
| | 762 | testing.expectEqual(u32(64), try ceilPowerOfTwo(u32, 63)); |
| | 763 | testing.expectEqual(u32(64), try ceilPowerOfTwo(u32, 64)); |
| | 764 | testing.expectEqual(u32(128), try ceilPowerOfTwo(u32, 65)); |
| | 765 | testing.expectEqual(u5(8), try ceilPowerOfTwo(u5, 7)); |
| | 766 | testing.expectEqual(u5(8), try ceilPowerOfTwo(u5, 8)); |
| | 767 | testing.expectEqual(u5(16), try ceilPowerOfTwo(u5, 9)); |
| | 768 | testing.expectError(error.Overflow, ceilPowerOfTwo(u4, 9)); |
| | 769 | } |
| | 770 | |
| 699 | pub fn log2_int(comptime T: type, x: T) Log2Int(T) { | 771 | pub fn log2_int(comptime T: type, x: T) Log2Int(T) { |
| 700 | assert(x != 0); | 772 | assert(x != 0); |
| 701 | return @intCast(Log2Int(T), T.bit_count - 1 - @clz(T, x)); | 773 | return @intCast(Log2Int(T), T.bit_count - 1 - @clz(T, x)); |
| ... | @@ -722,15 +794,6 @@ test "std.math.log2_int_ceil" { | ... | @@ -722,15 +794,6 @@ test "std.math.log2_int_ceil" { |
| 722 | testing.expect(log2_int_ceil(u32, 10) == 4); | 794 | testing.expect(log2_int_ceil(u32, 10) == 4); |
| 723 | } | 795 | } |
| 724 | | 796 | |
| 725 | fn testFloorPowerOfTwo() void { | | |
| 726 | testing.expect(floorPowerOfTwo(u32, 63) == 32); | | |
| 727 | testing.expect(floorPowerOfTwo(u32, 64) == 64); | | |
| 728 | testing.expect(floorPowerOfTwo(u32, 65) == 64); | | |
| 729 | testing.expect(floorPowerOfTwo(u4, 7) == 4); | | |
| 730 | testing.expect(floorPowerOfTwo(u4, 8) == 8); | | |
| 731 | testing.expect(floorPowerOfTwo(u4, 9) == 8); | | |
| 732 | } | | |
| 733 | | | |
| 734 | pub fn lossyCast(comptime T: type, value: var) T { | 797 | pub fn lossyCast(comptime T: type, value: var) T { |
| 735 | switch (@typeInfo(@typeOf(value))) { | 798 | switch (@typeInfo(@typeOf(value))) { |
| 736 | builtin.TypeId.Int => return @intToFloat(T, value), | 799 | builtin.TypeId.Int => return @intToFloat(T, value), |