Skip to content

Commit 15f315c

Browse files
committed
combine examples
1 parent f60fb83 commit 15f315c

File tree

1 file changed

+45
-77
lines changed

1 file changed

+45
-77
lines changed

README.md

Lines changed: 45 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -186,34 +186,68 @@ StructArrays support structures with non-standard data layout (where `getpropert
186186

187187
```julia
188188
using StructArrays
189-
struct MyType{NT<:NamedTuple}
190-
data::Float64
189+
190+
struct MyType{T, NT<:NamedTuple}
191+
data::T
191192
rest::NT
192193
end
193194

194195
MyType(x; kwargs...) = MyType(x, values(kwargs))
195196

196197
Base.getproperty(b::MyType, s::Symbol) = s == :data ? getfield(b, 1) : getproperty(getfield(b, 2), s)
197-
198-
getnamestypes(::Type{NamedTuple{names, types}}) where {names, types} = (names, types)
199-
getnamestypes(::Type{MyType{NT}}) where NT = getnamestypes(NT)
198+
Base.propertynames(b::MyType) = (:data, propertynames(getfield(b, 2))...)
200199

201200
# explicitly give the "schema" of the object to StructArrays
202-
function StructArrays.staticschema(::Type{T}) where {T<:MyType}
203-
names, types = getnamestypes(T)
204-
NamedTuple{(:data, names...), Base.tuple_type_cons(Float64, types)}
201+
function StructArrays.staticschema(::Type{MyType{T, NamedTuple{names, types}}}) where {T, names, types}
202+
NamedTuple{(:data, names...), Base.tuple_type_cons(T, types)}
205203
end
206204

207205
# generate an instance of MyType type
208-
function StructArrays.createinstance(::Type{T}, x, args...) where {T<:MyType}
209-
names, types = getnamestypes(T)
210-
MyType(x, NamedTuple{names, types}(args))
206+
function StructArrays.createinstance(::Type{MyType{T, NT}}, x, args...) where {T, NT}
207+
MyType(x, NT(args))
211208
end
212209

213210
s = [MyType(rand(), a=1, b=2) for i in 1:10]
214211
StructArray(s)
215212
```
216213

214+
In the above example, our `MyType` was composed of `data` of type `Float64` and `rest` of type `NamedTuple`. In many practical cases where there are custom types involved it's hard for StructArrays to automatically widen the types in case they are heterogeneous. The following example demonstrates a widening method in that scenario.
215+
216+
```julia
217+
using Tables
218+
219+
# add a source of custom type data
220+
struct Location{U}
221+
x::U
222+
y::U
223+
end
224+
struct Region{V}
225+
area::V
226+
end
227+
228+
s1 = MyType(Location(1, 0), (place = "Delhi"))
229+
s2 = MyType(Location(2.5, 1.9), (place = "Mumbai"))
230+
s3 = MyType(Region([Location(1, 0), Location(2.5, 1.9)]), (place = "North India"))
231+
232+
s = [s1, s2, s3]
233+
# Now if we try to do StructArray(s)
234+
# we will get an error
235+
236+
function meta_table(iter)
237+
cols = Tables.columntable(iter)
238+
meta_table(first(cols), Base.tail(cols))
239+
end
240+
241+
function meta_table(data, rest::NT) where NT<:NamedTuple
242+
F = MyType{eltype(data), StructArrays.eltypes(NT)}
243+
return StructArray{F}(; data=data, rest...)
244+
end
245+
246+
meta_table(s)
247+
```
248+
249+
The above strategy has been tested and implemented in [GeometryBasics.jl](https://github.com/JuliaGeometry/GeometryBasics.jl).
250+
217251
## Advanced: mutate-or-widen style accumulation
218252

219253
StructArrays provides a function `StructArrays.append!!(dest, src)` (unexported) for "mutate-or-widen" style accumulation. This function can be used via [`BangBang.append!!`](https://juliafolds.github.io/BangBang.jl/dev/#BangBang.append!!) and [`BangBang.push!!`](https://juliafolds.github.io/BangBang.jl/dev/#BangBang.push!!) as well.
@@ -305,69 +339,3 @@ julia> s
305339
Foo(44, "d")
306340
Foo(55, "e")
307341
```
308-
309-
In the above example "for structures with non-standard data layout" our `MyType` was composed of `data` of type `Float64` and `rest` of type `NamedTuple`. In many practical cases where there are custom types involved it's hard for StructArrays to automatically widen the types in case they are heterogeneous. The following example demonstrates a widening method in that scenario.
310-
311-
```julia
312-
struct MyType1{T, Names, Types}
313-
data::T
314-
rest::NamedTuple{Names, Types}
315-
end
316-
317-
MyType1(x; kwargs...) = MyType1(x, values(kwargs))
318-
319-
# and a source of custom type data
320-
struct location{U}
321-
x::U
322-
y::U
323-
end
324-
struct region{G<:Array{location}}
325-
area::G
326-
end
327-
328-
function Base.getproperty(x::MyType1, field::Symbol)
329-
if field == :data
330-
getfield(x, :data)
331-
elseif field == :rest
332-
getfield(x, :rest)
333-
else
334-
getproperty(getfield(x, :rest), field)
335-
end
336-
end
337-
338-
getnamestypes(::Type{MyType1{T, Names, Types}}) where {T, Names, Types} = (T, Names, Types)
339-
340-
# explicitly give the "schema" of the object to StructArrays
341-
function StructArrays.staticschema(::Type{T}) where {T<:MyType1}
342-
K, names, types = getnamestypes(T)
343-
NamedTuple{(:data, names...), Base.tuple_type_cons(K, types)}
344-
end
345-
346-
# generate an instance of MyType type
347-
function StructArrays.createinstance(::Type{T}, x, args...) where {T<:MyType1}
348-
K, names, types = getnamestypes(T)
349-
MyType1(x, NamedTuple{names, types}(args))
350-
end
351-
352-
s1 = MyType1(location(1, 0), (place = "Delhi"))
353-
s2 = MyType1(location(2.5, 1.9), (place = "Mumbai"))
354-
s3 = MyType1(region([location(1, 0), location(2.5, 1.9)]), (place = "North India"))
355-
356-
s = [s1, s2, s3]
357-
# Now if we try to do StructArray(s)
358-
# we will get an error
359-
360-
function meta_table(iter)
361-
cols = Tables.columntable(iter)
362-
meta_table(first(cols), Base.tail(cols))
363-
end
364-
365-
function meta_table(data, rest::NamedTuple{names, types}) where {names, types}
366-
F = MyType1{eltype(data), names, StructArrays.eltypes(types)}
367-
return StructArray{F}(; data=data, rest...)
368-
end
369-
370-
meta_table(s)
371-
```
372-
373-
The above example has been tested and implemented in [GeometryBasics.jl](https://github.com/JuliaGeometry/GeometryBasics.jl).

0 commit comments

Comments
 (0)