Function toString [src]

Converts self to a string in the requested base. Asserts that base is in the range [2, 36]. string is a caller-provided slice of at least sizeInBaseUpperBound bytes, where the result is written to. Returns the length of the string. limbs_buffer is caller-provided memory for toString to use as a working area. It must have length of at least calcToStringLimbsBufferLen. In the case of power-of-two base, limbs_buffer is ignored. See also toStringAlloc, a higher level function than this.

Prototype

pub fn toString(self: Const, string: []u8, base: u8, case: std.fmt.Case, limbs_buffer: []Limb) usize

Parameters

self: Conststring: []u8base: u8case: std.fmt.Caselimbs_buffer: []Limb

Source

pub fn toString(self: Const, string: []u8, base: u8, case: std.fmt.Case, limbs_buffer: []Limb) usize { assert(base >= 2); assert(base <= 36); if (self.eqlZero()) { string[0] = '0'; return 1; } var digits_len: usize = 0; // Power of two: can do a single pass and use masks to extract digits. if (math.isPowerOfTwo(base)) { const base_shift = math.log2_int(Limb, base); outer: for (self.limbs[0..self.limbs.len]) |limb| { var shift: usize = 0; while (shift < limb_bits) : (shift += base_shift) { const r = @as(u8, @intCast((limb >> @as(Log2Limb, @intCast(shift))) & @as(Limb, base - 1))); const ch = std.fmt.digitToChar(r, case); string[digits_len] = ch; digits_len += 1; // If we hit the end, it must be all zeroes from here. if (digits_len == string.len) break :outer; } } // Always will have a non-zero digit somewhere. while (string[digits_len - 1] == '0') { digits_len -= 1; } } else { // Non power-of-two: batch divisions per word size. // We use a HalfLimb here so the division uses the faster lldiv0p5 over lldiv1 codepath. const digits_per_limb = math.log(HalfLimb, base, maxInt(HalfLimb)); var limb_base: Limb = 1; var j: usize = 0; while (j < digits_per_limb) : (j += 1) { limb_base *= base; } const b: Const = .{ .limbs = &[_]Limb{limb_base}, .positive = true }; var q: Mutable = .{ .limbs = limbs_buffer[0 .. self.limbs.len + 2], .positive = true, // Make absolute by ignoring self.positive. .len = self.limbs.len, }; @memcpy(q.limbs[0..self.limbs.len], self.limbs); var r: Mutable = .{ .limbs = limbs_buffer[q.limbs.len..][0..self.limbs.len], .positive = true, .len = 1, }; r.limbs[0] = 0; const rest_of_the_limbs_buf = limbs_buffer[q.limbs.len + r.limbs.len ..]; while (q.len >= 2) { // Passing an allocator here would not be helpful since this division is destroying // information, not creating it. [TODO citation needed] q.divTrunc(&r, q.toConst(), b, rest_of_the_limbs_buf); var r_word = r.limbs[0]; var i: usize = 0; while (i < digits_per_limb) : (i += 1) { const ch = std.fmt.digitToChar(@as(u8, @intCast(r_word % base)), case); r_word /= base; string[digits_len] = ch; digits_len += 1; } } { assert(q.len == 1); var r_word = q.limbs[0]; while (r_word != 0) { const ch = std.fmt.digitToChar(@as(u8, @intCast(r_word % base)), case); r_word /= base; string[digits_len] = ch; digits_len += 1; } } } if (!self.positive) { string[digits_len] = '-'; digits_len += 1; } const s = string[0..digits_len]; mem.reverse(u8, s); return s.len; }