| ... | ... | @@ -34,6 +34,7 @@ const std = @import("std"); |
| 34 | 34 | const mem = std.mem; |
| 35 | 35 | const leb = std.debug.leb; |
| 36 | 36 | const log = std.log.scoped(.link); |
| 37 | const testing = std.testing; |
| 37 | 38 | const Allocator = mem.Allocator; |
| 38 | 39 | |
| 39 | 40 | pub const Symbol = struct { |
| ... | ... | @@ -67,48 +68,33 @@ const Node = struct { |
| 67 | 68 | self.edges.deinit(alloc); |
| 68 | 69 | } |
| 69 | 70 | |
| 70 | | fn put(self: *Node, alloc: *Allocator, fromEdge: ?*Edge, prefix: usize, label: []const u8) !*Node { |
| 71 | | // Traverse all edges. |
| 71 | fn put(self: *Node, alloc: *Allocator, label: []const u8) !*Node { |
| 72 | // Check for match with edges from this node. |
| 72 | 73 | for (self.edges.items) |*edge| { |
| 73 | | const match = mem.indexOfDiff(u8, edge.label, label) orelse return self; // Got a full match, don't do anything. |
| 74 | | if (match - prefix > 0) { |
| 75 | | // If we match, we advance further down the trie. |
| 76 | | return edge.to.put(alloc, edge, match, label); |
| 77 | | } |
| 78 | | } |
| 79 | | |
| 80 | | if (fromEdge) |from| { |
| 81 | | if (mem.eql(u8, from.label, label[0..prefix])) { |
| 82 | | if (prefix == label.len) return self; |
| 74 | const match = mem.indexOfDiff(u8, edge.label, label) orelse return edge.to; |
| 75 | if (match == 0) continue; |
| 76 | if (match == edge.label.len) return edge.to.put(alloc, label[match..]); |
| 77 | |
| 78 | // Found a match, need to splice up nodes. |
| 79 | // From: A -> B |
| 80 | // To: A -> C -> B |
| 81 | const mid = try alloc.create(Node); |
| 82 | mid.* = .{}; |
| 83 | const to_label = edge.label; |
| 84 | const to_node = edge.to; |
| 85 | edge.to = mid; |
| 86 | edge.label = label[0..match]; |
| 87 | |
| 88 | try mid.edges.append(alloc, .{ |
| 89 | .from = mid, |
| 90 | .to = to_node, |
| 91 | .label = to_label[match..], |
| 92 | }); |
| 93 | |
| 94 | if (match == label.len) { |
| 95 | return to_node; |
| 83 | 96 | } else { |
| 84 | | // Fixup nodes. We need to insert an intermediate node between |
| 85 | | // from.to and self. |
| 86 | | // Is: A -> B |
| 87 | | // Should be: A -> C -> B |
| 88 | | const mid = try alloc.create(Node); |
| 89 | | mid.* = .{}; |
| 90 | | const to_label = from.label; |
| 91 | | from.to = mid; |
| 92 | | from.label = label[0..prefix]; |
| 93 | | |
| 94 | | try mid.edges.append(alloc, .{ |
| 95 | | .from = mid, |
| 96 | | .to = self, |
| 97 | | .label = to_label, |
| 98 | | }); |
| 99 | | |
| 100 | | if (prefix == label.len) return self; // We're done. |
| 101 | | |
| 102 | | const new_node = try alloc.create(Node); |
| 103 | | new_node.* = .{}; |
| 104 | | |
| 105 | | try mid.edges.append(alloc, .{ |
| 106 | | .from = mid, |
| 107 | | .to = new_node, |
| 108 | | .label = label, |
| 109 | | }); |
| 110 | | |
| 111 | | return new_node; |
| 97 | return mid.put(alloc, label[match..]); |
| 112 | 98 | } |
| 113 | 99 | } |
| 114 | 100 | |
| ... | ... | @@ -148,7 +134,7 @@ const Node = struct { |
| 148 | 134 | // Write number of edges (max legal number of edges is 256). |
| 149 | 135 | try buffer.append(alloc, @intCast(u8, self.edges.items.len)); |
| 150 | 136 | |
| 151 | | var node_offset_info: [@sizeOf(u8)]u64 = undefined; |
| 137 | var node_offset_info: [std.math.maxInt(u8)]u64 = undefined; |
| 152 | 138 | for (self.edges.items) |edge, i| { |
| 153 | 139 | // Write edges labels leaving out space in-between to later populate |
| 154 | 140 | // with offsets to each node. |
| ... | ... | @@ -185,7 +171,7 @@ root: Node, |
| 185 | 171 | /// This operation may change the layout of the trie by splicing edges in |
| 186 | 172 | /// certain circumstances. |
| 187 | 173 | pub fn put(self: *Trie, alloc: *Allocator, symbol: Symbol) !void { |
| 188 | | const node = try self.root.put(alloc, null, 0, symbol.name); |
| 174 | const node = try self.root.put(alloc, symbol.name); |
| 189 | 175 | node.offset = symbol.offset; |
| 190 | 176 | node.export_flags = symbol.export_flags; |
| 191 | 177 | } |
| ... | ... | @@ -202,9 +188,7 @@ pub fn deinit(self: *Trie, alloc: *Allocator) void { |
| 202 | 188 | } |
| 203 | 189 | |
| 204 | 190 | test "Trie basic" { |
| 205 | | const testing = @import("std").testing; |
| 206 | 191 | var gpa = testing.allocator; |
| 207 | | |
| 208 | 192 | var trie: Trie = .{ |
| 209 | 193 | .root = .{}, |
| 210 | 194 | }; |
| ... | ... | @@ -223,7 +207,7 @@ test "Trie basic" { |
| 223 | 207 | testing.expect(mem.eql(u8, trie.root.edges.items[0].label, "_st")); |
| 224 | 208 | |
| 225 | 209 | { |
| 226 | | // root --- _st ---> node --- _start ---> node |
| 210 | // root --- _st ---> node --- art ---> node |
| 227 | 211 | try trie.put(gpa, .{ |
| 228 | 212 | .name = "_start", |
| 229 | 213 | .offset = 0, |
| ... | ... | @@ -234,12 +218,12 @@ test "Trie basic" { |
| 234 | 218 | const nextEdge = &trie.root.edges.items[0]; |
| 235 | 219 | testing.expect(mem.eql(u8, nextEdge.label, "_st")); |
| 236 | 220 | testing.expect(nextEdge.to.edges.items.len == 1); |
| 237 | | testing.expect(mem.eql(u8, nextEdge.to.edges.items[0].label, "_start")); |
| 221 | testing.expect(mem.eql(u8, nextEdge.to.edges.items[0].label, "art")); |
| 238 | 222 | } |
| 239 | 223 | { |
| 240 | | // root --- _ ---> node --- _st ---> node --- _start ---> node |
| 224 | // root --- _ ---> node --- st ---> node --- art ---> node |
| 241 | 225 | // | |
| 242 | | // | --- _main ---> node |
| 226 | // | --- main ---> node |
| 243 | 227 | try trie.put(gpa, .{ |
| 244 | 228 | .name = "_main", |
| 245 | 229 | .offset = 0, |
| ... | ... | @@ -250,10 +234,103 @@ test "Trie basic" { |
| 250 | 234 | const nextEdge = &trie.root.edges.items[0]; |
| 251 | 235 | testing.expect(mem.eql(u8, nextEdge.label, "_")); |
| 252 | 236 | testing.expect(nextEdge.to.edges.items.len == 2); |
| 253 | | testing.expect(mem.eql(u8, nextEdge.to.edges.items[0].label, "_st")); |
| 254 | | testing.expect(mem.eql(u8, nextEdge.to.edges.items[1].label, "_main")); |
| 237 | testing.expect(mem.eql(u8, nextEdge.to.edges.items[0].label, "st")); |
| 238 | testing.expect(mem.eql(u8, nextEdge.to.edges.items[1].label, "main")); |
| 255 | 239 | |
| 256 | 240 | const nextNextEdge = &nextEdge.to.edges.items[0]; |
| 257 | | testing.expect(mem.eql(u8, nextNextEdge.to.edges.items[0].label, "_start")); |
| 241 | testing.expect(mem.eql(u8, nextNextEdge.to.edges.items[0].label, "art")); |
| 258 | 242 | } |
| 259 | 243 | } |
| 244 | |
| 245 | test "Trie.writeULEB128Mem" { |
| 246 | var gpa = testing.allocator; |
| 247 | var trie: Trie = .{ |
| 248 | .root = .{}, |
| 249 | }; |
| 250 | defer trie.deinit(gpa); |
| 251 | |
| 252 | try trie.put(gpa, .{ |
| 253 | .name = "__mh_execute_header", |
| 254 | .offset = 0, |
| 255 | .export_flags = 0, |
| 256 | }); |
| 257 | try trie.put(gpa, .{ |
| 258 | .name = "_main", |
| 259 | .offset = 0x1000, |
| 260 | .export_flags = 0, |
| 261 | }); |
| 262 | |
| 263 | var buffer: std.ArrayListUnmanaged(u8) = .{}; |
| 264 | defer buffer.deinit(gpa); |
| 265 | |
| 266 | try trie.writeULEB128Mem(gpa, &buffer); |
| 267 | |
| 268 | const exp_buffer = [_]u8{ |
| 269 | 0x0, |
| 270 | 0x1, |
| 271 | 0x5f, |
| 272 | 0x0, |
| 273 | 0xc, |
| 274 | 0x0, |
| 275 | 0x0, |
| 276 | 0x0, |
| 277 | 0x0, |
| 278 | 0x0, |
| 279 | 0x0, |
| 280 | 0x0, |
| 281 | 0x0, |
| 282 | 0x2, |
| 283 | 0x5f, |
| 284 | 0x6d, |
| 285 | 0x68, |
| 286 | 0x5f, |
| 287 | 0x65, |
| 288 | 0x78, |
| 289 | 0x65, |
| 290 | 0x63, |
| 291 | 0x75, |
| 292 | 0x74, |
| 293 | 0x65, |
| 294 | 0x5f, |
| 295 | 0x68, |
| 296 | 0x65, |
| 297 | 0x61, |
| 298 | 0x64, |
| 299 | 0x65, |
| 300 | 0x72, |
| 301 | 0x0, |
| 302 | 0x36, |
| 303 | 0x0, |
| 304 | 0x0, |
| 305 | 0x0, |
| 306 | 0x0, |
| 307 | 0x0, |
| 308 | 0x0, |
| 309 | 0x0, |
| 310 | 0x6d, |
| 311 | 0x61, |
| 312 | 0x69, |
| 313 | 0x6e, |
| 314 | 0x0, |
| 315 | 0x3a, |
| 316 | 0x0, |
| 317 | 0x0, |
| 318 | 0x0, |
| 319 | 0x0, |
| 320 | 0x0, |
| 321 | 0x0, |
| 322 | 0x0, |
| 323 | 0x2, |
| 324 | 0x0, |
| 325 | 0x0, |
| 326 | 0x0, |
| 327 | 0x3, |
| 328 | 0x0, |
| 329 | 0x80, |
| 330 | 0x20, |
| 331 | 0x0, |
| 332 | }; |
| 333 | |
| 334 | testing.expect(buffer.items.len == exp_buffer.len); |
| 335 | testing.expect(mem.eql(u8, buffer.items, exp_buffer[0..])); |
| 336 | } |