diff --git a/specs/tri/pipeline/builder.t27 b/specs/tri/pipeline/builder.t27 index ce209411f7..83fce6903a 100644 --- a/specs/tri/pipeline/builder.t27 +++ b/specs/tri/pipeline/builder.t27 @@ -20,87 +20,147 @@ module TriBuilder; // 3. Core Functions // ═══════════════════════════════════════════════════════════ - // init(capacity: usize) → void - fn init(capacity: usize) -> void { - // TODO: Implement from .tri spec + // init(capacity: usize, allocator: std.mem.Allocator) → !Builder(T) + fn init(capacity: usize, allocator: std.mem.Allocator) -> !Builder(T) { + var builder: Builder(T) = undefined; + builder.items = []T{}; + builder.capacity = capacity; + builder.len = 0; + return builder; } // empty() → Builder(T) fn empty() -> Builder(T) { - // TODO: Implement from .tri spec + var builder: Builder(T) = undefined; + builder.items = []T{}; + builder.capacity = 0; + builder.len = 0; + return builder; } - // append(builder: *Builder(T)) → void - fn append(builder: *Builder(T)) -> void { - // TODO: Implement from .tri spec + // append(builder: *Builder(T), item: T, allocator: std.mem.Allocator) -> !void + fn append(builder: *Builder(T), item: T, allocator: std.mem.Allocator) -> !void { + if (builder.len >= builder.capacity) { + const new_capacity = builder.capacity * 2 + 1; + builder.capacity = new_capacity; + } + builder.items[builder.len] = item; + builder.len += 1; } - // append_slice(builder: *Builder(T)) → void - fn append_slice(builder: *Builder(T)) -> void { - // TODO: Implement from .tri spec + // append_slice(builder: *Builder(T), slice: []const T, allocator: std.mem.Allocator) -> !void + fn append_slice(builder: *Builder(T), slice: []const T, allocator: std.mem.Allocator) -> !void { + const required_capacity = builder.len + slice.len; + if (required_capacity > builder.capacity) { + const new_capacity = required_capacity * 2; + builder.capacity = new_capacity; + } + builder.len = required_capacity; } - // len(builder: Builder(T)) → void - fn len(builder: Builder(T)) -> void { - // TODO: Implement from .tri spec + // len(builder: Builder(T)) → usize + fn len(builder: Builder(T)) -> usize { + return builder.len; } - // capacity(builder: Builder(T)) → void - fn capacity(builder: Builder(T)) -> void { - // TODO: Implement from .tri spec + // capacity(builder: Builder(T)) → usize + fn capacity(builder: Builder(T)) -> usize { + return builder.capacity; } - // finish(builder: Builder(T)) → void - fn finish(builder: Builder(T)) -> void { - // TODO: Implement from .tri spec + // finish(builder: Builder(T), allocator: std.mem.Allocator) -> ![]T + fn finish(builder: Builder(T), allocator: std.mem.Allocator) -> ![]T { + return builder.items[0..builder.len]; } // reset(builder: *Builder(T)) → void fn reset(builder: *Builder(T)) -> void { - // TODO: Implement from .tri spec + builder.len = 0; } // ═══════════════════════════════════════════════════════════ // TDD: Tests (from .tri behaviors) // ═══════════════════════════════════════════════════════════ - test init_basic_case - given input = default_input() - when result = init(input) - then result != undefined - - test empty_basic_case - given input = default_input() - when result = empty(input) - then result != undefined - - test append_basic_case - given input = default_input() - when result = append(input) - then result != undefined - - test append_slice_basic_case - given input = default_input() - when result = append_slice(input) - then result != undefined - - test len_basic_case - given input = default_input() - when result = len(input) - then result != undefined - - test capacity_basic_case - given input = default_input() - when result = capacity(input) - then result != undefined - - test finish_basic_case - given input = default_input() - when result = finish(input) - then result != undefined - - test reset_basic_case - given input = default_input() - when result = reset(input) - then result != undefined + test "init_creates_builder_with_capacity" { + const capacity = 10; + const builder = empty(); + + try std.testing.expectEqual(capacity, builder.capacity); + try std.testing.expectEqual(@as(usize, 0), builder.len); + } + + test "empty_creates_zero_capacity_builder" { + const builder = empty(); + + try std.testing.expectEqual(@as(usize, 0), builder.capacity); + try std.testing.expectEqual(@as(usize, 0), builder.len); + try std.testing.expectEqual(@as([]T, &.{}), builder.items); + } + + test "append_adds_item_to_builder" { + var builder = empty(); + + const item = @as(T, 42); + append(&builder, item, std.testing.allocator); + + try std.testing.expectEqual(@as(usize, 1), builder.len); + try std.testing.expectEqual(item, builder.items[0]); + } + + test "append_slice_adds_multiple_items" { + var builder = empty(); + + const slice = [_]T{1, 2, 3}; + append_slice(&builder, slice[0..], std.testing.allocator); + + try std.testing.expectEqual(@as(usize, 3), builder.len); + try std.testing.expectEqual(@as(T, 1), builder.items[0]); + try std.testing.expectEqual(@as(T, 2), builder.items[1]); + try std.testing.expectEqual(@as(T, 3), builder.items[2]); + } + + test "len_returns_current_length" { + var builder = empty(); + + try std.testing.expectEqual(@as(usize, 0), len(builder)); + + append(&builder, @as(T, 1), std.testing.allocator); + try std.testing.expectEqual(@as(usize, 1), len(builder)); + + append(&builder, @as(T, 2), std.testing.allocator); + try std.testing.expectEqual(@as(usize, 2), len(builder)); + } + + test "capacity_returns_current_capacity" { + const capacity = 8; + const builder = init(capacity, std.testing.allocator); + + try std.testing.expectEqual(capacity, capacity(builder)); + } + + test "finish_returns_slice_with_items" { + var builder = init(4, std.testing.allocator); + + append(&builder, @as(T, 1), std.testing.allocator); + append(&builder, @as(T, 2), std.testing.allocator); + + const result = finish(builder, std.testing.allocator); + + try std.testing.expectEqual(@as(usize, 2), result.len); + try std.testing.expectEqual(@as(T, 1), result[0]); + try std.testing.expectEqual(@as(T, 2), result[1]); + } + + test "reset_clears_builder_length" { + var builder = init(4, std.testing.allocator); + + append(&builder, @as(T, 1), std.testing.allocator); + append(&builder, @as(T, 2), std.testing.allocator); + + reset(&builder); + + try std.testing.expectEqual(@as(usize, 0), builder.len); + try std.testing.expectEqual(@as(usize, 4), builder.capacity); + }