Skip to content

Commit 4483b57

Browse files
author
Pietro Vertechi
authored
Merge pull request #121 from JuliaArrays/pv/static
foreachfield and staticschema cleanup
2 parents 3b5d1d3 + d9c40f8 commit 4483b57

File tree

6 files changed

+39
-38
lines changed

6 files changed

+39
-38
lines changed

src/StructArrays.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
module StructArrays
22

33
using Base: tuple_type_cons, tuple_type_head, tuple_type_tail, tail
4-
using Tables: getcolumn, Tables
54

65
export StructArray, StructVector, LazyRow, LazyRows
76
export collect_structarray, fieldarrays

src/lazy.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ Base.getproperty(s::LazyRows, key::Symbol) = getproperty(parent(s), key)
4040
Base.getproperty(s::LazyRows, key::Int) = getproperty(parent(s), key)
4141
Base.propertynames(c::LazyRows) = propertynames(parent(c))
4242

43-
staticschema(::Type{LazyRows{T, N, C, I}}) where {T, N, C, I} = staticschema(StructArray{T, N, C, I})
44-
4543
Base.size(v::LazyRows) = size(parent(v))
4644
Base.getindex(v::LazyRows{<:Any, <:Any, <:Any, Int}, i::Int) = LazyRow(parent(v), i)
4745
Base.getindex(v::LazyRows{<:Any, <:Any, <:Any, CartesianIndex{N}}, i::Vararg{Int, N}) where {N} = LazyRow(parent(v), CartesianIndex(i))

src/structarray.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ fieldarrays(s::StructArray) = getfield(s, :fieldarrays)
126126
Base.getproperty(s::StructArray, key::Symbol) = getfield(fieldarrays(s), key)
127127
Base.getproperty(s::StructArray, key::Int) = getfield(fieldarrays(s), key)
128128
Base.propertynames(s::StructArray) = propertynames(fieldarrays(s))
129-
staticschema(::Type{<:StructArray{T}}) where {T} = staticschema(T)
130129

131130
Base.size(s::StructArray) = size(fieldarrays(s)[1])
132131
Base.size(s::StructArray{<:Any, <:Any, <:EmptyTup}) = (0,)

src/tables.jl

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,32 @@
1+
import Tables
2+
13
Tables.isrowtable(::Type{<:StructArray}) = true
24

35
Tables.columnaccess(::Type{<:StructArray}) = true
46
Tables.columns(s::StructArray) = fieldarrays(s)
5-
Tables.getcolumn(s::StructArray, i::Int) = getproperty(s, i)
6-
Tables.schema(s::StructArray) = Tables.Schema(staticschema(eltype(s)))
7+
Tables.schema(s::StructArray) = _schema(staticschema(eltype(s)))
8+
9+
_schema(::Type{NT}) where {NT<:NamedTuple} = Tables.Schema(NT)
10+
# make schema for unnamed case
11+
function _schema(::Type{T}) where {T<:NTuple{N, Any}} where N
12+
return Tables.Schema{ntuple(identity, N), T}
13+
end
14+
15+
function try_compatible_columns(rows::R, s::StructArray) where {R}
16+
Tables.isrowtable(rows) && Tables.columnaccess(rows) || return nothing
17+
T = eltype(rows)
18+
hasfields(T) || return nothing
19+
NT = staticschema(T)
20+
_schema(NT) == Tables.schema(rows) || return nothing
21+
table = Tables.columns(rows)
22+
fieldnames(NT) == propertynames(table) ? table : nothing
23+
end
724

825
function Base.append!(s::StructVector, rows)
9-
if Tables.isrowtable(rows) && Tables.columnaccess(rows)
26+
table = try_compatible_columns(rows, s)
27+
if table !== nothing
1028
# Input `rows` is a container of rows _and_ satisfies column
1129
# table interface. Thus, we can add the input column-by-column.
12-
table = Tables.columns(rows)
13-
isempty(_setdiff(propertynames(s), Tables.columnnames(rows))) ||
14-
_invalid_columns_error(s, rows)
1530
foreachfield(append!, s, table)
1631
return s
1732
else
@@ -20,12 +35,3 @@ function Base.append!(s::StructVector, rows)
2035
return foldl(push!, rows; init = s)
2136
end
2237
end
23-
24-
@noinline function _invalid_columns_error(s, rows)
25-
missingnames = setdiff!(collect(Tables.columnnames(rows)), propertynames(s))
26-
throw(ArgumentError(string(
27-
"Cannot append rows from `$(typeof(rows))` to `$(typeof(s))` due to ",
28-
"missing column(s):\n",
29-
join(missingnames, ", "),
30-
)))
31-
end

src/utils.jl

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ function buildfromschema(initializer, ::Type{T}, ::Type{NT}) where {T, NT<:Tup}
2121
StructArray{T}(nt)
2222
end
2323

24+
@static if VERSION < v"1.2.0"
25+
@inline _getproperty(v::Tuple, field) = getfield(v, field)
26+
@inline _getproperty(v, field) = getproperty(v, field)
27+
else
28+
const _getproperty = getproperty
29+
end
30+
2431
function _foreachfield(names, L)
2532
vars = ntuple(i -> gensym(), L)
2633
exprs = Expr[]
@@ -29,19 +36,19 @@ function _foreachfield(names, L)
2936
end
3037
for field in names
3138
sym = QuoteNode(field)
32-
args = [Expr(:call, :getcolumn, var, sym) for var in vars]
39+
args = [Expr(:call, :_getproperty, var, sym) for var in vars]
3340
push!(exprs, Expr(:call, :f, args...))
3441
end
3542
push!(exprs, :(return nothing))
3643
return Expr(:block, exprs...)
3744
end
3845

39-
@generated foreachfield(::Type{<:NamedTuple{names}}, f, xs::Vararg{Any, L}) where {names, L} =
46+
@generated foreachfield_gen(::NamedTuple{names}, f, xs::Vararg{Any, L}) where {names, L} =
4047
_foreachfield(names, L)
41-
@generated foreachfield(::Type{<:NTuple{N, Any}}, f, xs::Vararg{Any, L}) where {N, L} =
48+
@generated foreachfield_gen(::NTuple{N, Any}, f, xs::Vararg{Any, L}) where {N, L} =
4249
_foreachfield(Base.OneTo(N), L)
4350

44-
foreachfield(f, x::T, xs...) where {T} = foreachfield(staticschema(T), f, x, xs...)
51+
foreachfield(f, x::StructArray, xs...) = foreachfield_gen(fieldarrays(x), f, x, xs...)
4552

4653
"""
4754
`iscompatible(::Type{S}, ::Type{V}) where {S, V<:AbstractArray}`
@@ -126,11 +133,3 @@ hasfields(::Type{<:NTuple{N, Any}}) where {N} = true
126133
hasfields(::Type{<:NamedTuple{names}}) where {names} = true
127134
hasfields(::Type{T}) where {T} = !isabstracttype(T)
128135
hasfields(::Union) = false
129-
130-
_setdiff(a, b) = setdiff(a, b)
131-
132-
@inline _setdiff(::Tuple{}, ::Tuple{}) = ()
133-
@inline _setdiff(::Tuple{}, ::Tuple) = ()
134-
@inline _setdiff(a::Tuple, ::Tuple{}) = a
135-
@inline _setdiff(a::Tuple, b::Tuple) = _setdiff(_exclude(a, b[1]), Base.tail(b))
136-
@inline _exclude(a, b) = foldl((ys, x) -> x == b ? ys : (ys..., x), a; init = ())

test/runtests.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ end
2424

2525
@testset "utils" begin
2626
t = StructArray(rand(ComplexF64, 2, 2))
27-
T = staticschema(typeof(t))
27+
T = staticschema(eltype(t))
2828
@test StructArrays.eltypes(T) == NamedTuple{(:re, :im), Tuple{Float64, Float64}}
2929
@test StructArrays.map_params(eltype, T) == NamedTuple{(:re, :im), Tuple{Float64, Float64}}
3030
@test StructArrays.map_params(eltype, StructArrays.astuple(T)) == Tuple{Float64, Float64}
@@ -336,10 +336,10 @@ end
336336
@test Tables.rowaccess(typeof(s))
337337
@test Tables.columnaccess(s)
338338
@test Tables.columnaccess(typeof(s))
339-
@test Tables.getcolumn(s, 1) == [1]
340-
@test Tables.getcolumn(s, :a) == [1]
341-
@test Tables.getcolumn(s, 2) == ["test"]
342-
@test Tables.getcolumn(s, :b) == ["test"]
339+
@test Tables.getcolumn(Tables.columns(s), 1) == [1]
340+
@test Tables.getcolumn(Tables.columns(s), :a) == [1]
341+
@test Tables.getcolumn(Tables.columns(s), 2) == ["test"]
342+
@test Tables.getcolumn(Tables.columns(s), :b) == ["test"]
343343
@test append!(StructArray([1im]), [(re = 111, im = 222)]) ==
344344
StructArray([1im, 111 + 222im])
345345
@test append!(StructArray([1im]), (x for x in [(re = 111, im = 222)])) ==
@@ -579,7 +579,7 @@ end
579579
rows = LazyRows(s)
580580
@test propertynames(rows) == (:re, :im)
581581
@test propertynames(rows[1]) == (:re, :im)
582-
@test staticschema(typeof(rows)) == staticschema(eltype(rows)) == staticschema(ComplexF64)
582+
@test staticschema(eltype(rows)) == staticschema(ComplexF64)
583583
@test getproperty(rows, 1) isa Matrix{Float64}
584584
@test getproperty(rows, :re) isa Matrix{Float64}
585585
@test IndexStyle(rows) isa IndexCartesian
@@ -593,7 +593,7 @@ end
593593
rows = LazyRows(s)
594594
@test propertynames(rows) == (:re, :im)
595595
@test propertynames(rows[1]) == (:re, :im)
596-
@test staticschema(typeof(rows)) == staticschema(eltype(rows)) == staticschema(ComplexF64)
596+
@test staticschema(eltype(rows)) == staticschema(ComplexF64)
597597
@test getproperty(rows, 1) isa Matrix{Float64}
598598
@test getproperty(rows, :re) isa Matrix{Float64}
599599
@test IndexStyle(rows) isa IndexLinear

0 commit comments

Comments
 (0)