aboutsummaryrefslogtreecommitdiff
path: root/src/stack.zig
blob: 1a70be185a04e2d17d2a1e0a0deeec1bb12ef5ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
const std = @import("std");
const vector = std.meta.Vector(2, i64);

pub const Stack = struct {
    allocator: std.mem.Allocator,
    data: std.ArrayList(i64),
    pub fn clear(self: *Stack) void {
        self.data.clearRetainingCapacity();
    }
    pub fn deinit(self: *Stack) void {
        self.data.deinit();
        self.allocator.destroy(self);
    }
    pub fn duplicate(self: *Stack) !void {
        if (self.data.items.len > 0) {
            try self.push(self.data.items[self.data.items.len - 1]);
        }
    }
    test "duplicate" {
        var s = try Stack.init(std.testing.allocator);
        defer s.deinit();
        try s.duplicate();
        try std.testing.expectEqual(s.popVector(), @as(vector, [2]i64{ 0, 0 }));
        try s.pushVector([2]i64{ 1, 2 });
        try s.duplicate();
        try s.duplicate();
        try std.testing.expectEqual(s.popVector(), @as(vector, [2]i64{ 2, 2 }));
        try std.testing.expectEqual(s.popVector(), @as(vector, [2]i64{ 1, 2 }));
    }
    pub fn init(allocator: std.mem.Allocator) !*Stack {
        var s = try allocator.create(Stack);
        s.allocator = allocator;
        s.data = std.ArrayList(i64).init(allocator);
        return s;
    }
    pub fn pop(self: *Stack) i64 {
        return if (self.data.popOrNull()) |v| v else 0;
    }
    pub fn popVector(self: *Stack) [2]i64 {
        const b = if (self.data.popOrNull()) |v| v else 0;
        const a = if (self.data.popOrNull()) |v| v else 0;
        return [2]i64{ a, b };
    }
    pub fn push(self: *Stack, n: i64) !void {
        try self.data.append(n);
    }
    pub fn pushVector(self: *Stack, v: [2]i64) !void {
        try self.data.appendSlice(v[0..]);
    }
    test "pushVector" {
        var s = try Stack.init(std.testing.allocator);
        defer s.deinit();
        try s.pushVector([2]i64{ 1, -1 });
        try s.pushVector([2]i64{ 2, -2 });
        try std.testing.expectEqual(s.data.items.len, 4);
        try std.testing.expectEqual(s.data.items[0], 1);
        try std.testing.expectEqual(s.data.items[1], -1);
        try std.testing.expectEqual(s.data.items[2], 2);
        try std.testing.expectEqual(s.data.items[3], -2);
    }
    pub fn swap(self: *Stack) !void {
        const v = self.popVector();
        try self.pushVector([2]i64{ v[1], v[0] });
    }
    test "swap" {
        var s = try Stack.init(std.testing.allocator);
        defer s.deinit();
        try s.swap();
        try std.testing.expectEqual(s.popVector(), @as(vector, [2]i64{ 0, 0 }));
        try s.push(1);
        try s.swap();
        try std.testing.expectEqual(s.popVector(), @as(vector, [2]i64{ 1, 0 }));
        try s.push(2);
        try s.swap();
        try std.testing.expectEqual(s.popVector(), @as(vector, [2]i64{ 2, 0 }));
    }
    pub fn transfert(toss: *Stack, soss: *Stack, n: u64) !void {
        // Implements a value transfert between two stacks, intended for use with the '{'
        // (aka begin) and '}' (aka end) stackstack commands
        try toss.data.ensureUnusedCapacity(n);
        var i: usize = n;
        while (i >= std.math.min(soss.data.items.len, n) + 1) : (i -= 1) {
            toss.data.appendAssumeCapacity(0);
        }
        while (i >= 1) : (i -= 1) {
            toss.data.appendAssumeCapacity(soss.data.items[soss.data.items.len - i]);
        }
        if (soss.data.items.len >= n) {
            soss.data.items.len -= n;
        } else {
            soss.data.items.len = 0;
        }
    }
    test "transfert" {
        var empty = try Stack.init(std.testing.allocator);
        defer empty.deinit();
        var empty2 = try Stack.init(std.testing.allocator);
        defer empty2.deinit();
        try empty.transfert(empty2, 4);
        const emptyResult = [_]i64{ 0, 0, 0, 0 };
        try std.testing.expectEqualSlices(i64, empty.data.items, emptyResult[0..]);
        const empty2Result = [_]i64{};
        try std.testing.expectEqualSlices(i64, empty2.data.items, empty2Result[0..]);
        try empty.transfert(empty2, 32);
        try std.testing.expectEqual(empty.data.items.len, 36);
        empty.clear();
        var some = try Stack.init(std.testing.allocator);
        defer some.deinit();
        try some.push(2);
        try empty.transfert(some, 3);
        const emptyResult2 = [_]i64{ 0, 0, 2 };
        try std.testing.expectEqualSlices(i64, empty.data.items, emptyResult2[0..]);
        try std.testing.expectEqualSlices(i64, some.data.items, empty2Result[0..]);
        empty.clear();
        var full = try Stack.init(std.testing.allocator);
        defer full.deinit();
        try full.push(1);
        try full.push(2);
        try full.push(3);
        try empty.transfert(full, 2);
        const emptyResult3 = [_]i64{ 2, 3 };
        try std.testing.expectEqualSlices(i64, empty.data.items, emptyResult3[0..]);
        const fullResult = [_]i64{1};
        try std.testing.expectEqualSlices(i64, full.data.items, fullResult[0..]);
    }
};

test "all" {
    std.testing.refAllDecls(@This());
}