aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authormeme <meme@users.noreply.github.com>2020-07-25 19:38:26 -0400
committerAndrew Kelley <andrew@ziglang.org>2020-07-26 05:42:38 +0000
commitf050150ffaef7bc5e72e23c48d46617f640117e2 (patch)
treebb5f1afd709a45f418624e928dfb3f6823f5ed93 /lib/std
parent9b75091fd4e2e6f406515fce645e1b50e978fded (diff)
downloadzig-f050150ffaef7bc5e72e23c48d46617f640117e2.tar.gz
zig-f050150ffaef7bc5e72e23c48d46617f640117e2.zip
Add memory replacement routines
* Added `replace` for simple pre-allocated search-and-replace * Added `replacementSize` for calculating ahead-of-time buffer sizes for performing a safe search-and-replace * Added `replaceOwned` for automatically allocating and performing replacement
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/mem.zig73
1 files changed, 73 insertions, 0 deletions
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index ac7bde47c1..0d6d7c118a 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -2030,6 +2030,79 @@ test "rotate" {
testing.expect(eql(i32, &arr, &[_]i32{ 1, 2, 4, 5, 3 }));
}
+/// Replace needle with replacement as many times as possible, writing to an output buffer which is assumed to be of
+/// appropriate size. Use replacementSize to calculate an appropriate buffer size.
+pub fn replace(comptime T: type, input: []const T, needle: []const T, replacement: []const T, output: []T) usize {
+ var i: usize = 0;
+ var slide: usize = 0;
+ var replacements: usize = 0;
+ while (slide < input.len) {
+ if (mem.indexOf(T, input[slide..], needle) == @as(usize, 0)) {
+ mem.copy(T, output[i..i + replacement.len], replacement);
+ i += replacement.len;
+ slide += needle.len;
+ replacements += 1;
+ } else {
+ output[i] = input[slide];
+ i += 1;
+ slide += 1;
+ }
+ }
+
+ return replacements;
+}
+
+test "replace" {
+ var output: [29]u8 = undefined;
+ var replacements = replace(u8, "All your base are belong to us", "base", "Zig", output[0..]);
+ testing.expect(replacements == 1);
+ testing.expect(eql(u8, output[0..], "All your Zig are belong to us"));
+
+ replacements = replace(u8, "Favor reading code over writing code.", "code", "", output[0..]);
+ testing.expect(replacements == 2);
+ testing.expect(eql(u8, output[0..], "Favor reading over writing ."));
+}
+
+/// Calculate the size needed in an output buffer to perform a replacement.
+pub fn replacementSize(comptime T: type, input: []const T, needle: []const T, replacement: []const T) usize {
+ var i: usize = 0;
+ var size: usize = input.len;
+ while (i < input.len) : (i += 1) {
+ if (mem.indexOf(T, input[i..], needle) == @as(usize, 0)) {
+ size = size - needle.len + replacement.len;
+ i += needle.len;
+ }
+ }
+
+ return size;
+}
+
+test "replacementSize" {
+ testing.expect(replacementSize(u8, "All your base are belong to us", "base", "Zig") == 29);
+ testing.expect(replacementSize(u8, "", "", "") == 0);
+ testing.expect(replacementSize(u8, "Favor reading code over writing code.", "code", "") == 29);
+ testing.expect(replacementSize(u8, "Only one obvious way to do things.", "things.", "things in Zig.") == 41);
+}
+
+/// Perform a replacement on an allocated buffer of pre-determined size. Caller must free returned memory.
+pub fn replaceOwned(comptime T: type, allocator: *Allocator, input: []const T, needle: []const T, replacement: []const T) Allocator.Error![]T {
+ var output = try allocator.alloc(T, replacementSize(T, input, needle, replacement));
+ _ = replace(T, input, needle, replacement, output);
+ return output;
+}
+
+test "replaceOwned" {
+ const allocator = std.heap.page_allocator;
+
+ const base_replace = replaceOwned(u8, allocator, "All your base are belong to us", "base", "Zig") catch unreachable;
+ defer allocator.free(base_replace);
+ testing.expect(eql(u8, base_replace, "All your Zig are belong to us"));
+
+ const zen_replace = replaceOwned(u8, allocator, "Favor reading code over writing code.", " code", "") catch unreachable;
+ defer allocator.free(zen_replace);
+ testing.expect(eql(u8, zen_replace, "Favor reading over writing."));
+}
+
/// Converts a little-endian integer to host endianness.
pub fn littleToNative(comptime T: type, x: T) T {
return switch (builtin.endian) {