aboutsummaryrefslogtreecommitdiff
path: root/src/view_stack.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/view_stack.zig')
-rw-r--r--src/view_stack.zig406
1 files changed, 0 insertions, 406 deletions
diff --git a/src/view_stack.zig b/src/view_stack.zig
deleted file mode 100644
index 0543d03..0000000
--- a/src/view_stack.zig
+++ /dev/null
@@ -1,406 +0,0 @@
-// This file is part of river, a dynamic tiling wayland compositor.
-//
-// Copyright 2020 Isaac Freund
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-const View = @import("View.zig");
-
-/// A specialized doubly-linked stack that allows for filtered iteration
-/// over the nodes. T must be View or *View.
-pub fn ViewStack(comptime T: type) type {
- if (!(T == View or T == *View)) {
- @compileError("ViewStack: T must be View or *View");
- }
- return struct {
- const Self = @This();
-
- pub const Node = struct {
- /// Previous/next nodes in the stack
- prev: ?*Node,
- next: ?*Node,
-
- /// The view stored in this node
- view: T,
- };
-
- /// Top/bottom nodes in the stack
- first: ?*Node,
- last: ?*Node,
-
- /// Initialize an undefined stack
- pub fn init(self: *Self) void {
- self.first = null;
- self.last = null;
- }
-
- /// Add a node to the top of the stack.
- pub fn push(self: *Self, new_node: *Node) void {
- // Set the prev/next pointers of the new node
- new_node.prev = null;
- new_node.next = self.first;
-
- if (self.first) |first| {
- // If the list is not empty, set the prev pointer of the current
- // first node to the new node.
- first.prev = new_node;
- } else {
- // If the list is empty set the last pointer to the new node.
- self.last = new_node;
- }
-
- // Set the first pointer to the new node
- self.first = new_node;
- }
-
- /// Remove a node from the view stack. This removes it from the stack of
- /// all views as well as the stack of visible ones.
- pub fn remove(self: *Self, target_node: *Node) void {
- // Set the previous node/list head to the next pointer
- if (target_node.prev) |prev_node| {
- prev_node.next = target_node.next;
- } else {
- self.first = target_node.next;
- }
-
- // Set the next node/list tail to the previous pointer
- if (target_node.next) |next_node| {
- next_node.prev = target_node.prev;
- } else {
- self.last = target_node.prev;
- }
- }
-
- const Iterator = struct {
- it: ?*Node,
- tags: u32,
- reverse: bool,
- pending: bool,
-
- /// Returns the next node in iteration order, or null if done.
- /// This function is horribly ugly, but it's well tested below.
- pub fn next(self: *Iterator) ?*Node {
- while (self.it) |node| : (self.it = if (self.reverse) node.prev else node.next) {
- if (if (self.pending)
- if (node.view.pending_tags) |pending_tags|
- self.tags & pending_tags != 0
- else
- self.tags & node.view.current_tags != 0
- else
- self.tags & node.view.current_tags != 0) {
- self.it = if (self.reverse) node.prev else node.next;
- return node;
- }
- }
- return null;
- }
- };
-
- /// Returns an iterator starting at the passed node and filtered by
- /// checking the passed tags against the current tags of each view.
- pub fn iterator(start: ?*Node, tags: u32) Iterator {
- return Iterator{
- .it = start,
- .tags = tags,
- .reverse = false,
- .pending = false,
- };
- }
-
- /// Returns a reverse iterator starting at the passed node and filtered by
- /// checking the passed tags against the current tags of each view.
- pub fn reverseIterator(start: ?*Node, tags: u32) Iterator {
- return Iterator{
- .it = start,
- .tags = tags,
- .reverse = true,
- .pending = false,
- };
- }
-
- /// Returns an iterator starting at the passed node and filtered by
- /// checking the passed tags against the pending tags of each view.
- /// If a view has no pending tags, the current tags are used.
- pub fn pendingIterator(start: ?*Node, tags: u32) Iterator {
- return Iterator{
- .it = start,
- .tags = tags,
- .reverse = false,
- .pending = true,
- };
- }
- };
-}
-
-test "push/remove (*View)" {
- const testing = @import("std").testing;
-
- const allocator = testing.allocator;
-
- var views: ViewStack(*View) = undefined;
- views.init();
-
- const one = try allocator.create(ViewStack(*View).Node);
- defer allocator.destroy(one);
- const two = try allocator.create(ViewStack(*View).Node);
- defer allocator.destroy(two);
- const three = try allocator.create(ViewStack(*View).Node);
- defer allocator.destroy(three);
- const four = try allocator.create(ViewStack(*View).Node);
- defer allocator.destroy(four);
- const five = try allocator.create(ViewStack(*View).Node);
- defer allocator.destroy(five);
-
- views.push(three); // {3}
- views.push(one); // {1, 3}
- views.push(four); // {4, 1, 3}
- views.push(five); // {5, 4, 1, 3}
- views.push(two); // {2, 5, 4, 1, 3}
-
- // Simple insertion
- {
- var it = views.first;
- testing.expect(it == two);
- it = it.?.next;
- testing.expect(it == five);
- it = it.?.next;
- testing.expect(it == four);
- it = it.?.next;
- testing.expect(it == one);
- it = it.?.next;
- testing.expect(it == three);
- it = it.?.next;
-
- testing.expect(it == null);
-
- testing.expect(views.first == two);
- testing.expect(views.last == three);
- }
-
- // Removal of first
- views.remove(two);
- {
- var it = views.first;
- testing.expect(it == five);
- it = it.?.next;
- testing.expect(it == four);
- it = it.?.next;
- testing.expect(it == one);
- it = it.?.next;
- testing.expect(it == three);
- it = it.?.next;
-
- testing.expect(it == null);
-
- testing.expect(views.first == five);
- testing.expect(views.last == three);
- }
-
- // Removal of last
- views.remove(three);
- {
- var it = views.first;
- testing.expect(it == five);
- it = it.?.next;
- testing.expect(it == four);
- it = it.?.next;
- testing.expect(it == one);
- it = it.?.next;
-
- testing.expect(it == null);
-
- testing.expect(views.first == five);
- testing.expect(views.last == one);
- }
-
- // Remove from middle
- views.remove(four);
- {
- var it = views.first;
- testing.expect(it == five);
- it = it.?.next;
- testing.expect(it == one);
- it = it.?.next;
-
- testing.expect(it == null);
-
- testing.expect(views.first == five);
- testing.expect(views.last == one);
- }
-
- // Reinsertion
- views.push(two);
- views.push(three);
- views.push(four);
- {
- var it = views.first;
- testing.expect(it == four);
- it = it.?.next;
- testing.expect(it == three);
- it = it.?.next;
- testing.expect(it == two);
- it = it.?.next;
- testing.expect(it == five);
- it = it.?.next;
- testing.expect(it == one);
- it = it.?.next;
-
- testing.expect(it == null);
-
- testing.expect(views.first == four);
- testing.expect(views.last == one);
- }
-
- // Clear
- views.remove(four);
- views.remove(two);
- views.remove(three);
- views.remove(one);
- views.remove(five);
-
- testing.expect(views.first == null);
- testing.expect(views.last == null);
-}
-
-test "iteration (View)" {
- const c = @import("c.zig");
- const testing = @import("std").testing;
-
- const allocator = testing.allocator;
-
- var views: ViewStack(View) = undefined;
- views.init();
-
- const one_a_pb = try allocator.create(ViewStack(View).Node);
- defer allocator.destroy(one_a_pb);
- one_a_pb.view.current_tags = 1 << 0;
- one_a_pb.view.pending_tags = 1 << 1;
-
- const two_a = try allocator.create(ViewStack(View).Node);
- defer allocator.destroy(two_a);
- two_a.view.current_tags = 1 << 0;
- two_a.view.pending_tags = null;
-
- const three_b_pa = try allocator.create(ViewStack(View).Node);
- defer allocator.destroy(three_b_pa);
- three_b_pa.view.current_tags = 1 << 1;
- three_b_pa.view.pending_tags = 1 << 0;
-
- const four_b = try allocator.create(ViewStack(View).Node);
- defer allocator.destroy(four_b);
- four_b.view.current_tags = 1 << 1;
- four_b.view.pending_tags = null;
-
- const five_b = try allocator.create(ViewStack(View).Node);
- defer allocator.destroy(five_b);
- five_b.view.current_tags = 1 << 1;
- five_b.view.pending_tags = null;
-
- views.push(three_b_pa); // {3}
- views.push(one_a_pb); // {1, 3}
- views.push(four_b); // {4, 1, 3}
- views.push(five_b); // {5, 4, 1, 3}
- views.push(two_a); // {2, 5, 4, 1, 3}
-
- // Iteration over all tags
- {
- var it = ViewStack(View).iterator(views.first, 0xFFFFFFFF);
- testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
- testing.expect(it.next() == null);
- }
-
- // Iteration over 'a' tags
- {
- var it = ViewStack(View).iterator(views.first, 1 << 0);
- testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
- testing.expect(it.next() == null);
- }
-
- // Iteration over 'b' tags
- {
- var it = ViewStack(View).iterator(views.first, 1 << 1);
- testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
- testing.expect(it.next() == null);
- }
-
- // Iteration over tags that aren't present
- {
- var it = ViewStack(View).iterator(views.first, 1 << 2);
- testing.expect(it.next() == null);
- }
-
- // Reverse iteration over all tags
- {
- var it = ViewStack(View).reverseIterator(views.last, 0xFFFFFFFF);
- testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
- testing.expect(it.next() == null);
- }
-
- // Reverse iteration over 'a' tags
- {
- var it = ViewStack(View).reverseIterator(views.last, 1 << 0);
- testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
- testing.expect(it.next() == null);
- }
-
- // Reverse iteration over 'b' tags
- {
- var it = ViewStack(View).reverseIterator(views.last, 1 << 1);
- testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
- testing.expect(it.next() == null);
- }
-
- // Reverse iteration over tags that aren't present
- {
- var it = ViewStack(View).reverseIterator(views.first, 1 << 2);
- testing.expect(it.next() == null);
- }
-
- // Iteration over (pending) 'a' tags
- {
- var it = ViewStack(View).pendingIterator(views.first, 1 << 0);
- testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
- testing.expect(it.next() == null);
- }
-
- // Iteration over (pending) 'b' tags
- {
- var it = ViewStack(View).pendingIterator(views.first, 1 << 1);
- testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
- testing.expect(it.next() == null);
- }
-
- // Iteration over (pending) tags that aren't present
- {
- var it = ViewStack(View).pendingIterator(views.first, 1 << 2);
- testing.expect(it.next() == null);
- }
-}