mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 11:17:05 -04:00
Add chat history accessible with up/down arrows (#1244)
* Add up down message history * Deduplicate messages when inserting into history * Add dedicated function for inserting strings into TextInput * Fix formatting issues * Change history behavior * Rename inputString to setString * Move clearing to setString * Apply suggestions from code review Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com> * Remove unused cursor capture * Use FixedSizeCircularBuffer for history * Restore large queue size * Allow navigation to empty entry * self.len must never be bigger than capacity * Move optional callbacks into struct * Use enum for moveCursorVertically return value * WA attempt #1 * Fix edge case from review * Update src/gui/windows/chat.zig Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com> * Remove isEmpty and isFull * Allow for empty history entry * Change empty message handling some more * Remove unused methods * Go to hell with all of those edge cases <3 * WA for 4b * Remove CircularBufferQueue methods * Fix queue thing --------- Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com>
This commit is contained in:
parent
7fed896a77
commit
67135b433d
@ -33,6 +33,7 @@ maxHeight: f32,
|
|||||||
textSize: Vec2f = undefined,
|
textSize: Vec2f = undefined,
|
||||||
scrollBar: *ScrollBar,
|
scrollBar: *ScrollBar,
|
||||||
onNewline: gui.Callback,
|
onNewline: gui.Callback,
|
||||||
|
optional: OptionalCallbacks,
|
||||||
|
|
||||||
pub fn __init() void {
|
pub fn __init() void {
|
||||||
texture = Texture.initFromFile("assets/cubyz/ui/text_input.png");
|
texture = Texture.initFromFile("assets/cubyz/ui/text_input.png");
|
||||||
@ -42,7 +43,12 @@ pub fn __deinit() void {
|
|||||||
texture.deinit();
|
texture.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(pos: Vec2f, maxWidth: f32, maxHeight: f32, text: []const u8, onNewline: gui.Callback) *TextInput {
|
const OptionalCallbacks = struct {
|
||||||
|
onUp: ?gui.Callback = null,
|
||||||
|
onDown: ?gui.Callback = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(pos: Vec2f, maxWidth: f32, maxHeight: f32, text: []const u8, onNewline: gui.Callback, optional: OptionalCallbacks) *TextInput {
|
||||||
const scrollBar = ScrollBar.init(undefined, scrollBarWidth, maxHeight - 2*border, 0);
|
const scrollBar = ScrollBar.init(undefined, scrollBarWidth, maxHeight - 2*border, 0);
|
||||||
const self = main.globalAllocator.create(TextInput);
|
const self = main.globalAllocator.create(TextInput);
|
||||||
self.* = TextInput{
|
self.* = TextInput{
|
||||||
@ -54,6 +60,7 @@ pub fn init(pos: Vec2f, maxWidth: f32, maxHeight: f32, text: []const u8, onNewli
|
|||||||
.maxHeight = maxHeight,
|
.maxHeight = maxHeight,
|
||||||
.scrollBar = scrollBar,
|
.scrollBar = scrollBar,
|
||||||
.onNewline = onNewline,
|
.onNewline = onNewline,
|
||||||
|
.optional = optional,
|
||||||
};
|
};
|
||||||
self.currentString.appendSlice(text);
|
self.currentString.appendSlice(text);
|
||||||
self.textSize = self.textBuffer.calculateLineBreaks(fontSize, maxWidth - 2*border - scrollBarWidth);
|
self.textSize = self.textBuffer.calculateLineBreaks(fontSize, maxWidth - 2*border - scrollBarWidth);
|
||||||
@ -239,8 +246,13 @@ pub fn right(self: *TextInput, mods: main.Window.Key.Modifiers) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn moveCursorVertically(self: *TextInput, relativeLines: f32) void {
|
fn moveCursorVertically(self: *TextInput, relativeLines: f32) enum {changed, same} {
|
||||||
self.cursor = self.textBuffer.mousePosToIndex(self.textBuffer.indexToCursorPos(self.cursor.?) + Vec2f{0, 16*relativeLines}, self.currentString.items.len);
|
const newCursor = self.textBuffer.mousePosToIndex(self.textBuffer.indexToCursorPos(self.cursor.?) + Vec2f{0, 16*relativeLines}, self.currentString.items.len);
|
||||||
|
self.cursor = newCursor;
|
||||||
|
if(self.cursor != newCursor) {
|
||||||
|
return .changed;
|
||||||
|
}
|
||||||
|
return .same;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn down(self: *TextInput, mods: main.Window.Key.Modifiers) void {
|
pub fn down(self: *TextInput, mods: main.Window.Key.Modifiers) void {
|
||||||
@ -249,7 +261,7 @@ pub fn down(self: *TextInput, mods: main.Window.Key.Modifiers) void {
|
|||||||
if(self.selectionStart == null) {
|
if(self.selectionStart == null) {
|
||||||
self.selectionStart = cursor.*;
|
self.selectionStart = cursor.*;
|
||||||
}
|
}
|
||||||
self.moveCursorVertically(1);
|
_ = self.moveCursorVertically(1);
|
||||||
if(self.selectionStart == self.cursor) {
|
if(self.selectionStart == self.cursor) {
|
||||||
self.selectionStart = null;
|
self.selectionStart = null;
|
||||||
}
|
}
|
||||||
@ -258,7 +270,9 @@ pub fn down(self: *TextInput, mods: main.Window.Key.Modifiers) void {
|
|||||||
cursor.* = @max(cursor.*, selectionStart);
|
cursor.* = @max(cursor.*, selectionStart);
|
||||||
self.selectionStart = null;
|
self.selectionStart = null;
|
||||||
} else {
|
} else {
|
||||||
self.moveCursorVertically(1);
|
if(self.moveCursorVertically(1) == .same) {
|
||||||
|
if(self.optional.onDown) |cb| cb.run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.ensureCursorVisibility();
|
self.ensureCursorVisibility();
|
||||||
@ -271,7 +285,7 @@ pub fn up(self: *TextInput, mods: main.Window.Key.Modifiers) void {
|
|||||||
if(self.selectionStart == null) {
|
if(self.selectionStart == null) {
|
||||||
self.selectionStart = cursor.*;
|
self.selectionStart = cursor.*;
|
||||||
}
|
}
|
||||||
self.moveCursorVertically(-1);
|
_ = self.moveCursorVertically(-1);
|
||||||
if(self.selectionStart == self.cursor) {
|
if(self.selectionStart == self.cursor) {
|
||||||
self.selectionStart = null;
|
self.selectionStart = null;
|
||||||
}
|
}
|
||||||
@ -280,7 +294,9 @@ pub fn up(self: *TextInput, mods: main.Window.Key.Modifiers) void {
|
|||||||
cursor.* = @min(cursor.*, selectionStart);
|
cursor.* = @min(cursor.*, selectionStart);
|
||||||
self.selectionStart = null;
|
self.selectionStart = null;
|
||||||
} else {
|
} else {
|
||||||
self.moveCursorVertically(-1);
|
if(self.moveCursorVertically(-1) == .same) {
|
||||||
|
if(self.optional.onUp) |cb| cb.run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.ensureCursorVisibility();
|
self.ensureCursorVisibility();
|
||||||
@ -393,6 +409,14 @@ pub fn inputCharacter(self: *TextInput, character: u21) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn setString(self: *TextInput, utf8EncodedString: []const u8) void {
|
||||||
|
self.clear();
|
||||||
|
self.currentString.insertSlice(0, utf8EncodedString);
|
||||||
|
self.reloadText();
|
||||||
|
if(self.cursor != null) self.cursor = @intCast(utf8EncodedString.len);
|
||||||
|
self.ensureCursorVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn selectAll(self: *TextInput, mods: main.Window.Key.Modifiers) void {
|
pub fn selectAll(self: *TextInput, mods: main.Window.Key.Modifiers) void {
|
||||||
if(mods.control) {
|
if(mods.control) {
|
||||||
self.selectionStart = 0;
|
self.selectionStart = 0;
|
||||||
|
@ -49,7 +49,7 @@ pub fn onOpen() void {
|
|||||||
list.add(Label.init(.{0, 0}, width, "\\**italic*\\* \\*\\***bold**\\*\\* \\_\\___underlined__\\_\\_ \\~\\~~~strike-through~~\\~\\~", .center));
|
list.add(Label.init(.{0, 0}, width, "\\**italic*\\* \\*\\***bold**\\*\\* \\_\\___underlined__\\_\\_ \\~\\~~~strike-through~~\\~\\~", .center));
|
||||||
list.add(Label.init(.{0, 0}, width, "Even colors are possible, using the hexadecimal color code:", .center));
|
list.add(Label.init(.{0, 0}, width, "Even colors are possible, using the hexadecimal color code:", .center));
|
||||||
list.add(Label.init(.{0, 0}, width, "\\##ff0000ff#ffffff00#ffffff00#ff0000red#ffffff \\##ff0000ff#00770077#ffffff00#ff7700orange#ffffff \\##ffffff00#00ff00ff#ffffff00#00ff00green#ffffff \\##ffffff00#ffffff00#0000ffff#0000ffblue", .center));
|
list.add(Label.init(.{0, 0}, width, "\\##ff0000ff#ffffff00#ffffff00#ff0000red#ffffff \\##ff0000ff#00770077#ffffff00#ff7700orange#ffffff \\##ffffff00#00ff00ff#ffffff00#00ff00green#ffffff \\##ffffff00#ffffff00#0000ffff#0000ffblue", .center));
|
||||||
textComponent = TextInput.init(.{0, 0}, width, 32, if(settings.playerName.len == 0) "quanturmdoelvloper" else settings.playerName, .{.callback = &apply});
|
textComponent = TextInput.init(.{0, 0}, width, 32, if(settings.playerName.len == 0) "quanturmdoelvloper" else settings.playerName, .{.callback = &apply}, .{});
|
||||||
list.add(textComponent);
|
list.add(textComponent);
|
||||||
list.add(Button.initText(.{0, 0}, 100, "Apply", .{.callback = &apply}));
|
list.add(Button.initText(.{0, 0}, 100, "Apply", .{.callback = &apply}));
|
||||||
list.finish(.center);
|
list.finish(.center);
|
||||||
|
@ -11,6 +11,7 @@ const Label = GuiComponent.Label;
|
|||||||
const MutexComponent = GuiComponent.MutexComponent;
|
const MutexComponent = GuiComponent.MutexComponent;
|
||||||
const TextInput = GuiComponent.TextInput;
|
const TextInput = GuiComponent.TextInput;
|
||||||
const VerticalList = @import("../components/VerticalList.zig");
|
const VerticalList = @import("../components/VerticalList.zig");
|
||||||
|
const FixedSizeCircularBuffer = main.utils.FixedSizeCircularBuffer;
|
||||||
|
|
||||||
pub var window: GuiWindow = GuiWindow{
|
pub var window: GuiWindow = GuiWindow{
|
||||||
.relativePosition = .{
|
.relativePosition = .{
|
||||||
@ -29,6 +30,7 @@ pub var window: GuiWindow = GuiWindow{
|
|||||||
const padding: f32 = 8;
|
const padding: f32 = 8;
|
||||||
const messageTimeout: i32 = 10000;
|
const messageTimeout: i32 = 10000;
|
||||||
const messageFade = 1000;
|
const messageFade = 1000;
|
||||||
|
const reusableHistoryMaxSize = 8192;
|
||||||
|
|
||||||
var history: main.List(*Label) = undefined;
|
var history: main.List(*Label) = undefined;
|
||||||
var messageQueue: main.utils.ConcurrentQueue([]const u8) = undefined;
|
var messageQueue: main.utils.ConcurrentQueue([]const u8) = undefined;
|
||||||
@ -37,9 +39,79 @@ var historyStart: u32 = 0;
|
|||||||
var fadeOutEnd: u32 = 0;
|
var fadeOutEnd: u32 = 0;
|
||||||
pub var input: *TextInput = undefined;
|
pub var input: *TextInput = undefined;
|
||||||
var hideInput: bool = true;
|
var hideInput: bool = true;
|
||||||
|
var messageHistory: History = undefined;
|
||||||
|
|
||||||
|
pub const History = struct {
|
||||||
|
up: FixedSizeCircularBuffer([]const u8, reusableHistoryMaxSize),
|
||||||
|
down: FixedSizeCircularBuffer([]const u8, reusableHistoryMaxSize),
|
||||||
|
|
||||||
|
fn init() History {
|
||||||
|
return .{
|
||||||
|
.up = .init(main.globalAllocator),
|
||||||
|
.down = .init(main.globalAllocator),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
fn deinit(self: *History) void {
|
||||||
|
self.clear();
|
||||||
|
self.up.deinit(main.globalAllocator);
|
||||||
|
self.down.deinit(main.globalAllocator);
|
||||||
|
}
|
||||||
|
fn clear(self: *History) void {
|
||||||
|
while(self.up.dequeue()) |msg| {
|
||||||
|
main.globalAllocator.free(msg);
|
||||||
|
}
|
||||||
|
while(self.down.dequeue()) |msg| {
|
||||||
|
main.globalAllocator.free(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn flushUp(self: *History) void {
|
||||||
|
while(self.down.dequeueFront()) |msg| {
|
||||||
|
if(msg.len == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(self.up.forceEnqueueFront(msg)) |old| {
|
||||||
|
main.globalAllocator.free(old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn isDuplicate(self: *History, new: []const u8) bool {
|
||||||
|
if(new.len == 0) return true;
|
||||||
|
if(self.down.peekFront()) |msg| {
|
||||||
|
if(std.mem.eql(u8, msg, new)) return true;
|
||||||
|
}
|
||||||
|
if(self.up.peekFront()) |msg| {
|
||||||
|
if(std.mem.eql(u8, msg, new)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pub fn pushDown(self: *History, new: []const u8) void {
|
||||||
|
if(self.down.forceEnqueueFront(new)) |old| {
|
||||||
|
main.globalAllocator.free(old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn pushUp(self: *History, new: []const u8) void {
|
||||||
|
if(self.up.forceEnqueueFront(new)) |old| {
|
||||||
|
main.globalAllocator.free(old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn cycleUp(self: *History) bool {
|
||||||
|
if(self.down.dequeueFront()) |msg| {
|
||||||
|
self.pushUp(msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pub fn cycleDown(self: *History) void {
|
||||||
|
if(self.up.dequeueFront()) |msg| {
|
||||||
|
self.pushDown(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub fn init() void {
|
pub fn init() void {
|
||||||
history = .init(main.globalAllocator);
|
history = .init(main.globalAllocator);
|
||||||
|
messageHistory = .init();
|
||||||
expirationTime = .init(main.globalAllocator);
|
expirationTime = .init(main.globalAllocator);
|
||||||
messageQueue = .init(main.globalAllocator, 16);
|
messageQueue = .init(main.globalAllocator, 16);
|
||||||
}
|
}
|
||||||
@ -52,6 +124,7 @@ pub fn deinit() void {
|
|||||||
while(messageQueue.dequeue()) |msg| {
|
while(messageQueue.dequeue()) |msg| {
|
||||||
main.globalAllocator.free(msg);
|
main.globalAllocator.free(msg);
|
||||||
}
|
}
|
||||||
|
messageHistory.deinit();
|
||||||
messageQueue.deinit();
|
messageQueue.deinit();
|
||||||
expirationTime.deinit();
|
expirationTime.deinit();
|
||||||
}
|
}
|
||||||
@ -87,10 +160,32 @@ fn refresh() void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn onOpen() void {
|
pub fn onOpen() void {
|
||||||
input = TextInput.init(.{0, 0}, 256, 32, "", .{.callback = &sendMessage});
|
input = TextInput.init(.{0, 0}, 256, 32, "", .{.callback = &sendMessage}, .{.onUp = .{.callback = loadNextHistoryEntry}, .onDown = .{.callback = loadPreviousHistoryEntry}});
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn loadNextHistoryEntry(_: usize) void {
|
||||||
|
const isSuccess = messageHistory.cycleUp();
|
||||||
|
if(messageHistory.isDuplicate(input.currentString.items)) {
|
||||||
|
if(isSuccess) messageHistory.cycleDown();
|
||||||
|
messageHistory.cycleDown();
|
||||||
|
} else {
|
||||||
|
messageHistory.pushDown(main.globalAllocator.dupe(u8, input.currentString.items));
|
||||||
|
messageHistory.cycleDown();
|
||||||
|
}
|
||||||
|
const msg = messageHistory.down.peekFront() orelse "";
|
||||||
|
input.setString(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loadPreviousHistoryEntry(_: usize) void {
|
||||||
|
_ = messageHistory.cycleUp();
|
||||||
|
if(messageHistory.isDuplicate(input.currentString.items)) {} else {
|
||||||
|
messageHistory.pushUp(main.globalAllocator.dupe(u8, input.currentString.items));
|
||||||
|
}
|
||||||
|
const msg = messageHistory.down.peekFront() orelse "";
|
||||||
|
input.setString(msg);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn onClose() void {
|
pub fn onClose() void {
|
||||||
while(history.popOrNull()) |label| {
|
while(history.popOrNull()) |label| {
|
||||||
label.deinit();
|
label.deinit();
|
||||||
@ -98,6 +193,7 @@ pub fn onClose() void {
|
|||||||
while(messageQueue.dequeue()) |msg| {
|
while(messageQueue.dequeue()) |msg| {
|
||||||
main.globalAllocator.free(msg);
|
main.globalAllocator.free(msg);
|
||||||
}
|
}
|
||||||
|
messageHistory.clear();
|
||||||
expirationTime.clearRetainingCapacity();
|
expirationTime.clearRetainingCapacity();
|
||||||
historyStart = 0;
|
historyStart = 0;
|
||||||
fadeOutEnd = 0;
|
fadeOutEnd = 0;
|
||||||
@ -156,6 +252,11 @@ pub fn sendMessage(_: usize) void {
|
|||||||
if(data.len > 10000 or main.graphics.TextBuffer.Parser.countVisibleCharacters(data) > 1000) {
|
if(data.len > 10000 or main.graphics.TextBuffer.Parser.countVisibleCharacters(data) > 1000) {
|
||||||
std.log.err("Chat message is too long with {}/{} characters. Limits are 1000/10000", .{main.graphics.TextBuffer.Parser.countVisibleCharacters(data), data.len});
|
std.log.err("Chat message is too long with {}/{} characters. Limits are 1000/10000", .{main.graphics.TextBuffer.Parser.countVisibleCharacters(data), data.len});
|
||||||
} else {
|
} else {
|
||||||
|
messageHistory.flushUp();
|
||||||
|
if(!messageHistory.isDuplicate(data)) {
|
||||||
|
messageHistory.pushUp(main.globalAllocator.dupe(u8, data));
|
||||||
|
}
|
||||||
|
|
||||||
main.network.Protocols.chat.send(main.game.world.?.conn, data);
|
main.network.Protocols.chat.send(main.game.world.?.conn, data);
|
||||||
input.clear();
|
input.clear();
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ pub fn onOpen() void {
|
|||||||
ipAddressLabel = Label.init(.{0, 0}, width, " ", .center);
|
ipAddressLabel = Label.init(.{0, 0}, width, " ", .center);
|
||||||
list.add(ipAddressLabel);
|
list.add(ipAddressLabel);
|
||||||
list.add(Button.initText(.{0, 0}, 100, "Copy IP", .{.callback = ©Ip}));
|
list.add(Button.initText(.{0, 0}, 100, "Copy IP", .{.callback = ©Ip}));
|
||||||
ipAddressEntry = TextInput.init(.{0, 0}, width, 32, settings.lastUsedIPAddress, .{.callback = &invite});
|
ipAddressEntry = TextInput.init(.{0, 0}, width, 32, settings.lastUsedIPAddress, .{.callback = &invite}, .{});
|
||||||
list.add(ipAddressEntry);
|
list.add(ipAddressEntry);
|
||||||
list.add(Button.initText(.{0, 0}, 100, "Invite", .{.callback = &invite}));
|
list.add(Button.initText(.{0, 0}, 100, "Invite", .{.callback = &invite}));
|
||||||
list.add(Button.initText(.{0, 0}, 100, "Manage Players", gui.openWindowCallback("manage_players")));
|
list.add(Button.initText(.{0, 0}, 100, "Manage Players", gui.openWindowCallback("manage_players")));
|
||||||
|
@ -92,7 +92,7 @@ pub fn onOpen() void {
|
|||||||
ipAddressLabel = Label.init(.{0, 0}, width, " ", .center);
|
ipAddressLabel = Label.init(.{0, 0}, width, " ", .center);
|
||||||
list.add(ipAddressLabel);
|
list.add(ipAddressLabel);
|
||||||
list.add(Button.initText(.{0, 0}, 100, "Copy IP", .{.callback = ©Ip}));
|
list.add(Button.initText(.{0, 0}, 100, "Copy IP", .{.callback = ©Ip}));
|
||||||
ipAddressEntry = TextInput.init(.{0, 0}, width, 32, settings.lastUsedIPAddress, .{.callback = &join});
|
ipAddressEntry = TextInput.init(.{0, 0}, width, 32, settings.lastUsedIPAddress, .{.callback = &join}, .{});
|
||||||
list.add(ipAddressEntry);
|
list.add(ipAddressEntry);
|
||||||
list.add(Button.initText(.{0, 0}, 100, "Join", .{.callback = &join}));
|
list.add(Button.initText(.{0, 0}, 100, "Join", .{.callback = &join}));
|
||||||
list.finish(.center);
|
list.finish(.center);
|
||||||
|
@ -109,7 +109,7 @@ pub fn onOpen() void {
|
|||||||
}
|
}
|
||||||
const name = std.fmt.allocPrint(main.stackAllocator.allocator, "Save{}", .{num}) catch unreachable;
|
const name = std.fmt.allocPrint(main.stackAllocator.allocator, "Save{}", .{num}) catch unreachable;
|
||||||
defer main.stackAllocator.free(name);
|
defer main.stackAllocator.free(name);
|
||||||
textInput = TextInput.init(.{0, 0}, 128, 22, name, .{.callback = &createWorld});
|
textInput = TextInput.init(.{0, 0}, 128, 22, name, .{.callback = &createWorld}, .{});
|
||||||
list.add(textInput);
|
list.add(textInput);
|
||||||
|
|
||||||
gamemodeInput = Button.initText(.{0, 0}, 128, @tagName(gamemode), .{.callback = &gamemodeCallback});
|
gamemodeInput = Button.initText(.{0, 0}, 128, @tagName(gamemode), .{.callback = &gamemodeCallback});
|
||||||
|
@ -338,12 +338,53 @@ pub fn FixedSizeCircularBuffer(T: type, capacity: comptime_int) type { // MARK:
|
|||||||
allocator.destroy(self.mem);
|
allocator.destroy(self.mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enqueue(self: *Self, elem: T) !void {
|
pub fn peekFront(self: Self) ?T {
|
||||||
|
if(self.len == 0) return null;
|
||||||
|
return self.mem[self.startIndex + self.len - 1 & mask];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn peekBack(self: Self) ?T {
|
||||||
|
if(self.len == 0) return null;
|
||||||
|
return self.mem[self.startIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enqueueFront(self: *Self, elem: T) !void {
|
||||||
if(self.len >= capacity) return error.OutOfMemory;
|
if(self.len >= capacity) return error.OutOfMemory;
|
||||||
|
self.enqueueFrontAssumeCapacity(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn forceEnqueueFront(self: *Self, elem: T) ?T {
|
||||||
|
const result = if(self.len >= capacity) self.dequeueBack() else null;
|
||||||
|
self.enqueueFrontAssumeCapacity(elem);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enqueueFrontAssumeCapacity(self: *Self, elem: T) void {
|
||||||
self.mem[self.startIndex + self.len & mask] = elem;
|
self.mem[self.startIndex + self.len & mask] = elem;
|
||||||
self.len += 1;
|
self.len += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enqueue(self: *Self, elem: T) !void {
|
||||||
|
return self.enqueueFront(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enqueueBack(self: *Self, elem: T) !void {
|
||||||
|
if(self.len >= capacity) return error.OutOfMemory;
|
||||||
|
self.enqueueBackAssumeCapacity(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enqueueBackAssumeCapacity(self: *Self, elem: T) void {
|
||||||
|
self.startIndex = (self.startIndex -% 1) & mask;
|
||||||
|
self.mem[self.startIndex] = elem;
|
||||||
|
self.len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn forceEnqueueBack(self: *Self, elem: T) ?T {
|
||||||
|
const result = if(self.len >= capacity) self.dequeueFront() else null;
|
||||||
|
self.enqueueBackAssumeCapacity(elem);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn enqueueSlice(self: *Self, elems: []const T) !void {
|
pub fn enqueueSlice(self: *Self, elems: []const T) !void {
|
||||||
if(elems.len + self.len > capacity) {
|
if(elems.len + self.len > capacity) {
|
||||||
return error.OutOfMemory;
|
return error.OutOfMemory;
|
||||||
@ -377,6 +418,16 @@ pub fn FixedSizeCircularBuffer(T: type, capacity: comptime_int) type { // MARK:
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn dequeue(self: *Self) ?T {
|
pub fn dequeue(self: *Self) ?T {
|
||||||
|
return self.dequeueBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dequeueFront(self: *Self) ?T {
|
||||||
|
if(self.len == 0) return null;
|
||||||
|
self.len -= 1;
|
||||||
|
return self.mem[self.startIndex + self.len & mask];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dequeueBack(self: *Self) ?T {
|
||||||
if(self.len == 0) return null;
|
if(self.len == 0) return null;
|
||||||
const result = self.mem[self.startIndex];
|
const result = self.mem[self.startIndex];
|
||||||
self.startIndex = (self.startIndex + 1) & mask;
|
self.startIndex = (self.startIndex + 1) & mask;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user