stage2 更多的工具库
This commit is contained in:
1 parent
b3e38ba7e4
commit
c30143609a
8 files changed
+2711
-1138
No files matched your search
+74
-41
@@ -1,11 +1,11 @@
|
||||
// Expect retcode = 0
|
||||
|
||||
// 数值/布尔格式化,写入 ByteBuffer。radix 取值 2..36;uppercase 只影响 10..35 的字母形式。
|
||||
// 不分配额外内存(除目标 ByteBuffer 自身扩容),失败不产生部分输出。
|
||||
// 整数转换统一复用 MPA。先在临时缓冲区完成转换,再一次性追加,失败不产生部分输出。
|
||||
|
||||
type .{ .Error, .Status, .make } = @import("error.spl");
|
||||
type .{ .ByteBuffer } = @import("byte_buffer.spl");
|
||||
type .{ .digit_char } = @import("ascii.spl");
|
||||
type .{ .BigInt, .Bits } = @import("mp.spl");
|
||||
|
||||
// 注意:radix 边界直接用字面量。stage1 刻意不做常量求值/折叠,
|
||||
// 顶层 const 不应用于运行时表达式。
|
||||
@@ -13,53 +13,47 @@ fn valid_radix(radix: u8): bool {
|
||||
ret radix >= 2 && radix <= 36;
|
||||
}
|
||||
|
||||
fn append_u64(out: *ByteBuffer, value: u64, radix: u8, uppercase: bool): Status {
|
||||
fn append_big_int(out: *ByteBuffer, value: BigInt,
|
||||
radix: u8, uppercase: bool): Status {
|
||||
if !valid_radix(radix) { ret .Err(make(.InvalidArgument)); }
|
||||
|
||||
var digits: [64]u8 = undefined;
|
||||
var count: usize = 0;
|
||||
|
||||
if value == 0 {
|
||||
digits[0] = '0';
|
||||
count = 1;
|
||||
} else {
|
||||
var v = value;
|
||||
var base = radix as u64;
|
||||
while v != 0 {
|
||||
var d = (v % base) as u8;
|
||||
match digit_char(d, uppercase) {
|
||||
.Ok(c) => { digits[count] = c; },
|
||||
.Err(error) => { ret .Err(error); },
|
||||
}
|
||||
count = count + 1;
|
||||
v = v / base;
|
||||
}
|
||||
var text = ByteBuffer.new();
|
||||
defer { ByteBuffer.drop(&text); }
|
||||
match BigInt.format(&text, value, radix, uppercase) {
|
||||
.Ok => {},
|
||||
.Err(error) => { ret .Err(error); },
|
||||
}
|
||||
ret ByteBuffer.append(out, ByteBuffer.as_slice(text));
|
||||
}
|
||||
|
||||
// digits 是低位在前,反向写入得到正常顺序。
|
||||
var i = count;
|
||||
while i > 0 {
|
||||
i = i - 1;
|
||||
match ByteBuffer.append_byte(out, digits[i]) {
|
||||
.Ok => {},
|
||||
.Err(error) => { ret .Err(error); },
|
||||
}
|
||||
fn append_bits(out: *ByteBuffer, value: Bits, signed: bool,
|
||||
radix: u8, uppercase: bool): Status {
|
||||
var integer = BigInt.zero();
|
||||
defer { BigInt.drop(&integer); }
|
||||
match Bits.to_big(&integer, value, signed) {
|
||||
.Ok => {},
|
||||
.Err(error) => { ret .Err(error); },
|
||||
}
|
||||
ret .Ok;
|
||||
ret append_big_int(out, integer, radix, uppercase);
|
||||
}
|
||||
|
||||
fn append_u64(out: *ByteBuffer, value: u64, radix: u8, uppercase: bool): Status {
|
||||
var integer = BigInt.zero();
|
||||
defer { BigInt.drop(&integer); }
|
||||
match BigInt.from_u64(&integer, value) {
|
||||
.Ok => {},
|
||||
.Err(error) => { ret .Err(error); },
|
||||
}
|
||||
ret append_big_int(out, integer, radix, uppercase);
|
||||
}
|
||||
|
||||
fn append_i64(out: *ByteBuffer, value: i64, radix: u8, uppercase: bool): Status {
|
||||
if !valid_radix(radix) { ret .Err(make(.InvalidArgument)); }
|
||||
if value < 0 {
|
||||
match ByteBuffer.append_byte(out, '-') {
|
||||
.Ok => {},
|
||||
.Err(error) => { ret .Err(error); },
|
||||
}
|
||||
// value 为补码,(0 - (value as u64)) 得到绝对值(含 i64 最小值)。
|
||||
var magnitude = 0 - (value as u64);
|
||||
ret append_u64(out, magnitude, radix, uppercase);
|
||||
var integer = BigInt.zero();
|
||||
defer { BigInt.drop(&integer); }
|
||||
match BigInt.from_i64(&integer, value) {
|
||||
.Ok => {},
|
||||
.Err(error) => { ret .Err(error); },
|
||||
}
|
||||
ret append_u64(out, value as u64, radix, uppercase);
|
||||
ret append_big_int(out, integer, radix, uppercase);
|
||||
}
|
||||
|
||||
fn append_usize(out: *ByteBuffer, value: usize, radix: u8, uppercase: bool): Status {
|
||||
@@ -201,6 +195,44 @@ fn test_usize_bool_and_errors() {
|
||||
expect_invalid(append_u64(&b, 1, 37, false));
|
||||
expect_invalid(append_i64(&b, -1, 0, false));
|
||||
@assert(ByteBuffer.size(b) == 0, "invalid radix writes nothing");
|
||||
|
||||
expect_ok(ByteBuffer.append(&b, "prefix"));
|
||||
expect_invalid(append_i64(&b, -123, 1, false));
|
||||
expect_text(&b, "prefix");
|
||||
}
|
||||
|
||||
fn test_mpa_integer_formatting() {
|
||||
var b = ByteBuffer.new();
|
||||
defer { ByteBuffer.drop(&b); }
|
||||
|
||||
var huge = BigInt.zero();
|
||||
defer { BigInt.drop(&huge); }
|
||||
expect_ok(BigInt.parse(&huge, "1234567890123456789012345678901234567890", 10));
|
||||
expect_ok(append_big_int(&b, huge, 10, false));
|
||||
expect_text(&b, "1234567890123456789012345678901234567890");
|
||||
ByteBuffer.clear(&b);
|
||||
|
||||
expect_ok(BigInt.parse(&huge, "-ffffffffffffffffffffffffffffffff", 16));
|
||||
expect_ok(append_big_int(&b, huge, 16, true));
|
||||
expect_text(&b, "-FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
|
||||
ByteBuffer.clear(&b);
|
||||
|
||||
var raw = BigInt.zero();
|
||||
defer { BigInt.drop(&raw); }
|
||||
expect_ok(BigInt.from_u64(&raw, 255));
|
||||
var bits: Bits = undefined;
|
||||
match Bits.new(8) {
|
||||
.Ok(value) => { bits = value; },
|
||||
.Err(error) => { @assert(false, "Bits construction"); },
|
||||
}
|
||||
defer { Bits.drop(&bits); }
|
||||
expect_ok(Bits.from_big_checked(&bits, raw, 8, false));
|
||||
|
||||
expect_ok(append_bits(&b, bits, false, 10, false));
|
||||
expect_text(&b, "255");
|
||||
ByteBuffer.clear(&b);
|
||||
expect_ok(append_bits(&b, bits, true, 10, false));
|
||||
expect_text(&b, "-1");
|
||||
}
|
||||
|
||||
fn test_composition_and_growth() {
|
||||
@@ -234,5 +266,6 @@ fn main() {
|
||||
test_unsigned();
|
||||
test_signed();
|
||||
test_usize_bool_and_errors();
|
||||
test_mpa_integer_formatting();
|
||||
test_composition_and_growth();
|
||||
}
|
||||
Reference in new issue
Block a user