module: Consolidate directory prefix scanning

a7dcdcfb69b8e5422d91abf61e8c589d8308337046e65c4dfef0798f137626c3
Directory length and basename start identify the same path boundary.
Use one separator scan for both and retain the directory length
already calculated when a module entry is allocated.

Assisted-by: Codex:gpt-6-astra
Alexis Sellier committed ago 1 parent 45c563a2
lib/std/lang/module.rad +5 -22
147 147
        return child.id;
148 148
    }
149 149
    // Inherit packageId from parent.
150 150
    let m = try allocModule(graph, parent.packageId, name, filePath);
151 151
152 -
    set m.dirLen = dirLength(m.filePath);
153 152
    set m.state = ModuleState::Registered;
154 153
    set m.parent = parentId;
155 154
156 155
    // Inherit path prefix from parent.
157 156
    for p in moduleQualifiedPath(parent) {
367 366
fn isValidId(graph: *ModuleGraph, id: u16) -> bool {
368 367
    return (id as u32) < graph.entriesLen;
369 368
}
370 369
371 370
/// Return the length of the directory prefix for `path`.
371 +
/// Return zero if the path has no separator.
372 372
fn dirLength(path: *[u8]) -> u32 {
373 -
    if path.len == 0 {
374 -
        return 0;
375 -
    }
376 -
    let mut last: i32 = -1;
373 +
    let mut start: u32 = 0;
377 374
    for i in 0..path.len {
378 375
        if path[i] == PATH_SEP {
379 -
            set last = i as i32;
376 +
            set start = i + 1;
380 377
        }
381 378
    }
382 -
    if last < 0 {
383 -
        return 0;
384 -
    }
385 -
    return (last as u32) + 1;
379 +
    return start;
386 380
}
387 381
388 382
/// Produce a subslice for the basename of `path` (without extension).
389 383
fn basenameSlice(path: *[u8]) -> *[u8] throws (ModuleError) {
390 -
    let start = basenameStart(path);
384 +
    let start = dirLength(path);
391 385
    let withoutExt = trimExtension(path) else {
392 386
        throw ModuleError::InvalidPath;
393 387
    };
394 388
    return &withoutExt[start..];
395 389
}
396 390
397 -
/// Find the byte offset immediately following the last separator.
398 -
fn basenameStart(path: *[u8]) -> u32 {
399 -
    let mut start: u32 = 0;
400 -
    for i in 0..path.len {
401 -
        if path[i] == PATH_SEP {
402 -
            set start = i + 1;
403 -
        }
404 -
    }
405 -
    return start;
406 -
}
407 -
408 391
/// Trim the `.rad` extension from `path` if present.
409 392
/// Returns the path slice without the extension.
410 393
export fn trimExtension(path: *[u8]) -> ?*[u8] {
411 394
    if path.len < SOURCE_EXT.len {
412 395
        return nil;