/
nv-lang
/
nova
Обзор
Документация
Войти
/
nv-lang
/
nova
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
std/src/runtime/string/slice.nv
69 строк
3 KB
Evgeniy Golovin
lint(std/src,examples): fix W_MANUAL_SLICE_TO_END (98) — canonical open-range slices
01 авг 2026, 17:03
01 авг 2026, 17:03
2ece7ec
Код
Авторство
О чём код?
// Co-equal file of module `runtime.string` (folder = one module). // Role: byte-range slice — `Index[Range, str]`. // // `s[a..b]` is a BYTE-range zero-copy sub-view (was codepoint-indexed — the bug // behind non-ASCII `split`). It shares the parent buffer (interior pointer at // `@ptr + start`; conservative GC keeps the buffer alive while the view is // reachable) — `str` is immutable, so the view never diverges. Mirrors // `[]T @index(Range)` (std/collections/vec/slice.nv). // // Both methods build the view via the inline byte-slice `@[a..b]` (which codegen // lowers to a `(nova_str){.ptr=…+from, .len=…}` view directly). They deliberately // do NOT write `str { ptr: @ptr + off, len }` — constructing a str sub-view via a // value-record literal with pointer arithmetic on the priv `@ptr` mis-compiles // ("passing nova_str to nova_int"); since `runtime.string` links into every // program, that would break all str code. See [M-152.1-str-subview-record-ctor]. // // `str` Nova-body methods. #no_prelude breaks the prelude->string->prelude // import cycle. #no_prelude module runtime.string import std.prelude.core.{Option, Some, None} import std.collections.range.{Range} // Byte-range sub-view `s[r.start, r.end)`. The numeric bounds are a `requires` // CONTRACT: Z3-proven call-sites elide the check (zero-cost), // unproven ones are checked at runtime (and in release — enforce-with-elision). // The inline `@[a..b]` also carries the UTF-8 codepoint-boundary guard // (data-dependent → a runtime panic; slicing through a codepoint would yield // invalid UTF-8). `s[a..b]` sugar lowers to the identical inline // byte-slice; this Nova body carries the contract for the `Index[Range, str]` // protocol and direct `s.index(a..b)` calls. export fn str @index(r Range) -> str requires 0 <= r.start && r.start <= r.end && r.end <= @byte_len() { @[r.start..r.end] } // Safe byte-range slice — `Some(view)` when `[r.start, r.end)` is in bounds AND // both cut points land on codepoint boundaries, `None` otherwise. The // non-panicking counterpart of `@index(Range)` (mirrors `[]T @get(Range)`). export fn str @get(r Range) -> Option[str] { ro n = @byte_len() if r.start < 0 || r.end < r.start || r.end > n { return None } ro bytes = @bytes() if r.start < n && (bytes[r.start] as int & 0xC0) == 0x80 { return None } if r.end < n && (bytes[r.end] as int & 0xC0) == 0x80 { return None } Some(@[r.start..r.end]) } // split_at / split_at_checked. // Split at byte offset `idx` → (before, from_idx). Panics on out-of-bounds. // Contract: 0 <= idx <= byte_len. export fn str @split_at(idx int) -> (str, str) requires 0 <= idx && idx <= @byte_len() { (@[..idx], @[idx..]) } // Checked split at byte offset `idx`. Returns None when idx is out of bounds // or does not land on a codepoint boundary. export fn str @split_at_checked(idx int) -> Option[(str, str)] { if idx < 0 || idx > @byte_len() || !@is_char_boundary(idx) { return None } Some((@[..idx], @[idx..])) }