| ... | @@ -5,6 +5,10 @@ const testing = std.testing; | ... | @@ -5,6 +5,10 @@ const testing = std.testing; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | const Allocator = mem.Allocator; | 6 | const Allocator = mem.Allocator; |
| 7 | | 7 | |
| | 8 | /// List of items. |
| | 9 | /// |
| | 10 | /// This is a wrapper around an array of T values. Initialize with |
| | 11 | /// `init`. |
| 8 | pub fn ArrayList(comptime T: type) type { | 12 | pub fn ArrayList(comptime T: type) type { |
| 9 | return AlignedArrayList(T, null); | 13 | return AlignedArrayList(T, null); |
| 10 | } | 14 | } |
| ... | @@ -37,18 +41,24 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -37,18 +41,24 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { |
| 37 | }; | 41 | }; |
| 38 | } | 42 | } |
| 39 | | 43 | |
| | 44 | /// Release all allocated memory. |
| 40 | pub fn deinit(self: Self) void { | 45 | pub fn deinit(self: Self) void { |
| 41 | self.allocator.free(self.items); | 46 | self.allocator.free(self.items); |
| 42 | } | 47 | } |
| 43 | | 48 | |
| | 49 | /// Return contents as a slice. Only valid while the list |
| | 50 | /// doesn't change size. |
| 44 | pub fn toSlice(self: Self) Slice { | 51 | pub fn toSlice(self: Self) Slice { |
| 45 | return self.items[0..self.len]; | 52 | return self.items[0..self.len]; |
| 46 | } | 53 | } |
| 47 | | 54 | |
| | 55 | /// Return list as const slice. Only valid while the list |
| | 56 | /// doesn't change size. |
| 48 | pub fn toSliceConst(self: Self) SliceConst { | 57 | pub fn toSliceConst(self: Self) SliceConst { |
| 49 | return self.items[0..self.len]; | 58 | return self.items[0..self.len]; |
| 50 | } | 59 | } |
| 51 | | 60 | |
| | 61 | /// Safely access index i of the list. |
| 52 | pub fn at(self: Self, i: usize) T { | 62 | pub fn at(self: Self, i: usize) T { |
| 53 | return self.toSliceConst()[i]; | 63 | return self.toSliceConst()[i]; |
| 54 | } | 64 | } |
| ... | @@ -66,10 +76,13 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -66,10 +76,13 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { |
| 66 | self.items[i] = item; | 76 | self.items[i] = item; |
| 67 | } | 77 | } |
| 68 | | 78 | |
| | 79 | /// Return length of the list. |
| 69 | pub fn count(self: Self) usize { | 80 | pub fn count(self: Self) usize { |
| 70 | return self.len; | 81 | return self.len; |
| 71 | } | 82 | } |
| 72 | | 83 | |
| | 84 | /// Return the maximum number of items the list can hold |
| | 85 | /// without allocating more memory. |
| 73 | pub fn capacity(self: Self) usize { | 86 | pub fn capacity(self: Self) usize { |
| 74 | return self.items.len; | 87 | return self.items.len; |
| 75 | } | 88 | } |
| ... | @@ -93,6 +106,8 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -93,6 +106,8 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { |
| 93 | return result; | 106 | return result; |
| 94 | } | 107 | } |
| 95 | | 108 | |
| | 109 | /// Insert `item` at index `n`. Moves `list[n .. list.count()]` |
| | 110 | /// to make room. |
| 96 | pub fn insert(self: *Self, n: usize, item: T) !void { | 111 | pub fn insert(self: *Self, n: usize, item: T) !void { |
| 97 | try self.ensureCapacity(self.len + 1); | 112 | try self.ensureCapacity(self.len + 1); |
| 98 | self.len += 1; | 113 | self.len += 1; |
| ... | @@ -101,6 +116,8 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -101,6 +116,8 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { |
| 101 | self.items[n] = item; | 116 | self.items[n] = item; |
| 102 | } | 117 | } |
| 103 | | 118 | |
| | 119 | /// Insert slice `items` at index `n`. Moves |
| | 120 | /// `list[n .. list.count()]` to make room. |
| 104 | pub fn insertSlice(self: *Self, n: usize, items: SliceConst) !void { | 121 | pub fn insertSlice(self: *Self, n: usize, items: SliceConst) !void { |
| 105 | try self.ensureCapacity(self.len + items.len); | 122 | try self.ensureCapacity(self.len + items.len); |
| 106 | self.len += items.len; | 123 | self.len += items.len; |
| ... | @@ -109,16 +126,22 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -109,16 +126,22 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { |
| 109 | mem.copy(T, self.items[n .. n + items.len], items); | 126 | mem.copy(T, self.items[n .. n + items.len], items); |
| 110 | } | 127 | } |
| 111 | | 128 | |
| | 129 | /// Extend the list by 1 element. Allocates more memory as |
| | 130 | /// necessary. |
| 112 | pub fn append(self: *Self, item: T) !void { | 131 | pub fn append(self: *Self, item: T) !void { |
| 113 | const new_item_ptr = try self.addOne(); | 132 | const new_item_ptr = try self.addOne(); |
| 114 | new_item_ptr.* = item; | 133 | new_item_ptr.* = item; |
| 115 | } | 134 | } |
| 116 | | 135 | |
| | 136 | /// Extend the list by 1 element, but asserting `self.capacity` |
| | 137 | /// is sufficient to hold an additional item. |
| 117 | pub fn appendAssumeCapacity(self: *Self, item: T) void { | 138 | pub fn appendAssumeCapacity(self: *Self, item: T) void { |
| 118 | const new_item_ptr = self.addOneAssumeCapacity(); | 139 | const new_item_ptr = self.addOneAssumeCapacity(); |
| 119 | new_item_ptr.* = item; | 140 | new_item_ptr.* = item; |
| 120 | } | 141 | } |
| 121 | | 142 | |
| | 143 | /// Remove the element at index `i` from the list and return |
| | 144 | /// its value. Asserts the array has at least one item. |
| 122 | pub fn orderedRemove(self: *Self, i: usize) T { | 145 | pub fn orderedRemove(self: *Self, i: usize) T { |
| 123 | const newlen = self.len - 1; | 146 | const newlen = self.len - 1; |
| 124 | if (newlen == i) return self.pop(); | 147 | if (newlen == i) return self.pop(); |
| ... | @@ -149,17 +172,22 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -149,17 +172,22 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { |
| 149 | return self.swapRemove(i); | 172 | return self.swapRemove(i); |
| 150 | } | 173 | } |
| 151 | | 174 | |
| | 175 | /// Append the slice of items to the list. Allocates more |
| | 176 | /// memory as necessary. |
| 152 | pub fn appendSlice(self: *Self, items: SliceConst) !void { | 177 | pub fn appendSlice(self: *Self, items: SliceConst) !void { |
| 153 | try self.ensureCapacity(self.len + items.len); | 178 | try self.ensureCapacity(self.len + items.len); |
| 154 | mem.copy(T, self.items[self.len..], items); | 179 | mem.copy(T, self.items[self.len..], items); |
| 155 | self.len += items.len; | 180 | self.len += items.len; |
| 156 | } | 181 | } |
| 157 | | 182 | |
| | 183 | /// Adjust the list's length to `new_len`. Doesn't initialize |
| | 184 | /// added items if any. |
| 158 | pub fn resize(self: *Self, new_len: usize) !void { | 185 | pub fn resize(self: *Self, new_len: usize) !void { |
| 159 | try self.ensureCapacity(new_len); | 186 | try self.ensureCapacity(new_len); |
| 160 | self.len = new_len; | 187 | self.len = new_len; |
| 161 | } | 188 | } |
| 162 | | 189 | |
| | 190 | /// Reduce allocated capacity to `new_len`. |
| 163 | pub fn shrink(self: *Self, new_len: usize) void { | 191 | pub fn shrink(self: *Self, new_len: usize) void { |
| 164 | assert(new_len <= self.len); | 192 | assert(new_len <= self.len); |
| 165 | self.len = new_len; | 193 | self.len = new_len; |
| ... | @@ -178,6 +206,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -178,6 +206,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { |
| 178 | self.items = try self.allocator.realloc(self.items, better_capacity); | 206 | self.items = try self.allocator.realloc(self.items, better_capacity); |
| 179 | } | 207 | } |
| 180 | | 208 | |
| | 209 | /// Increase length by 1, returning pointer to the new item. |
| 181 | pub fn addOne(self: *Self) !*T { | 210 | pub fn addOne(self: *Self) !*T { |
| 182 | const new_length = self.len + 1; | 211 | const new_length = self.len + 1; |
| 183 | try self.ensureCapacity(new_length); | 212 | try self.ensureCapacity(new_length); |
| ... | @@ -191,11 +220,14 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -191,11 +220,14 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { |
| 191 | return result; | 220 | return result; |
| 192 | } | 221 | } |
| 193 | | 222 | |
| | 223 | /// Remove and return the last element from the list. Asserts |
| | 224 | /// the list has at least one item. |
| 194 | pub fn pop(self: *Self) T { | 225 | pub fn pop(self: *Self) T { |
| 195 | self.len -= 1; | 226 | self.len -= 1; |
| 196 | return self.items[self.len]; | 227 | return self.items[self.len]; |
| 197 | } | 228 | } |
| 198 | | 229 | |
| | 230 | /// Like `pop` but returns `null` if empty. |
| 199 | pub fn popOrNull(self: *Self) ?T { | 231 | pub fn popOrNull(self: *Self) ?T { |
| 200 | if (self.len == 0) return null; | 232 | if (self.len == 0) return null; |
| 201 | return self.pop(); | 233 | return self.pop(); |
| ... | @@ -218,6 +250,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -218,6 +250,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { |
| 218 | } | 250 | } |
| 219 | }; | 251 | }; |
| 220 | | 252 | |
| | 253 | /// Return an iterator over the list. |
| 221 | pub fn iterator(self: *const Self) Iterator { | 254 | pub fn iterator(self: *const Self) Iterator { |
| 222 | return Iterator{ | 255 | return Iterator{ |
| 223 | .list = self, | 256 | .list = self, |