Sequence

← Reference
Io

C implementation of the Sequence / String / Symbol proto. A Sequence is an IoObject whose dataPointer is a UArray — a typed, resizable byte array from the basekit runtime that tracks itemType, encoding, and item size in addition to raw bytes. A single proto serves three roles: mutable Sequence, immutable Symbol (interned; pointer-equality for equal strings), and typed numeric vector (uint8, int32, float32, etc.) used by the fast math methods. The split across IoSeq.c, IoSeq_immutable.c, IoSeq_mutable.c, and IoSeq_vector.c is purely a code-organization partition: this file owns lifecycle (clone/free/ compare), the constructor API, and cross-partition helpers; IoSeq_immutable.c holds read-only methods also usable on Symbols; IoSeq_mutable.c holds the in-place-mutating methods; IoSeq_vector.c holds the SIMD/vector math. Symbols are detected via IoObject_isSymbol; rawClone short-circuits on them (returning the original) so every "clone" of a Symbol is the same interned object.

ISMUTABLESEQ(self)

Type predicate — a mutable Sequence is any Sequence that is not a Symbol. Used by mutating methods to reject Symbol receivers and preserve interning semantics.

ISVECTOR(self)

Type predicate — a "Vector" is a Sequence whose UArray itemType is float32. Written as a function (not a macro) so the argument is evaluated exactly once, since ISSEQ and UArray_itemType both need to probe it.

IoAssertNotSymbol(self, m)

Guard rail for every mutating method. Raises an Io-level error naming the offending method when called on a Symbol. The IO_ASSERT_NOT_SYMBOL macro above wraps this plus the canonical "return nil on error" so handlers do not need to repeat the check.

IoMessage_locals_pointArgAt_(m, locals, n)

Like vectorArgAt_ but additionally asserts the Vector has at least 2 elements, so 2D graphics code can safely dereference x/y without a separate bounds check. Raises via IOASSERT (IO-level error) if not.

IoMessage_locals_vectorArgAt_(self, locals, n)

Extracts and type-checks the n-th argument as a Vector. Raises a Vector-typed error through IoMessage_locals_numberArgAt_errorForType_ when the arg is not a float32 Sequence so bindings get the same error format as scalar-typed coercions.

IoSeq_addImmutableMethods(self)

Installs the immutable-safe method table onto the Sequence proto. Called from IoSeq_protoFinish during VM bootstrap. The methods here never mutate the receiver, so they are safe to call on Symbols as well as mutable Sequences.

IoSeq_addMutableMethods(self)

Installs the mutating method table onto the Sequence proto. Called from IoSeq_protoFinish during VM bootstrap. Every entry here ultimately guards against Symbol receivers via the IO_ASSERT_NOT_SYMBOL macro at the top of each handler.

IoSeq_asUTF8Seq(state, self)

Transcodes the receiver into a fresh UTF-8 Sequence via UArray_asUTF8. Zero-copy adopts the new UArray since it is freshly minted.

IoSeq_assertIsVector(self, locals, m)

Raises an Io-level error if the receiver is not a float32-typed Sequence. Used by vector-math methods that need the strict typing guarantee before memcpy'ing struct-shaped buffers.

IoSeq_byteArrayListForSeqList(self, locals, m, seqs)

Converts an IoList of Sequences into a basekit List of borrowed UArray pointers so UArray_split_ can do the byte-level work without extra allocations. Verifies each element is a Sequence; raises and returns NULL if not. Caller owns the returned List.

IoSeq_byteCompare(a, b)

qsort comparator for the sort method. Compares two bytes pointed at by a and b — adequate because sort is only enabled on uint8-typed Sequences. Typed-vector sorts go through different paths.

IoSeq_clone(self)

Public clone entry point used by the non-destructive arithmetic ops (+, -, *, /, **). Forwards to the tag's rawClone; does NOT interpose a Symbol short-circuit because those ops always produce a mutable result even when given a Symbol input.

IoSeq_compare(self, v)

Registered as the tag's compareFunc. Identity fast path first, then byte-wise UArray comparison honoring itemType. Falls back to IoObject_defaultCompare for mixed types so generic sorting stays total.

IoSeq_floatPointerOfLength_(self, size)

Returns a borrowed float pointer into the receiver's bytes if it is a float32 Sequence of at least `size` elements; otherwise NULL. Used by the vec2f/vec3f bridges to decide whether direct memcpy is safe without tripping a bounds or type violation.

IoSeq_free(self)

Registered as the tag's freeFunc. Symbols are removed from the state's intern table first so stale entries do not leak — without this a future lookup for the same string could hit a dangling pointer. Then the UArray bytes are released.

IoSeq_makeFloatArrayOfSize_(self, size)

Reconfigures the receiver's UArray to hold `size` float32 elements (zeroed) and returns a typed pointer into its bytes. Destructive — discards existing content. Caller typically memcpy's a vec struct into the returned pointer immediately.

IoSeq_new(state)

Convenience constructor: look up the proto and IOCLONE to get a fresh empty Sequence. Most of the IoSeq_newWith* family funnel through this.

IoSeq_newFloatArrayOfSize_(state, size)

Convenience: allocate a Sequence and configure it as a float32 array of the requested length in one step.

IoSeq_newFromFilePath_(state, path)

Reads a file fully into a new Sequence using UArray_readFromFilePath_. Builds a stack UArray for the path so no intermediate heap allocation is needed for the filename.

IoSeq_newSymbolWithData_length_(state, s, length)

Internal Symbol builder — only IoState should call this. Allocates a Sequence and copies the given bytes. IoState interns the result into the global symbol table; subsequent lookups for the same string return the same pointer, which is what makes Symbol equality a pointer compare.

IoSeq_newSymbolWithFormat_(state, format, ...)

printf-style Symbol constructor safe to call from anywhere. Renders into a UArray via UArray_newWithVargs_ and hands it to the state's interner with copy=0 so the freshly built bytes are adopted instead of duplicated.

IoSeq_newSymbolWithUArray_copy_(state, ba, copy)

Internal Symbol builder from a UArray — as with the data_length variant, only IoState should call this. The copy flag controls whether ba is cloned or adopted; adopt path transfers ownership to the new Sequence and frees the proto-cloned placeholder UArray.

IoSeq_newTag(state)

Builds the Sequence tag with clone/free/compare hooks. The stream read/write hooks shown in the commented-out block above are the old BStream-based serialization path. No markFunc is needed — a Sequence holds no GC-visible references, only its UArray payload.

IoSeq_newVec2f(state, v)

Creates a new 2-element float32 Sequence from a vec2f struct by memcpy. Relies on vec2f being tightly packed float x, float y — any struct padding would break the layout match.

IoSeq_newVec3f(state, v)

3-element analogue of IoSeq_newVec2f. Same layout assumption about vec3f being packed float x, y, z.

IoSeq_newWithData_length_(state, s, length)

Constructs a mutable Sequence holding a copy of the given byte buffer. Forces itemType uint8 — typed-vector Sequences come through UArray_setData_type_size_copy_ variants directly. Used by most "string from bytes" call sites.

IoSeq_newWithData_length_copy_(state, s, length, copy)

Same as IoSeq_newWithData_length_ but lets the caller opt out of the copy when they own the bytes and want the new Sequence to adopt them. Zero-copy adoption is common in parser-to-AST paths.

IoSeq_newWithUArray_copy_(state, ba, int copy)

Wraps an existing UArray as a Sequence, optionally adopting the caller's array outright. The non-copy path frees the proto-cloned empty UArray first and installs ba as the new dataPointer — the Sequence takes full ownership of ba after this.

IoSeq_proto(state)

Creates the Sequence proto with an empty UArray payload and registers it on the state. The method table is installed later by IoSeq_protoFinish — splitting the two steps lets IoState install the proto early (so IOSEQ-valued proto references work during bootstrap) and wire up the immutable/mutable method partitions afterward.

IoSeq_protoFinish(self)

Second-phase proto setup — installs the full method table by calling into IoSeq_immutable.c and IoSeq_mutable.c. Called by IoState after all primitive protos are registered so immutable/mutable methods can reference other protos (Number, List) safely.

IoSeq_rawAsDoubleFromHex(self)

Parses the receiver as a hexadecimal integer and returns it as a double. Used by the parser for 0x... numeric literals. Uses 64-bit intermediate to preserve precision up to 2^53.

IoSeq_rawAsDoubleFromOctal(self)

Parses the receiver as an octal integer and returns it as a double. Used by the parser for 0NNN numeric literals.

IoSeq_rawAsSymbol(self)

Returns the interned Symbol form of a Sequence. No-op when already a Symbol — preserves pointer identity so hashing and symbol-table lookups stay cheap. Otherwise copies the bytes through the state's symbol table so the result is the canonical interned version.

IoSeq_rawAsUnescapedSymbol(self)

Resolves backslash escape sequences (\n, \t, \xNN, etc.) and interns the result. Used by the parser after unquoting a string literal.

IoSeq_rawAsUnquotedSymbol(self)

Strips one layer of surrounding quotes and returns the interned Symbol form. Used by the parser for normal "..." string literals. Clones the UArray before mutating so the original Sequence (possibly a Symbol) is untouched.

IoSeq_rawAsUntriquotedSymbol(self)

Strips three layers of surrounding quotes (Io's triple-quoted string literal) and returns the interned Symbol form. Used by the parser when it sees """...""" source syntax.

IoSeq_rawClone(proto)

Registered as the tag's cloneFunc. Short-circuits on Symbols and returns the proto itself — that is what makes Symbols interned: every "clone" of a Symbol is the same object, and equality is pointer identity. Non-Symbols get a fresh IoObject whose UArray is a deep clone of the proto's bytes.

IoSeq_rawCopy_(self, other)

Byte-level copy from other's UArray into self's. Does NOT check for Symbol-ness or mark dirty — callers must do both. Used as a primitive by the Io-visible copy method and by internal paths that have already validated the receiver.

IoSeq_rawIsNotAlphaNumeric(self)

Returns true if the receiver contains no alphanumeric character at all. Scans until it either hits an alphanumeric byte (return false) or reaches the terminator (return true). Used by the parser to decide whether a symbol name needs quoting in error messages.

IoSeq_rawMutableCopy(self)

Returns a mutable copy of a Sequence. Needed when the input might be a Symbol: mutating it in place would corrupt the interned symbol table, so callers that want to edit bytes first materialize a copy.

IoSeq_rawPio_reallocateToSize_(self, size)

Grows the backing UArray to hold at least `size` items without changing the logical size. Used by IO bindings (pio_* = portable I/O) that need a preallocated buffer before reading bytes in. Does not assert not-symbol — callers are C-internal and already know.

IoSeq_setVec2f_(self, v)

Writes a vec2f into the receiver's first two floats. Silent no-op if the receiver is not a float32 Sequence of length >= 2 — consistent with the vec2f reader's permissive behavior.

IoSeq_setVec3f_(self, v)

3-element analogue of IoSeq_setVec2f_.

IoSeq_splitToFunction(self, locals, m, func)

Shared engine for split and splitAt. Resolves the separator set, delegates the actual scanning to UArray_split_, then wraps each chunk via the caller-supplied func — which picks between a mutable Sequence constructor and a Symbol constructor depending on the variant invoked. Empty separators are rejected up front since UArray_split_ would loop.

IoSeq_stringListForArgs(self, locals, m)

Picks the separator set for split: either the evaluated argument list, or whiteSpaceStrings when split is called with no arguments.

IoSeq_vec2f(self)

Reads the receiver's first two floats into a vec2f struct, returning {0,0} if the receiver is not a suitable float32 Sequence. The zero fallback keeps misuse from crashing — callers that must distinguish present-but-zero from absent should test isVec2f first.

IoSeq_vec3f(self)

3-element analogue of IoSeq_vec2f. Returns {0,0,0} when the receiver is not a float32 Sequence of length >= 3.

ioSymbolFindFunc(s, ioSymbol)

strcmp-based comparator registered with IoState's symbol table so a C string key can find an interned IoSymbol. Reaches into the symbol's UArray bytes rather than copying — the table is hot.

parse_json_array(self, array)

Converts a parson JSON_Array into an IoList. Each element is parsed through parse_json_value so the type dispatch stays centralized.

parse_json_object(self, object)

Recursive helper that converts a parson JSON_Object into an IoMap. Keys become interned Symbols so repeated object keys share storage; values go through parse_json_value to keep the type dispatch in one place.

parse_json_value(self, value)

Maps a parson JSON_Value to the equivalent Io object: String to Sequence, Number to Number, Object/Array to Map/List (recursively), Boolean to ioTrue/ioFalse, Null to ioNil. JSONError falls through to a NULL return, which the callers propagate.

url_decode(str, isPercentEncoded)

Returns a freshly malloc'd URL-decoded copy of str. Reverses url_encode: '+' becomes space only in form-encoding mode, %NN sequences become the single byte, everything else passes through. Caller owns the buffer and must free it.

url_encode(str, isPercentEncoded)

Returns a freshly malloc'd URL-encoded copy of str. Unreserved characters (alphanumerics plus - _ . ~) pass through; space becomes '+' only for the non-percent-encoded form-encoding mode; everything else is emitted as %NN. Caller owns the buffer and must free it.