From 71aeed27a224454630ef4a0044207476b1f83ab2 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Fri, 19 Jan 2024 22:11:19 -0400 Subject: [PATCH] Fix doctests --- docs/src/advanced.md | 97 +++++++++++++++----------------------------- docs/src/index.md | 70 ++++++++------------------------ src/utils.jl | 4 +- 3 files changed, 53 insertions(+), 118 deletions(-) diff --git a/docs/src/advanced.md b/docs/src/advanced.md index 8f70caac..b529fb99 100644 --- a/docs/src/advanced.md +++ b/docs/src/advanced.md @@ -6,89 +6,56 @@ StructArrays support structures with custom data layout. The user is required to Here is an example of a type `MyType` that has as custom fields either its field `data` or fields of its field `rest` (which is a named tuple): -```jldoctest advanced1 -julia> using StructArrays +```@repl advanced1 +using StructArrays -julia> struct MyType{T, NT<:NamedTuple} - data::T - rest::NT - end +struct MyType{T, NT<:NamedTuple} + data::T + rest::NT +end -julia> MyType(x; kwargs...) = MyType(x, values(kwargs)) -MyType +MyType(x; kwargs...) = MyType(x, values(kwargs)) ``` Let's create a small array of these objects: -```jldoctest advanced1 -julia> s = [MyType(i/5, a=6-i, b=2) for i in 1:5] -5-element Vector{MyType{Float64, NamedTuple{(:a, :b), Tuple{Int64, Int64}}}}: - MyType{Float64, NamedTuple{(:a, :b), Tuple{Int64, Int64}}}(0.2, (a = 5, b = 2)) - MyType{Float64, NamedTuple{(:a, :b), Tuple{Int64, Int64}}}(0.4, (a = 4, b = 2)) - MyType{Float64, NamedTuple{(:a, :b), Tuple{Int64, Int64}}}(0.6, (a = 3, b = 2)) - MyType{Float64, NamedTuple{(:a, :b), Tuple{Int64, Int64}}}(0.8, (a = 2, b = 2)) - MyType{Float64, NamedTuple{(:a, :b), Tuple{Int64, Int64}}}(1.0, (a = 1, b = 2)) +```@repl advanced1 +s = [MyType(i/5, a=6-i, b=2) for i in 1:5] ``` The default `StructArray` does not unpack the `NamedTuple`: -```jldoctest advanced1 -julia> sa = StructArray(s); - -julia> sa.rest -5-element Vector{NamedTuple{(:a, :b), Tuple{Int64, Int64}}}: - (a = 5, b = 2) - (a = 4, b = 2) - (a = 3, b = 2) - (a = 2, b = 2) - (a = 1, b = 2) - -julia> sa.a -ERROR: type NamedTuple has no field a -Stacktrace: - [1] component -[...] +```@repl advanced1 +sa = StructArray(s); +sa.rest +sa.a ``` Suppose we wish to give the keywords their own fields. We can define custom `staticschema`, `component`, and `createinstance` methods for `MyType`: -```jldoctest advanced1 -julia> function StructArrays.staticschema(::Type{MyType{T, NamedTuple{names, types}}}) where {T, names, types} - # Define the desired names and eltypes of the "fields" - return NamedTuple{(:data, names...), Base.tuple_type_cons(T, types)} - end; - -julia> function StructArrays.component(m::MyType, key::Symbol) - # Define a component-extractor - return key === :data ? getfield(m, 1) : getfield(getfield(m, 2), key) - end; - -julia> function StructArrays.createinstance(::Type{MyType{T, NT}}, x, args...) where {T, NT} - # Generate an instance of MyType from components - return MyType(x, NT(args)) - end; +```@repl advanced1 +function StructArrays.staticschema(::Type{MyType{T, NamedTuple{names, types}}}) where {T, names, types} + # Define the desired names and eltypes of the "fields" + return NamedTuple{(:data, names...), Base.tuple_type_cons(T, types)} +end; + +function StructArrays.component(m::MyType, key::Symbol) + # Define a component-extractor + return key === :data ? getfield(m, 1) : getfield(getfield(m, 2), key) +end; + +function StructArrays.createinstance(::Type{MyType{T, NT}}, x, args...) where {T, NT} + # Generate an instance of MyType from components + return MyType(x, NT(args)) +end; ``` and now: -```jldoctest advanced1 -julia> sa = StructArray(s); - -julia> sa.a -5-element Vector{Int64}: - 5 - 4 - 3 - 2 - 1 - -julia> sa.b -5-element Vector{Int64}: - 2 - 2 - 2 - 2 - 2 +```@repl advanced1 +sa = StructArray(s); +sa.a +sa.b ``` The above strategy has been tested and implemented in [GeometryBasics.jl](https://github.com/JuliaGeometry/GeometryBasics.jl). diff --git a/docs/src/index.md b/docs/src/index.md index df7caa65..73dfed5c 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -9,73 +9,39 @@ The package was largely inspired by the `Columns` type in [IndexedTables](https: ## Collection and initialization One can create a `StructArray` by providing the struct type and a tuple or NamedTuple of field arrays: -```jldoctest intro -julia> using StructArrays - -julia> struct Foo{T} - a::T - b::T - end - -julia> adata = [1 2; 3 4]; bdata = [10 20; 30 40]; - -julia> x = StructArray{Foo}((adata, bdata)) -2×2 StructArray(::Matrix{Int64}, ::Matrix{Int64}) with eltype Foo: - Foo{Int64}(1, 10) Foo{Int64}(2, 20) - Foo{Int64}(3, 30) Foo{Int64}(4, 40) +```@repl intro +using StructArrays +struct Foo{T} + a::T + b::T +end +adata = [1 2; 3 4]; bdata = [10 20; 30 40]; +x = StructArray{Foo}((adata, bdata)) ``` You can also initialze a StructArray by passing in a NamedTuple, in which case the name (rather than the order) specifies how the input arrays are assigned to fields: -```jldoctest intro -julia> x = StructArray{Foo}((b = adata, a = bdata)) # initialize a with bdata and vice versa -2×2 StructArray(::Matrix{Int64}, ::Matrix{Int64}) with eltype Foo: - Foo{Int64}(10, 1) Foo{Int64}(20, 2) - Foo{Int64}(30, 3) Foo{Int64}(40, 4) +```@repl intro +x = StructArray{Foo}((b = adata, a = bdata)) # initialize a with bdata and vice versa ``` If a struct is not specified, a StructArray with Tuple or NamedTuple elements will be created: -```jldoctest intro -julia> x = StructArray((adata, bdata)) -2×2 StructArray(::Matrix{Int64}, ::Matrix{Int64}) with eltype Tuple{Int64, Int64}: - (1, 10) (2, 20) - (3, 30) (4, 40) - -julia> x = StructArray((a = adata, b = bdata)) -2×2 StructArray(::Matrix{Int64}, ::Matrix{Int64}) with eltype NamedTuple{(:a, :b), Tuple{Int64, Int64}}: - (a = 1, b = 10) (a = 2, b = 20) - (a = 3, b = 30) (a = 4, b = 40) +```@repl intro +x = StructArray((adata, bdata)) +x = StructArray((a = adata, b = bdata)) ``` It's also possible to create a `StructArray` by choosing a particular dimension to interpret as the components of a struct: -```jldoctest intro -julia> x = StructArray{Complex{Int}}(adata; dims=1) # along dimension 1, the first item `re` and the second is `im` -2-element StructArray(view(::Matrix{Int64}, 1, :), view(::Matrix{Int64}, 2, :)) with eltype Complex{Int64}: - 1 + 3im - 2 + 4im - -julia> x = StructArray{Complex{Int}}(adata; dims=2) # along dimension 2, the first item `re` and the second is `im` -2-element StructArray(view(::Matrix{Int64}, :, 1), view(::Matrix{Int64}, :, 2)) with eltype Complex{Int64}: - 1 + 2im - 3 + 4im +```@repl intro +x = StructArray{Complex{Int}}(adata; dims=1) # along dimension 1, the first item `re` and the second is `im` +x = StructArray{Complex{Int}}(adata; dims=2) # along dimension 2, the first item `re` and the second is `im` ``` One can also create a `StructArray` from an iterable of structs without creating an intermediate `Array`: -```jldoctest intro -julia> StructArray(log(j+2.0*im) for j in 1:10) -10-element StructArray(::Vector{Float64}, ::Vector{Float64}) with eltype ComplexF64: - 0.8047189562170501 + 1.1071487177940904im - 1.0397207708399179 + 0.7853981633974483im - 1.2824746787307684 + 0.5880026035475675im - 1.4978661367769954 + 0.4636476090008061im - 1.683647914993237 + 0.3805063771123649im - 1.8444397270569681 + 0.3217505543966422im - 1.985145956776061 + 0.27829965900511133im - 2.1097538525880535 + 0.24497866312686414im - 2.2213256282451583 + 0.21866894587394195im - 2.3221954495706862 + 0.19739555984988078im +```@repl intro +StructArray(log(j+2.0*im) for j in 1:10) ``` Another option is to create an uninitialized `StructArray` and then fill it with data. Just like in normal arrays, this is done with the `undef` syntax: diff --git a/src/utils.jl b/src/utils.jl index c4874d72..328fb897 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -145,8 +145,10 @@ julia> s_pooled = StructArrays.replace_storage(s) do v end $(if VERSION < v"1.6-" "3-element StructArray(::UnitRange{Int64}, ::PooledArray{String,UInt32,1,Array{UInt32,1}}) with eltype NamedTuple{(:a, :b),Tuple{Int64,String}}:" +elseif VERSION < v"1.10-" + "3-element StructArray(::UnitRange{Int64}, ::PooledVector{String, UInt32, Vector{UInt32}}) with eltype NamedTuple{(:a, :b), Tuple{Int64, String}}:" else - "3-element StructArray(::UnitRange{Int64}, ::PooledVector{String, UInt32, Vector{UInt32}}) with eltype NamedTuple{(:a, :b), Tuple{Int64, String}}:" + "3-element StructArray(::UnitRange{Int64}, ::PooledVector{String, UInt32, Vector{UInt32}}) with eltype @NamedTuple{a::Int64, b::String}:" end) (a = 1, b = "string") (a = 2, b = "string")