mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
137 lines
3.3 KiB
Zig
137 lines
3.3 KiB
Zig
//! A wrapper over a byte-slice, providing useful methods for parsing string floating point values.
|
|
|
|
const std = @import("std");
|
|
const FloatStream = @This();
|
|
const common = @import("common.zig");
|
|
|
|
slice: []const u8,
|
|
offset: usize,
|
|
underscore_count: usize,
|
|
|
|
pub fn init(s: []const u8) FloatStream {
|
|
return .{ .slice = s, .offset = 0, .underscore_count = 0 };
|
|
}
|
|
|
|
// Returns the offset from the start *excluding* any underscores that were found.
|
|
pub fn offsetTrue(self: FloatStream) usize {
|
|
return self.offset - self.underscore_count;
|
|
}
|
|
|
|
pub fn reset(self: *FloatStream) void {
|
|
self.offset = 0;
|
|
self.underscore_count = 0;
|
|
}
|
|
|
|
pub fn len(self: FloatStream) usize {
|
|
if (self.offset > self.slice.len) {
|
|
return 0;
|
|
}
|
|
return self.slice.len - self.offset;
|
|
}
|
|
|
|
pub fn hasLen(self: FloatStream, n: usize) bool {
|
|
return self.offset + n <= self.slice.len;
|
|
}
|
|
|
|
pub fn firstUnchecked(self: FloatStream) u8 {
|
|
return self.slice[self.offset];
|
|
}
|
|
|
|
pub fn first(self: FloatStream) ?u8 {
|
|
return if (self.hasLen(1))
|
|
return self.firstUnchecked()
|
|
else
|
|
null;
|
|
}
|
|
|
|
pub fn isEmpty(self: FloatStream) bool {
|
|
return !self.hasLen(1);
|
|
}
|
|
|
|
pub fn firstIs(self: FloatStream, c: u8) bool {
|
|
if (self.first()) |ok| {
|
|
return ok == c;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
pub fn firstIsLower(self: FloatStream, c: u8) bool {
|
|
if (self.first()) |ok| {
|
|
return ok | 0x20 == c;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
pub fn firstIs2(self: FloatStream, c1: u8, c2: u8) bool {
|
|
if (self.first()) |ok| {
|
|
return ok == c1 or ok == c2;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
pub fn firstIs3(self: FloatStream, c1: u8, c2: u8, c3: u8) bool {
|
|
if (self.first()) |ok| {
|
|
return ok == c1 or ok == c2 or ok == c3;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
pub fn firstIsDigit(self: FloatStream, comptime base: u8) bool {
|
|
comptime std.debug.assert(base == 10 or base == 16);
|
|
|
|
if (self.first()) |ok| {
|
|
return common.isDigit(ok, base);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
pub fn advance(self: *FloatStream, n: usize) void {
|
|
self.offset += n;
|
|
}
|
|
|
|
pub fn skipChars(self: *FloatStream, c: u8) void {
|
|
while (self.firstIs(c)) : (self.advance(1)) {}
|
|
}
|
|
|
|
pub fn skipChars2(self: *FloatStream, c1: u8, c2: u8) void {
|
|
while (self.firstIs2(c1, c2)) : (self.advance(1)) {}
|
|
}
|
|
|
|
pub fn readU64Unchecked(self: FloatStream) u64 {
|
|
return std.mem.readInt(u64, self.slice[self.offset..][0..8], .little);
|
|
}
|
|
|
|
pub fn readU64(self: FloatStream) ?u64 {
|
|
if (self.hasLen(8)) {
|
|
return self.readU64Unchecked();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
pub fn atUnchecked(self: *FloatStream, i: usize) u8 {
|
|
return self.slice[self.offset + i];
|
|
}
|
|
|
|
pub fn scanDigit(self: *FloatStream, comptime base: u8) ?u8 {
|
|
comptime std.debug.assert(base == 10 or base == 16);
|
|
|
|
retry: while (true) {
|
|
if (self.first()) |ok| {
|
|
if ('0' <= ok and ok <= '9') {
|
|
self.advance(1);
|
|
return ok - '0';
|
|
} else if (base == 16 and 'a' <= ok and ok <= 'f') {
|
|
self.advance(1);
|
|
return ok - 'a' + 10;
|
|
} else if (base == 16 and 'A' <= ok and ok <= 'F') {
|
|
self.advance(1);
|
|
return ok - 'A' + 10;
|
|
} else if (ok == '_') {
|
|
self.advance(1);
|
|
self.underscore_count += 1;
|
|
continue :retry;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|