| ... | ... | @@ -5,6 +5,8 @@ items: std.MultiArrayList(Item) = .{}, |
| 5 | 5 | extra: std.ArrayListUnmanaged(u32) = .{}, |
| 6 | 6 | /// On 32-bit systems, this array is ignored and extra is used for everything. |
| 7 | 7 | /// On 64-bit systems, this array is used for big integers and associated metadata. |
| 8 | /// Use the helper methods instead of accessing this directly in order to not |
| 9 | /// violate the above mechanism. |
| 8 | 10 | limbs: std.ArrayListUnmanaged(u64) = .{}, |
| 9 | 11 | |
| 10 | 12 | const std = @import("std"); |
| ... | ... | @@ -12,6 +14,7 @@ const Allocator = std.mem.Allocator; |
| 12 | 14 | const assert = std.debug.assert; |
| 13 | 15 | const BigIntConst = std.math.big.int.Const; |
| 14 | 16 | const BigIntMutable = std.math.big.int.Mutable; |
| 17 | const Limb = std.math.big.Limb; |
| 15 | 18 | |
| 16 | 19 | const InternPool = @This(); |
| 17 | 20 | const DeclIndex = enum(u32) { _ }; |
| ... | ... | @@ -233,9 +236,23 @@ pub const Key = union(enum) { |
| 233 | 236 | |
| 234 | 237 | .int => |a_info| { |
| 235 | 238 | const b_info = b.int; |
| 236 | | _ = a_info; |
| 237 | | _ = b_info; |
| 238 | | @panic("TODO"); |
| 239 | return switch (a_info.storage) { |
| 240 | .u64 => |aa| switch (b_info.storage) { |
| 241 | .u64 => |bb| aa == bb, |
| 242 | .i64 => |bb| aa == bb, |
| 243 | .big_int => |bb| bb.orderAgainstScalar(aa) == .eq, |
| 244 | }, |
| 245 | .i64 => |aa| switch (b_info.storage) { |
| 246 | .u64 => |bb| aa == bb, |
| 247 | .i64 => |bb| aa == bb, |
| 248 | .big_int => |bb| bb.orderAgainstScalar(aa) == .eq, |
| 249 | }, |
| 250 | .big_int => |aa| switch (b_info.storage) { |
| 251 | .u64 => |bb| aa.orderAgainstScalar(bb) == .eq, |
| 252 | .i64 => |bb| aa.orderAgainstScalar(bb) == .eq, |
| 253 | .big_int => |bb| aa.eq(bb), |
| 254 | }, |
| 255 | }; |
| 239 | 256 | }, |
| 240 | 257 | |
| 241 | 258 | .enum_tag => |a_info| { |
| ... | ... | @@ -1056,8 +1073,8 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 1056 | 1073 | .ty = .comptime_int_type, |
| 1057 | 1074 | .storage = .{ .i64 = @bitCast(i32, data) }, |
| 1058 | 1075 | } }, |
| 1059 | | .int_positive => @panic("TODO"), |
| 1060 | | .int_negative => @panic("TODO"), |
| 1076 | .int_positive => indexToKeyBigInt(ip, data, true), |
| 1077 | .int_negative => indexToKeyBigInt(ip, data, false), |
| 1061 | 1078 | .enum_tag_positive => @panic("TODO"), |
| 1062 | 1079 | .enum_tag_negative => @panic("TODO"), |
| 1063 | 1080 | .float_f32 => @panic("TODO"), |
| ... | ... | @@ -1068,6 +1085,17 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 1068 | 1085 | }; |
| 1069 | 1086 | } |
| 1070 | 1087 | |
| 1088 | fn indexToKeyBigInt(ip: InternPool, limb_index: u32, positive: bool) Key { |
| 1089 | const int_info = ip.limbData(Int, limb_index); |
| 1090 | return .{ .int = .{ |
| 1091 | .ty = int_info.ty, |
| 1092 | .storage = .{ .big_int = .{ |
| 1093 | .limbs = ip.limbSlice(Int, limb_index, int_info.limbs_len), |
| 1094 | .positive = positive, |
| 1095 | } }, |
| 1096 | } }; |
| 1097 | } |
| 1098 | |
| 1071 | 1099 | pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 1072 | 1100 | const adapter: KeyAdapter = .{ .intern_pool = ip }; |
| 1073 | 1101 | const gop = try ip.map.getOrPutAdapted(gpa, key, adapter); |
| ... | ... | @@ -1293,7 +1321,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 1293 | 1321 | try addInt(ip, gpa, int.ty, tag, big_int.limbs); |
| 1294 | 1322 | }, |
| 1295 | 1323 | inline .i64, .u64 => |x| { |
| 1296 | | var buf: [2]usize = undefined; |
| 1324 | var buf: [2]Limb = undefined; |
| 1297 | 1325 | const big_int = BigIntMutable.init(&buf, x).toConst(); |
| 1298 | 1326 | const tag: Tag = if (big_int.positive) .int_positive else .int_negative; |
| 1299 | 1327 | try addInt(ip, gpa, int.ty, tag, big_int.limbs); |
| ... | ... | @@ -1324,7 +1352,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 1324 | 1352 | return @intToEnum(Index, ip.items.len - 1); |
| 1325 | 1353 | } |
| 1326 | 1354 | |
| 1327 | | fn addInt(ip: *InternPool, gpa: Allocator, ty: Index, tag: Tag, limbs: []const usize) !void { |
| 1355 | fn addInt(ip: *InternPool, gpa: Allocator, ty: Index, tag: Tag, limbs: []const Limb) !void { |
| 1328 | 1356 | const limbs_len = @intCast(u32, limbs.len); |
| 1329 | 1357 | try ip.reserveLimbs(gpa, @typeInfo(Int).Struct.fields.len + limbs_len); |
| 1330 | 1358 | ip.items.appendAssumeCapacity(.{ |
| ... | ... | @@ -1360,7 +1388,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { |
| 1360 | 1388 | } |
| 1361 | 1389 | |
| 1362 | 1390 | fn reserveLimbs(ip: *InternPool, gpa: Allocator, n: usize) !void { |
| 1363 | | switch (@sizeOf(usize)) { |
| 1391 | switch (@sizeOf(Limb)) { |
| 1364 | 1392 | @sizeOf(u32) => try ip.extra.ensureUnusedCapacity(gpa, n), |
| 1365 | 1393 | @sizeOf(u64) => try ip.limbs.ensureUnusedCapacity(gpa, n), |
| 1366 | 1394 | else => @compileError("unsupported host"), |
| ... | ... | @@ -1368,7 +1396,7 @@ fn reserveLimbs(ip: *InternPool, gpa: Allocator, n: usize) !void { |
| 1368 | 1396 | } |
| 1369 | 1397 | |
| 1370 | 1398 | fn addLimbsExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { |
| 1371 | | switch (@sizeOf(usize)) { |
| 1399 | switch (@sizeOf(Limb)) { |
| 1372 | 1400 | @sizeOf(u32) => return addExtraAssumeCapacity(ip, extra), |
| 1373 | 1401 | @sizeOf(u64) => {}, |
| 1374 | 1402 | else => @compileError("unsupported host"), |
| ... | ... | @@ -1389,8 +1417,8 @@ fn addLimbsExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { |
| 1389 | 1417 | return result; |
| 1390 | 1418 | } |
| 1391 | 1419 | |
| 1392 | | fn addLimbsAssumeCapacity(ip: *InternPool, limbs: []const usize) void { |
| 1393 | | switch (@sizeOf(usize)) { |
| 1420 | fn addLimbsAssumeCapacity(ip: *InternPool, limbs: []const Limb) void { |
| 1421 | switch (@sizeOf(Limb)) { |
| 1394 | 1422 | @sizeOf(u32) => ip.extra.appendSliceAssumeCapacity(limbs), |
| 1395 | 1423 | @sizeOf(u64) => ip.limbs.appendSliceAssumeCapacity(limbs), |
| 1396 | 1424 | else => @compileError("unsupported host"), |
| ... | ... | @@ -1416,7 +1444,7 @@ fn extraData(ip: InternPool, comptime T: type, index: usize) T { |
| 1416 | 1444 | |
| 1417 | 1445 | /// Asserts the struct has 32-bit fields and the number of fields is evenly divisible by 2. |
| 1418 | 1446 | fn limbData(ip: InternPool, comptime T: type, index: usize) T { |
| 1419 | | switch (@sizeOf(usize)) { |
| 1447 | switch (@sizeOf(Limb)) { |
| 1420 | 1448 | @sizeOf(u32) => return extraData(ip, T, index), |
| 1421 | 1449 | @sizeOf(u64) => {}, |
| 1422 | 1450 | else => @compileError("unsupported host"), |
| ... | ... | @@ -1438,6 +1466,21 @@ fn limbData(ip: InternPool, comptime T: type, index: usize) T { |
| 1438 | 1466 | return result; |
| 1439 | 1467 | } |
| 1440 | 1468 | |
| 1469 | fn limbSlice(ip: InternPool, comptime S: type, limb_index: u32, len: u32) []const Limb { |
| 1470 | const field_count = @typeInfo(S).Struct.fields.len; |
| 1471 | switch (@sizeOf(Limb)) { |
| 1472 | @sizeOf(u32) => { |
| 1473 | const start = limb_index + field_count; |
| 1474 | return ip.extra.items[start..][0..len]; |
| 1475 | }, |
| 1476 | @sizeOf(u64) => { |
| 1477 | const start = limb_index + @divExact(field_count, 2); |
| 1478 | return ip.limbs.items[start..][0..len]; |
| 1479 | }, |
| 1480 | else => @compileError("unsupported host"), |
| 1481 | } |
| 1482 | } |
| 1483 | |
| 1441 | 1484 | test "basic usage" { |
| 1442 | 1485 | const gpa = std.testing.allocator; |
| 1443 | 1486 | |