llm
Download
103 lines 4.7 KiBTomoModified 2026-08-30 raw
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
# reverse-complement, from The Computer Language Benchmarks Game
#
# A Tomo port of the gcc-4 reference (single-threaded). Reads FASTA on stdin;
# for each record it prints the header unchanged, then the reverse-complement
# of the sequence, re-wrapped to 60 columns and upper-cased.
#
# Design notes:
#   - The whole input is slurped once as raw `[Byte]` (`read_bytes()`), and all
#     work is byte-level: no Text decoding, no per-line allocation.
#   - `comp` is a 256-entry byte table mapping each nucleotide (upper OR lower
#     case) to its upper-case complement, and everything else, crucially
#     newlines, to 0. Walking the sequence backwards and emitting only the
#     non-zero lookups reverses, complements, upper-cases and strips newlines in
#     a single pass, exactly like the reference's `xtab` (where `if (c)` skips
#     the zero entries).
#   - Header/record boundaries are located with `.find()` (memchr-backed,
#     vectorized) instead of a manual per-byte scan loop, the same technique
#     the fast reference implementations use (Go's line-splitting bufio
#     reader, C#'s `Array.IndexOf`), which a hand-written scalar loop can't
#     match without SIMD.
#   - The output buffer is `data`'s own bytes reused as scratch space (plus a
#     little padding): a `[Byte]` slice shares its backing storage (CoW) until
#     the first write, which triggers exactly one bulk copy-on-write compact
#     for the *whole* buffer; every write after that is a plain bounds-checked
#     pointer store, with no growth logic and no per-byte `memcpy()` call. This
#     replaced a per-byte `out.insert(c)`, which (even after fixing
#     `List$insert`'s growth path to bulk-copy) still called a real `memcpy()`
#     once per byte to place the new item.
#   - Output goes through a raw `byte_writer` (like fasta), one whole record at
#     a time.
#
# Usage: reversecomplement < fasta_input   (stdin is FASTA text)

# Build the complement lookup: index by byte value + 1 (lists are 1-indexed).
# Zeros elsewhere mean "drop this byte" (newlines, stray characters). Each
# nucleotide in `letters` maps to the complement at the same position in
# `comps` (A<->T, C<->G, plus the IUB ambiguity codes); all ASCII, so
# `.utf8()` yields exactly their byte values.
func build_comp(-> [Byte])
    letters := "ABCDGHKMNRSTVWY".utf8()
    comps := "TVGHCDMKNYSABWR".utf8()
    comp := &[Byte(0) for _ in 256]
    for i in letters.length
        u := Int64(letters[i]!)
        c := comps[i]!
        comp[u + 1] = c       # upper-case input
        comp[u + 32 + 1] = c  # lower-case input (byte + 32)
    return comp[]

func main()
    data := (/dev/stdin).read_bytes()!
    n := Int64(data.length)
    comp := build_comp()
    emit := (/dev/stdout).byte_writer(append=yes)

    # Reused write buffer for every record's output, shared across the whole
    # run. Output can never be longer than the input (re-wrapping only removes
    # or repositions newlines), so `n` bytes of `data` itself, plus a little
    # slack for a wrap-width mismatch between input and output, is always
    # enough room. Sliced (not copied) from `data`, so the first indexed write
    # below triggers one bulk copy-on-write compact, not a per-byte cost.
    out := &(data ++ [Byte(0) for _ in n // 60 + 64])
    p := Int64(0)  # write cursor into `out`, shared across all records

    i := Int64(1)
    while i <= n
        # Header line: from '>' up to (not including) the newline. `.find()`
        # on a `[Byte]` is memchr-backed (vectorized), so this locates the
        # newline in one call instead of a manual per-byte scan.
        hstart := i
        nl := data.from(i).find(Byte(10))
        i = if nl then i + Int64(nl) - 1 else n + 1
        emit(data.slice(hstart, i - 1))!
        emit([Byte(10)])!
        i += 1  # step past the newline

        # Sequence bytes run until the next '>' (or EOF), found the same way.
        seq_start := i
        if i <= n
            gt := data.from(i).find(Byte(62))
            i = if gt then i + Int64(gt) - 1 else n + 1
        seq_end := i  # exclusive

        # Walk the sequence backwards, emitting only non-zero complements, and
        # re-wrap at 60 columns. Newlines map to 0 and are skipped for free.
        record_start := p + 1
        col := Int64(0)
        j := seq_end - 1
        while j >= seq_start
            c := comp[Int64(data[j]!) + 1]!
            if Int64(c) != 0
                p += 1
                out[p] = c
                col += 1
                if col == 60
                    p += 1
                    out[p] = Byte(10)
                    col = 0
            j -= 1
        if col > 0
            p += 1
            out[p] = Byte(10)
        emit(out[].slice(record_start, p))!