From d139fff33debf1f8fc0d2f28aac0b903ede7e454 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 5 May 2026 16:46:30 +0100 Subject: [PATCH 01/13] Start documenting librt.vecs --- mypyc/doc/index.rst | 1 + mypyc/doc/librt.rst | 2 ++ mypyc/doc/librt_vecs.rst | 59 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 mypyc/doc/librt_vecs.rst diff --git a/mypyc/doc/index.rst b/mypyc/doc/index.rst index fe683c4188f20..8be1086bdd707 100644 --- a/mypyc/doc/index.rst +++ b/mypyc/doc/index.rst @@ -35,6 +35,7 @@ generate fast code. librt_base64 librt_strings librt_time + librt_vecs .. toctree:: :maxdepth: 2 diff --git a/mypyc/doc/librt.rst b/mypyc/doc/librt.rst index f18cc93c80294..9e03024ed3147 100644 --- a/mypyc/doc/librt.rst +++ b/mypyc/doc/librt.rst @@ -30,6 +30,8 @@ Follow submodule links in the table to a detailed description of each submodule. - String and bytes utilities * - :doc:`librt.time ` - Time utilities + * - :doc:`librt.vecs ` + - Fast growable array-like container ``vec``` Installing librt ---------------- diff --git a/mypyc/doc/librt_vecs.rst b/mypyc/doc/librt_vecs.rst new file mode 100644 index 0000000000000..cc6a0cbd15a5e --- /dev/null +++ b/mypyc/doc/librt_vecs.rst @@ -0,0 +1,59 @@ +librt.vecs +========== + +The ``librt.vecs`` module is part of the ``librt`` package on PyPI, and it includes +a low-level growable array type ``vec`` and helper functions. + +Classes +------- + +.. class:: vec(items: Iterable[T] = ..., *, capacity: i64 = ...) + + A generic growable array type. The type parameter ``T`` determines the + element type. + + TODO + + .. method:: __len__() -> i64 + + TODO + + .. method:: __getitem__(i: i64) -> T + __getitem__(i: slice) -> vec[T] + + TODO + + .. method:: __setitem__(i: i64, o: T) -> None + + TODO + + .. method:: __contains__(o: object) -> bool + + TODO + + .. method:: __iter__() -> Iterator[T] + + TODO + + .. method:: __buffer__(flags: int) -> memoryview + + TODO + +Functions +--------- + +.. function:: append(v: vec[T], o: T) -> vec[T] + + TODO + +.. function:: remove(v: vec[T], o: T) -> vec[T] + + TODO + +.. function:: pop(v: vec[T], i: i64 = -1) -> tuple[vec[T], T] + + TODO + +.. function:: extend(v: vec[T], o: Iterable[T]) -> vec[T] + + TODO From dcdeffc088e8d7d4911ce63b485040018a516997 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 5 May 2026 17:10:07 +0100 Subject: [PATCH 02/13] Improve vec docs --- mypyc/doc/librt_vecs.rst | 83 +++++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 22 deletions(-) diff --git a/mypyc/doc/librt_vecs.rst b/mypyc/doc/librt_vecs.rst index cc6a0cbd15a5e..04a41cd3883c8 100644 --- a/mypyc/doc/librt_vecs.rst +++ b/mypyc/doc/librt_vecs.rst @@ -2,7 +2,44 @@ librt.vecs ========== The ``librt.vecs`` module is part of the ``librt`` package on PyPI, and it includes -a low-level growable array type ``vec`` and helper functions. +a low-level, uniform growable array type ``vec`` and helper functions. A vec can be +a more efficient alternative to ``array.array`` or ``list`` in some uses cases.` + +A vec instance perform runtime type checking of item types. This allows using +an optimized memory representation based on item type. + +A vec instance must always we created using ``vec[](...)``, where ```` is a non-generic +supported item type, so that the item type is known at runtime. + +Since vec performs runtime type checking, only simple uniform types are supported. Summary +of supported item types: + +* Value item types (``i64``, ``i32``, ``i16``, ``u8``, ``float`` and ``bool``) are stored + as efficient packed arrays. No other value item types are supported. + + * ``int`` is not a valid item type, since it has an arbitrary precision, and vec is an efficiency + focused type. Use one of the fixed-length integer types instead. + +* Class item types (e.g. ``str`` or ``MyNativeClass``) are stored as normal object references. +* Optional class item types (e.g. ``str | None``) are supported for convenience, but arbitrary + union types are not supported as item types. +* Nested vecs are support, e.g. ``vec[vec[i64]]``. + +Here are some examples of valid vec types: + +.. list-table:: + :header-rows: 1 + + * - Type + - Item representation + * - ``vec[i32]`` + - Packed 32-bit integers + * - ``vec[float]`` + - Packed 64-bit floats + * - ``vec[str]`` + - Object references + * - ``vec[vec[u8]]`` + - Object references (nested vecs) Classes ------- @@ -12,48 +49,50 @@ Classes A generic growable array type. The type parameter ``T`` determines the element type. - TODO + .. describe:: len(v) → i64 - .. method:: __len__() -> i64 + Return the length of ``v```. - TODO + .. describe:: v[i] → T - .. method:: __getitem__(i: i64) -> T - __getitem__(i: slice) -> vec[T] + ``vec`` supports indexing. - TODO + .. describe:: v[i:j] → vec[T] - .. method:: __setitem__(i: i64, o: T) -> None + ``vec`` supports slicing. This constructs a new ``vec`` object. - TODO + .. describe:: v[i] = o - .. method:: __contains__(o: object) -> bool + ``vec`` supports indexed assignment. - TODO + .. describe:: o in v → bool - .. method:: __iter__() -> Iterator[T] + ``vec`` supports the ``in`` operator. - TODO + .. describe:: for o in v - .. method:: __buffer__(flags: int) -> memoryview + ``vec`` supports iteration. - TODO + .. describe:: memoryview(v) + + ``vec`` implements the buffer protocol (TODO for given item types). Functions --------- .. function:: append(v: vec[T], o: T) -> vec[T] - TODO + Return ``v`` with item ``o`` appended to it. -.. function:: remove(v: vec[T], o: T) -> vec[T] +.. function:: extend(v: vec[T], it: Iterable[T]) -> vec[T] - TODO + Return ``v`` with all items from iterable ``o`` appended to it. -.. function:: pop(v: vec[T], i: i64 = -1) -> tuple[vec[T], T] +.. function:: remove(v: vec[T], o: T) -> vec[T] - TODO + Return ``v`` with the first instance of item ``o`` removed from it. -.. function:: extend(v: vec[T], o: Iterable[T]) -> vec[T] +.. function:: pop(v: vec[T], i: i64 = -1) -> tuple[vec[T], T] - TODO + Return tuple with first being ``v`` with an item at index ``i`` removed, + and second being the removed item. From 3cca60d339e1079783f85c07d53f08457f5e9ae4 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 5 May 2026 17:13:13 +0100 Subject: [PATCH 03/13] Updates --- mypyc/doc/librt_vecs.rst | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mypyc/doc/librt_vecs.rst b/mypyc/doc/librt_vecs.rst index 04a41cd3883c8..b60fb3da4e1a9 100644 --- a/mypyc/doc/librt_vecs.rst +++ b/mypyc/doc/librt_vecs.rst @@ -9,7 +9,18 @@ A vec instance perform runtime type checking of item types. This allows using an optimized memory representation based on item type. A vec instance must always we created using ``vec[](...)``, where ```` is a non-generic -supported item type, so that the item type is known at runtime. +supported item type, so that the item type is known at runtime. Examples:: + + from vec import vec + from mypy_extensions import i32 + + def example() -> None: + v = vec[i32]([4, 5]) # Ok + v2 = vec([4, 5]) # Error: item type not specified + +A vec value is immutable, it is effectively a (length, buffer) pair. This means that any operations +that change the length of a vec, including ``append``, return a modified value. An immutable +length allows more efficient to be generated by mypyc. Since vec performs runtime type checking, only simple uniform types are supported. Summary of supported item types: From 82bc37c3cd27e1bcd97b90072bf631e8e85e4635 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Wed, 6 May 2026 10:34:44 +0100 Subject: [PATCH 04/13] Various updates --- mypyc/doc/librt_vecs.rst | 84 +++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/mypyc/doc/librt_vecs.rst b/mypyc/doc/librt_vecs.rst index b60fb3da4e1a9..a3e5f3464b626 100644 --- a/mypyc/doc/librt_vecs.rst +++ b/mypyc/doc/librt_vecs.rst @@ -2,11 +2,11 @@ librt.vecs ========== The ``librt.vecs`` module is part of the ``librt`` package on PyPI, and it includes -a low-level, uniform growable array type ``vec`` and helper functions. A vec can be -a more efficient alternative to ``array.array`` or ``list`` in some uses cases.` +a low-level, uniform growable array type ``vec`` and related utility functions. A vec can be +a more efficient alternative to ``array.array`` or ``list`` in code compiled using mypyc. -A vec instance perform runtime type checking of item types. This allows using -an optimized memory representation based on item type. +Vec instances perform runtime checking of item types. This allows using an optimized +packed memory representation based on the item type. A vec instance must always we created using ``vec[](...)``, where ```` is a non-generic supported item type, so that the item type is known at runtime. Examples:: @@ -18,14 +18,18 @@ supported item type, so that the item type is known at runtime. Examples:: v = vec[i32]([4, 5]) # Ok v2 = vec([4, 5]) # Error: item type not specified -A vec value is immutable, it is effectively a (length, buffer) pair. This means that any operations -that change the length of a vec, including ``append``, return a modified value. An immutable -length allows more efficient to be generated by mypyc. +A vec value is immutable; it is effectively a (length, buffer) pair. This means that any operations +that change the length of a vec, including ``append``, return a modified value. -Since vec performs runtime type checking, only simple uniform types are supported. Summary -of supported item types: +.. note:: + An immutable length allows more efficient code to be generated by mypyc, and vec values + can be allocated to machine registers effectively. However, vec values must be boxed + if used in a non-native context, such as if appended to a list. -* Value item types (``i64``, ``i32``, ``i16``, ``u8``, ``float`` and ``bool``) are stored +Since vec performs runtime type checking, only simple uniform types are supported -- more complex +types would be too expensive to check at runtime. Summary of supported item types: + +* *Value item types* (``i64``, ``i32``, ``i16``, ``u8``, ``float`` and ``bool``) are stored as efficient packed arrays. No other value item types are supported. * ``int`` is not a valid item type, since it has an arbitrary precision, and vec is an efficiency @@ -55,10 +59,15 @@ Here are some examples of valid vec types: Classes ------- -.. class:: vec(items: Iterable[T] = ..., *, capacity: i64 = ...) +.. class:: vec[T](items: Iterable[T] = ..., *, capacity: i64 = ...) + + A generic growable array type. The runtime type parameter ``T`` used when + calling ``vec[T](...)`` determines the element type. - A generic growable array type. The type parameter ``T`` determines the - element type. + The ``capacity`` parameter allows defining the initial + minimum capacity of the buffer, some of which may be unused after + construction. Unused capacity allows fast ``append`` and ``extend`` + operations that don't need to reallocate the buffer. .. describe:: len(v) → i64 @@ -86,24 +95,63 @@ Classes .. describe:: memoryview(v) - ``vec`` implements the buffer protocol (TODO for given item types). + ``vec`` implements the buffer protocol (valid for value item types that use a + packed representation only). Functions --------- .. function:: append(v: vec[T], o: T) -> vec[T] - Return ``v`` with item ``o`` appended to it. + Return ``v`` with item ``o`` appended to it. If ``v`` has unused capacity, reuse + the existing buffer. The time complexity is O(1) on average. .. function:: extend(v: vec[T], it: Iterable[T]) -> vec[T] - Return ``v`` with all items from iterable ``o`` appended to it. + Return ``v`` with all items from iterable ``o`` appended to it. If ``v`` has sufficient + unused capacity, reuse the existing buffer. The time complexity is O(n) on average, + where n is the length of ``it``.` .. function:: remove(v: vec[T], o: T) -> vec[T] - Return ``v`` with the first instance of item ``o`` removed from it. + Return ``v`` with the first instance of item ``o`` removed from it. Reuse the buffer + from ``v``.` .. function:: pop(v: vec[T], i: i64 = -1) -> tuple[vec[T], T] Return tuple with first being ``v`` with an item at index ``i`` removed, - and second being the removed item. + and second being the removed item. Reuse the buffer from ``v``. + +Macro operations +---------------- + +Certain combinations of operations that would be multiple separate operations in +regular Python are guaranteed to be compiled by mypyc to be optimized operations +with no unnecessary temporary objects. + +.. list-table:: + :header-rows: 1 + + * - Operation + - Description + * - ``vec[T]()`` + - Construct empty vec (value type -- no construction in native context) + * - ``vec[T]([element1, ...])`` + - Directly construct a vec object with given items without a temporary list + * - ``vec[T]([element1] * n)`` + - Directly construct a vec with length n without a temporary list + * - ``vec[T]([ for ... in ])`` + - Vec comprehension: no temporary list + +Implementation details +---------------------- + +In a native context, such as in a local variable or a parameter in a native function, +or in an attribute of a native class, vec values are implement as value objects with two +fields: length and buffer. The buffer is a normal Python object. If a vec object is +empty, no buffer object is required. This means that empty vecs are particularly efficient +in a native context (16 bytes on a 64-bit platform). + +A packed representation is used for buffers with supported value item types, including for +nested vecs. The packed representation is much more efficient than a Python list object, and +it's also significantly more efficient than ``array.array`` for small sequences. From 79a45f878b8eea1e89e13e191d5c4182ba64e3bb Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Wed, 6 May 2026 13:21:42 +0100 Subject: [PATCH 05/13] More doc updates --- mypyc/doc/librt_vecs.rst | 136 ++++++++++++++++++++++++--------------- 1 file changed, 85 insertions(+), 51 deletions(-) diff --git a/mypyc/doc/librt_vecs.rst b/mypyc/doc/librt_vecs.rst index a3e5f3464b626..59aa7661bb928 100644 --- a/mypyc/doc/librt_vecs.rst +++ b/mypyc/doc/librt_vecs.rst @@ -1,44 +1,61 @@ librt.vecs ========== -The ``librt.vecs`` module is part of the ``librt`` package on PyPI, and it includes -a low-level, uniform growable array type ``vec`` and related utility functions. A vec can be -a more efficient alternative to ``array.array`` or ``list`` in code compiled using mypyc. +The ``librt.vecs`` module defines the ``vec`` type, a low-level, uniform growable array type. +It's part of the ``librt`` package on PyPI. -Vec instances perform runtime checking of item types. This allows using an optimized -packed memory representation based on the item type. +When constructing a ``vec``, the item type ``T`` is always explicitly given via ``vec[T]``:: -A vec instance must always we created using ``vec[](...)``, where ```` is a non-generic -supported item type, so that the item type is known at runtime. Examples:: + from librt.vecs import append, vec - from vec import vec - from mypy_extensions import i32 + v = vec[float]([1.0, 2.5]) # Construct vec[float] with two items - def example() -> None: - v = vec[i32]([4, 5]) # Ok - v2 = vec([4, 5]) # Error: item type not specified +``vec`` supports many sequence operations, though it's not a full sequence type:: -A vec value is immutable; it is effectively a (length, buffer) pair. This means that any operations -that change the length of a vec, including ``append``, return a modified value. + len(v) # 2 + v[0] # 1.0 + v[-1] # 2.5 + for x in v: + print(x) -.. note:: - An immutable length allows more efficient code to be generated by mypyc, and vec values - can be allocated to machine registers effectively. However, vec values must be boxed - if used in a non-native context, such as if appended to a list. +The length of each ``vec`` value is immutable. Appending an item is still a fast operation, +but it returns a new ``vec`` value:: + + v = append(v, -0.5) + print(v) # vec[float]([1.0, 2.5, -0.5]) -Since vec performs runtime type checking, only simple uniform types are supported -- more complex -types would be too expensive to check at runtime. Summary of supported item types: +``vec`` only supports simple, uniform item types. It uses an efficient packed binary encoding +for these *value item types*: -* *Value item types* (``i64``, ``i32``, ``i16``, ``u8``, ``float`` and ``bool``) are stored - as efficient packed arrays. No other value item types are supported. +* ``mypy_extensions.i64`` (signed 64-bit integer) +* ``mypy_extensions.i32`` (signed 32-bit integer) +* ``mypy_extensions.i16`` (signed 16-bit integer) +* ``mypy_extensions.u8`` (unsigned byte) +* ``float`` (64-bit float) +* ``bool`` - * ``int`` is not a valid item type, since it has an arbitrary precision, and vec is an efficiency - focused type. Use one of the fixed-length integer types instead. +``int`` is not a valid item type, since it has an arbitrary precision, and vec is an +efficiency-focused type. Use one of the fixed-length integer types instead. -* Class item types (e.g. ``str`` or ``MyNativeClass``) are stored as normal object references. -* Optional class item types (e.g. ``str | None``) are supported for convenience, but arbitrary - union types are not supported as item types. -* Nested vecs are support, e.g. ``vec[vec[i64]]``. +Class item types (e.g. ``str`` or ``MyNativeClass``) are represented as regular object references. +Optional class item types (e.g. ``str | None``) are supported for convenience, but arbitrary +union types are not supported as item types. Nested vecs are supported, e.g. ``vec[vec[i64]]``. + +A vec value is often used as an efficient alternative to ``list`` or ``array.array`` in code +compiled using mypyc. Its primary advantages are an efficient packed memory representation +for value item types and very fast inlined get and set item operations. + +Vec instances perform runtime checking of item types. Since values of type variables are +not available at runtime (they are *erased*), type variables can't be used as item types. + +A vec value is effectively an immutable (length, buffer) pair. This means that any operation +that changes the length of a vec, including ``append`` as we saw above, returns a modified +value. + +.. note:: + An immutable length allows more efficient code to be generated by mypyc, and vec values + can be allocated to machine registers effectively. However, vec values must be boxed + if used in a non-native context, such as if added to a list or dict. Here are some examples of valid vec types: @@ -54,10 +71,10 @@ Here are some examples of valid vec types: * - ``vec[str]`` - Object references * - ``vec[vec[u8]]`` - - Object references (nested vecs) + - Packed vec values -Classes -------- +The ``vec`` class +----------------- .. class:: vec[T](items: Iterable[T] = ..., *, capacity: i64 = ...) @@ -69,34 +86,37 @@ Classes construction. Unused capacity allows fast ``append`` and ``extend`` operations that don't need to reallocate the buffer. + It's an error to construct a ``vec`` object without providing an + item type: ``vec()`` raises an exception. + .. describe:: len(v) → i64 - Return the length of ``v```. + Return the length of ``v``. .. describe:: v[i] → T - ``vec`` supports indexing. + Return item at index ``i`` (index may be negative). .. describe:: v[i:j] → vec[T] - ``vec`` supports slicing. This constructs a new ``vec`` object. + Return a slice. This constructs a new ``vec`` object. .. describe:: v[i] = o - ``vec`` supports indexed assignment. + Assign to an item. .. describe:: o in v → bool - ``vec`` supports the ``in`` operator. + Return True if ``v`` contains ``o``. .. describe:: for o in v - ``vec`` supports iteration. + Iterate over items. .. describe:: memoryview(v) - ``vec`` implements the buffer protocol (valid for value item types that use a - packed representation only). + ``vec`` implements the buffer protocol, but only for value item types that use a + packed representation. Functions --------- @@ -108,25 +128,25 @@ Functions .. function:: extend(v: vec[T], it: Iterable[T]) -> vec[T] - Return ``v`` with all items from iterable ``o`` appended to it. If ``v`` has sufficient + Return ``v`` with all items from iterable ``it`` appended to it. If ``v`` has sufficient unused capacity, reuse the existing buffer. The time complexity is O(n) on average, - where n is the length of ``it``.` + where n is the length of ``it``. .. function:: remove(v: vec[T], o: T) -> vec[T] - Return ``v`` with the first instance of item ``o`` removed from it. Reuse the buffer - from ``v``.` + Return ``v`` with the first instance of item ``o`` removed. Reuse the buffer + from ``v``. Raise ``ValueError`` if value doesn't exist. .. function:: pop(v: vec[T], i: i64 = -1) -> tuple[vec[T], T] - Return tuple with first being ``v`` with an item at index ``i`` removed, - and second being the removed item. Reuse the buffer from ``v``. + Return ``(new_v, item)``, where ``item`` is the value at index ``i`` and + ``new_v`` is ``v`` with that item removed. Reuse the buffer from ``v``. Macro operations ---------------- Certain combinations of operations that would be multiple separate operations in -regular Python are guaranteed to be compiled by mypyc to be optimized operations +regular Python are guaranteed to be compiled by mypyc to direct operations with no unnecessary temporary objects. .. list-table:: @@ -135,13 +155,27 @@ with no unnecessary temporary objects. * - Operation - Description * - ``vec[T]()`` - - Construct empty vec (value type -- no construction in native context) + - Construct empty vec with no buffer. This doesn't perform any dynamic allocation + (at least for non-nested vecs). * - ``vec[T]([element1, ...])`` - - Directly construct a vec object with given items without a temporary list + - Directly construct a vec object with given items, without a temporary list. * - ``vec[T]([element1] * n)`` - - Directly construct a vec with length n without a temporary list + - Directly construct a vec with length n, without any temporary list. * - ``vec[T]([ for ... in ])`` - - Vec comprehension: no temporary list + - Vec comprehension creates no temporary list. + +Thread safety +------------- + +In free-threaded Python builds, it's unsafe to write or modify an item if other +threads might be concurrently accessing *the same item*. For example, writing ``v[4]`` +is not safe to do if another thread might be reading ``v[4]``. Similarly, two +threads concurrently calling ``append`` or ``remove`` on the same vec object is not safe. + +This is different from list objects, since vec is a lower-level type where implicit +synchronization would have a significant performance cost. However, since vec lengths +are immutable, some race conditions that lists can be susceptible to are not possible +with vecs. Implementation details ---------------------- @@ -150,7 +184,7 @@ In a native context, such as in a local variable or a parameter in a native func or in an attribute of a native class, vec values are implement as value objects with two fields: length and buffer. The buffer is a normal Python object. If a vec object is empty, no buffer object is required. This means that empty vecs are particularly efficient -in a native context (16 bytes on a 64-bit platform). +in a native context (usually 16 bytes). A packed representation is used for buffers with supported value item types, including for nested vecs. The packed representation is much more efficient than a Python list object, and From d779643aa21020983617b8bf31837367533c5b83 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Wed, 6 May 2026 13:22:37 +0100 Subject: [PATCH 06/13] Minor tweaks --- mypyc/doc/librt.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/doc/librt.rst b/mypyc/doc/librt.rst index 9e03024ed3147..a9492e1d61268 100644 --- a/mypyc/doc/librt.rst +++ b/mypyc/doc/librt.rst @@ -31,7 +31,7 @@ Follow submodule links in the table to a detailed description of each submodule. * - :doc:`librt.time ` - Time utilities * - :doc:`librt.vecs ` - - Fast growable array-like container ``vec``` + - Fast growable array type ``vec`` Installing librt ---------------- From 2550a65b7dceb5f746101ec985123fc7de9066f6 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Wed, 6 May 2026 13:31:02 +0100 Subject: [PATCH 07/13] More updates --- mypyc/doc/librt_vecs.rst | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/mypyc/doc/librt_vecs.rst b/mypyc/doc/librt_vecs.rst index 59aa7661bb928..e79da821b9a11 100644 --- a/mypyc/doc/librt_vecs.rst +++ b/mypyc/doc/librt_vecs.rst @@ -99,11 +99,11 @@ The ``vec`` class .. describe:: v[i:j] → vec[T] - Return a slice. This constructs a new ``vec`` object. + Return a slice. This constructs a new ``vec`` object. ``i`` and ``j`` may be negative. .. describe:: v[i] = o - Assign to an item. + Assign to an item (index may be negative). .. describe:: o in v → bool @@ -181,11 +181,21 @@ Implementation details ---------------------- In a native context, such as in a local variable or a parameter in a native function, -or in an attribute of a native class, vec values are implement as value objects with two -fields: length and buffer. The buffer is a normal Python object. If a vec object is -empty, no buffer object is required. This means that empty vecs are particularly efficient -in a native context (usually 16 bytes). +or in an attribute of a native class, vec values are implemented as value objects with two +fields: length and buffer. The buffer is a normal Python object, but it's not directly +accessible to users. If a vec object is empty, no buffer object is required. This means that +empty vecs are particularly efficient in a native context (usually 16 bytes). A packed representation is used for buffers with supported value item types, including for nested vecs. The packed representation is much more efficient than a Python list object, and it's also significantly more efficient than ``array.array`` for small sequences. + +Using vecs outside compiled code +-------------------------------- + +``vec`` is fully supported in non-compiled code, but ``vec`` values` will be boxed in such +non-native contexts. There will be always two objects, a boxed vec object and a buffer object, +whereas in native contexts usually only the buffer is a dynamically allocated object. +``vec`` is primarily useful in code compiled using mypyc, and it's been heavily optimized +for this use case. There may be no performance benefit in interpreted code over using +``list`` or ``array.array``. From 6f9bd02877b0ae04cfd75c612222aca9c21680f4 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Wed, 6 May 2026 13:37:24 +0100 Subject: [PATCH 08/13] Updates --- mypyc/doc/librt_vecs.rst | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/mypyc/doc/librt_vecs.rst b/mypyc/doc/librt_vecs.rst index e79da821b9a11..ceb9bcf77a9a3 100644 --- a/mypyc/doc/librt_vecs.rst +++ b/mypyc/doc/librt_vecs.rst @@ -121,26 +121,44 @@ The ``vec`` class Functions --------- +Since the following operations return a modified value, they are module-level functions +instead of methods. + .. function:: append(v: vec[T], o: T) -> vec[T] Return ``v`` with item ``o`` appended to it. If ``v`` has unused capacity, reuse - the existing buffer. The time complexity is O(1) on average. + the existing buffer. The time complexity is O(1) on average. Example:: + + v = vec[i32]() + v = append(v, 1) .. function:: extend(v: vec[T], it: Iterable[T]) -> vec[T] Return ``v`` with all items from iterable ``it`` appended to it. If ``v`` has sufficient unused capacity, reuse the existing buffer. The time complexity is O(n) on average, - where n is the length of ``it``. + where n is the length of ``it``. Example:: + + v = vec[u8]() + v = extend(v, b"foo") .. function:: remove(v: vec[T], o: T) -> vec[T] Return ``v`` with the first instance of item ``o`` removed. Reuse the buffer - from ``v``. Raise ``ValueError`` if value doesn't exist. + from ``v``. Raise ``ValueError`` if value doesn't exist. Example:: + + v = vec[i32]([1, 2, 3]) + v = remove(v, 2) + # v has items [1, 3] .. function:: pop(v: vec[T], i: i64 = -1) -> tuple[vec[T], T] Return ``(new_v, item)``, where ``item`` is the value at index ``i`` and ``new_v`` is ``v`` with that item removed. Reuse the buffer from ``v``. + Example:: + + v = vec[i32]([1, 2, 3]) + v, x = pop(v) + # x is 3; v has items [1, 2] Macro operations ---------------- @@ -193,7 +211,7 @@ it's also significantly more efficient than ``array.array`` for small sequences. Using vecs outside compiled code -------------------------------- -``vec`` is fully supported in non-compiled code, but ``vec`` values` will be boxed in such +``vec`` is fully supported in non-compiled code, but ``vec`` values will be boxed in such non-native contexts. There will be always two objects, a boxed vec object and a buffer object, whereas in native contexts usually only the buffer is a dynamically allocated object. ``vec`` is primarily useful in code compiled using mypyc, and it's been heavily optimized From 443edc425485e7e35d9c97351a94258d26fc8a66 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Thu, 7 May 2026 16:35:26 +0100 Subject: [PATCH 09/13] Small updates --- mypyc/doc/librt_vecs.rst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/mypyc/doc/librt_vecs.rst b/mypyc/doc/librt_vecs.rst index ceb9bcf77a9a3..bbdb987d474aa 100644 --- a/mypyc/doc/librt_vecs.rst +++ b/mypyc/doc/librt_vecs.rst @@ -81,10 +81,16 @@ The ``vec`` class A generic growable array type. The runtime type parameter ``T`` used when calling ``vec[T](...)`` determines the element type. - The ``capacity`` parameter allows defining the initial - minimum capacity of the buffer, some of which may be unused after + The ``capacity`` parameter allows defining the minimum initial + capacity of the buffer, some of which may be unused after construction. Unused capacity allows fast ``append`` and ``extend`` - operations that don't need to reallocate the buffer. + operations that don't need to reallocate the buffer. Actual capacity + will be larger than ``capacity`` if ``items`` has more than ``capacity`` + items. + + Mypyc treats ``vec[T]([x] * n)`` as a special form. For example, + ``vec[u8]([0] * n)`` constructs a zero-initialized vec object + efficiently, without building an intermediate list. It's an error to construct a ``vec`` object without providing an item type: ``vec()`` raises an exception. From e75651c164c376eb0bf98f7fe3aa0b1ef7daaf64 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Thu, 7 May 2026 16:39:31 +0100 Subject: [PATCH 10/13] More small tweaks --- mypyc/doc/librt_vecs.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mypyc/doc/librt_vecs.rst b/mypyc/doc/librt_vecs.rst index bbdb987d474aa..75893dd3f21d0 100644 --- a/mypyc/doc/librt_vecs.rst +++ b/mypyc/doc/librt_vecs.rst @@ -90,7 +90,9 @@ The ``vec`` class Mypyc treats ``vec[T]([x] * n)`` as a special form. For example, ``vec[u8]([0] * n)`` constructs a zero-initialized vec object - efficiently, without building an intermediate list. + efficiently, without building an intermediate list. There are + also other constructor-related special forms -- see `Special + forms`_ below. It's an error to construct a ``vec`` object without providing an item type: ``vec()`` raises an exception. @@ -166,8 +168,8 @@ instead of methods. v, x = pop(v) # x is 3; v has items [1, 2] -Macro operations ----------------- +Special forms +-------------- Certain combinations of operations that would be multiple separate operations in regular Python are guaranteed to be compiled by mypyc to direct operations @@ -176,7 +178,7 @@ with no unnecessary temporary objects. .. list-table:: :header-rows: 1 - * - Operation + * - Special form - Description * - ``vec[T]()`` - Construct empty vec with no buffer. This doesn't perform any dynamic allocation From 71b9df16502fa9076f6d5d41a08b24fe9ea24990 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Thu, 7 May 2026 16:48:09 +0100 Subject: [PATCH 11/13] More discussion about construction --- mypyc/doc/librt_vecs.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mypyc/doc/librt_vecs.rst b/mypyc/doc/librt_vecs.rst index 75893dd3f21d0..5631d3df481ba 100644 --- a/mypyc/doc/librt_vecs.rst +++ b/mypyc/doc/librt_vecs.rst @@ -88,6 +88,11 @@ The ``vec`` class will be larger than ``capacity`` if ``items`` has more than ``capacity`` items. + Construction from ``list`` and ``tuple`` objects is optimized. + Also, for value item types, construction from an object that implements + the buffer protocol is optimized (such as ``bytes``), if the format + is compatible with the vec item type. + Mypyc treats ``vec[T]([x] * n)`` as a special form. For example, ``vec[u8]([0] * n)`` constructs a zero-initialized vec object efficiently, without building an intermediate list. There are From 576019171e6cfed1f59d6d5f526e74391db97222 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Thu, 7 May 2026 16:56:32 +0100 Subject: [PATCH 12/13] Explain buffer sharing --- mypyc/doc/librt_vecs.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/mypyc/doc/librt_vecs.rst b/mypyc/doc/librt_vecs.rst index 5631d3df481ba..d4bd63129114c 100644 --- a/mypyc/doc/librt_vecs.rst +++ b/mypyc/doc/librt_vecs.rst @@ -221,6 +221,27 @@ A packed representation is used for buffers with supported value item types, inc nested vecs. The packed representation is much more efficient than a Python list object, and it's also significantly more efficient than ``array.array`` for small sequences. +Multiple vec values can share the same underlying buffer. For example, assigning a vec +to another variable creates an alias that refers to the same buffer:: + + v = vec[i32]([1, 2, 3]) + w = v # v and w share the same buffer + + w[0] = 99 + print(v[0]) # 99 -- both see the change + +However, this sharing is not guaranteed to persist if there are operations that change +the length (such as ``append``). These may reallocate the buffer, breaking the sharing +silently:: + + v = append(v, 4) # reallocates the buffer if there is no free capacity + v[0] = 0 + print(w[0]) # still 99 -- v and w may no longer share a buffer + +If you need independent copies, use slicing (``v[:]``) to explicitly create a vec with +its own buffer. It's not recommended to rely on the details of buffer reallocation, +as these might change between ``librt`` releases. + Using vecs outside compiled code -------------------------------- From 20c4544ea9a59f7906de96fce01442d1c021028b Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Thu, 7 May 2026 17:08:13 +0100 Subject: [PATCH 13/13] Update mypyc/doc/librt_vecs.rst Co-authored-by: Piotr Sawicki --- mypyc/doc/librt_vecs.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mypyc/doc/librt_vecs.rst b/mypyc/doc/librt_vecs.rst index d4bd63129114c..dad3be621ff4c 100644 --- a/mypyc/doc/librt_vecs.rst +++ b/mypyc/doc/librt_vecs.rst @@ -224,7 +224,7 @@ it's also significantly more efficient than ``array.array`` for small sequences. Multiple vec values can share the same underlying buffer. For example, assigning a vec to another variable creates an alias that refers to the same buffer:: - v = vec[i32]([1, 2, 3]) + v = vec[i32]([1, 2, 3], capacity=3) w = v # v and w share the same buffer w[0] = 99 @@ -234,9 +234,9 @@ However, this sharing is not guaranteed to persist if there are operations that the length (such as ``append``). These may reallocate the buffer, breaking the sharing silently:: - v = append(v, 4) # reallocates the buffer if there is no free capacity + v = append(v, 4) # reallocates the buffer since there is no free capacity v[0] = 0 - print(w[0]) # still 99 -- v and w may no longer share a buffer + print(w[0]) # still 99 -- v and w no longer share a buffer If you need independent copies, use slicing (``v[:]``) to explicitly create a vec with its own buffer. It's not recommended to rely on the details of buffer reallocation,