|
Stratax 0.3.1
|
Version: v0.3.1
Status: Complete
Header: include/stratax/core/ArrayBase.hpp
ArrayBase<T> is the shared owning base for Stratax's Vector<T>, Matrix<T>, and Tensor<T> containers. It keeps three pieces of state together:
The class supplies the common one-dimensional container interface and protected offset helpers. Derived containers remain responsible for rank constraints, constructors, and public multidimensional indexing APIs.
ArrayBase cannot be constructed directly by users because its constructors are protected.
ArrayBase is responsible for:
fill() and swap() operationsIt is not responsible for validating container-specific rank requirements, defining multidimensional public APIs, numerical operations, broadcasting, or formatting.
For every successfully constructed object:
size() == shape().elements()rank() == shape().rank()rank() == strides().rank()strides() represents the row-major layout of shape()[data(), data() + size())swap() exchanges all three state members together, preserving these relationships.
The aliases mirror Buffer<T>:
The pointer-based iterator types provide contiguous random-access traversal.
size() returns the number of stored elements.empty() is equivalent to size() == 0.rank() returns the number of logical dimensions.shape() and strides() return read-only metadata references.Each operation is O(1).
Returns the first element's address, or nullptr when empty. Pointers remain valid until the object is assigned to, moved from, swapped, or destroyed.
Complexity: O(1).
Returns the first or final flat element. Each operation throws Exceptions::IndexError when storage is empty.
Complexity: O(1).
Returns a flat element without bounds checking. Behavior is undefined unless index < size().
Complexity: O(1).
Accepts indices in [-size(), size()). Negative indices count backward from the final flat element. An out-of-range index, including any index into empty storage, throws Exceptions::IndexError.
Complexity: O(1).
Each accessor is O(1). Traversing the full element range is O(size()). Begin and end pairs compare equal when storage is empty.
Copy-assigns value to every element from first to last. If assignment throws, earlier elements retain their new values and later elements retain their old values.
Complexity: O(size()).
Exchanges the buffer, shape, and strides in constant time. Pointers, references, and iterators remain valid but refer to elements owned by the other object after the exchange.
Complexity: O(1).
Allocates shape.elements() elements initialized from value_type{}, copies the shape, and computes its row-major strides.
Complexity: O(shape.elements() + shape.rank()).
Allocates shape.elements() copies of value, copies the shape, and computes its row-major strides.
Complexity: O(shape.elements() + shape.rank()).
Both allocating constructors may throw:
Exceptions::DimensionError for an unrepresentable element count or stridestd::bad_alloc if storage or metadata allocation failsTransfers ownership of buffer, copies the shape, computes strides, and then requires buffer.size() == shape.elements(). A mismatch throws Exceptions::ShapeError; the adopted buffer is released during unwinding.
Complexity: O(shape.rank()) plus O(1) ownership transfer.
Metadata allocation or an unrepresentable element/stride calculation can also throw before construction completes.
Converts one signed index per dimension into a row-major flat offset. Negative components count backward within their corresponding dimensions.
The index container must provide size() and indexed access. A rank mismatch throws Exceptions::IndexError using rank_mismatch_message. An invalid component also throws IndexError; when component_oob_message is non-null, that message replaces the lower-level normalization message.
Complexity: O(rank()).
ArrayBase uses compiler-generated copy and move operations:
Buffer's strong exception guarantee for each member assignment, but the compiler-generated member-by-member operation is not transactional across all three members.Concrete containers inherit these operations unless they define their own.
| Operation | Complexity |
|---|---|
| Metadata, individual access, iterator creation | O(1) |
Full traversal or fill() | O(size()) |
swap() | O(1) |
| Shape-based construction | O(elements + rank) |
| Buffer-adopting construction | O(rank) |
| Checked multidimensional offset | O(rank) |
| Copy construction | O(size + rank) |
| Move construction | O(1) |
Keeping the common flat interface in one base class gives all owning arrays the same storage and iterator semantics. Container-specific classes stay small and focus on shape restrictions and multidimensional access.
Public at() implementations use normalized_flat_offset() for checked, Python-style multidimensional indexing. Unchecked container indexing calls stratax::indexing::offset() directly with the container's stride metadata.