Skip to content

Commit 5947eca

Browse files
committed
lazily resolve document handle import uris
1 parent d6b1890 commit 5947eca

File tree

1 file changed

+63
-52
lines changed

1 file changed

+63
-52
lines changed

src/DocumentStore.zig

Lines changed: 63 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,6 @@ pub const BuildFile = struct {
178178
pub const Handle = struct {
179179
uri: Uri,
180180
tree: Ast,
181-
/// Contains one entry for every import in the document
182-
import_uris: std.ArrayListUnmanaged(Uri),
183181
/// Contains one entry for every cimport in the document
184182
cimports: std.MultiArrayList(CImportHandle),
185183

@@ -194,6 +192,7 @@ pub const Handle = struct {
194192
/// See `getLazy`
195193
lazy_condition: std.Thread.Condition = .{},
196194

195+
import_uris: ?[]Uri = null,
197196
document_scope: DocumentScope = undefined,
198197
zzoiir: ZirOrZoir = undefined,
199198

@@ -245,7 +244,7 @@ pub const Handle = struct {
245244
_: u27 = 0,
246245
};
247246

248-
/// Takes ownership of `text` on success. The `import_uris` be initialized to `.empty`.
247+
/// Takes ownership of `text` on success.
249248
pub fn init(
250249
allocator: std.mem.Allocator,
251250
uri: Uri,
@@ -263,7 +262,6 @@ pub const Handle = struct {
263262
return .{
264263
.uri = uri,
265264
.tree = tree,
266-
.import_uris = .empty,
267265
.cimports = cimports,
268266
.impl = .{
269267
.status = .init(@bitCast(Status{
@@ -291,8 +289,10 @@ pub const Handle = struct {
291289
allocator.free(self.tree.source);
292290
self.tree.deinit(allocator);
293291

294-
for (self.import_uris.items) |uri| allocator.free(uri);
295-
self.import_uris.deinit(allocator);
292+
if (self.impl.import_uris) |import_uris| {
293+
for (import_uris) |uri| allocator.free(uri);
294+
allocator.free(import_uris);
295+
}
296296

297297
for (self.cimports.items(.source)) |source| allocator.free(source);
298298
self.cimports.deinit(allocator);
@@ -305,6 +305,42 @@ pub const Handle = struct {
305305
self.* = undefined;
306306
}
307307

308+
pub fn getImportUris(self: *Handle) error{OutOfMemory}![]const Uri {
309+
self.impl.lock.lock();
310+
defer self.impl.lock.unlock();
311+
312+
const allocator = self.impl.allocator;
313+
314+
if (self.impl.import_uris) |import_uris| return import_uris;
315+
316+
var imports = try analysis.collectImports(allocator, self.tree);
317+
318+
var i: usize = 0;
319+
errdefer {
320+
// only free the uris
321+
for (imports.items[0..i]) |uri| allocator.free(uri);
322+
imports.deinit(allocator);
323+
}
324+
325+
// Convert to URIs
326+
while (i < imports.items.len) {
327+
const import_str = imports.items[i];
328+
if (!std.mem.endsWith(u8, import_str, ".zig")) {
329+
_ = imports.swapRemove(i);
330+
continue;
331+
}
332+
// The raw import strings are owned by the document and do not need to be freed here.
333+
imports.items[i] = try uriFromFileImportStr(allocator, self, import_str) orelse {
334+
_ = imports.swapRemove(i);
335+
continue;
336+
};
337+
i += 1;
338+
}
339+
340+
self.impl.import_uris = try imports.toOwnedSlice(allocator);
341+
return self.impl.import_uris.?;
342+
}
343+
308344
pub fn getDocumentScope(self: *Handle) error{OutOfMemory}!DocumentScope {
309345
if (self.getStatus().has_document_scope) return self.impl.document_scope;
310346
return try self.getLazy(DocumentScope, "document_scope", struct {
@@ -1285,7 +1321,7 @@ fn uriInImports(
12851321
return std.mem.eql(u8, associated_build_file_uri, build_file_uri);
12861322
}
12871323

1288-
for (handle.import_uris.items) |import_uri| {
1324+
for (try handle.getImportUris()) |import_uri| {
12891325
if (try self.uriInImports(checked_uris, build_file_uri, import_uri, uri))
12901326
return true;
12911327
}
@@ -1346,37 +1382,6 @@ fn createAndStoreDocument(
13461382
return gop.value_ptr.*;
13471383
}
13481384

1349-
/// Caller owns returned memory.
1350-
/// **Thread safe** takes a shared lock
1351-
fn collectImportUris(self: *DocumentStore, handle: *Handle) error{OutOfMemory}!std.ArrayListUnmanaged(Uri) {
1352-
const tracy_zone = tracy.trace(@src());
1353-
defer tracy_zone.end();
1354-
1355-
var imports = try analysis.collectImports(self.allocator, handle.tree);
1356-
1357-
var i: usize = 0;
1358-
errdefer {
1359-
// only free the uris
1360-
for (imports.items[0..i]) |uri| self.allocator.free(uri);
1361-
imports.deinit(self.allocator);
1362-
}
1363-
1364-
// Convert to URIs
1365-
while (i < imports.items.len) {
1366-
const maybe_uri = try self.uriFromImportStr(self.allocator, handle, imports.items[i]);
1367-
1368-
if (maybe_uri) |uri| {
1369-
// The raw import strings are owned by the document and do not need to be freed here.
1370-
imports.items[i] = uri;
1371-
i += 1;
1372-
} else {
1373-
_ = imports.swapRemove(i);
1374-
}
1375-
}
1376-
1377-
return imports;
1378-
}
1379-
13801385
pub const CImportHandle = struct {
13811386
/// the `@cImport` node
13821387
node: Ast.Node.Index,
@@ -1438,8 +1443,10 @@ pub fn collectDependencies(
14381443
store.lock.lockShared();
14391444
defer store.lock.unlockShared();
14401445

1441-
try dependencies.ensureUnusedCapacity(allocator, handle.import_uris.items.len + handle.cimports.len);
1442-
for (handle.import_uris.items) |uri| {
1446+
const import_uris = try handle.getImportUris();
1447+
1448+
try dependencies.ensureUnusedCapacity(allocator, import_uris.len + handle.cimports.len);
1449+
for (import_uris) |uri| {
14431450
dependencies.appendAssumeCapacity(try allocator.dupe(u8, uri));
14441451
}
14451452

@@ -1746,18 +1753,22 @@ pub fn uriFromImportStr(self: *DocumentStore, allocator: std.mem.Allocator, hand
17461753
}
17471754
return null;
17481755
} else {
1749-
const base_path = URI.toFsPath(allocator, handle.uri) catch |err| switch (err) {
1750-
error.OutOfMemory => return error.OutOfMemory,
1751-
else => return null,
1752-
};
1753-
defer allocator.free(base_path);
1756+
return try uriFromFileImportStr(allocator, handle, import_str);
1757+
}
1758+
}
17541759

1755-
const joined_path = std.fs.path.resolve(allocator, &.{ base_path, "..", import_str }) catch |err| switch (err) {
1756-
error.OutOfMemory => return error.OutOfMemory,
1757-
else => return null,
1758-
};
1759-
defer allocator.free(joined_path);
1760+
fn uriFromFileImportStr(allocator: std.mem.Allocator, handle: *Handle, import_str: []const u8) error{OutOfMemory}!?Uri {
1761+
const base_path = URI.toFsPath(allocator, handle.uri) catch |err| switch (err) {
1762+
error.OutOfMemory => return error.OutOfMemory,
1763+
else => return null,
1764+
};
1765+
defer allocator.free(base_path);
17601766

1761-
return try URI.fromPath(allocator, joined_path);
1762-
}
1767+
const joined_path = std.fs.path.resolve(allocator, &.{ base_path, "..", import_str }) catch |err| switch (err) {
1768+
error.OutOfMemory => return error.OutOfMemory,
1769+
else => return null,
1770+
};
1771+
defer allocator.free(joined_path);
1772+
1773+
return try URI.fromPath(allocator, joined_path);
17631774
}

0 commit comments

Comments
 (0)