| author | |
| committer | |
| log | 289ba5dfc2dbd5f6f179c49e974b0332f16604a6 |
| tree | 8f04ab5cf1ffb0c7417e666c739cc89a632a9a52 |
| parent | 7b7f45dc2a54aa9dfd6263b2654a5ccc8c5d2c82 |
3 files changed, 317 insertions(+), 317 deletions(-)
src/InternArena.zig deleted-316| ... | ... | @@ -1,316 +0,0 @@ |
| 1 | map: std.AutoArrayHashMapUnmanaged(void, void) = .{}, | |
| 2 | items: std.MultiArrayList(Item) = .{}, | |
| 3 | extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 4 | ||
| 5 | const InternArena = @This(); | |
| 6 | const std = @import("std"); | |
| 7 | const Allocator = std.mem.Allocator; | |
| 8 | const assert = std.debug.assert; | |
| 9 | ||
| 10 | const KeyAdapter = struct { | |
| 11 | intern_arena: *const InternArena, | |
| 12 | ||
| 13 | pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool { | |
| 14 | _ = b_void; | |
| 15 | return ctx.intern_arena.indexToKey(@intToEnum(Index, b_map_index)).eql(a); | |
| 16 | } | |
| 17 | ||
| 18 | pub fn hash(ctx: @This(), a: Key) u32 { | |
| 19 | _ = ctx; | |
| 20 | return a.hash(); | |
| 21 | } | |
| 22 | }; | |
| 23 | ||
| 24 | pub const Key = union(enum) { | |
| 25 | int_type: struct { | |
| 26 | signedness: std.builtin.Signedness, | |
| 27 | bits: u16, | |
| 28 | }, | |
| 29 | ptr_type: struct { | |
| 30 | elem_type: Index, | |
| 31 | sentinel: Index, | |
| 32 | alignment: u16, | |
| 33 | size: std.builtin.Type.Pointer.Size, | |
| 34 | is_const: bool, | |
| 35 | is_volatile: bool, | |
| 36 | is_allowzero: bool, | |
| 37 | address_space: std.builtin.AddressSpace, | |
| 38 | }, | |
| 39 | array_type: struct { | |
| 40 | len: u64, | |
| 41 | child: Index, | |
| 42 | sentinel: Index, | |
| 43 | }, | |
| 44 | vector_type: struct { | |
| 45 | len: u32, | |
| 46 | child: Index, | |
| 47 | }, | |
| 48 | optional_type: struct { | |
| 49 | payload_type: Index, | |
| 50 | }, | |
| 51 | error_union_type: struct { | |
| 52 | error_set_type: Index, | |
| 53 | payload_type: Index, | |
| 54 | }, | |
| 55 | simple: Simple, | |
| 56 | ||
| 57 | pub fn hash(key: Key) u32 { | |
| 58 | var hasher = std.hash.Wyhash.init(0); | |
| 59 | switch (key) { | |
| 60 | .int_type => |int_type| { | |
| 61 | std.hash.autoHash(&hasher, int_type); | |
| 62 | }, | |
| 63 | .array_type => |array_type| { | |
| 64 | std.hash.autoHash(&hasher, array_type); | |
| 65 | }, | |
| 66 | else => @panic("TODO"), | |
| 67 | } | |
| 68 | return @truncate(u32, hasher.final()); | |
| 69 | } | |
| 70 | ||
| 71 | pub fn eql(a: Key, b: Key) bool { | |
| 72 | const KeyTag = std.meta.Tag(Key); | |
| 73 | const a_tag: KeyTag = a; | |
| 74 | const b_tag: KeyTag = b; | |
| 75 | if (a_tag != b_tag) return false; | |
| 76 | switch (a) { | |
| 77 | .int_type => |a_info| { | |
| 78 | const b_info = b.int_type; | |
| 79 | return std.meta.eql(a_info, b_info); | |
| 80 | }, | |
| 81 | .array_type => |a_info| { | |
| 82 | const b_info = b.array_type; | |
| 83 | return std.meta.eql(a_info, b_info); | |
| 84 | }, | |
| 85 | else => @panic("TODO"), | |
| 86 | } | |
| 87 | } | |
| 88 | }; | |
| 89 | ||
| 90 | pub const Item = struct { | |
| 91 | tag: Tag, | |
| 92 | /// The doc comments on the respective Tag explain how to interpret this. | |
| 93 | data: u32, | |
| 94 | }; | |
| 95 | ||
| 96 | /// Represents an index into `map`. It represents the canonical index | |
| 97 | /// of a `Value` within this `InternArena`. The values are typed. | |
| 98 | /// Two values which have the same type can be equality compared simply | |
| 99 | /// by checking if their indexes are equal, provided they are both in | |
| 100 | /// the same `InternArena`. | |
| 101 | pub const Index = enum(u32) { | |
| 102 | none = std.math.maxInt(u32), | |
| 103 | _, | |
| 104 | }; | |
| 105 | ||
| 106 | pub const Tag = enum(u8) { | |
| 107 | /// An integer type. | |
| 108 | /// data is number of bits | |
| 109 | type_int_signed, | |
| 110 | /// An integer type. | |
| 111 | /// data is number of bits | |
| 112 | type_int_unsigned, | |
| 113 | /// An array type. | |
| 114 | /// data is payload to Array. | |
| 115 | type_array, | |
| 116 | /// A type or value that can be represented with only an enum tag. | |
| 117 | /// data is Simple enum value | |
| 118 | simple, | |
| 119 | /// An unsigned integer value that can be represented by u32. | |
| 120 | /// data is integer value | |
| 121 | int_u32, | |
| 122 | /// An unsigned integer value that can be represented by i32. | |
| 123 | /// data is integer value bitcasted to u32. | |
| 124 | int_i32, | |
| 125 | /// A positive integer value that does not fit in 32 bits. | |
| 126 | /// data is a extra index to BigInt. | |
| 127 | int_big_positive, | |
| 128 | /// A negative integer value that does not fit in 32 bits. | |
| 129 | /// data is a extra index to BigInt. | |
| 130 | int_big_negative, | |
| 131 | /// A float value that can be represented by f32. | |
| 132 | /// data is float value bitcasted to u32. | |
| 133 | float_f32, | |
| 134 | /// A float value that can be represented by f64. | |
| 135 | /// data is payload index to Float64. | |
| 136 | float_f64, | |
| 137 | /// A float value that can be represented by f128. | |
| 138 | /// data is payload index to Float128. | |
| 139 | float_f128, | |
| 140 | }; | |
| 141 | ||
| 142 | pub const Simple = enum(u32) { | |
| 143 | f16, | |
| 144 | f32, | |
| 145 | f64, | |
| 146 | f80, | |
| 147 | f128, | |
| 148 | usize, | |
| 149 | isize, | |
| 150 | c_short, | |
| 151 | c_ushort, | |
| 152 | c_int, | |
| 153 | c_uint, | |
| 154 | c_long, | |
| 155 | c_ulong, | |
| 156 | c_longlong, | |
| 157 | c_ulonglong, | |
| 158 | c_longdouble, | |
| 159 | anyopaque, | |
| 160 | bool, | |
| 161 | void, | |
| 162 | type, | |
| 163 | anyerror, | |
| 164 | comptime_int, | |
| 165 | comptime_float, | |
| 166 | noreturn, | |
| 167 | @"anyframe", | |
| 168 | null_type, | |
| 169 | undefined_type, | |
| 170 | enum_literal_type, | |
| 171 | @"undefined", | |
| 172 | void_value, | |
| 173 | @"null", | |
| 174 | bool_true, | |
| 175 | bool_false, | |
| 176 | }; | |
| 177 | ||
| 178 | pub const Array = struct { | |
| 179 | len: u32, | |
| 180 | child: Index, | |
| 181 | }; | |
| 182 | ||
| 183 | pub fn deinit(ia: *InternArena, gpa: Allocator) void { | |
| 184 | ia.map.deinit(gpa); | |
| 185 | ia.items.deinit(gpa); | |
| 186 | ia.extra.deinit(gpa); | |
| 187 | } | |
| 188 | ||
| 189 | pub fn indexToKey(ia: InternArena, index: Index) Key { | |
| 190 | const item = ia.items.get(@enumToInt(index)); | |
| 191 | const data = item.data; | |
| 192 | return switch (item.tag) { | |
| 193 | .type_int_signed => .{ | |
| 194 | .int_type = .{ | |
| 195 | .signedness = .signed, | |
| 196 | .bits = @intCast(u16, data), | |
| 197 | }, | |
| 198 | }, | |
| 199 | .type_int_unsigned => .{ | |
| 200 | .int_type = .{ | |
| 201 | .signedness = .unsigned, | |
| 202 | .bits = @intCast(u16, data), | |
| 203 | }, | |
| 204 | }, | |
| 205 | .type_array => { | |
| 206 | const array_info = ia.extraData(Array, data); | |
| 207 | return .{ .array_type = .{ | |
| 208 | .len = array_info.len, | |
| 209 | .child = array_info.child, | |
| 210 | .sentinel = .none, | |
| 211 | } }; | |
| 212 | }, | |
| 213 | .simple => .{ .simple = @intToEnum(Simple, data) }, | |
| 214 | ||
| 215 | else => @panic("TODO"), | |
| 216 | }; | |
| 217 | } | |
| 218 | ||
| 219 | pub fn get(ia: *InternArena, gpa: Allocator, key: Key) Allocator.Error!Index { | |
| 220 | const adapter: KeyAdapter = .{ .intern_arena = ia }; | |
| 221 | const gop = try ia.map.getOrPutAdapted(gpa, key, adapter); | |
| 222 | if (gop.found_existing) { | |
| 223 | return @intToEnum(Index, gop.index); | |
| 224 | } | |
| 225 | switch (key) { | |
| 226 | .int_type => |int_type| { | |
| 227 | const tag: Tag = switch (int_type.signedness) { | |
| 228 | .signed => .type_int_signed, | |
| 229 | .unsigned => .type_int_unsigned, | |
| 230 | }; | |
| 231 | try ia.items.append(gpa, .{ | |
| 232 | .tag = tag, | |
| 233 | .data = int_type.bits, | |
| 234 | }); | |
| 235 | }, | |
| 236 | .array_type => |array_type| { | |
| 237 | const len = @intCast(u32, array_type.len); // TODO have a big_array encoding | |
| 238 | assert(array_type.sentinel == .none); // TODO have a sentinel_array encoding | |
| 239 | try ia.items.append(gpa, .{ | |
| 240 | .tag = .type_array, | |
| 241 | .data = try ia.addExtra(gpa, Array{ | |
| 242 | .len = len, | |
| 243 | .child = array_type.child, | |
| 244 | }), | |
| 245 | }); | |
| 246 | }, | |
| 247 | else => @panic("TODO"), | |
| 248 | } | |
| 249 | return @intToEnum(Index, ia.items.len - 1); | |
| 250 | } | |
| 251 | ||
| 252 | fn addExtra(ia: *InternArena, gpa: Allocator, extra: anytype) Allocator.Error!u32 { | |
| 253 | const fields = std.meta.fields(@TypeOf(extra)); | |
| 254 | try ia.extra.ensureUnusedCapacity(gpa, fields.len); | |
| 255 | return ia.addExtraAssumeCapacity(extra); | |
| 256 | } | |
| 257 | ||
| 258 | fn addExtraAssumeCapacity(ia: *InternArena, extra: anytype) u32 { | |
| 259 | const fields = std.meta.fields(@TypeOf(extra)); | |
| 260 | const result = @intCast(u32, ia.extra.items.len); | |
| 261 | inline for (fields) |field| { | |
| 262 | ia.extra.appendAssumeCapacity(switch (field.field_type) { | |
| 263 | u32 => @field(extra, field.name), | |
| 264 | Index => @enumToInt(@field(extra, field.name)), | |
| 265 | i32 => @bitCast(u32, @field(extra, field.name)), | |
| 266 | else => @compileError("bad field type"), | |
| 267 | }); | |
| 268 | } | |
| 269 | return result; | |
| 270 | } | |
| 271 | ||
| 272 | fn extraData(ia: InternArena, comptime T: type, index: usize) T { | |
| 273 | const fields = std.meta.fields(T); | |
| 274 | var i: usize = index; | |
| 275 | var result: T = undefined; | |
| 276 | inline for (fields) |field| { | |
| 277 | @field(result, field.name) = switch (field.field_type) { | |
| 278 | u32 => ia.extra.items[i], | |
| 279 | Index => @intToEnum(Index, ia.extra.items[i]), | |
| 280 | i32 => @bitCast(i32, ia.extra.items[i]), | |
| 281 | else => @compileError("bad field type"), | |
| 282 | }; | |
| 283 | i += 1; | |
| 284 | } | |
| 285 | return result; | |
| 286 | } | |
| 287 | ||
| 288 | test "basic usage" { | |
| 289 | const gpa = std.testing.allocator; | |
| 290 | ||
| 291 | var ia: InternArena = .{}; | |
| 292 | defer ia.deinit(gpa); | |
| 293 | ||
| 294 | const i32_type = try ia.get(gpa, .{ .int_type = .{ | |
| 295 | .signedness = .signed, | |
| 296 | .bits = 32, | |
| 297 | } }); | |
| 298 | const array_i32 = try ia.get(gpa, .{ .array_type = .{ | |
| 299 | .len = 10, | |
| 300 | .child = i32_type, | |
| 301 | .sentinel = .none, | |
| 302 | } }); | |
| 303 | ||
| 304 | const another_i32_type = try ia.get(gpa, .{ .int_type = .{ | |
| 305 | .signedness = .signed, | |
| 306 | .bits = 32, | |
| 307 | } }); | |
| 308 | try std.testing.expect(another_i32_type == i32_type); | |
| 309 | ||
| 310 | const another_array_i32 = try ia.get(gpa, .{ .array_type = .{ | |
| 311 | .len = 10, | |
| 312 | .child = i32_type, | |
| 313 | .sentinel = .none, | |
| 314 | } }); | |
| 315 | try std.testing.expect(another_array_i32 == array_i32); | |
| 316 | } |
src/InternPool.zig created+316| ... | ... | @@ -0,0 +1,316 @@ |
| 1 | map: std.AutoArrayHashMapUnmanaged(void, void) = .{}, | |
| 2 | items: std.MultiArrayList(Item) = .{}, | |
| 3 | extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 4 | ||
| 5 | const InternPool = @This(); | |
| 6 | const std = @import("std"); | |
| 7 | const Allocator = std.mem.Allocator; | |
| 8 | const assert = std.debug.assert; | |
| 9 | ||
| 10 | const KeyAdapter = struct { | |
| 11 | intern_pool: *const InternPool, | |
| 12 | ||
| 13 | pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool { | |
| 14 | _ = b_void; | |
| 15 | return ctx.intern_pool.indexToKey(@intToEnum(Index, b_map_index)).eql(a); | |
| 16 | } | |
| 17 | ||
| 18 | pub fn hash(ctx: @This(), a: Key) u32 { | |
| 19 | _ = ctx; | |
| 20 | return a.hash(); | |
| 21 | } | |
| 22 | }; | |
| 23 | ||
| 24 | pub const Key = union(enum) { | |
| 25 | int_type: struct { | |
| 26 | signedness: std.builtin.Signedness, | |
| 27 | bits: u16, | |
| 28 | }, | |
| 29 | ptr_type: struct { | |
| 30 | elem_type: Index, | |
| 31 | sentinel: Index, | |
| 32 | alignment: u16, | |
| 33 | size: std.builtin.Type.Pointer.Size, | |
| 34 | is_const: bool, | |
| 35 | is_volatile: bool, | |
| 36 | is_allowzero: bool, | |
| 37 | address_space: std.builtin.AddressSpace, | |
| 38 | }, | |
| 39 | array_type: struct { | |
| 40 | len: u64, | |
| 41 | child: Index, | |
| 42 | sentinel: Index, | |
| 43 | }, | |
| 44 | vector_type: struct { | |
| 45 | len: u32, | |
| 46 | child: Index, | |
| 47 | }, | |
| 48 | optional_type: struct { | |
| 49 | payload_type: Index, | |
| 50 | }, | |
| 51 | error_union_type: struct { | |
| 52 | error_set_type: Index, | |
| 53 | payload_type: Index, | |
| 54 | }, | |
| 55 | simple: Simple, | |
| 56 | ||
| 57 | pub fn hash(key: Key) u32 { | |
| 58 | var hasher = std.hash.Wyhash.init(0); | |
| 59 | switch (key) { | |
| 60 | .int_type => |int_type| { | |
| 61 | std.hash.autoHash(&hasher, int_type); | |
| 62 | }, | |
| 63 | .array_type => |array_type| { | |
| 64 | std.hash.autoHash(&hasher, array_type); | |
| 65 | }, | |
| 66 | else => @panic("TODO"), | |
| 67 | } | |
| 68 | return @truncate(u32, hasher.final()); | |
| 69 | } | |
| 70 | ||
| 71 | pub fn eql(a: Key, b: Key) bool { | |
| 72 | const KeyTag = std.meta.Tag(Key); | |
| 73 | const a_tag: KeyTag = a; | |
| 74 | const b_tag: KeyTag = b; | |
| 75 | if (a_tag != b_tag) return false; | |
| 76 | switch (a) { | |
| 77 | .int_type => |a_info| { | |
| 78 | const b_info = b.int_type; | |
| 79 | return std.meta.eql(a_info, b_info); | |
| 80 | }, | |
| 81 | .array_type => |a_info| { | |
| 82 | const b_info = b.array_type; | |
| 83 | return std.meta.eql(a_info, b_info); | |
| 84 | }, | |
| 85 | else => @panic("TODO"), | |
| 86 | } | |
| 87 | } | |
| 88 | }; | |
| 89 | ||
| 90 | pub const Item = struct { | |
| 91 | tag: Tag, | |
| 92 | /// The doc comments on the respective Tag explain how to interpret this. | |
| 93 | data: u32, | |
| 94 | }; | |
| 95 | ||
| 96 | /// Represents an index into `map`. It represents the canonical index | |
| 97 | /// of a `Value` within this `InternPool`. The values are typed. | |
| 98 | /// Two values which have the same type can be equality compared simply | |
| 99 | /// by checking if their indexes are equal, provided they are both in | |
| 100 | /// the same `InternPool`. | |
| 101 | pub const Index = enum(u32) { | |
| 102 | none = std.math.maxInt(u32), | |
| 103 | _, | |
| 104 | }; | |
| 105 | ||
| 106 | pub const Tag = enum(u8) { | |
| 107 | /// An integer type. | |
| 108 | /// data is number of bits | |
| 109 | type_int_signed, | |
| 110 | /// An integer type. | |
| 111 | /// data is number of bits | |
| 112 | type_int_unsigned, | |
| 113 | /// An array type. | |
| 114 | /// data is payload to Array. | |
| 115 | type_array, | |
| 116 | /// A type or value that can be represented with only an enum tag. | |
| 117 | /// data is Simple enum value | |
| 118 | simple, | |
| 119 | /// An unsigned integer value that can be represented by u32. | |
| 120 | /// data is integer value | |
| 121 | int_u32, | |
| 122 | /// An unsigned integer value that can be represented by i32. | |
| 123 | /// data is integer value bitcasted to u32. | |
| 124 | int_i32, | |
| 125 | /// A positive integer value that does not fit in 32 bits. | |
| 126 | /// data is a extra index to BigInt. | |
| 127 | int_big_positive, | |
| 128 | /// A negative integer value that does not fit in 32 bits. | |
| 129 | /// data is a extra index to BigInt. | |
| 130 | int_big_negative, | |
| 131 | /// A float value that can be represented by f32. | |
| 132 | /// data is float value bitcasted to u32. | |
| 133 | float_f32, | |
| 134 | /// A float value that can be represented by f64. | |
| 135 | /// data is payload index to Float64. | |
| 136 | float_f64, | |
| 137 | /// A float value that can be represented by f128. | |
| 138 | /// data is payload index to Float128. | |
| 139 | float_f128, | |
| 140 | }; | |
| 141 | ||
| 142 | pub const Simple = enum(u32) { | |
| 143 | f16, | |
| 144 | f32, | |
| 145 | f64, | |
| 146 | f80, | |
| 147 | f128, | |
| 148 | usize, | |
| 149 | isize, | |
| 150 | c_short, | |
| 151 | c_ushort, | |
| 152 | c_int, | |
| 153 | c_uint, | |
| 154 | c_long, | |
| 155 | c_ulong, | |
| 156 | c_longlong, | |
| 157 | c_ulonglong, | |
| 158 | c_longdouble, | |
| 159 | anyopaque, | |
| 160 | bool, | |
| 161 | void, | |
| 162 | type, | |
| 163 | anyerror, | |
| 164 | comptime_int, | |
| 165 | comptime_float, | |
| 166 | noreturn, | |
| 167 | @"anyframe", | |
| 168 | null_type, | |
| 169 | undefined_type, | |
| 170 | enum_literal_type, | |
| 171 | @"undefined", | |
| 172 | void_value, | |
| 173 | @"null", | |
| 174 | bool_true, | |
| 175 | bool_false, | |
| 176 | }; | |
| 177 | ||
| 178 | pub const Array = struct { | |
| 179 | len: u32, | |
| 180 | child: Index, | |
| 181 | }; | |
| 182 | ||
| 183 | pub fn deinit(ip: *InternPool, gpa: Allocator) void { | |
| 184 | ip.map.deinit(gpa); | |
| 185 | ip.items.deinit(gpa); | |
| 186 | ip.extra.deinit(gpa); | |
| 187 | } | |
| 188 | ||
| 189 | pub fn indexToKey(ip: InternPool, index: Index) Key { | |
| 190 | const item = ip.items.get(@enumToInt(index)); | |
| 191 | const data = item.data; | |
| 192 | return switch (item.tag) { | |
| 193 | .type_int_signed => .{ | |
| 194 | .int_type = .{ | |
| 195 | .signedness = .signed, | |
| 196 | .bits = @intCast(u16, data), | |
| 197 | }, | |
| 198 | }, | |
| 199 | .type_int_unsigned => .{ | |
| 200 | .int_type = .{ | |
| 201 | .signedness = .unsigned, | |
| 202 | .bits = @intCast(u16, data), | |
| 203 | }, | |
| 204 | }, | |
| 205 | .type_array => { | |
| 206 | const array_info = ip.extraData(Array, data); | |
| 207 | return .{ .array_type = .{ | |
| 208 | .len = array_info.len, | |
| 209 | .child = array_info.child, | |
| 210 | .sentinel = .none, | |
| 211 | } }; | |
| 212 | }, | |
| 213 | .simple => .{ .simple = @intToEnum(Simple, data) }, | |
| 214 | ||
| 215 | else => @panic("TODO"), | |
| 216 | }; | |
| 217 | } | |
| 218 | ||
| 219 | pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | |
| 220 | const adapter: KeyAdapter = .{ .intern_pool = ip }; | |
| 221 | const gop = try ip.map.getOrPutAdapted(gpa, key, adapter); | |
| 222 | if (gop.found_existing) { | |
| 223 | return @intToEnum(Index, gop.index); | |
| 224 | } | |
| 225 | switch (key) { | |
| 226 | .int_type => |int_type| { | |
| 227 | const tag: Tag = switch (int_type.signedness) { | |
| 228 | .signed => .type_int_signed, | |
| 229 | .unsigned => .type_int_unsigned, | |
| 230 | }; | |
| 231 | try ip.items.append(gpa, .{ | |
| 232 | .tag = tag, | |
| 233 | .data = int_type.bits, | |
| 234 | }); | |
| 235 | }, | |
| 236 | .array_type => |array_type| { | |
| 237 | const len = @intCast(u32, array_type.len); // TODO have a big_array encoding | |
| 238 | assert(array_type.sentinel == .none); // TODO have a sentinel_array encoding | |
| 239 | try ip.items.append(gpa, .{ | |
| 240 | .tag = .type_array, | |
| 241 | .data = try ip.addExtra(gpa, Array{ | |
| 242 | .len = len, | |
| 243 | .child = array_type.child, | |
| 244 | }), | |
| 245 | }); | |
| 246 | }, | |
| 247 | else => @panic("TODO"), | |
| 248 | } | |
| 249 | return @intToEnum(Index, ip.items.len - 1); | |
| 250 | } | |
| 251 | ||
| 252 | fn addExtra(ip: *InternPool, gpa: Allocator, extra: anytype) Allocator.Error!u32 { | |
| 253 | const fields = std.meta.fields(@TypeOf(extra)); | |
| 254 | try ip.extra.ensureUnusedCapacity(gpa, fields.len); | |
| 255 | return ip.addExtraAssumeCapacity(extra); | |
| 256 | } | |
| 257 | ||
| 258 | fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { | |
| 259 | const fields = std.meta.fields(@TypeOf(extra)); | |
| 260 | const result = @intCast(u32, ip.extra.items.len); | |
| 261 | inline for (fields) |field| { | |
| 262 | ip.extra.appendAssumeCapacity(switch (field.field_type) { | |
| 263 | u32 => @field(extra, field.name), | |
| 264 | Index => @enumToInt(@field(extra, field.name)), | |
| 265 | i32 => @bitCast(u32, @field(extra, field.name)), | |
| 266 | else => @compileError("bad field type"), | |
| 267 | }); | |
| 268 | } | |
| 269 | return result; | |
| 270 | } | |
| 271 | ||
| 272 | fn extraData(ip: InternPool, comptime T: type, index: usize) T { | |
| 273 | const fields = std.meta.fields(T); | |
| 274 | var i: usize = index; | |
| 275 | var result: T = undefined; | |
| 276 | inline for (fields) |field| { | |
| 277 | @field(result, field.name) = switch (field.field_type) { | |
| 278 | u32 => ip.extra.items[i], | |
| 279 | Index => @intToEnum(Index, ip.extra.items[i]), | |
| 280 | i32 => @bitCast(i32, ip.extra.items[i]), | |
| 281 | else => @compileError("bad field type"), | |
| 282 | }; | |
| 283 | i += 1; | |
| 284 | } | |
| 285 | return result; | |
| 286 | } | |
| 287 | ||
| 288 | test "basic usage" { | |
| 289 | const gpa = std.testing.allocator; | |
| 290 | ||
| 291 | var ip: InternPool = .{}; | |
| 292 | defer ip.deinit(gpa); | |
| 293 | ||
| 294 | const i32_type = try ip.get(gpa, .{ .int_type = .{ | |
| 295 | .signedness = .signed, | |
| 296 | .bits = 32, | |
| 297 | } }); | |
| 298 | const array_i32 = try ip.get(gpa, .{ .array_type = .{ | |
| 299 | .len = 10, | |
| 300 | .child = i32_type, | |
| 301 | .sentinel = .none, | |
| 302 | } }); | |
| 303 | ||
| 304 | const another_i32_type = try ip.get(gpa, .{ .int_type = .{ | |
| 305 | .signedness = .signed, | |
| 306 | .bits = 32, | |
| 307 | } }); | |
| 308 | try std.testing.expect(another_i32_type == i32_type); | |
| 309 | ||
| 310 | const another_array_i32 = try ip.get(gpa, .{ .array_type = .{ | |
| 311 | .len = 10, | |
| 312 | .child = i32_type, | |
| 313 | .sentinel = .none, | |
| 314 | } }); | |
| 315 | try std.testing.expect(another_array_i32 == array_i32); | |
| 316 | } |
src/link/Dwarf.zig+1-1| ... | ... | @@ -39,7 +39,7 @@ atom_last: ?*Atom = null, |
| 39 | 39 | |
| 40 | 40 | abbrev_table_offset: ?u64 = null, |
| 41 | 41 | |
| 42 | /// TODO replace with InternArena | |
| 42 | /// TODO replace with InternPool | |
| 43 | 43 | /// Table of debug symbol names. |
| 44 | 44 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 45 | 45 |