Zig std.mem.rotate: หมุน slice in-place สำหรับคิวแบบวงแหวน
เมื่ออยากย้ายสมาชิกช่วงหน้าไปท้ายโดยยังใช้ buffer เดิม std.mem.rotate หมุน slice แบบ in-place ได้ครับ เหมือนหมุนถาดอาหารวงกลมให้จานที่อยู่หน้าเราเลื่อนไปอีกฝั่ง โดยไม่ยกจานทั้งหมดไปใส่ถาดใหม่
HOW: amount คือจำนวนสมาชิกที่เลื่อนไปทางซ้าย
const std = @import("std");
test "rotate queue left in place" {
var queue = [_]u8{ 10, 20, 30, 40 };
std.mem.rotate(u8, &queue, 2);
try std.testing.expectEqualSlices(u8, &.{ 30, 40, 10, 20 }, &queue);
}
test "zero rotation keeps the slice" {
var queue = [_]u8{ 1, 2, 3 };
std.mem.rotate(u8, &queue, 0);
try std.testing.expectEqualSlices(u8, &.{ 1, 2, 3 }, &queue);
}
ฟังก์ชันนี้แก้ข้อมูลจริง จึงเหมาะกับงาน batch ที่ต้องส่ง slice ต่อในลำดับใหม่ทันที เช่น เลื่อนงานที่ประมวลผลแล้วไปท้ายรอบ หรือทำ canonical rotation ก่อนเปรียบเทียบ แต่ถ้าเป็น ring buffer ที่หมุนทุก request การขยับสมาชิกซ้ำอาจแพงกว่าการเก็บ head index แล้วคำนวณตำแหน่งด้วย modulo
ใน Zig 0.16 caller ต้องให้ amount <= items.len ตามสัญญาของ API อย่าส่งค่าจากผู้ใช้ตรง ๆ ควร normalize ด้วย % items.len หลังตรวจว่า slice ไม่ว่าง เพราะ modulo ศูนย์ก็เป็น bug อีกแบบหนึ่งครับ
Recap
-
amountย้ายสมาชิกช่วงหน้าไปท้าย - ฟังก์ชันแก้ slice เดิมและไม่ allocate
- normalize ค่า input ก่อนเรียก โดยแยกกรณี slice ว่าง
- ring buffer ที่หมุนบ่อยควรใช้ head index แทนการย้ายข้อมูล