aboutsummaryrefslogtreecommitdiff
path: root/src/stack.zig
blob: 58c7103c833833efda7539b5caf786e31f1751a4 (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
const std = @import("std");
const vector = @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 {
        const v = self.pop();
        try self.pushVector([2]i64{ v, v });
    }
    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 >= @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..]);
    }
    pub fn discard(self: *Stack, n: u64) void {
        // Implements a discard mechanism intended for use with the '}'(aka end) stackstack command
        if (self.data.items.len > n) {
            self.data.items.len -= n;
        } else {
            self.data.items.len = 0;
        }
    }
    test "discard" {
        var empty = try Stack.init(std.testing.allocator);
        defer empty.deinit();
        empty.discard(1);
        const emptyResult = [_]i64{};
        try std.testing.expectEqualSlices(i64, empty.data.items, emptyResult[0..]);
        try empty.push(2);
        empty.discard(3);
        try std.testing.expectEqualSlices(i64, empty.data.items, emptyResult[0..]);
        try empty.push(4);
        try empty.push(5);
        try empty.push(6);
        empty.discard(1);
        const emptyResult2 = [_]i64{ 4, 5 };
        try std.testing.expectEqualSlices(i64, empty.data.items, emptyResult2[0..]);
    }
    pub fn yCommandPick(self: *Stack, n: usize, h: usize) !void {
        if (n > self.data.items.len) {
            self.data.items.len = 1;
            self.data.items[0] = 0;
        } else {
            const v = self.data.items[self.data.items.len - n];
            self.data.items.len = h;
            try self.push(v);
        }
    }
};