diff --git a/NDTensors/src/SmallVectors/README.md b/NDTensors/src/SmallVectors/README.md index b771e20e7b..71ee904af7 100644 --- a/NDTensors/src/SmallVectors/README.md +++ b/NDTensors/src/SmallVectors/README.md @@ -1,18 +1,73 @@ # SmallVectors -A module that defines small (mutable and immutable) vectors with a maximum length. Externally the have a dynamic (or in the case of immuatable vectors, runtime) length, but internally they are backed by a statically sized vector. This makes it so that operations can be performed faster because they can remain on the stack, but it provides some more convenience compared to StaticArrays.jl where the length is encoded in the type. +## Introduction + +A module that defines small (mutable and immutable) vectors with a maximum length. Externally they have a dynamic/runtime length, but internally they are backed by a statically sized vector. This makes it so that operations can be performed faster because they can remain on the stack, but it provides some more convenience compared to StaticArrays.jl where the length is encoded in the type. + +## Examples For example: ```julia using NDTensors.SmallVectors -v = SmallVector{10}([1, 2, 3]) # Immutable vector with length 3, maximum length 10 -v = push(v, 4) -v = setindex(v, 4, 4) -v = sort(v; rev=true) mv = MSmallVector{10}([1, 2, 3]) # Mutable vector with length 3, maximum length 10 push!(mv, 4) mv[2] = 12 sort!(mv; rev=true) + +v = SmallVector{10}([1, 2, 3]) # Immutable vector with length 3, maximum length 10 +v = SmallVectors.push(v, 4) +v = SmallVectors.setindex(v, 12, 2) +v = SmallVectors.sort(v; rev=true) ``` This also has the advantage that you can efficiently store collections of `SmallVector`/`MSmallVector` that have different runtime lengths, as long as they have the same maximum length. + +## List of functionality + +`SmallVector` and `MSmallVector` are subtypes of `AbstractVector` and therefore can be used in `Base` `AbstractVector` functions, though `SmallVector` will fail for mutating functions like `setindex!` because it is immutable. + +`MSmallVector` has specialized implementations of `Base` functions that involve resizing such as: +- `resize!` +- `push!` +- `pushfirst!` +- `pop!` +- `popfirst!` +- `append!` +- `prepend!` +- `insert!` +- `deleteat!` +which are guaranteed to not realocate memory, and instead just use the memory buffer that already exists, unlike Base's `Vector` which may have to reallocate memory depending on the operation. However, they will error if they involve operations that resize beyond the maximum length of the `MSmallVector`, which you can access with `SmallVectors.maxlength(v)`. + +In addition, `SmallVector` and `MSmallVector` implement basic non-mutating operations such as: +- `SmallVectors.setindex` +, non-mutating resizing operations: +- `SmallVector.resize` +- `SmallVector.push` +- `SmallVector.pushfirst` +- `SmallVector.pop` +- `SmallVector.popfirst` +- `SmallVector.append` +- `SmallVector.prepend` +- `SmallVector.insert` +- `SmallVector.deleteat` +which output a new vector. In addition, it implements: +- `SmallVectors.circshift` +- `sort` (overloaded from `Base`). + +Finally, it provides some new helpful functions that are not in `Base`: +- `SmallVectors.insertsorted[!]` +- `SmallVectors.insertsortedunique[!]` +- `SmallVectors.mergesorted[!]` +- `SmallVectors.mergesortedunique[!]` + +## TODO + +Add specialized overloads for: +- `splice[!]` +- `union[!]` (`∪`) +- `intersect[!]` (`∩`) +- `setdiff[!]` +- `symdiff[!]` +- `unique[!]` + +Please let us know if there are other operations that would warrant specialized implmentations for `AbstractSmallVector`. diff --git a/NDTensors/src/SmallVectors/src/abstractsmallvector/deque.jl b/NDTensors/src/SmallVectors/src/abstractsmallvector/deque.jl index 5dd872cc73..f4a276b96e 100644 --- a/NDTensors/src/SmallVectors/src/abstractsmallvector/deque.jl +++ b/NDTensors/src/SmallVectors/src/abstractsmallvector/deque.jl @@ -1,9 +1,10 @@ -# TODO: Set operations -# union, ∪, union! -# intersect, ∩, intersect! -# setdiff, setdiff! -# symdiff, symdiff! -# unique, unique! +# TODO: add +# splice[!] +# union[!] (∪) +# intersect[!] (∩) +# setdiff[!] +# symdiff[!] +# unique[!] Base.resize!(vec::AbstractSmallVector, len) = throw(NotImplemented()) @@ -281,8 +282,3 @@ function Base.vcat(vec1::AbstractSmallVector, vec2::AbstractVector) append!(mvec1, vec2) return convert(similar_type(vec1), mvec1) end - -# TODO: inline when defined. -function Base.splice!(a::AbstractSmallVector, args...) - return throw(NotImplemented()) -end diff --git a/NDTensors/src/SmallVectors/test/runtests.jl b/NDTensors/src/SmallVectors/test/runtests.jl index f8068aa101..9455c09bf3 100644 --- a/NDTensors/src/SmallVectors/test/runtests.jl +++ b/NDTensors/src/SmallVectors/test/runtests.jl @@ -1,7 +1,28 @@ using NDTensors.SmallVectors -using StaticArrays using Test +using NDTensors.SmallVectors: + setindex, + resize, + push, + pushfirst, + pop, + popfirst, + append, + prepend, + insert, + deleteat, + circshift, + insertsorted, + insertsorted!, + insertsortedunique, + insertsortedunique!, + mergesorted, + mergesorted!, + mergesortedunique, + mergesortedunique! + + function test_smallvectors() x = SmallVector{10}([1, 3, 5]) mx = MSmallVector(x) @@ -32,9 +53,8 @@ function test_smallvectors() f!, f, ans, args, f!_impl_broken, f!_noalloc_broken, f_impl_broken, f_noalloc_broken ) in [ (:push!, :push, [1, 3, 5, item], (item,), no_broken...), - (:append!, :(SmallVectors.append), [1, 3, 5, item], ([item],), no_broken...), - (:prepend!, :(SmallVectors.prepend), [item, 1, 3, 5], ([item],), no_broken...), - # (:splice!, :(SmallVectors.splice), [1, item, 3], (2, [item],), true, true, true, true), # Not implemented + (:append!, :append, [1, 3, 5, item], ([item],), no_broken...), + (:prepend!, :prepend, [item, 1, 3, 5], ([item],), no_broken...), (:pushfirst!, :pushfirst, [item, 1, 3, 5], (item,), no_broken...), (:setindex!, :setindex, [1, item, 5], (item, 2), no_broken...), (:pop!, :pop, [1, 3], (), no_broken...), @@ -44,43 +64,43 @@ function test_smallvectors() (:circshift!, :circshift, [5, 1, 3], (1,), no_broken...), (:sort!, :sort, [1, 3, 5], (), no_broken...), ( - :(SmallVectors.insertsorted!), - :(SmallVectors.insertsorted), + :insertsorted!, + :insertsorted, [1, 2, 3, 5], (2,), no_broken..., ), ( - :(SmallVectors.insertsorted!), - :(SmallVectors.insertsorted), + :insertsorted!, + :insertsorted, [1, 3, 3, 5], (3,), no_broken..., ), ( - :(SmallVectors.insertsortedunique!), - :(SmallVectors.insertsortedunique), + :insertsortedunique!, + :insertsortedunique, [1, 2, 3, 5], (2,), no_broken..., ), ( - :(SmallVectors.insertsortedunique!), - :(SmallVectors.insertsortedunique), + :insertsortedunique!, + :insertsortedunique, [1, 3, 5], (3,), no_broken..., ), ( - :(SmallVectors.mergesorted!), - :(SmallVectors.mergesorted), + :mergesorted!, + :mergesorted, [1, 2, 3, 3, 5], ([2, 3],), no_broken..., ), ( - :(SmallVectors.mergesortedunique!), - :(SmallVectors.mergesortedunique), + :mergesortedunique!, + :mergesortedunique, [1, 2, 3, 5], ([2, 3],), no_broken...,