authorgravatar for pyrogx1133@gmail.comRonald Chen <pyrogx1133@gmail.com> 2022-12-10 13:57:50-08:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-12-12 07:07:56+02:00
log959c10c5e53d35f059dae577cd606d8c96a5feb4
treeda17eb4089a5122380260d9519e2bb455a4f15ca
parent4d23721395e463758ded226c6e086cf632444e3e

std: added std.mem.window


1 files changed, 150 insertions(+), 0 deletions(-)

lib/std/mem.zig+150
......@@ -2190,6 +2190,156 @@ test "splitBackwards (reset)" {
21902190 try testing.expect(it.next() == null);
21912191}
21922192
2193/// Returns an iterator with a sliding window of slices for `buffer`.
2194/// The sliding window has length `size` and on every iteration moves
2195/// forward by `advance`.
2196///
2197/// Extract data for moving average with:
2198/// `window(u8, "abcdefg", 3, 1)` will return slices
2199/// "abc", "bcd", "cde", "def", "efg", null, in that order.
2200///
2201/// Chunk or split every N items with:
2202/// `window(u8, "abcdefg", 3, 3)` will return slices
2203/// "abc", "def", "g", null, in that order.
2204///
2205/// Pick every even index with:
2206/// `window(u8, "abcdefg", 1, 2)` will return slices
2207/// "a", "c", "e", "g" null, in that order.
2208///
2209/// The `size` and `advance` must be not be zero.
2210pub fn window(comptime T: type, buffer: []const T, size: usize, advance: usize) WindowIterator(T) {
2211 assert(size != 0);
2212 assert(advance != 0);
2213 return .{
2214 .index = 0,
2215 .buffer = buffer,
2216 .size = size,
2217 .advance = advance,
2218 };
2219}
2220
2221test "window" {
2222 {
2223 // moving average size 3
2224 var it = window(u8, "abcdefg", 3, 1);
2225 try testing.expectEqualSlices(u8, it.next().?, "abc");
2226 try testing.expectEqualSlices(u8, it.next().?, "bcd");
2227 try testing.expectEqualSlices(u8, it.next().?, "cde");
2228 try testing.expectEqualSlices(u8, it.next().?, "def");
2229 try testing.expectEqualSlices(u8, it.next().?, "efg");
2230 try testing.expectEqual(it.next(), null);
2231
2232 // multibyte
2233 var it16 = window(u16, std.unicode.utf8ToUtf16LeStringLiteral("abcdefg"), 3, 1);
2234 try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("abc"));
2235 try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("bcd"));
2236 try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("cde"));
2237 try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("def"));
2238 try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("efg"));
2239 try testing.expectEqual(it16.next(), null);
2240 }
2241
2242 {
2243 // chunk/split every 3
2244 var it = window(u8, "abcdefg", 3, 3);
2245 try testing.expectEqualSlices(u8, it.next().?, "abc");
2246 try testing.expectEqualSlices(u8, it.next().?, "def");
2247 try testing.expectEqualSlices(u8, it.next().?, "g");
2248 try testing.expectEqual(it.next(), null);
2249 }
2250
2251 {
2252 // pick even
2253 var it = window(u8, "abcdefg", 1, 2);
2254 try testing.expectEqualSlices(u8, it.next().?, "a");
2255 try testing.expectEqualSlices(u8, it.next().?, "c");
2256 try testing.expectEqualSlices(u8, it.next().?, "e");
2257 try testing.expectEqualSlices(u8, it.next().?, "g");
2258 try testing.expectEqual(it.next(), null);
2259 }
2260
2261 {
2262 // empty
2263 var it = window(u8, "", 1, 1);
2264 try testing.expectEqualSlices(u8, it.next().?, "");
2265 try testing.expectEqual(it.next(), null);
2266
2267 it = window(u8, "", 10, 1);
2268 try testing.expectEqualSlices(u8, it.next().?, "");
2269 try testing.expectEqual(it.next(), null);
2270
2271 it = window(u8, "", 1, 10);
2272 try testing.expectEqualSlices(u8, it.next().?, "");
2273 try testing.expectEqual(it.next(), null);
2274
2275 it = window(u8, "", 10, 10);
2276 try testing.expectEqualSlices(u8, it.next().?, "");
2277 try testing.expectEqual(it.next(), null);
2278 }
2279
2280 {
2281 // first
2282 var it = window(u8, "abcdefg", 3, 3);
2283 try testing.expectEqualSlices(u8, it.first(), "abc");
2284 it.reset();
2285 try testing.expectEqualSlices(u8, it.next().?, "abc");
2286 }
2287
2288 {
2289 // reset
2290 var it = window(u8, "abcdefg", 3, 3);
2291 try testing.expectEqualSlices(u8, it.next().?, "abc");
2292 try testing.expectEqualSlices(u8, it.next().?, "def");
2293 try testing.expectEqualSlices(u8, it.next().?, "g");
2294 try testing.expectEqual(it.next(), null);
2295
2296 it.reset();
2297 try testing.expectEqualSlices(u8, it.next().?, "abc");
2298 try testing.expectEqualSlices(u8, it.next().?, "def");
2299 try testing.expectEqualSlices(u8, it.next().?, "g");
2300 try testing.expectEqual(it.next(), null);
2301 }
2302}
2303
2304pub fn WindowIterator(comptime T: type) type {
2305 return struct {
2306 buffer: []const T,
2307 index: ?usize,
2308 size: usize,
2309 advance: usize,
2310
2311 const Self = @This();
2312
2313 /// Returns a slice of the first window. This never fails.
2314 /// Call this only to get the first window and then use `next` to get
2315 /// all subsequent windows.
2316 pub fn first(self: *Self) []const T {
2317 assert(self.index.? == 0);
2318 return self.next().?;
2319 }
2320
2321 /// Returns a slice of the next window, or null if window is at end.
2322 pub fn next(self: *Self) ?[]const T {
2323 const start = self.index orelse return null;
2324 const next_index = start + self.advance;
2325 const end = if (start + self.size < self.buffer.len and next_index < self.buffer.len) blk: {
2326 self.index = next_index;
2327 break :blk start + self.size;
2328 } else blk: {
2329 self.index = null;
2330 break :blk self.buffer.len;
2331 };
2332
2333 return self.buffer[start..end];
2334 }
2335
2336 /// Resets the iterator to the initial window.
2337 pub fn reset(self: *Self) void {
2338 self.index = 0;
2339 }
2340 };
2341}
2342
21932343pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
21942344 return if (needle.len > haystack.len) false else eql(T, haystack[0..needle.len], needle);
21952345}