// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie // SPDX-License-Identifier: MIT //! The order `as65` prints the symbol table in. //! //! It is neither ASCII order nor any locale's collation: probing as65 with //! one label per character shows the sequence //! //! . A a B b C c ... Z z 0 1 ... 9 ? _ //! //! — a full stop below everything, then the letters case-insensitively with //! the upper case of each pair first, then the digits, then `?` and `_`. Those //! seven characters plus the letters and digits are the whole of what a label //! may contain, so the table below is complete rather than a best effort. const std = @import("std"); const weights = blk: { var w: [256]u8 = @splat(0); var next: u8 = 1; w['.'] = next; next += 1; for ('A'..'Z' + 1) |c| { w[c] = next; next += 1; w[c - 'A' + 'a'] = next; next += 1; } for ('0'..'9' + 1) |c| { w[c] = next; next += 1; } w['?'] = next; next += 1; w['_'] = next; break :blk w; }; pub fn order(a: []const u8, b: []const u8) std.math.Order { const shared = @min(a.len, b.len); for (a[0..shared], b[0..shared]) |ca, cb| { const wa = weights[ca]; const wb = weights[cb]; if (wa != wb) return if (wa < wb) .lt else .gt; } return std.math.order(a.len, b.len); } pub fn lessThan(_: void, a: []const u8, b: []const u8) bool { return order(a, b) == .lt; } test "upper case sorts immediately before its lower case" { try std.testing.expectEqual(std.math.Order.lt, order("Aa", "aa")); try std.testing.expectEqual(std.math.Order.lt, order("aa", "Ba")); try std.testing.expectEqual(std.math.Order.lt, order("Mz", "ma")); } test "the anomalies that gave the order away" { // A capital first letter keeps a name ahead of every lower-case one, which // is why `Message1` precedes `macro_one` although `a` precedes `e`. try std.testing.expectEqual(std.math.Order.lt, order("Message1", "macro_one")); // Digits, `?` and `_` all sort above the letters. try std.testing.expectEqual(std.math.Order.lt, order("zz", "_a")); try std.testing.expectEqual(std.math.Order.lt, order("_a", "__6502__")); try std.testing.expectEqual(std.math.Order.lt, order("macroone", "macroXone")); try std.testing.expectEqual(std.math.Order.lt, order("macroXone", "macro2")); try std.testing.expectEqual(std.math.Order.lt, order("macro2", "macro_one")); } test "a prefix sorts before what extends it" { try std.testing.expectEqual(std.math.Order.lt, order("ANOTHER", "AnotherLabel")); try std.testing.expectEqual(std.math.Order.eq, order("same", "same")); }