query
On this page

substring

builtins.substring

Primop
Docs pulled from | This Revision | 3 days ago


Nix manual

Takes 3 arguments

start, len, s

Return the substring of s from byte position start (zero-based) up to but not including start + len. If start is greater than the length of the string, an empty string is returned. If start + len lies beyond the end of the string or len is -1, only the substring up to the end of the string is returned. start must be non-negative. For example,

builtins.substring 0 3 "nixos"

evaluates to "nix".

Noogle detected

Aliases

Detected Type
substring :: Int -> Int -> String -> String

Implementation

This function is implemented in c++ and is part of the native nix runtime.

src/libexpr/primops.cc:4715

static void prim_substring(EvalState & state, const PosIdx pos, Value ** args, Value & v)
{
    using NixUInt = std::make_unsigned_t<NixInt::Inner>;
    NixInt::Inner start =
        state
            .forceInt(
                *args[0], pos, "while evaluating the first argument (the start offset) passed to builtins.substring")
            .value;

    if (start < 0)
        state.error<EvalError>("negative start position in 'substring'").atPos(pos).debugThrow();

    NixInt::Inner len =
        state
            .forceInt(
                *args[1],
                pos,
                "while evaluating the second argument (the substring length) passed to builtins.substring")
            .value;

    // Negative length may be idiomatically passed to builtins.substring to get
    // the tail of the string.
    auto _len = std::numeric_limits<std::string::size_type>::max();

    // Special-case on empty substring to avoid O(n) strlen
    // This allows for the use of empty substrings to efficiently capture string context
    if (len == 0) {
        state.forceValue(*args[2], pos);
        if (args[2]->type() == nString) {
            v.mkStringNoCopy(""_sds, args[2]->context());
            return;
        }
    }

    if (len >= 0 && NixUInt(len) < _len) {
        _len = len;
    }

    NixStringContext context;
    auto s = state.coerceToString(
        pos, *args[2], context, "while evaluating the third argument (the string) passed to builtins.substring");

    v.mkString(NixUInt(start) >= s->size() ? "" : s->substr(start, _len), context, state.mem);
}