| ... | @@ -174,18 +174,115 @@ pub fn Deque(comptime T: type) type { | ... | @@ -174,18 +174,115 @@ pub fn Deque(comptime T: type) type { |
| 174 | deque.len += 1; | 174 | deque.len += 1; |
| 175 | } | 175 | } |
| 176 | | 176 | |
| | 177 | /// Add `items` to the front of the deque. |
| | 178 | /// This is equivalent to iterating `items` in reverse and calling |
| | 179 | /// `pushFront` on every single entry. |
| | 180 | /// |
| | 181 | /// Invalidates element pointers if additional memory is needed. |
| | 182 | pub fn pushFrontSlice(deque: *Self, gpa: Allocator, items: []const T) error{OutOfMemory}!void { |
| | 183 | try deque.ensureUnusedCapacity(gpa, items.len); |
| | 184 | return deque.pushFrontSliceAssumeCapacity(items); |
| | 185 | } |
| | 186 | |
| | 187 | /// Add `items` to the front of the deque. |
| | 188 | /// This is equivalent to iterating `items` in reverse and calling |
| | 189 | /// `pushFront` on every single entry. |
| | 190 | /// |
| | 191 | /// Never invalidates element pointers. |
| | 192 | /// |
| | 193 | /// If the deque lacks unused capacity for the additional items, returns |
| | 194 | /// `error.OutOfMemory`. |
| | 195 | pub fn pushFrontSliceBounded(deque: *Self, items: []const T) error{OutOfMemory}!void { |
| | 196 | if (deque.buffer.len - deque.len < items.len) return error.OutOfMemory; |
| | 197 | return deque.pushFrontSliceAssumeCapacity(items); |
| | 198 | } |
| | 199 | |
| | 200 | /// Add `items` to the front of the deque. |
| | 201 | /// This is equivalent to iterating `items` in reverse and calling |
| | 202 | /// `pushFront` on every single entry. |
| | 203 | /// |
| | 204 | /// Never invalidates element pointers. |
| | 205 | /// |
| | 206 | /// Asserts that the deque can hold the additional items. |
| | 207 | pub fn pushFrontSliceAssumeCapacity(deque: *Self, items: []const T) void { |
| | 208 | assert(deque.buffer.len - deque.len >= items.len); |
| | 209 | if (deque.head < items.len) { |
| | 210 | @memcpy(deque.buffer[0..deque.head], items[items.len - deque.head ..]); |
| | 211 | deque.head = deque.buffer.len - items.len + deque.head; |
| | 212 | @memcpy(deque.buffer[deque.head..], items.ptr); |
| | 213 | } else { |
| | 214 | deque.head -= items.len; |
| | 215 | @memcpy(deque.buffer[deque.head..][0..items.len], items); |
| | 216 | } |
| | 217 | deque.len += items.len; |
| | 218 | } |
| | 219 | |
| | 220 | /// Add `items` to the back of the deque. |
| | 221 | /// This is equivalent to iterating `items` in order and calling |
| | 222 | /// `pushBack` on every single entry. |
| | 223 | /// |
| | 224 | /// Invalidates element pointers if additional memory is needed. |
| | 225 | pub fn pushBackSlice(deque: *Self, gpa: Allocator, items: []const T) error{OutOfMemory}!void { |
| | 226 | try deque.ensureUnusedCapacity(gpa, items.len); |
| | 227 | return deque.pushBackSliceAssumeCapacity(items); |
| | 228 | } |
| | 229 | |
| | 230 | /// Add `items` to the back of the deque. |
| | 231 | /// This is equivalent to iterating `items` in order and calling |
| | 232 | /// `pushBack` on every single entry. |
| | 233 | /// |
| | 234 | /// Never invalidates element pointers. |
| | 235 | /// |
| | 236 | /// If the deque lacks unused capacity for the additional items, returns |
| | 237 | /// `error.OutOfMemory`. |
| | 238 | pub fn pushBackSliceBounded(deque: *Self, items: []const T) error{OutOfMemory}!void { |
| | 239 | if (deque.buffer.len - deque.len < items.len) return error.OutOfMemory; |
| | 240 | return deque.pushBackSliceAssumeCapacity(items); |
| | 241 | } |
| | 242 | |
| | 243 | /// Add `items` to the back of the deque. |
| | 244 | /// This is equivalent to iterating `items` in order and calling |
| | 245 | /// `pushBack` on every single entry. |
| | 246 | /// |
| | 247 | /// Never invalidates element pointers. |
| | 248 | /// |
| | 249 | /// Asserts that the deque can hold the additional items. |
| | 250 | pub fn pushBackSliceAssumeCapacity(deque: *Self, items: []const T) void { |
| | 251 | assert(deque.buffer.len - deque.len >= items.len); |
| | 252 | const trailing_buffer = deque.buffer[deque.bufferIndex(deque.len)..]; |
| | 253 | if (trailing_buffer.len < items.len) { |
| | 254 | @memcpy(trailing_buffer, items[0..trailing_buffer.len]); |
| | 255 | @memcpy(deque.buffer.ptr, items[trailing_buffer.len..]); |
| | 256 | } else { |
| | 257 | @memcpy(trailing_buffer[0..items.len], items); |
| | 258 | } |
| | 259 | deque.len += items.len; |
| | 260 | } |
| | 261 | |
| 177 | /// Return the first item in the deque or null if empty. | 262 | /// Return the first item in the deque or null if empty. |
| 178 | pub fn front(deque: *const Self) ?T { | 263 | pub fn front(deque: *const Self) ?T { |
| 179 | if (deque.len == 0) return null; | 264 | if (deque.len == 0) return null; |
| 180 | return deque.buffer[deque.head]; | 265 | return deque.buffer[deque.head]; |
| 181 | } | 266 | } |
| 182 | | 267 | |
| | 268 | /// Return pointer to the first item in the deque or null if empty. |
| | 269 | pub fn frontPtr(deque: *const Self) ?*T { |
| | 270 | if (deque.len == 0) return null; |
| | 271 | return &deque.buffer[deque.head]; |
| | 272 | } |
| | 273 | |
| 183 | /// Return the last item in the deque or null if empty. | 274 | /// Return the last item in the deque or null if empty. |
| 184 | pub fn back(deque: *const Self) ?T { | 275 | pub fn back(deque: *const Self) ?T { |
| 185 | if (deque.len == 0) return null; | 276 | if (deque.len == 0) return null; |
| 186 | return deque.buffer[deque.bufferIndex(deque.len - 1)]; | 277 | return deque.buffer[deque.bufferIndex(deque.len - 1)]; |
| 187 | } | 278 | } |
| 188 | | 279 | |
| | 280 | /// Return the last item in the deque or null if empty. |
| | 281 | pub fn backPtr(deque: *const Self) ?*T { |
| | 282 | if (deque.len == 0) return null; |
| | 283 | return &deque.buffer[deque.bufferIndex(deque.len - 1)]; |
| | 284 | } |
| | 285 | |
| 189 | /// Return the item at the given index in the deque. | 286 | /// Return the item at the given index in the deque. |
| 190 | /// | 287 | /// |
| 191 | /// The first item in the queue is at index 0. | 288 | /// The first item in the queue is at index 0. |
| ... | @@ -196,6 +293,16 @@ pub fn Deque(comptime T: type) type { | ... | @@ -196,6 +293,16 @@ pub fn Deque(comptime T: type) type { |
| 196 | return deque.buffer[deque.bufferIndex(index)]; | 293 | return deque.buffer[deque.bufferIndex(index)]; |
| 197 | } | 294 | } |
| 198 | | 295 | |
| | 296 | /// Return pointer to the item at the given index in the deque. |
| | 297 | /// |
| | 298 | /// The first item in the queue is at index 0. |
| | 299 | /// |
| | 300 | /// Asserts that the index is in-bounds. |
| | 301 | pub fn atPtr(deque: *const Self, index: usize) *T { |
| | 302 | assert(index < deque.len); |
| | 303 | return &deque.buffer[deque.bufferIndex(index)]; |
| | 304 | } |
| | 305 | |
| 199 | /// Remove and return the first item in the deque or null if empty. | 306 | /// Remove and return the first item in the deque or null if empty. |
| 200 | pub fn popFront(deque: *Self) ?T { | 307 | pub fn popFront(deque: *Self) ?T { |
| 201 | if (deque.len == 0) return null; | 308 | if (deque.len == 0) return null; |
| ... | @@ -216,13 +323,24 @@ pub fn Deque(comptime T: type) type { | ... | @@ -216,13 +323,24 @@ pub fn Deque(comptime T: type) type { |
| 216 | deque: *const Self, | 323 | deque: *const Self, |
| 217 | index: usize, | 324 | index: usize, |
| 218 | | 325 | |
| | 326 | pub fn peek(it: Iterator) ?T { |
| | 327 | if (it.index >= it.deque.len) return null; |
| | 328 | return it.deque.at(it.index); |
| | 329 | } |
| 219 | pub fn next(it: *Iterator) ?T { | 330 | pub fn next(it: *Iterator) ?T { |
| 220 | if (it.index < it.deque.len) { | 331 | const item = it.peek() orelse return null; |
| 221 | defer it.index += 1; | 332 | it.index += 1; |
| 222 | return it.deque.at(it.index); | 333 | return item; |
| 223 | } else { | 334 | } |
| 224 | return null; | 335 | |
| 225 | } | 336 | pub fn peekPtr(it: Iterator) ?*T { |
| | 337 | if (it.index >= it.deque.len) return null; |
| | 338 | return it.deque.atPtr(it.index); |
| | 339 | } |
| | 340 | pub fn nextPtr(it: *Iterator) ?*T { |
| | 341 | const item_ptr = it.peekPtr() orelse return null; |
| | 342 | it.index += 1; |
| | 343 | return item_ptr; |
| 226 | } | 344 | } |
| 227 | }; | 345 | }; |
| 228 | | 346 | |
| ... | @@ -328,6 +446,74 @@ test "slow growth" { | ... | @@ -328,6 +446,74 @@ test "slow growth" { |
| 328 | try testing.expectEqual(null, q.popBack()); | 446 | try testing.expectEqual(null, q.popBack()); |
| 329 | } | 447 | } |
| 330 | | 448 | |
| | 449 | test "slice" { |
| | 450 | const testing = std.testing; |
| | 451 | const gpa = testing.allocator; |
| | 452 | |
| | 453 | var q: Deque(i32) = .empty; |
| | 454 | defer q.deinit(gpa); |
| | 455 | |
| | 456 | try q.pushBackSlice(gpa, &.{ 3, 4, 5 }); |
| | 457 | try q.pushBackSlice(gpa, &.{ 6, 7 }); |
| | 458 | try q.pushFrontSlice(gpa, &.{2}); |
| | 459 | try q.pushBackSlice(gpa, &.{}); |
| | 460 | try q.pushFrontSlice(gpa, &.{ 0, 1 }); |
| | 461 | try q.pushFrontSlice(gpa, &.{}); |
| | 462 | |
| | 463 | try testing.expectEqual(0, q.popFront()); |
| | 464 | try testing.expectEqual(1, q.popFront()); |
| | 465 | try testing.expectEqual(7, q.popBack()); |
| | 466 | try testing.expectEqual(6, q.popBack()); |
| | 467 | |
| | 468 | try q.pushFrontSlice(gpa, &.{ 0, 1 }); |
| | 469 | try q.pushBackSlice(gpa, &.{ 6, 7 }); |
| | 470 | |
| | 471 | try testing.expectEqual(0, q.popFront()); |
| | 472 | try testing.expectEqual(1, q.popFront()); |
| | 473 | try testing.expectEqual(2, q.popFront()); |
| | 474 | try testing.expectEqual(7, q.popBack()); |
| | 475 | try testing.expectEqual(6, q.popBack()); |
| | 476 | try testing.expectEqual(3, q.popFront()); |
| | 477 | try testing.expectEqual(4, q.popFront()); |
| | 478 | try testing.expectEqual(5, q.popBack()); |
| | 479 | try testing.expectEqual(null, q.popFront()); |
| | 480 | try testing.expectEqual(null, q.popBack()); |
| | 481 | } |
| | 482 | |
| | 483 | test "iterator" { |
| | 484 | const testing = std.testing; |
| | 485 | const gpa = testing.allocator; |
| | 486 | |
| | 487 | var q: Deque(i32) = .empty; |
| | 488 | defer q.deinit(gpa); |
| | 489 | |
| | 490 | const items: []const i32 = &.{ 0, 1, 2, 3, 4, 5 }; |
| | 491 | try q.pushFrontSlice(gpa, items); |
| | 492 | |
| | 493 | { |
| | 494 | var it = q.iterator(); |
| | 495 | for (items) |item| { |
| | 496 | try testing.expectEqual(item, it.peek()); |
| | 497 | try testing.expectEqual(item, it.next()); |
| | 498 | } |
| | 499 | try testing.expectEqual(null, it.peek()); |
| | 500 | try testing.expectEqual(null, it.next()); |
| | 501 | } |
| | 502 | { |
| | 503 | var it = q.iterator(); |
| | 504 | for (items) |item| { |
| | 505 | if (it.peekPtr()) |ptr| { |
| | 506 | try testing.expectEqual(item, ptr.*); |
| | 507 | } else return error.TestExpectedNonNull; |
| | 508 | if (it.nextPtr()) |ptr| { |
| | 509 | try testing.expectEqual(item, ptr.*); |
| | 510 | } else return error.TestExpectedNonNull; |
| | 511 | } |
| | 512 | try testing.expectEqual(null, it.peekPtr()); |
| | 513 | try testing.expectEqual(null, it.nextPtr()); |
| | 514 | } |
| | 515 | } |
| | 516 | |
| 331 | test "fuzz against ArrayList oracle" { | 517 | test "fuzz against ArrayList oracle" { |
| 332 | try std.testing.fuzz({}, fuzzAgainstArrayList, .{}); | 518 | try std.testing.fuzz({}, fuzzAgainstArrayList, .{}); |
| 333 | } | 519 | } |
| ... | @@ -362,6 +548,8 @@ fn fuzzAgainstArrayList(_: void, input: []const u8) anyerror!void { | ... | @@ -362,6 +548,8 @@ fn fuzzAgainstArrayList(_: void, input: []const u8) anyerror!void { |
| 362 | const Action = enum { | 548 | const Action = enum { |
| 363 | push_back, | 549 | push_back, |
| 364 | push_front, | 550 | push_front, |
| | 551 | push_back_slice, |
| | 552 | push_front_slice, |
| 365 | pop_back, | 553 | pop_back, |
| 366 | pop_front, | 554 | pop_front, |
| 367 | grow, | 555 | grow, |
| ... | @@ -384,6 +572,28 @@ fn fuzzAgainstArrayList(_: void, input: []const u8) anyerror!void { | ... | @@ -384,6 +572,28 @@ fn fuzzAgainstArrayList(_: void, input: []const u8) anyerror!void { |
| 384 | q.pushFrontBounded(item), | 572 | q.pushFrontBounded(item), |
| 385 | ); | 573 | ); |
| 386 | }, | 574 | }, |
| | 575 | .push_back_slice => { |
| | 576 | var buffer: [std.math.maxInt(u3)]u32 = undefined; |
| | 577 | const items = buffer[0..random.int(u3)]; |
| | 578 | for (items) |*item| { |
| | 579 | item.* = random.int(u8); |
| | 580 | } |
| | 581 | try testing.expectEqual( |
| | 582 | l.appendSliceBounded(items), |
| | 583 | q.pushBackSliceBounded(items), |
| | 584 | ); |
| | 585 | }, |
| | 586 | .push_front_slice => { |
| | 587 | var buffer: [std.math.maxInt(u3)]u32 = undefined; |
| | 588 | const items = buffer[0..random.int(u3)]; |
| | 589 | for (items) |*item| { |
| | 590 | item.* = random.int(u8); |
| | 591 | } |
| | 592 | try testing.expectEqual( |
| | 593 | l.insertSliceBounded(0, items), |
| | 594 | q.pushFrontSliceBounded(items), |
| | 595 | ); |
| | 596 | }, |
| 387 | .pop_back => { | 597 | .pop_back => { |
| 388 | try testing.expectEqual(l.pop(), q.popBack()); | 598 | try testing.expectEqual(l.pop(), q.popBack()); |
| 389 | }, | 599 | }, |