authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-07 16:42:14-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-01-07 16:42:14-05:00
log9f064bcf74ec0246630c0e5ed8df83df5c46aaaa
tree21f432c171afa4a70eaa7dabff8fbc90cb393b72
parent7b73c7fe12e96de1be92b27474048566244f98c4
parent814b54d7980c2b71b99539ceb23fc09b21d347c0
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4091 from xackus/json_copy_strings

json: implement copy_strings=false

1 files changed, 51 insertions(+), 12 deletions(-)

lib/std/json.zig+51-12
......@@ -1414,11 +1414,9 @@ pub const Parser = struct {
14141414 }
14151415
14161416 fn parseString(p: *Parser, allocator: *Allocator, s: std.meta.TagPayloadType(Token, Token.String), input: []const u8, i: usize) !Value {
1417 // TODO: We don't strictly have to copy values which do not contain any escape
1418 // characters if flagged with the option.
14191417 const slice = s.slice(input, i);
14201418 switch (s.escapes) {
1421 .None => return Value{ .String = try mem.dupe(allocator, u8, slice) },
1419 .None => return Value{ .String = if (p.copy_strings) try mem.dupe(allocator, u8, slice) else slice },
14221420 .Some => |some_escapes| {
14231421 const output = try allocator.alloc(u8, s.decodedLength());
14241422 errdefer allocator.free(output);
......@@ -1497,7 +1495,10 @@ fn unescapeString(output: []u8, input: []const u8) !void {
14971495}
14981496
14991497test "json.parser.dynamic" {
1500 var p = Parser.init(debug.global_allocator, false);
1498 var memory: [1024 * 16]u8 = undefined;
1499 var buf_alloc = std.heap.FixedBufferAllocator.init(&memory);
1500
1501 var p = Parser.init(&buf_alloc.allocator, false);
15011502 defer p.deinit();
15021503
15031504 const s =
......@@ -1600,17 +1601,21 @@ test "write json then parse it" {
16001601 testing.expect(mem.eql(u8, tree.root.Object.get("str").?.value.String, "hello"));
16011602}
16021603
1603fn test_parse(json_str: []const u8) !Value {
1604 var p = Parser.init(debug.global_allocator, false);
1604fn test_parse(memory: []u8, json_str: []const u8) !Value {
1605 // buf_alloc goes out of scope, but we don't use it after parsing
1606 var buf_alloc = std.heap.FixedBufferAllocator.init(memory);
1607 var p = Parser.init(&buf_alloc.allocator, false);
16051608 return (try p.parse(json_str)).root;
16061609}
16071610
16081611test "parsing empty string gives appropriate error" {
1609 testing.expectError(error.UnexpectedEndOfJson, test_parse(""));
1612 var memory: [1024 * 4]u8 = undefined;
1613 testing.expectError(error.UnexpectedEndOfJson, test_parse(&memory, ""));
16101614}
16111615
16121616test "integer after float has proper type" {
1613 const json = try test_parse(
1617 var memory: [1024 * 8]u8 = undefined;
1618 const json = try test_parse(&memory,
16141619 \\{
16151620 \\ "float": 3.14,
16161621 \\ "ints": [1, 2, 3]
......@@ -1620,6 +1625,7 @@ test "integer after float has proper type" {
16201625}
16211626
16221627test "escaped characters" {
1628 var memory: [1024 * 16]u8 = undefined;
16231629 const input =
16241630 \\{
16251631 \\ "backslash": "\\",
......@@ -1635,10 +1641,7 @@ test "escaped characters" {
16351641 \\}
16361642 ;
16371643
1638 var p = Parser.init(debug.global_allocator, false);
1639 const tree = try p.parse(input);
1640
1641 const obj = tree.root.Object;
1644 const obj = (try test_parse(&memory, input)).Object;
16421645
16431646 testing.expectEqualSlices(u8, obj.get("backslash").?.value.String, "\\");
16441647 testing.expectEqualSlices(u8, obj.get("forwardslash").?.value.String, "/");
......@@ -1651,3 +1654,39 @@ test "escaped characters" {
16511654 testing.expectEqualSlices(u8, obj.get("unicode").?.value.String, "ą");
16521655 testing.expectEqualSlices(u8, obj.get("surrogatepair").?.value.String, "😂");
16531656}
1657
1658test "string copy option" {
1659 const input =
1660 \\{
1661 \\ "noescape": "aąðŸ˜‚",
1662 \\ "simple": "\\\/\n\r\t\f\b\"",
1663 \\ "unicode": "\u0105",
1664 \\ "surrogatepair": "\ud83d\ude02"
1665 \\}
1666 ;
1667
1668 var mem_buffer: [1024 * 16]u8 = undefined;
1669 var buf_alloc = std.heap.FixedBufferAllocator.init(&mem_buffer);
1670
1671 const tree_nocopy = try Parser.init(&buf_alloc.allocator, false).parse(input);
1672 const obj_nocopy = tree_nocopy.root.Object;
1673
1674 const tree_copy = try Parser.init(&buf_alloc.allocator, true).parse(input);
1675 const obj_copy = tree_copy.root.Object;
1676
1677 for ([_][]const u8{ "noescape", "simple", "unicode", "surrogatepair" }) |field_name| {
1678 testing.expectEqualSlices(u8, obj_nocopy.getValue(field_name).?.String, obj_copy.getValue(field_name).?.String);
1679 }
1680
1681 const nocopy_addr = &obj_nocopy.getValue("noescape").?.String[0];
1682 const copy_addr = &obj_copy.getValue("noescape").?.String[0];
1683
1684 var found_nocopy = false;
1685 for (input) |_, index| {
1686 testing.expect(copy_addr != &input[index]);
1687 if (nocopy_addr == &input[index]) {
1688 found_nocopy = true;
1689 }
1690 }
1691 testing.expect(found_nocopy);
1692}