Skip to content

Commit 6567009

Browse files
authored
support ConstructionBase: constructorof and setproperties (#319)
1 parent dd01296 commit 6567009

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

src/StructArrays.jl

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ include("utils.jl")
1313
include("collect.jl")
1414
include("sort.jl")
1515
include("lazy.jl")
16+
include("constructionbase.jl")
1617
include("tables.jl")
1718

1819
# Implement refarray and refvalue to deal with pooled arrays and weakrefstrings effectively

src/constructionbase.jl

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using ConstructionBase
2+
3+
# (named)tuple eltypes: components/fields are all that's needed for the StructArray() constructor
4+
ConstructionBase.constructorof(::Type{<:StructArray{<:Union{Tuple, NamedTuple}}}) = StructArray
5+
6+
# other eltypes: need to pass eltype to the constructor in addition to components
7+
ConstructionBase.constructorof(::Type{<:StructArray{T}}) where {T} = function(comps::CT) where {CT}
8+
# the resulting eltype is like T, but potentially with different type parameters, eg Complex{Int} -> Complex{Float64}
9+
# probe its constructorof to get the right concrete type
10+
ET = Base.promote_op(constructorof(T), map(eltype, fieldtypes(CT))...)
11+
StructArray{ET}(comps)
12+
end
13+
14+
# two methods with the same body, required to avoid ambiguities
15+
# just redirect setproperties to constructorof
16+
ConstructionBase.setproperties(x::StructArray, patch::NamedTuple) = constructorof(typeof(x))(setproperties(getproperties(x), patch))
17+
ConstructionBase.setproperties(x::StructArray, patch::Tuple) = constructorof(typeof(x))(setproperties(getproperties(x), patch))

test/runtests.jl

+42
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ using StaticArrays
55
using TypedTables: Table
66
using DataAPI: refarray, refvalue
77
using Adapt: adapt, Adapt
8+
using ConstructionBase: constructorof, setproperties, getproperties, getfields
89
using JLArrays
910
using LinearAlgebra
1011
using Test
@@ -529,6 +530,47 @@ end
529530
@test_throws ArgumentError StructArray(a=[1, 2], b=[3])
530531
end
531532

533+
@testset "ConstructionBase" begin
534+
# first, check the required invariants
535+
@testset for obj in Any[
536+
StructArray(([1, 2, 3],)),
537+
StructArray((Int[],)),
538+
StructArray(([1, 2, 3], 4:6)),
539+
StructArray(a=[1, 2, 3]),
540+
StructArray(a=[1, 2, 3], b=4:6),
541+
StructArray([1+2im, 3+4im, 5+6im]),
542+
StructArray(ComplexF64[]),
543+
]
544+
# constructorof of getfields returns the same object
545+
@test constructorof(typeof(obj))(getfields(obj)...) === obj
546+
547+
# setproperties with getproperties, or with empty properties, returns the same object
548+
@test setproperties(obj, getproperties(obj)) === obj
549+
if getproperties(obj) isa Tuple
550+
@test setproperties(obj, ()) === obj
551+
else
552+
@test setproperties(obj, (;)) === obj
553+
end
554+
end
555+
556+
# now, check less trivial cases: reconstruction with different property types and names
557+
s = StructArray(a=[1, 2, 3])
558+
@test constructorof(typeof(s))((a=1:3,)) === StructArray(a=1:3)
559+
@test constructorof(typeof(s))((b=1.0:3.0,)) === StructArray(b=1.0:3.0)
560+
561+
s = StructArray(a=[1, 2, 3], b=4:6)
562+
@test setproperties(s, a=10:12)::StructArray === StructArray(a=10:12, b=4:6)
563+
@test_throws ArgumentError setproperties(s, ccc=10:12)
564+
565+
s = StructArray(([1, 2, 3], 4:6))
566+
@test setproperties(s, (10:12,))::StructArray === StructArray((10:12, 4:6))
567+
568+
s = StructArray([1+2im, 3+4im, 5+6im])
569+
@test constructorof(typeof(s))((re=10:0.1:10.2, im=[1,2,3]))::StructArray == StructArray{ComplexF64}((10:0.1:10.2, [1,2,3]))
570+
@test constructorof(typeof(s))((10:0.1:10.2, [1,2,3]))::StructArray == StructArray{ComplexF64}((10:0.1:10.2, [1,2,3]))
571+
@test setproperties(s, re=10:0.1:10.2)::StructArray == StructArray{ComplexF64}((10:0.1:10.2, [2,4,6]))
572+
end
573+
532574
@testset "complex" begin
533575
a, b = [1 2; 3 4], [4 5; 6 7]
534576
t = StructArray{ComplexF64}((a, b))

0 commit comments

Comments
 (0)