diff --git a/.travis.yml b/.travis.yml index 8b94205..bd06434 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,12 @@ language: julia os: - linux julia: + - 1.0 - 1.1 - nightly matrix: allow_failures: + - julia: 1.0 - julia: nightly notifications: email: false diff --git a/Project.toml b/Project.toml index 2cb6bd6..6e97f30 100644 --- a/Project.toml +++ b/Project.toml @@ -5,6 +5,7 @@ version = "0.2.2" author = ["Brandon Taylor "] [deps] +Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" IterTools = "c8e1da08-722c-5040-9ed9-7db0dc04731e" MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" @@ -24,4 +25,4 @@ Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" test = ["CSV", "Dates", "Documenter", "Statistics", "Test", "TimeZones", "Unitful"] [compat] -julia = "1.1" +julia = "1.0" diff --git a/src/LightQuery.jl b/src/LightQuery.jl index 5947205..b6056e9 100644 --- a/src/LightQuery.jl +++ b/src/LightQuery.jl @@ -2,13 +2,13 @@ module LightQuery import Base: axes, collect_similar, copyto!, eltype, empty, get, getindex, getproperty, haskey, IndexStyle, IteratorEltype, IteratorSize, isless, - LinearIndices, length, iterate, merge, NamedTuple, push!, push_widen, - startswith, size, setindex!, setindex_widen_up_to, show, similar, view, zip + LinearIndices, length, iterate, merge, NamedTuple, push!, startswith, size, + setindex!, show, similar, view, zip using Base: argument_datatype, _collect, @default_eltype, diff_names, EltypeUnknown, Generator, HasEltype, HasLength, HasShape, isvarargtype, isvatuple, @pure, promote_op, @propagate_inbounds, SizeUnknown, sym_in, tail -using Base.Iterators: Filter, flatten, product, take, Zip, _zip_iterator_eltype, - _zip_iterator_size +using Base.Iterators: Filter, flatten, product, take, Zip +using Compat: fieldcount using Core: TypeofBottom using Base.Meta: quot using IterTools: @ifsomething @@ -19,6 +19,18 @@ using Markdown: MD, Table using Tables: Schema, schema export Generator, Filter, flatten +@static if VERSION < v"1.1" + fieldtypes(T::Type) = ntuple(i -> fieldtype(T, i), fieldcount(T)) + + using Base.Iterators: Zip2 + get_columns(zipped::Zip) = zipped.a, get_columns(zipped.z)... + get_columns(zipped::Zip2) = zipped.a, zipped.b +else + import Base: push_widen, setindex_widen_up_to + + get_columns(zipped::Zip) = zipped.is +end + include("utilities.jl") include("macros.jl") include("rows.jl") @@ -26,4 +38,15 @@ include("columns.jl") include("make_columns.jl") include("pivot.jl") +@static if VERSION < v"1.1" + @inline getindex(zipped::Zip2, index...) = + partial_map(getindex_reverse, index, get_columns(zipped)) + @inline view(zipped::Zip2, index...) = + zip(partial_map(view_reverse, index, get_columns(zipped))...) + state_to_index(zipped::Zip2, state) = + state_to_index(first(get_columns(zipped)), first(state)) + to_columns(rows::Generator{<: Zip2, <: Some{Name}}) = + rows.f(get_columns(rows.iter)) +end + end diff --git a/src/make_columns.jl b/src/make_columns.jl index 364539a..21ef525 100644 --- a/src/make_columns.jl +++ b/src/make_columns.jl @@ -24,11 +24,6 @@ end to_columns(rows::Rows) = map(tuple, rows.names, rows.columns) -@inline IteratorEltype(::Type{Rows{Row, Dimensions, Columns}}) where {Row, Dimensions, Columns} = - _zip_iterator_eltype(Columns) -@inline IteratorSize(::Type{Rows{Row, Dimensions, Columns}}) where {Row, Dimensions, Columns} = - _zip_iterator_size(Columns) - axes(rows::Rows, dimensions...) = axes(first(rows.columns), dimensions...) size(rows::Rows, dimensions...) = @@ -58,20 +53,20 @@ push_at!(columns, (name, value)) = end push!(rows::Rows, row) = partial_map(push_at!, to_columns(rows), row) -similar_at((model, dimensions), ::Val{AType}) where {AType} = - fieldtype(AType, 1)(), similar(model, fieldtype(AType, 2), dimensions) +similar_named((model, dimensions), ::Val{Tuple{Name{name}, Value}}) where {name, Value} = + Name{name}(), similar(model, Value, dimensions) similar(rows::Rows{Tuple{}}, ::Type{Row}, dimensions::Dims) where Row = Rows(partial_map( - similar_at, + similar_named, (1:1, 0), - val_fieldtypes(Row) + val_fieldtypes_or_empty(Row) )) similar(rows::Rows, ::Type{Row}, dimensions::Dims) where Row = Rows(partial_map( - similar_at, + similar_named, (first(rows.columns), dimensions), - val_fieldtypes(Row) + val_fieldtypes_or_empty(Row) )) empty(column::Rows{OldRow}, ::Type{NewRow} = OldRow) where {OldRow, NewRow} = @@ -149,3 +144,64 @@ make_columns(rows) = to_columns(_collect( IteratorSize(rows) )) export make_columns + +@static if VERSION < v"1.1" + # backport #30076 just for Rows + import Base: collect_to!, grow_to! + using Base: promote_typejoin + + function collect_to!(dest::Rows{T}, itr, offs, st) where T + # collect to dest array, checking the type of each result. if a result does not + # match, widen the result type and re-dispatch. + i = offs + while true + y = iterate(itr, st) + y === nothing && break + el, st = y + if el isa T || typeof(el) === T + @inbounds dest[i] = el::T + i += 1 + else + new = setindex_widen_up_to(dest, el, i) + return collect_to!(new, itr, i+1, st) + end + end + return dest + end + + @inline function setindex_widen_up_to(dest::AbstractArray{T}, el, i) where T + new = similar(dest, promote_typejoin(T, typeof(el))) + copyto!(new, firstindex(new), dest, firstindex(dest), i-1) + @inbounds new[i] = el + return new + end + + function grow_to!(dest::Rows, itr, st) + T = eltype(dest) + y = iterate(itr, st) + while y !== nothing + el, st = y + if el isa T || typeof(el) === T + push!(dest, el::T) + else + new = push_widen(dest, el) + return grow_to!(new, itr, st) + end + y = iterate(itr, st) + end + return dest + end + + @inline function push_widen(dest, el) + new = sizehint!(empty(dest, promote_typejoin(eltype(dest), typeof(el))), length(dest)) + if new isa AbstractSet + # TODO: merge back these two branches when copy! is re-enabled for sets/vectors + union!(new, dest) + else + append!(new, dest) + end + push!(new, el) + return new + end + +end diff --git a/src/pivot.jl b/src/pivot.jl index d5fd6a0..88a732d 100644 --- a/src/pivot.jl +++ b/src/pivot.jl @@ -73,5 +73,5 @@ julia> @name to_columns(to_rows((a = [1, 2], b = [1.0, 2.0]))) ``` """ to_columns(rows::Generator{<: Zip, <: Some{Name}}) = - rows.f(rows.iter.is) + rows.f(get_columns(rows.iter)) export to_columns diff --git a/src/rows.jl b/src/rows.jl index 21f9241..5b20cf9 100644 --- a/src/rows.jl +++ b/src/rows.jl @@ -3,7 +3,7 @@ state_to_index(::Array, state) = state - 1 state_to_index(filtered::Filter, state) = state_to_index(filtered.itr, state) state_to_index(mapped::Generator, state) = state_to_index(mapped.iter, state) state_to_index(zipped::Zip, state) = - state_to_index(first(zipped.is), first(state)) + state_to_index(first(get_columns(zipped)), first(state)) """ Enumerated{Iterator} @@ -401,10 +401,10 @@ similar(old::Dict, ::Type{Tuple{Key, Value}}) where {Key, Value} = @inline getindex_reverse(index, column) = column[index...] @inline getindex(zipped::Zip, index...) = - partial_map(getindex_reverse, index, zipped.is) + partial_map(getindex_reverse, index, get_columns(zipped)) @inline view_reverse(index, column) = view(column, index...) @inline view(zipped::Zip, index...) = - zip(partial_map(view_reverse, index, zipped.is)...) + zip(partial_map(view_reverse, index, get_columns(zipped))...) @inline view(filtered::Filter, index...) = view(filtered.itr, index...) diff --git a/src/utilities.jl b/src/utilities.jl index c38e2e9..608c86b 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -26,10 +26,10 @@ function filter_unrolled(f, them::Some{Any}) end end -val_fieldtypes(type::TypeofBottom) = () -val_fieldtypes(type::Union) = () -val_fieldtypes(type::UnionAll) = () -@pure val_fieldtypes(type::DataType) = +val_fieldtypes_or_empty(type::TypeofBottom) = () +val_fieldtypes_or_empty(type::Union) = () +val_fieldtypes_or_empty(type::UnionAll) = () +@pure val_fieldtypes_or_empty(type::DataType) = if type.abstract || (type.name === Tuple.name && isvatuple(type)) () else