Advertisement
Guest User

Untitled

a guest
Feb 18th, 2019
154
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.19 KB | None | 0 0
  1. const std = @import("std");
  2. const TypeId = @import("builtin").TypeId;
  3.  
  4. fn is_signed(comptime N: type) bool {
  5.     switch (@typeInfo(N)) {
  6.         TypeId.Int => |int| {
  7.             return int.is_signed;
  8.         },
  9.         else => {
  10.             @compileError("Is_signed is only available on integer types. Found `" ++ @typeName(N) ++ "`.");
  11.         }
  12.     }
  13. }
  14.  
  15. fn bitcount(comptime N: type) u32 {
  16.     switch (@typeInfo(N)) {
  17.         TypeId.Int => |int| {
  18.             return @intCast(u32, int.bits);
  19.         },
  20.         else => {
  21.             @compileError("Bitcount only available on integer types. Found `" ++ @typeName(N) ++ "`.");
  22.         }
  23.     }
  24. }
  25.  
  26. fn is_negative(comptime N: type, num: N) bool {
  27.     return num < 0;
  28. }
  29.  
  30. fn digits10(comptime N: type, n: N, comptime unroll: ?u8) usize {
  31.  
  32.     // If we encouter a signed int,
  33.     // check if it's negative,
  34.     // if so, multiply by minus one (make positive), and call digits10 on the unsigned version of the int,
  35.     // if not negative, just call digits10 on the unsigned version,
  36.     // and if we dont encouter a signed int, just skip this whole if :)
  37.     if (comptime is_signed(N)) {
  38.  
  39.         const nbits = comptime bitcount(N);
  40.  
  41.         const unsigned_friend = @IntType(false, nbits);
  42.  
  43.         if (is_negative(N, n)) {
  44.             // we can't use @intCast for some reason :(
  45.             var num = @bitCast(unsigned_friend, n *% -1);
  46.  
  47.             return digits10(unsigned_friend, num, unroll);
  48.         }
  49.         else {
  50.             return digits10(unsigned_friend, @intCast(unsigned_friend, n), unroll);
  51.         }
  52.     }
  53.  
  54.     comptime var digits: usize = 1;
  55.     comptime var check: usize = 10;
  56.  
  57.     if (comptime unroll) |unroll_count| {
  58.         var num: usize = n;
  59.         var result: usize = 0;
  60.         comptime var counter: usize = 0;
  61.  
  62.         while (true) {
  63.             inline while (counter != unroll_count) : ({counter += 1; check *= 10; digits += 1;}) {
  64.                 if (num < check) {
  65.                     return result + digits;
  66.                 }
  67.             }
  68.            
  69.             result += unroll_count;
  70.             num /= comptime (check / 10);
  71.         }
  72.     } else {
  73.         comptime var overflowed1 = false;
  74.         comptime var overflowed2 = false;
  75.         inline while (check <= @maxValue(N) and (!overflowed1 and !overflowed2)) : (
  76.             {
  77.                 overflowed1 = @mulWithOverflow(usize, check, 10, &check);
  78.                 overflowed2 = @addWithOverflow(usize, digits, 1, &digits);
  79.             }
  80.         ) {
  81.             if (n < check) {
  82.                 return digits;
  83.             }
  84.         }
  85.         return digits;
  86.     }
  87. }
  88.  
  89. fn iter(comptime N: usize) [N]void {
  90.     return undefined;
  91. }
  92.  
  93.  
  94. fn assert_value(length: usize, comptime inttype: type, input: inttype, comptime unroll_count: ?u8) void {
  95.     std.debug.assert(length == digits10(inttype, input, unroll_count));
  96. }
  97.  
  98. test "corner cases" {
  99.  
  100.     const bitcounts = []u32 {8, 16, 32, 64};
  101.     const lenghts = []usize {3, 5, 10, 19};
  102.  
  103.     inline for(bitcounts) |nbits, idx| {
  104.         comptime var unsigned_type = @IntType(false, @intCast(u32, nbits));
  105.         comptime var signed_type =  @IntType(true, @intCast(u32, nbits));
  106.            
  107.         const length = lenghts[idx];
  108.  
  109.         inline for (comptime iter(10)) |_, i| {
  110.             const unroll_count = @intCast(u8, i + 1);
  111.  
  112.             assert_value(length, signed_type, @minValue(signed_type), unroll_count);
  113.             assert_value(length, signed_type, @maxValue(signed_type), unroll_count);
  114.  
  115.             assert_value(1, unsigned_type, 0, unroll_count);
  116.  
  117.             // i64 has a length of 19, but u64 20.. :3
  118.             if (unsigned_type == u64) {
  119.                 assert_value(length + 1, unsigned_type, @maxValue(unsigned_type), unroll_count);
  120.             } else {
  121.                 assert_value(length, unsigned_type, @maxValue(unsigned_type), unroll_count);
  122.             }
  123.         }
  124.  
  125.         assert_value(1, unsigned_type, 0, null);
  126.  
  127.         if (unsigned_type == u64) {
  128.             assert_value(length + 1, unsigned_type, @maxValue(unsigned_type), null);
  129.         } else {
  130.             assert_value(length, unsigned_type, @maxValue(unsigned_type), null);
  131.         }
  132.     }
  133. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement