| ... | ... | @@ -19,7 +19,7 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF |
| 19 | 19 | const Self = @This(); |
| 20 | 20 | |
| 21 | 21 | items: []T, |
| 22 | | len: usize, |
| 22 | cap: usize, |
| 23 | 23 | allocator: Allocator, |
| 24 | 24 | context: Context, |
| 25 | 25 | |
| ... | ... | @@ -27,7 +27,7 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF |
| 27 | 27 | pub fn init(allocator: Allocator, context: Context) Self { |
| 28 | 28 | return Self{ |
| 29 | 29 | .items = &[_]T{}, |
| 30 | | .len = 0, |
| 30 | .cap = 0, |
| 31 | 31 | .allocator = allocator, |
| 32 | 32 | .context = context, |
| 33 | 33 | }; |
| ... | ... | @@ -35,7 +35,7 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF |
| 35 | 35 | |
| 36 | 36 | /// Free memory used by the queue. |
| 37 | 37 | pub fn deinit(self: Self) void { |
| 38 | | self.allocator.free(self.items); |
| 38 | self.allocator.free(self.allocatedSlice()); |
| 39 | 39 | } |
| 40 | 40 | |
| 41 | 41 | /// Insert a new element, maintaining priority. |
| ... | ... | @@ -45,9 +45,9 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF |
| 45 | 45 | } |
| 46 | 46 | |
| 47 | 47 | fn addUnchecked(self: *Self, elem: T) void { |
| 48 | | self.items[self.len] = elem; |
| 49 | | siftUp(self, self.len); |
| 50 | | self.len += 1; |
| 48 | self.items.len += 1; |
| 49 | self.items[self.items.len - 1] = elem; |
| 50 | siftUp(self, self.items.len - 1); |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | 53 | fn siftUp(self: *Self, start_index: usize) void { |
| ... | ... | @@ -74,13 +74,13 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF |
| 74 | 74 | /// Look at the highest priority element in the queue. Returns |
| 75 | 75 | /// `null` if empty. |
| 76 | 76 | pub fn peek(self: *Self) ?T { |
| 77 | | return if (self.len > 0) self.items[0] else null; |
| 77 | return if (self.items.len > 0) self.items[0] else null; |
| 78 | 78 | } |
| 79 | 79 | |
| 80 | 80 | /// Pop the highest priority element from the queue. Returns |
| 81 | 81 | /// `null` if empty. |
| 82 | 82 | pub fn removeOrNull(self: *Self) ?T { |
| 83 | | return if (self.len > 0) self.remove() else null; |
| 83 | return if (self.items.len > 0) self.remove() else null; |
| 84 | 84 | } |
| 85 | 85 | |
| 86 | 86 | /// Remove and return the highest priority element from the |
| ... | ... | @@ -93,13 +93,15 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF |
| 93 | 93 | /// same order as iterator, which is not necessarily priority |
| 94 | 94 | /// order. |
| 95 | 95 | pub fn removeIndex(self: *Self, index: usize) T { |
| 96 | | assert(self.len > index); |
| 97 | | const last = self.items[self.len - 1]; |
| 96 | assert(self.items.len > index); |
| 97 | const last = self.items[self.items.len - 1]; |
| 98 | 98 | const item = self.items[index]; |
| 99 | 99 | self.items[index] = last; |
| 100 | | self.len -= 1; |
| 100 | self.items.len -= 1; |
| 101 | 101 | |
| 102 | | if (index == 0) { |
| 102 | if (index == self.items.len) { |
| 103 | // Last element removed, nothing more to do. |
| 104 | } else if (index == 0) { |
| 103 | 105 | siftDown(self, index); |
| 104 | 106 | } else { |
| 105 | 107 | const parent_index = ((index - 1) >> 1); |
| ... | ... | @@ -117,13 +119,20 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF |
| 117 | 119 | /// Return the number of elements remaining in the priority |
| 118 | 120 | /// queue. |
| 119 | 121 | pub fn count(self: Self) usize { |
| 120 | | return self.len; |
| 122 | return self.items.len; |
| 121 | 123 | } |
| 122 | 124 | |
| 123 | 125 | /// Return the number of elements that can be added to the |
| 124 | 126 | /// queue before more memory is allocated. |
| 125 | 127 | pub fn capacity(self: Self) usize { |
| 126 | | return self.items.len; |
| 128 | return self.cap; |
| 129 | } |
| 130 | |
| 131 | /// Returns a slice of all the items plus the extra capacity, whose memory |
| 132 | /// contents are `undefined`. |
| 133 | fn allocatedSlice(self: Self) []T { |
| 134 | // `items.len` is the length, not the capacity. |
| 135 | return self.items.ptr[0..self.cap]; |
| 127 | 136 | } |
| 128 | 137 | |
| 129 | 138 | fn siftDown(self: *Self, target_index: usize) void { |
| ... | ... | @@ -131,10 +140,10 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF |
| 131 | 140 | var index = target_index; |
| 132 | 141 | while (true) { |
| 133 | 142 | var lesser_child_i = (std.math.mul(usize, index, 2) catch break) | 1; |
| 134 | | if (!(lesser_child_i < self.len)) break; |
| 143 | if (!(lesser_child_i < self.items.len)) break; |
| 135 | 144 | |
| 136 | 145 | const next_child_i = lesser_child_i + 1; |
| 137 | | if (next_child_i < self.len and compareFn(self.context, self.items[next_child_i], self.items[lesser_child_i]) == .lt) { |
| 146 | if (next_child_i < self.items.len and compareFn(self.context, self.items[next_child_i], self.items[lesser_child_i]) == .lt) { |
| 138 | 147 | lesser_child_i = next_child_i; |
| 139 | 148 | } |
| 140 | 149 | |
| ... | ... | @@ -152,12 +161,12 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF |
| 152 | 161 | pub fn fromOwnedSlice(allocator: Allocator, items: []T, context: Context) Self { |
| 153 | 162 | var self = Self{ |
| 154 | 163 | .items = items, |
| 155 | | .len = items.len, |
| 164 | .cap = items.len, |
| 156 | 165 | .allocator = allocator, |
| 157 | 166 | .context = context, |
| 158 | 167 | }; |
| 159 | 168 | |
| 160 | | var i = self.len >> 1; |
| 169 | var i = self.items.len >> 1; |
| 161 | 170 | while (i > 0) { |
| 162 | 171 | i -= 1; |
| 163 | 172 | self.siftDown(i); |
| ... | ... | @@ -167,39 +176,45 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF |
| 167 | 176 | |
| 168 | 177 | /// Ensure that the queue can fit at least `new_capacity` items. |
| 169 | 178 | pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) !void { |
| 170 | | var better_capacity = self.capacity(); |
| 179 | var better_capacity = self.cap; |
| 171 | 180 | if (better_capacity >= new_capacity) return; |
| 172 | 181 | while (true) { |
| 173 | 182 | better_capacity += better_capacity / 2 + 8; |
| 174 | 183 | if (better_capacity >= new_capacity) break; |
| 175 | 184 | } |
| 176 | | self.items = try self.allocator.realloc(self.items, better_capacity); |
| 185 | const old_memory = self.allocatedSlice(); |
| 186 | const new_memory = try self.allocator.realloc(old_memory, better_capacity); |
| 187 | self.items.ptr = new_memory.ptr; |
| 188 | self.cap = new_memory.len; |
| 177 | 189 | } |
| 178 | 190 | |
| 179 | 191 | /// Ensure that the queue can fit at least `additional_count` **more** item. |
| 180 | 192 | pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) !void { |
| 181 | | return self.ensureTotalCapacity(self.len + additional_count); |
| 193 | return self.ensureTotalCapacity(self.items.len + additional_count); |
| 182 | 194 | } |
| 183 | 195 | |
| 184 | | /// Reduce allocated capacity to `new_len`. |
| 185 | | pub fn shrinkAndFree(self: *Self, new_len: usize) void { |
| 186 | | assert(new_len <= self.items.len); |
| 196 | /// Reduce allocated capacity to `new_capacity`. |
| 197 | pub fn shrinkAndFree(self: *Self, new_capacity: usize) void { |
| 198 | assert(new_capacity <= self.cap); |
| 187 | 199 | |
| 188 | 200 | // Cannot shrink to smaller than the current queue size without invalidating the heap property |
| 189 | | assert(new_len >= self.len); |
| 201 | assert(new_capacity >= self.items.len); |
| 190 | 202 | |
| 191 | | self.items = self.allocator.realloc(self.items[0..], new_len) catch |e| switch (e) { |
| 203 | const old_memory = self.allocatedSlice(); |
| 204 | const new_memory = self.allocator.realloc(old_memory, new_capacity) catch |e| switch (e) { |
| 192 | 205 | error.OutOfMemory => { // no problem, capacity is still correct then. |
| 193 | | self.items.len = new_len; |
| 194 | 206 | return; |
| 195 | 207 | }, |
| 196 | 208 | }; |
| 209 | |
| 210 | self.items.ptr = new_memory.ptr; |
| 211 | self.cap = new_memory.len; |
| 197 | 212 | } |
| 198 | 213 | |
| 199 | 214 | pub fn update(self: *Self, elem: T, new_elem: T) !void { |
| 200 | 215 | const update_index = blk: { |
| 201 | 216 | var idx: usize = 0; |
| 202 | | while (idx < self.len) : (idx += 1) { |
| 217 | while (idx < self.items.len) : (idx += 1) { |
| 203 | 218 | const item = self.items[idx]; |
| 204 | 219 | if (compareFn(self.context, item, elem) == .eq) break :blk idx; |
| 205 | 220 | } |
| ... | ... | @@ -219,7 +234,7 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF |
| 219 | 234 | count: usize, |
| 220 | 235 | |
| 221 | 236 | pub fn next(it: *Iterator) ?T { |
| 222 | | if (it.count >= it.queue.len) return null; |
| 237 | if (it.count >= it.queue.items.len) return null; |
| 223 | 238 | const out = it.count; |
| 224 | 239 | it.count += 1; |
| 225 | 240 | return it.queue.items[out]; |
| ... | ... | @@ -244,16 +259,15 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF |
| 244 | 259 | const print = std.debug.print; |
| 245 | 260 | print("{{ ", .{}); |
| 246 | 261 | print("items: ", .{}); |
| 247 | | for (self.items, 0..) |e, i| { |
| 248 | | if (i >= self.len) break; |
| 262 | for (self.items) |e| { |
| 249 | 263 | print("{}, ", .{e}); |
| 250 | 264 | } |
| 251 | 265 | print("array: ", .{}); |
| 252 | 266 | for (self.items) |e| { |
| 253 | 267 | print("{}, ", .{e}); |
| 254 | 268 | } |
| 255 | | print("len: {} ", .{self.len}); |
| 256 | | print("capacity: {}", .{self.capacity()}); |
| 269 | print("len: {} ", .{self.items.len}); |
| 270 | print("capacity: {}", .{self.cap}); |
| 257 | 271 | print(" }}\n", .{}); |
| 258 | 272 | } |
| 259 | 273 | }; |
| ... | ... | @@ -369,7 +383,7 @@ test "fromOwnedSlice trivial case 0" { |
| 369 | 383 | const queue_items = try testing.allocator.dupe(u32, &items); |
| 370 | 384 | var queue = PQlt.fromOwnedSlice(testing.allocator, queue_items[0..], {}); |
| 371 | 385 | defer queue.deinit(); |
| 372 | | try expectEqual(@as(usize, 0), queue.len); |
| 386 | try expectEqual(@as(usize, 0), queue.count()); |
| 373 | 387 | try expect(queue.removeOrNull() == null); |
| 374 | 388 | } |
| 375 | 389 | |
| ... | ... | @@ -379,7 +393,7 @@ test "fromOwnedSlice trivial case 1" { |
| 379 | 393 | var queue = PQlt.fromOwnedSlice(testing.allocator, queue_items[0..], {}); |
| 380 | 394 | defer queue.deinit(); |
| 381 | 395 | |
| 382 | | try expectEqual(@as(usize, 1), queue.len); |
| 396 | try expectEqual(@as(usize, 1), queue.count()); |
| 383 | 397 | try expectEqual(items[0], queue.remove()); |
| 384 | 398 | try expect(queue.removeOrNull() == null); |
| 385 | 399 | } |
| ... | ... | @@ -500,11 +514,11 @@ test "shrinkAndFree" { |
| 500 | 514 | try queue.add(2); |
| 501 | 515 | try queue.add(3); |
| 502 | 516 | try expect(queue.capacity() >= 4); |
| 503 | | try expectEqual(@as(usize, 3), queue.len); |
| 517 | try expectEqual(@as(usize, 3), queue.count()); |
| 504 | 518 | |
| 505 | 519 | queue.shrinkAndFree(3); |
| 506 | 520 | try expectEqual(@as(usize, 3), queue.capacity()); |
| 507 | | try expectEqual(@as(usize, 3), queue.len); |
| 521 | try expectEqual(@as(usize, 3), queue.count()); |
| 508 | 522 | |
| 509 | 523 | try expectEqual(@as(u32, 1), queue.remove()); |
| 510 | 524 | try expectEqual(@as(u32, 2), queue.remove()); |
| ... | ... | @@ -589,7 +603,7 @@ test "siftUp in remove" { |
| 589 | 603 | |
| 590 | 604 | try queue.addSlice(&.{ 0, 1, 100, 2, 3, 101, 102, 4, 5, 6, 7, 103, 104, 105, 106, 8 }); |
| 591 | 605 | |
| 592 | | _ = queue.removeIndex(std.mem.indexOfScalar(u32, queue.items[0..queue.len], 102).?); |
| 606 | _ = queue.removeIndex(std.mem.indexOfScalar(u32, queue.items[0..queue.count()], 102).?); |
| 593 | 607 | |
| 594 | 608 | const sorted_items = [_]u32{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 100, 101, 103, 104, 105, 106 }; |
| 595 | 609 | for (sorted_items) |e| { |