| ... | ... | @@ -33,9 +33,8 @@ pub const Header = extern struct { |
| 33 | 33 | pub const Wip = struct { |
| 34 | 34 | gpa: Allocator, |
| 35 | 35 | string_table: StringTable = .empty, |
| 36 | | /// De-duplicates an array inside `extra` that has first element length |
| 37 | | /// followed by length elements. |
| 38 | | length_prefixed_table: LengthPrefixedTable = .empty, |
| 36 | /// De-duplicates an array inside `extra`. |
| 37 | dedupe_table: DedupeTable = .empty, |
| 39 | 38 | targets_table: TargetsTable = .empty, |
| 40 | 39 | |
| 41 | 40 | string_bytes: std.ArrayList(u8) = .empty, |
| ... | ... | @@ -46,25 +45,27 @@ pub const Wip = struct { |
| 46 | 45 | path_deps: std.MultiArrayList(Path) = .empty, |
| 47 | 46 | extra: std.ArrayList(u32) = .empty, |
| 48 | 47 | |
| 49 | | const LengthPrefixedTable = std.HashMapUnmanaged(u32, void, LengthPrefixedContext, std.hash_map.default_max_load_percentage); |
| 48 | const DedupeTable = std.HashMapUnmanaged(ExtraSlice, void, ExtraSlice.Context, std.hash_map.default_max_load_percentage); |
| 50 | 49 | const TargetsTable = std.HashMapUnmanaged(TargetQuery.Index, void, TargetsTableContext, std.hash_map.default_max_load_percentage); |
| 51 | 50 | |
| 52 | | const LengthPrefixedContext = struct { |
| 53 | | extra: []const u32, |
| 51 | const ExtraSlice = struct { |
| 52 | index: u32, |
| 53 | len: u32, |
| 54 | 54 | |
| 55 | | pub fn eql(ctx: @This(), a: u32, b: u32) bool { |
| 56 | | const len_a = ctx.extra[a]; |
| 57 | | const len_b = ctx.extra[b]; |
| 58 | | const slice_a = ctx.extra[a + 1 ..][0..len_a]; |
| 59 | | const slice_b = ctx.extra[b + 1 ..][0..len_b]; |
| 60 | | return std.mem.eql(u32, slice_a, slice_b); |
| 61 | | } |
| 55 | const Context = struct { |
| 56 | extra: []const u32, |
| 62 | 57 | |
| 63 | | pub fn hash(ctx: @This(), key: u32) u64 { |
| 64 | | const len = ctx.extra[key]; |
| 65 | | const slice = ctx.extra[key + 1 ..][0..len]; |
| 66 | | return std.hash_map.hashString(@ptrCast(slice)); |
| 67 | | } |
| 58 | pub fn eql(ctx: @This(), a: ExtraSlice, b: ExtraSlice) bool { |
| 59 | const slice_a = ctx.extra[a.index..][0..a.len]; |
| 60 | const slice_b = ctx.extra[b.index..][0..b.len]; |
| 61 | return std.mem.eql(u32, slice_a, slice_b); |
| 62 | } |
| 63 | |
| 64 | pub fn hash(ctx: @This(), key: ExtraSlice) u64 { |
| 65 | const slice = ctx.extra[key.index..][0..key.len]; |
| 66 | return std.hash_map.hashString(@ptrCast(slice)); |
| 67 | } |
| 68 | }; |
| 68 | 69 | }; |
| 69 | 70 | |
| 70 | 71 | const TargetsTableContext = struct { |
| ... | ... | @@ -323,34 +324,33 @@ pub const Wip = struct { |
| 323 | 324 | } |
| 324 | 325 | } |
| 325 | 326 | |
| 326 | | pub fn reserveLengthPrefixed(wip: *Wip, n: usize) Allocator.Error![]u32 { |
| 327 | | const slice = try wip.extra.addManyAsSlice(wip.gpa, n + 1); |
| 328 | | slice[0] = @intCast(n); |
| 329 | | return slice[1..]; |
| 327 | pub fn addExtra(wip: *Wip, extra: anytype) Allocator.Error!u32 { |
| 328 | const extra_len = Storage.extraLen(extra); |
| 329 | try wip.extra.ensureUnusedCapacity(wip.gpa, extra_len); |
| 330 | return addExtraAssumeCapacity(wip, extra); |
| 330 | 331 | } |
| 331 | 332 | |
| 332 | | pub fn dedupeLengthPrefixed(wip: *Wip, index: u32) Allocator.Error!u32 { |
| 333 | | assert(wip.extra.items.len == index + wip.extra.items[index] + 1); |
| 333 | /// Same as `addExtra` but uses a hash map to possibly return an already |
| 334 | /// existing index instead of appending to `extra`. |
| 335 | pub fn addDeduped(wip: *Wip, extra: anytype) Allocator.Error!u32 { |
| 334 | 336 | const gpa = wip.gpa; |
| 335 | | const gop = try wip.length_prefixed_table.getOrPutContext(gpa, index, @as(LengthPrefixedContext, .{ |
| 336 | | .extra = wip.extra.items, |
| 337 | | })); |
| 337 | const revert_index = wip.extra.items.len; |
| 338 | const extra_len = Storage.extraLen(extra); |
| 339 | try wip.extra.ensureUnusedCapacity(gpa, extra_len); |
| 340 | const new_index = addExtraAssumeCapacity(wip, extra); |
| 341 | const len: u32 = @intCast(wip.extra.items.len - new_index); |
| 342 | |
| 343 | const gop = try wip.dedupe_table.getOrPutContext(gpa, .{ |
| 344 | .index = new_index, |
| 345 | .len = len, |
| 346 | }, @as(ExtraSlice.Context, .{ .extra = wip.extra.items })); |
| 347 | |
| 338 | 348 | if (gop.found_existing) { |
| 339 | | wip.extra.items.len = index; |
| 340 | | return gop.key_ptr.*; |
| 341 | | } else { |
| 342 | | return index; |
| 349 | wip.extra.items.len = revert_index; |
| 350 | return gop.key_ptr.index; |
| 343 | 351 | } |
| 344 | | } |
| 345 | 352 | |
| 346 | | pub fn dedupeDeps(wip: *Wip, deps: Deps) Allocator.Error!Deps { |
| 347 | | return @enumFromInt(try dedupeLengthPrefixed(wip, @intFromEnum(deps))); |
| 348 | | } |
| 349 | | |
| 350 | | pub fn addExtra(wip: *Wip, extra: anytype) Allocator.Error!u32 { |
| 351 | | const extra_len = Storage.extraLen(extra); |
| 352 | | try wip.extra.ensureUnusedCapacity(wip.gpa, extra_len); |
| 353 | | return addExtraAssumeCapacity(wip, extra); |
| 353 | return new_index; |
| 354 | 354 | } |
| 355 | 355 | |
| 356 | 356 | pub fn addExtraAssumeCapacity(wip: *Wip, extra: anytype) u32 { |
| ... | ... | @@ -399,7 +399,7 @@ pub const AvailableOption = extern struct { |
| 399 | 399 | pub const Step = extern struct { |
| 400 | 400 | name: String, |
| 401 | 401 | owner: Package.Index, |
| 402 | | deps: Deps, |
| 402 | deps: Deps.Index, |
| 403 | 403 | max_rss: MaxRss, |
| 404 | 404 | extended: Storage.Extended(Flags, union(Tag) { |
| 405 | 405 | check_file: CheckFile, |
| ... | ... | @@ -1074,14 +1074,12 @@ pub const Package = struct { |
| 1074 | 1074 | }; |
| 1075 | 1075 | }; |
| 1076 | 1076 | |
| 1077 | | /// Trailing: |
| 1078 | | /// * frameworks: FlagsPrefixedList(FrameworkFlags), // if flag is set |
| 1079 | 1077 | pub const Module = struct { |
| 1080 | 1078 | flags: Flags, |
| 1081 | 1079 | flags2: Flags2, |
| 1080 | import_table: ImportTable.Index, |
| 1082 | 1081 | owner: Package.Index, |
| 1083 | 1082 | root_source_file: OptionalLazyPath, |
| 1084 | | import_table: ImportTable, |
| 1085 | 1083 | resolved_target: ResolvedTarget.OptionalIndex, |
| 1086 | 1084 | c_macros: Storage.FlagLengthPrefixedList(.flags, .c_macros, String), |
| 1087 | 1085 | lib_paths: Storage.FlagLengthPrefixedList(.flags, .lib_paths, LazyPath), |
| ... | ... | @@ -1089,6 +1087,7 @@ pub const Module = struct { |
| 1089 | 1087 | include_dirs: Storage.UnionList(.flags, .include_dirs, IncludeDir), |
| 1090 | 1088 | rpaths: Storage.UnionList(.flags, .rpaths, RPath), |
| 1091 | 1089 | link_objects: Storage.UnionList(.flags, .link_objects, LinkObject), |
| 1090 | frameworks: Storage.FlagLengthPrefixedList(.flags, .frameworks, Framework), |
| 1092 | 1091 | |
| 1093 | 1092 | pub const Optimize = enum(u3) { |
| 1094 | 1093 | debug, |
| ... | ... | @@ -1220,28 +1219,47 @@ pub const Module = struct { |
| 1220 | 1219 | win32_resource_file: RcSourceFile.Index, |
| 1221 | 1220 | }; |
| 1222 | 1221 | |
| 1223 | | pub const FrameworkFlags = packed struct(u2) { |
| 1224 | | needed: bool, |
| 1225 | | weak: bool, |
| 1222 | pub const Framework = struct { |
| 1223 | flags: @This().Flags, |
| 1224 | name: String, |
| 1225 | |
| 1226 | pub const Flags = packed struct(u32) { |
| 1227 | needed: bool, |
| 1228 | weak: bool, |
| 1229 | _: u30 = 0, |
| 1230 | }; |
| 1226 | 1231 | }; |
| 1227 | 1232 | }; |
| 1228 | 1233 | |
| 1229 | | /// Points into `extra`, first element is len, then: |
| 1230 | | /// * import_name: String, // for each len |
| 1231 | | /// * Module.Index, // for each len |
| 1232 | | pub const ImportTable = enum(u32) { |
| 1233 | | _, |
| 1234 | pub const ImportTable = struct { |
| 1235 | imports: Storage.MultiList(Import), |
| 1236 | |
| 1237 | pub const Import = struct { |
| 1238 | name: String, |
| 1239 | module: Module.Index, |
| 1240 | }; |
| 1241 | |
| 1242 | /// Points into `extra`. |
| 1243 | pub const Index = enum(u32) { |
| 1244 | invalid = maxInt(u32), |
| 1245 | _, |
| 1246 | }; |
| 1234 | 1247 | }; |
| 1235 | 1248 | |
| 1236 | | /// Points into `extra`, where the first element is count of deps, following |
| 1237 | | /// elements is `Step.Index` per count. |
| 1238 | | pub const Deps = enum(u32) { |
| 1239 | | _, |
| 1249 | pub const Deps = struct { |
| 1250 | steps: Storage.LengthPrefixedList(Step.Index), |
| 1240 | 1251 | |
| 1241 | | pub fn slice(deps: Deps, c: *const Configuration) []Step.Index { |
| 1242 | | const len = c.extra[@intFromEnum(deps)]; |
| 1243 | | return @ptrCast(c.extra[@intFromEnum(deps) + 1 ..][0..len]); |
| 1244 | | } |
| 1252 | pub const Index = enum(u32) { |
| 1253 | _, |
| 1254 | |
| 1255 | pub fn get(this: @This(), c: *const Configuration) Deps { |
| 1256 | return extraData(c, Deps, @intFromEnum(this)); |
| 1257 | } |
| 1258 | |
| 1259 | pub fn slice(this: @This(), c: *const Configuration) []const Step.Index { |
| 1260 | return get(this, c).steps.slice; |
| 1261 | } |
| 1262 | }; |
| 1245 | 1263 | }; |
| 1246 | 1264 | |
| 1247 | 1265 | /// Points into `extra`, where the first element is count of strings, following |
| ... | ... | @@ -1760,6 +1778,7 @@ pub const Storage = enum { |
| 1760 | 1778 | flag_length_prefixed_list, |
| 1761 | 1779 | union_list, |
| 1762 | 1780 | flag_union, |
| 1781 | multi_list, |
| 1763 | 1782 | |
| 1764 | 1783 | /// The presence of the field is determined by a boolean within a packed |
| 1765 | 1784 | /// struct. |
| ... | ... | @@ -1853,7 +1872,8 @@ pub const Storage = enum { |
| 1853 | 1872 | }; |
| 1854 | 1873 | } |
| 1855 | 1874 | |
| 1856 | | /// The field contains a u32 length followed by that many items. |
| 1875 | /// The field contains a u32 length followed by that many items, each |
| 1876 | /// element bitcastable to u32. |
| 1857 | 1877 | pub fn LengthPrefixedList(comptime ElemArg: type) type { |
| 1858 | 1878 | return struct { |
| 1859 | 1879 | slice: []const Elem, |
| ... | ... | @@ -1867,6 +1887,17 @@ pub const Storage = enum { |
| 1867 | 1887 | }; |
| 1868 | 1888 | } |
| 1869 | 1889 | |
| 1890 | /// The field contains a u32 length followed by that many items for the |
| 1891 | /// first field, that many items for the second field, etc. |
| 1892 | pub fn MultiList(comptime ElemArg: type) type { |
| 1893 | return struct { |
| 1894 | mal: std.MultiArrayList(Elem), |
| 1895 | |
| 1896 | pub const storage: Storage = .multi_list; |
| 1897 | pub const Elem = ElemArg; |
| 1898 | }; |
| 1899 | } |
| 1900 | |
| 1870 | 1901 | /// `UnionArg` is a tagged union with a small integer for the enum tag. |
| 1871 | 1902 | /// |
| 1872 | 1903 | /// A field in flags determines whether the metadata is present. |
| ... | ... | @@ -2028,6 +2059,16 @@ pub const Storage = enum { |
| 2028 | 2059 | defer i.* = data_start + len; |
| 2029 | 2060 | return .{ .slice = @ptrCast(buffer[data_start..][0..len]) }; |
| 2030 | 2061 | }, |
| 2062 | .multi_list => { |
| 2063 | const data_start = i.* + 1; |
| 2064 | const len = buffer[data_start - 1]; |
| 2065 | defer i.* = data_start + len * @typeInfo(Field.Elem).@"struct".fields.len; |
| 2066 | return .{ .mal = .{ |
| 2067 | .bytes = @ptrCast(buffer[data_start..][0..len]), |
| 2068 | .len = len, |
| 2069 | .capacity = len, |
| 2070 | } }; |
| 2071 | }, |
| 2031 | 2072 | .union_list => { |
| 2032 | 2073 | const flags = @field(container, @tagName(Field.flags)); |
| 2033 | 2074 | const flag = @field(flags, @tagName(Field.flag)); |
| ... | ... | @@ -2082,6 +2123,7 @@ pub const Storage = enum { |
| 2082 | 2123 | .auto => switch (Field.storage) { |
| 2083 | 2124 | .flag_optional, .enum_optional, .extended => 1, |
| 2084 | 2125 | .length_prefixed_list, .flag_length_prefixed_list => field.slice.len + 1, |
| 2126 | .multi_list => 1 + field.mal.len * @typeInfo(Field.Elem).@"struct".fields.len, |
| 2085 | 2127 | .union_list => Field.extraLen(field.len), |
| 2086 | 2128 | .flag_union => switch (field.u) { |
| 2087 | 2129 | inline else => |v| extraFieldLen(v), |
| ... | ... | @@ -2153,6 +2195,17 @@ pub const Storage = enum { |
| 2153 | 2195 | @memcpy(buffer[i + 1 ..][0..len], @as([]const u32, @ptrCast(value.slice))); |
| 2154 | 2196 | return len + 1; |
| 2155 | 2197 | }, |
| 2198 | .multi_list => { |
| 2199 | const len: u32 = @intCast(value.mal.len); |
| 2200 | if (len == 0) return 0; |
| 2201 | buffer[i] = len; |
| 2202 | const fields = @typeInfo(Field.Elem).@"struct".fields; |
| 2203 | inline for (0..fields.len) |field_i| @memcpy( |
| 2204 | buffer[i + 1 + field_i * len ..][0..len], |
| 2205 | @as([]const u32, @ptrCast(value.mal.items(@enumFromInt(field_i)))), |
| 2206 | ); |
| 2207 | return 1 + fields.len * len; |
| 2208 | }, |
| 2156 | 2209 | .union_list => { |
| 2157 | 2210 | if (value.len == 0) return 0; |
| 2158 | 2211 | const Tag = @typeInfo(Field.Union).@"union".tag_type.?; |