authorgravatar for meme@users.noreply.github.commeme <meme@users.noreply.github.com> 2020-07-25 19:38:26-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-26 05:42:38+00:00
logf050150ffaef7bc5e72e23c48d46617f640117e2
treebb5f1afd709a45f418624e928dfb3f6823f5ed93
parent9b75091fd4e2e6f406515fce645e1b50e978fded

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

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

lib/std/mem.zig+73
......@@ -2030,6 +2030,79 @@ test "rotate" {
20302030 testing.expect(eql(i32, &arr, &[_]i32{ 1, 2, 4, 5, 3 }));
20312031}
20322032
2033/// Replace needle with replacement as many times as possible, writing to an output buffer which is assumed to be of
2034/// appropriate size. Use replacementSize to calculate an appropriate buffer size.
2035pub fn replace(comptime T: type, input: []const T, needle: []const T, replacement: []const T, output: []T) usize {
2036 var i: usize = 0;
2037 var slide: usize = 0;
2038 var replacements: usize = 0;
2039 while (slide < input.len) {
2040 if (mem.indexOf(T, input[slide..], needle) == @as(usize, 0)) {
2041 mem.copy(T, output[i..i + replacement.len], replacement);
2042 i += replacement.len;
2043 slide += needle.len;
2044 replacements += 1;
2045 } else {
2046 output[i] = input[slide];
2047 i += 1;
2048 slide += 1;
2049 }
2050 }
2051
2052 return replacements;
2053}
2054
2055test "replace" {
2056 var output: [29]u8 = undefined;
2057 var replacements = replace(u8, "All your base are belong to us", "base", "Zig", output[0..]);
2058 testing.expect(replacements == 1);
2059 testing.expect(eql(u8, output[0..], "All your Zig are belong to us"));
2060
2061 replacements = replace(u8, "Favor reading code over writing code.", "code", "", output[0..]);
2062 testing.expect(replacements == 2);
2063 testing.expect(eql(u8, output[0..], "Favor reading over writing ."));
2064}
2065
2066/// Calculate the size needed in an output buffer to perform a replacement.
2067pub fn replacementSize(comptime T: type, input: []const T, needle: []const T, replacement: []const T) usize {
2068 var i: usize = 0;
2069 var size: usize = input.len;
2070 while (i < input.len) : (i += 1) {
2071 if (mem.indexOf(T, input[i..], needle) == @as(usize, 0)) {
2072 size = size - needle.len + replacement.len;
2073 i += needle.len;
2074 }
2075 }
2076
2077 return size;
2078}
2079
2080test "replacementSize" {
2081 testing.expect(replacementSize(u8, "All your base are belong to us", "base", "Zig") == 29);
2082 testing.expect(replacementSize(u8, "", "", "") == 0);
2083 testing.expect(replacementSize(u8, "Favor reading code over writing code.", "code", "") == 29);
2084 testing.expect(replacementSize(u8, "Only one obvious way to do things.", "things.", "things in Zig.") == 41);
2085}
2086
2087/// Perform a replacement on an allocated buffer of pre-determined size. Caller must free returned memory.
2088pub fn replaceOwned(comptime T: type, allocator: *Allocator, input: []const T, needle: []const T, replacement: []const T) Allocator.Error![]T {
2089 var output = try allocator.alloc(T, replacementSize(T, input, needle, replacement));
2090 _ = replace(T, input, needle, replacement, output);
2091 return output;
2092}
2093
2094test "replaceOwned" {
2095 const allocator = std.heap.page_allocator;
2096
2097 const base_replace = replaceOwned(u8, allocator, "All your base are belong to us", "base", "Zig") catch unreachable;
2098 defer allocator.free(base_replace);
2099 testing.expect(eql(u8, base_replace, "All your Zig are belong to us"));
2100
2101 const zen_replace = replaceOwned(u8, allocator, "Favor reading code over writing code.", " code", "") catch unreachable;
2102 defer allocator.free(zen_replace);
2103 testing.expect(eql(u8, zen_replace, "Favor reading over writing."));
2104}
2105
20332106/// Converts a little-endian integer to host endianness.
20342107pub fn littleToNative(comptime T: type, x: T) T {
20352108 return switch (builtin.endian) {