authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-01-17 18:44:02 -08:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-01-17 18:44:02 -08:00
log1775b61ec4a6676719a8c369e56af7f183bd303a
tree036a1644cfb8d50b6f4534eab4ffefa07968a3da
parent58f624046834b2b965baa22767ba0bc178efa939

add swapMany


2 files changed, 143 insertions(+), 0 deletions(-)

src/lib.zig+1
......@@ -112,3 +112,4 @@ pub usingnamespace @import("./StructOfArrays.zig");
112112pub usingnamespace @import("./StaticMultiList.zig");
113113pub usingnamespace @import("./join.zig");
114114pub usingnamespace @import("./omit.zig");
115pub usingnamespace @import("./swapMany.zig");
src/swapMany.zig created+142
......@@ -0,0 +1,142 @@
1const std = @import("std");
2const string = []const u8;
3const extras = @import("./lib.zig");
4
5/// Swap subregions slice[a..][0..an] and slice[b..][0..bn].
6/// Subregions may not overlap.
7pub fn swapMany(T: type, slice: []T, a: usize, an: usize, b: usize, bn: usize) void {
8 if (a == b) return;
9 if (a < b) return swapManyLR(T, slice, a, an, b, bn);
10 if (a > b) return swapManyLR(T, slice, b, bn, a, an);
11 unreachable;
12}
13pub fn swapManyLR(T: type, slice: []T, a: usize, an: usize, b: usize, bn: usize) void {
14 std.debug.assert(a + an <= b);
15 std.debug.assert(b + bn <= slice.len);
16
17 if (an == bn) {
18 for (0..an, 0..bn) |i, j| {
19 std.mem.swap(T, &slice[a + i], &slice[b + j]);
20 }
21 return;
22 }
23
24 const m = @min(an, bn);
25
26 if (an < bn) {
27 for (0..m) |i| {
28 std.mem.swap(T, &slice[a + i], &slice[b + i]);
29 }
30 for (m..bn) |i| {
31 const temp = slice[b + i];
32 std.mem.copyBackwards(
33 T,
34 slice[a + i + 1 .. b + i + 1],
35 slice[a + i .. b + i],
36 );
37 slice[a + i] = temp;
38 }
39 return;
40 }
41 if (an > bn) {
42 for (0..m) |i| {
43 std.mem.swap(T, &slice[a + i], &slice[b + i]);
44 }
45 for (m..an) |_| {
46 const temp = slice[a + m];
47 for (a + m..b + m - 1) |w| slice[w] = slice[w + 1];
48 slice[b + m - 1] = temp;
49 }
50 }
51}
52
53test {
54 var buf = [_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
55 swapMany(u8, &buf, 2, 3, 6, 3);
56 try std.testing.expectEqualSlices(u8, &.{ 0, 1, 6, 7, 8, 5, 2, 3, 4, 9 }, &buf);
57}
58test {
59 var buf = [_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
60 swapMany(u8, &buf, 2, 2, 6, 4);
61 try std.testing.expectEqualSlices(u8, &.{ 0, 1, 6, 7, 8, 9, 4, 5, 2, 3 }, &buf);
62}
63test {
64 var buf = [_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
65 swapMany(u8, &buf, 6, 4, 2, 2);
66 try std.testing.expectEqualSlices(u8, &.{ 0, 1, 6, 7, 8, 9, 4, 5, 2, 3 }, &buf);
67}
68
69test {
70 // 43111_ABCDIHEFGJ
71 var actual = "ABCDEFGHIJ".*;
72 swapMany(u8, &actual, 4, 3, 8, 1);
73 try std.testing.expectEqualSlices(u8, "ABCDIHEFGJ", &actual);
74}
75test {
76 // 33121_ABCHIGDEFJ
77 var actual = "ABCDEFGHIJ".*;
78 swapMany(u8, &actual, 3, 3, 7, 2);
79 try std.testing.expectEqualSlices(u8, "ABCHIGDEFJ", &actual);
80}
81test {
82 // 14131_AGHIFBCDEJ
83 var actual = "ABCDEFGHIJ".*;
84 swapMany(u8, &actual, 1, 4, 6, 3);
85 try std.testing.expectEqualSlices(u8, "AGHIFBCDEJ", &actual);
86}
87
88comptime {
89 @setEvalBranchQuota(20_000);
90 for (1..5) |an| {
91 for (1..5) |bn| {
92 for (1..5) |cn| {
93 for (1..5) |dn| {
94 for (1..5) |en| {
95 _ = struct {
96 test {
97 // | a | b | c | d | e |
98 const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
99 const digits = "0123456789";
100 var i: usize = 0;
101 var j: usize = 0;
102 var a: [an]u8 = undefined;
103 j = 0;
104 while (j < an) : (j += 1) a[j] = letters[i + j];
105 i += an;
106 var b: [bn]u8 = undefined;
107 j = 0;
108 while (j < bn) : (j += 1) b[j] = letters[i + j];
109 i += bn;
110 var c: [cn]u8 = undefined;
111 j = 0;
112 while (j < cn) : (j += 1) c[j] = letters[i + j];
113 i += cn;
114 var d: [dn]u8 = undefined;
115 j = 0;
116 while (j < dn) : (j += 1) d[j] = letters[i + j];
117 i += dn;
118 var e: [en]u8 = undefined;
119 j = 0;
120 while (j < en) : (j += 1) e[j] = letters[i + j];
121 i += en;
122 const key = [_]u8{ digits[an], digits[bn], digits[cn], digits[dn], digits[en], '_' };
123 var actual = key ++ a ++ b ++ c ++ d ++ e;
124 // | a | b | c | d | e |
125 swapMany(
126 u8,
127 &actual,
128 key.len + a.len,
129 b.len,
130 key.len + a.len + b.len + c.len,
131 d.len,
132 );
133 const expected = key ++ a ++ d ++ c ++ b ++ e;
134 try std.testing.expectEqualStrings(&expected, &actual);
135 }
136 };
137 }
138 }
139 }
140 }
141 }
142}