diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-01-07 16:42:14 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-01-07 16:42:14 -0500 |
| commit | 9f064bcf74ec0246630c0e5ed8df83df5c46aaaa (patch) | |
| tree | 21f432c171afa4a70eaa7dabff8fbc90cb393b72 /lib/std/json.zig | |
| parent | 7b73c7fe12e96de1be92b27474048566244f98c4 (diff) | |
| parent | 814b54d7980c2b71b99539ceb23fc09b21d347c0 (diff) | |
| download | zig-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.zig | 63 |
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); +} |
