aboutsummaryrefslogtreecommitdiff
path: root/lib/std/json.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-01-07 16:42:14 -0500
committerGitHub <noreply@github.com>2020-01-07 16:42:14 -0500
commit9f064bcf74ec0246630c0e5ed8df83df5c46aaaa (patch)
tree21f432c171afa4a70eaa7dabff8fbc90cb393b72 /lib/std/json.zig
parent7b73c7fe12e96de1be92b27474048566244f98c4 (diff)
parent814b54d7980c2b71b99539ceb23fc09b21d347c0 (diff)
downloadzig-9f064bcf74ec0246630c0e5ed8df83df5c46aaaa.tar.gz
zig-9f064bcf74ec0246630c0e5ed8df83df5c46aaaa.zip
Merge pull request #4091 from xackus/json_copy_strings
json: implement copy_strings=false
Diffstat (limited to 'lib/std/json.zig')
-rw-r--r--lib/std/json.zig63
1 files changed, 51 insertions, 12 deletions
diff --git a/lib/std/json.zig b/lib/std/json.zig
index 481ca7dd95..1b10be0763 100644
--- a/lib/std/json.zig
+++ b/lib/std/json.zig
@@ -1414,11 +1414,9 @@ pub const Parser = struct {
}
fn parseString(p: *Parser, allocator: *Allocator, s: std.meta.TagPayloadType(Token, Token.String), input: []const u8, i: usize) !Value {
- // TODO: We don't strictly have to copy values which do not contain any escape
- // characters if flagged with the option.
const slice = s.slice(input, i);
switch (s.escapes) {
- .None => return Value{ .String = try mem.dupe(allocator, u8, slice) },
+ .None => return Value{ .String = if (p.copy_strings) try mem.dupe(allocator, u8, slice) else slice },
.Some => |some_escapes| {
const output = try allocator.alloc(u8, s.decodedLength());
errdefer allocator.free(output);
@@ -1497,7 +1495,10 @@ fn unescapeString(output: []u8, input: []const u8) !void {
}
test "json.parser.dynamic" {
- var p = Parser.init(debug.global_allocator, false);
+ var memory: [1024 * 16]u8 = undefined;
+ var buf_alloc = std.heap.FixedBufferAllocator.init(&memory);
+
+ var p = Parser.init(&buf_alloc.allocator, false);
defer p.deinit();
const s =
@@ -1600,17 +1601,21 @@ test "write json then parse it" {
testing.expect(mem.eql(u8, tree.root.Object.get("str").?.value.String, "hello"));
}
-fn test_parse(json_str: []const u8) !Value {
- var p = Parser.init(debug.global_allocator, false);
+fn test_parse(memory: []u8, json_str: []const u8) !Value {
+ // buf_alloc goes out of scope, but we don't use it after parsing
+ var buf_alloc = std.heap.FixedBufferAllocator.init(memory);
+ var p = Parser.init(&buf_alloc.allocator, false);
return (try p.parse(json_str)).root;
}
test "parsing empty string gives appropriate error" {
- testing.expectError(error.UnexpectedEndOfJson, test_parse(""));
+ var memory: [1024 * 4]u8 = undefined;
+ testing.expectError(error.UnexpectedEndOfJson, test_parse(&memory, ""));
}
test "integer after float has proper type" {
- const json = try test_parse(
+ var memory: [1024 * 8]u8 = undefined;
+ const json = try test_parse(&memory,
\\{
\\ "float": 3.14,
\\ "ints": [1, 2, 3]
@@ -1620,6 +1625,7 @@ test "integer after float has proper type" {
}
test "escaped characters" {
+ var memory: [1024 * 16]u8 = undefined;
const input =
\\{
\\ "backslash": "\\",
@@ -1635,10 +1641,7 @@ test "escaped characters" {
\\}
;
- var p = Parser.init(debug.global_allocator, false);
- const tree = try p.parse(input);
-
- const obj = tree.root.Object;
+ const obj = (try test_parse(&memory, input)).Object;
testing.expectEqualSlices(u8, obj.get("backslash").?.value.String, "\\");
testing.expectEqualSlices(u8, obj.get("forwardslash").?.value.String, "/");
@@ -1651,3 +1654,39 @@ test "escaped characters" {
testing.expectEqualSlices(u8, obj.get("unicode").?.value.String, "ą");
testing.expectEqualSlices(u8, obj.get("surrogatepair").?.value.String, "😂");
}
+
+test "string copy option" {
+ const input =
+ \\{
+ \\ "noescape": "aą😂",
+ \\ "simple": "\\\/\n\r\t\f\b\"",
+ \\ "unicode": "\u0105",
+ \\ "surrogatepair": "\ud83d\ude02"
+ \\}
+ ;
+
+ var mem_buffer: [1024 * 16]u8 = undefined;
+ var buf_alloc = std.heap.FixedBufferAllocator.init(&mem_buffer);
+
+ const tree_nocopy = try Parser.init(&buf_alloc.allocator, false).parse(input);
+ const obj_nocopy = tree_nocopy.root.Object;
+
+ const tree_copy = try Parser.init(&buf_alloc.allocator, true).parse(input);
+ const obj_copy = tree_copy.root.Object;
+
+ for ([_][]const u8{ "noescape", "simple", "unicode", "surrogatepair" }) |field_name| {
+ testing.expectEqualSlices(u8, obj_nocopy.getValue(field_name).?.String, obj_copy.getValue(field_name).?.String);
+ }
+
+ const nocopy_addr = &obj_nocopy.getValue("noescape").?.String[0];
+ const copy_addr = &obj_copy.getValue("noescape").?.String[0];
+
+ var found_nocopy = false;
+ for (input) |_, index| {
+ testing.expect(copy_addr != &input[index]);
+ if (nocopy_addr == &input[index]) {
+ found_nocopy = true;
+ }
+ }
+ testing.expect(found_nocopy);
+}