| ... | @@ -15,6 +15,7 @@ pub fn parse(alloc: std.mem.Allocator, path: string, inreader: anytype, options: | ... | @@ -15,6 +15,7 @@ pub fn parse(alloc: std.mem.Allocator, path: string, inreader: anytype, options: |
| 15 | var p = Parser.init(alloc, inreader.any(), options); | 15 | var p = Parser.init(alloc, inreader.any(), options); |
| 16 | defer p.temp.deinit(alloc); | 16 | defer p.temp.deinit(alloc); |
| 17 | defer p.strings_map.deinit(alloc); | 17 | defer p.strings_map.deinit(alloc); |
| | 18 | defer p.numbers_map.deinit(alloc); |
| 18 | errdefer p.extras.deinit(alloc); | 19 | errdefer p.extras.deinit(alloc); |
| 19 | | 20 | |
| 20 | comptime std.debug.assert(@intFromEnum(Value.zero) == 0); | 21 | comptime std.debug.assert(@intFromEnum(Value.zero) == 0); |
| ... | @@ -257,6 +258,7 @@ const Parser = struct { | ... | @@ -257,6 +258,7 @@ const Parser = struct { |
| 257 | col: usize = 1, | 258 | col: usize = 1, |
| 258 | extras: std.ArrayListUnmanaged(u8) = .{}, | 259 | extras: std.ArrayListUnmanaged(u8) = .{}, |
| 259 | strings_map: std.StringArrayHashMapUnmanaged(StringIndex) = .{}, | 260 | strings_map: std.StringArrayHashMapUnmanaged(StringIndex) = .{}, |
| | 261 | numbers_map: std.StringArrayHashMapUnmanaged(NumberIndex) = .{}, |
| 260 | depth: u16 = 0, | 262 | depth: u16 = 0, |
| 261 | | 263 | |
| 262 | support_trailing_commas: bool, | 264 | support_trailing_commas: bool, |
| ... | @@ -432,16 +434,40 @@ const Parser = struct { | ... | @@ -432,16 +434,40 @@ const Parser = struct { |
| 432 | const t = tracer.trace(@src(), "({s})", .{v}); | 434 | const t = tracer.trace(@src(), "({s})", .{v}); |
| 433 | defer t.end(); | 435 | defer t.end(); |
| 434 | | 436 | |
| | 437 | const adapter: AdapterNum = .{ .p = p }; |
| | 438 | const res = try p.numbers_map.getOrPutAdapted(alloc, v, adapter); |
| | 439 | if (res.found_existing) return @enumFromInt(@intFromEnum(res.value_ptr.*)); |
| | 440 | errdefer p.numbers_map.orderedRemoveAt(res.index); |
| 435 | const r = p.extras.items.len; | 441 | const r = p.extras.items.len; |
| 436 | const l = v.len; | 442 | const l = v.len; |
| 437 | if (l > std.math.maxInt(u8)) return error.JsonExpectedTODO; | 443 | try p.extras.ensureUnusedCapacity(alloc, 1 + 4 + l); |
| 438 | try p.extras.ensureUnusedCapacity(alloc, 1 + 1 + l); | | |
| 439 | p.extras.appendAssumeCapacity(@intFromEnum(Value.Tag.number)); | 444 | p.extras.appendAssumeCapacity(@intFromEnum(Value.Tag.number)); |
| 440 | p.extras.appendAssumeCapacity(@intCast(l)); | 445 | p.extras.appendSliceAssumeCapacity(&std.mem.toBytes(@as(u32, @intCast(l)))); |
| 441 | p.extras.appendSliceAssumeCapacity(v); | 446 | p.extras.appendSliceAssumeCapacity(v); |
| | 447 | res.value_ptr.* = @enumFromInt(r); |
| 442 | return @enumFromInt(r); | 448 | return @enumFromInt(r); |
| 443 | } | 449 | } |
| 444 | | 450 | |
| | 451 | const AdapterNum = struct { |
| | 452 | p: *const Parser, |
| | 453 | |
| | 454 | pub fn hash(ctx: @This(), a: string) u32 { |
| | 455 | _ = ctx; |
| | 456 | var hasher = std.hash.Wyhash.init(0); |
| | 457 | hasher.update(a); |
| | 458 | return @truncate(hasher.final()); |
| | 459 | } |
| | 460 | |
| | 461 | pub fn eql(ctx: @This(), a: string, _: string, b_index: usize) bool { |
| | 462 | const sidx = ctx.p.numbers_map.values()[b_index]; |
| | 463 | const i: u32 = @intFromEnum(sidx); |
| | 464 | std.debug.assert(@as(Value.Tag, @enumFromInt(ctx.p.extras.items[i])) == .number); |
| | 465 | const l: u32 = @bitCast(ctx.p.extras.items[i..][1..][0..4].*); |
| | 466 | const b = ctx.p.extras.items[i..][1..][4..][0..l]; |
| | 467 | return std.mem.eql(u8, a, b); |
| | 468 | } |
| | 469 | }; |
| | 470 | |
| 445 | pub fn getStr(p: *const Parser, sidx: StringIndex) string { | 471 | pub fn getStr(p: *const Parser, sidx: StringIndex) string { |
| 446 | const i: u32 = @intFromEnum(sidx); | 472 | const i: u32 = @intFromEnum(sidx); |
| 447 | std.debug.assert(@as(Value.Tag, @enumFromInt(p.extras.items[i])) == .string); | 473 | std.debug.assert(@as(Value.Tag, @enumFromInt(p.extras.items[i])) == .string); |