mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 01:24:49 +01:00
Merge branch std.Deque: add *Ptr and *Slice functions
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31179
This commit is contained in:
commit
469bf6af07
1 changed files with 216 additions and 6 deletions
|
|
@ -174,18 +174,115 @@ pub fn Deque(comptime T: type) type {
|
|||
deque.len += 1;
|
||||
}
|
||||
|
||||
/// Add `items` to the front of the deque.
|
||||
/// This is equivalent to iterating `items` in reverse and calling
|
||||
/// `pushFront` on every single entry.
|
||||
///
|
||||
/// Invalidates element pointers if additional memory is needed.
|
||||
pub fn pushFrontSlice(deque: *Self, gpa: Allocator, items: []const T) error{OutOfMemory}!void {
|
||||
try deque.ensureUnusedCapacity(gpa, items.len);
|
||||
return deque.pushFrontSliceAssumeCapacity(items);
|
||||
}
|
||||
|
||||
/// Add `items` to the front of the deque.
|
||||
/// This is equivalent to iterating `items` in reverse and calling
|
||||
/// `pushFront` on every single entry.
|
||||
///
|
||||
/// Never invalidates element pointers.
|
||||
///
|
||||
/// If the deque lacks unused capacity for the additional items, returns
|
||||
/// `error.OutOfMemory`.
|
||||
pub fn pushFrontSliceBounded(deque: *Self, items: []const T) error{OutOfMemory}!void {
|
||||
if (deque.buffer.len - deque.len < items.len) return error.OutOfMemory;
|
||||
return deque.pushFrontSliceAssumeCapacity(items);
|
||||
}
|
||||
|
||||
/// Add `items` to the front of the deque.
|
||||
/// This is equivalent to iterating `items` in reverse and calling
|
||||
/// `pushFront` on every single entry.
|
||||
///
|
||||
/// Never invalidates element pointers.
|
||||
///
|
||||
/// Asserts that the deque can hold the additional items.
|
||||
pub fn pushFrontSliceAssumeCapacity(deque: *Self, items: []const T) void {
|
||||
assert(deque.buffer.len - deque.len >= items.len);
|
||||
if (deque.head < items.len) {
|
||||
@memcpy(deque.buffer[0..deque.head], items[items.len - deque.head ..]);
|
||||
deque.head = deque.buffer.len - items.len + deque.head;
|
||||
@memcpy(deque.buffer[deque.head..], items.ptr);
|
||||
} else {
|
||||
deque.head -= items.len;
|
||||
@memcpy(deque.buffer[deque.head..][0..items.len], items);
|
||||
}
|
||||
deque.len += items.len;
|
||||
}
|
||||
|
||||
/// Add `items` to the back of the deque.
|
||||
/// This is equivalent to iterating `items` in order and calling
|
||||
/// `pushBack` on every single entry.
|
||||
///
|
||||
/// Invalidates element pointers if additional memory is needed.
|
||||
pub fn pushBackSlice(deque: *Self, gpa: Allocator, items: []const T) error{OutOfMemory}!void {
|
||||
try deque.ensureUnusedCapacity(gpa, items.len);
|
||||
return deque.pushBackSliceAssumeCapacity(items);
|
||||
}
|
||||
|
||||
/// Add `items` to the back of the deque.
|
||||
/// This is equivalent to iterating `items` in order and calling
|
||||
/// `pushBack` on every single entry.
|
||||
///
|
||||
/// Never invalidates element pointers.
|
||||
///
|
||||
/// If the deque lacks unused capacity for the additional items, returns
|
||||
/// `error.OutOfMemory`.
|
||||
pub fn pushBackSliceBounded(deque: *Self, items: []const T) error{OutOfMemory}!void {
|
||||
if (deque.buffer.len - deque.len < items.len) return error.OutOfMemory;
|
||||
return deque.pushBackSliceAssumeCapacity(items);
|
||||
}
|
||||
|
||||
/// Add `items` to the back of the deque.
|
||||
/// This is equivalent to iterating `items` in order and calling
|
||||
/// `pushBack` on every single entry.
|
||||
///
|
||||
/// Never invalidates element pointers.
|
||||
///
|
||||
/// Asserts that the deque can hold the additional items.
|
||||
pub fn pushBackSliceAssumeCapacity(deque: *Self, items: []const T) void {
|
||||
assert(deque.buffer.len - deque.len >= items.len);
|
||||
const trailing_buffer = deque.buffer[deque.bufferIndex(deque.len)..];
|
||||
if (trailing_buffer.len < items.len) {
|
||||
@memcpy(trailing_buffer, items[0..trailing_buffer.len]);
|
||||
@memcpy(deque.buffer.ptr, items[trailing_buffer.len..]);
|
||||
} else {
|
||||
@memcpy(trailing_buffer[0..items.len], items);
|
||||
}
|
||||
deque.len += items.len;
|
||||
}
|
||||
|
||||
/// Return the first item in the deque or null if empty.
|
||||
pub fn front(deque: *const Self) ?T {
|
||||
if (deque.len == 0) return null;
|
||||
return deque.buffer[deque.head];
|
||||
}
|
||||
|
||||
/// Return pointer to the first item in the deque or null if empty.
|
||||
pub fn frontPtr(deque: *const Self) ?*T {
|
||||
if (deque.len == 0) return null;
|
||||
return &deque.buffer[deque.head];
|
||||
}
|
||||
|
||||
/// Return the last item in the deque or null if empty.
|
||||
pub fn back(deque: *const Self) ?T {
|
||||
if (deque.len == 0) return null;
|
||||
return deque.buffer[deque.bufferIndex(deque.len - 1)];
|
||||
}
|
||||
|
||||
/// Return the last item in the deque or null if empty.
|
||||
pub fn backPtr(deque: *const Self) ?*T {
|
||||
if (deque.len == 0) return null;
|
||||
return &deque.buffer[deque.bufferIndex(deque.len - 1)];
|
||||
}
|
||||
|
||||
/// Return the item at the given index in the deque.
|
||||
///
|
||||
/// The first item in the queue is at index 0.
|
||||
|
|
@ -196,6 +293,16 @@ pub fn Deque(comptime T: type) type {
|
|||
return deque.buffer[deque.bufferIndex(index)];
|
||||
}
|
||||
|
||||
/// Return pointer to the item at the given index in the deque.
|
||||
///
|
||||
/// The first item in the queue is at index 0.
|
||||
///
|
||||
/// Asserts that the index is in-bounds.
|
||||
pub fn atPtr(deque: *const Self, index: usize) *T {
|
||||
assert(index < deque.len);
|
||||
return &deque.buffer[deque.bufferIndex(index)];
|
||||
}
|
||||
|
||||
/// Remove and return the first item in the deque or null if empty.
|
||||
pub fn popFront(deque: *Self) ?T {
|
||||
if (deque.len == 0) return null;
|
||||
|
|
@ -216,13 +323,24 @@ pub fn Deque(comptime T: type) type {
|
|||
deque: *const Self,
|
||||
index: usize,
|
||||
|
||||
pub fn peek(it: Iterator) ?T {
|
||||
if (it.index >= it.deque.len) return null;
|
||||
return it.deque.at(it.index);
|
||||
}
|
||||
pub fn next(it: *Iterator) ?T {
|
||||
if (it.index < it.deque.len) {
|
||||
defer it.index += 1;
|
||||
return it.deque.at(it.index);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
const item = it.peek() orelse return null;
|
||||
it.index += 1;
|
||||
return item;
|
||||
}
|
||||
|
||||
pub fn peekPtr(it: Iterator) ?*T {
|
||||
if (it.index >= it.deque.len) return null;
|
||||
return it.deque.atPtr(it.index);
|
||||
}
|
||||
pub fn nextPtr(it: *Iterator) ?*T {
|
||||
const item_ptr = it.peekPtr() orelse return null;
|
||||
it.index += 1;
|
||||
return item_ptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -328,6 +446,74 @@ test "slow growth" {
|
|||
try testing.expectEqual(null, q.popBack());
|
||||
}
|
||||
|
||||
test "slice" {
|
||||
const testing = std.testing;
|
||||
const gpa = testing.allocator;
|
||||
|
||||
var q: Deque(i32) = .empty;
|
||||
defer q.deinit(gpa);
|
||||
|
||||
try q.pushBackSlice(gpa, &.{ 3, 4, 5 });
|
||||
try q.pushBackSlice(gpa, &.{ 6, 7 });
|
||||
try q.pushFrontSlice(gpa, &.{2});
|
||||
try q.pushBackSlice(gpa, &.{});
|
||||
try q.pushFrontSlice(gpa, &.{ 0, 1 });
|
||||
try q.pushFrontSlice(gpa, &.{});
|
||||
|
||||
try testing.expectEqual(0, q.popFront());
|
||||
try testing.expectEqual(1, q.popFront());
|
||||
try testing.expectEqual(7, q.popBack());
|
||||
try testing.expectEqual(6, q.popBack());
|
||||
|
||||
try q.pushFrontSlice(gpa, &.{ 0, 1 });
|
||||
try q.pushBackSlice(gpa, &.{ 6, 7 });
|
||||
|
||||
try testing.expectEqual(0, q.popFront());
|
||||
try testing.expectEqual(1, q.popFront());
|
||||
try testing.expectEqual(2, q.popFront());
|
||||
try testing.expectEqual(7, q.popBack());
|
||||
try testing.expectEqual(6, q.popBack());
|
||||
try testing.expectEqual(3, q.popFront());
|
||||
try testing.expectEqual(4, q.popFront());
|
||||
try testing.expectEqual(5, q.popBack());
|
||||
try testing.expectEqual(null, q.popFront());
|
||||
try testing.expectEqual(null, q.popBack());
|
||||
}
|
||||
|
||||
test "iterator" {
|
||||
const testing = std.testing;
|
||||
const gpa = testing.allocator;
|
||||
|
||||
var q: Deque(i32) = .empty;
|
||||
defer q.deinit(gpa);
|
||||
|
||||
const items: []const i32 = &.{ 0, 1, 2, 3, 4, 5 };
|
||||
try q.pushFrontSlice(gpa, items);
|
||||
|
||||
{
|
||||
var it = q.iterator();
|
||||
for (items) |item| {
|
||||
try testing.expectEqual(item, it.peek());
|
||||
try testing.expectEqual(item, it.next());
|
||||
}
|
||||
try testing.expectEqual(null, it.peek());
|
||||
try testing.expectEqual(null, it.next());
|
||||
}
|
||||
{
|
||||
var it = q.iterator();
|
||||
for (items) |item| {
|
||||
if (it.peekPtr()) |ptr| {
|
||||
try testing.expectEqual(item, ptr.*);
|
||||
} else return error.TestExpectedNonNull;
|
||||
if (it.nextPtr()) |ptr| {
|
||||
try testing.expectEqual(item, ptr.*);
|
||||
} else return error.TestExpectedNonNull;
|
||||
}
|
||||
try testing.expectEqual(null, it.peekPtr());
|
||||
try testing.expectEqual(null, it.nextPtr());
|
||||
}
|
||||
}
|
||||
|
||||
test "fuzz against ArrayList oracle" {
|
||||
try std.testing.fuzz({}, fuzzAgainstArrayList, .{});
|
||||
}
|
||||
|
|
@ -362,6 +548,8 @@ fn fuzzAgainstArrayList(_: void, input: []const u8) anyerror!void {
|
|||
const Action = enum {
|
||||
push_back,
|
||||
push_front,
|
||||
push_back_slice,
|
||||
push_front_slice,
|
||||
pop_back,
|
||||
pop_front,
|
||||
grow,
|
||||
|
|
@ -384,6 +572,28 @@ fn fuzzAgainstArrayList(_: void, input: []const u8) anyerror!void {
|
|||
q.pushFrontBounded(item),
|
||||
);
|
||||
},
|
||||
.push_back_slice => {
|
||||
var buffer: [std.math.maxInt(u3)]u32 = undefined;
|
||||
const items = buffer[0..random.int(u3)];
|
||||
for (items) |*item| {
|
||||
item.* = random.int(u8);
|
||||
}
|
||||
try testing.expectEqual(
|
||||
l.appendSliceBounded(items),
|
||||
q.pushBackSliceBounded(items),
|
||||
);
|
||||
},
|
||||
.push_front_slice => {
|
||||
var buffer: [std.math.maxInt(u3)]u32 = undefined;
|
||||
const items = buffer[0..random.int(u3)];
|
||||
for (items) |*item| {
|
||||
item.* = random.int(u8);
|
||||
}
|
||||
try testing.expectEqual(
|
||||
l.insertSliceBounded(0, items),
|
||||
q.pushFrontSliceBounded(items),
|
||||
);
|
||||
},
|
||||
.pop_back => {
|
||||
try testing.expectEqual(l.pop(), q.popBack());
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue