diff --git a/src/Extents.jl b/src/Extents.jl index b630378..be43f76 100644 --- a/src/Extents.jl +++ b/src/Extents.jl @@ -123,21 +123,26 @@ for all dimensions. $ORDER_DOC """ +union(ext1::Extent{()}, ext2::Extent{()}; strict=false) = Extent() function union(ext1::Extent, ext2::Extent; strict=false) _maybe_check_keys_match(ext1, ext2, strict) || return nothing - keys = _shared_keys(ext1, ext2) - if length(keys) == 0 - return nothing - else - values = map(keys) do k - k = _unwrap(k) - k_exts = (ext1[k], ext2[k]) - a = min(map(first, k_exts)...) - b = max(map(last, k_exts)...) - (a, b) + keys = _all_keys(ext1, ext2) + values = map(keys) do k + k = _unwrap(k) + if haskey(ext1, k) + if haskey(ext2, k) + k_exts = (ext1[k], ext2[k]) + a = min(map(first, k_exts)...) + b = max(map(last, k_exts)...) + (a, b) + else + ext1[k] + end + else + ext2[k] end - return Extent{map(_unwrap, keys)}(values) end + return Extent{map(_unwrap, keys)}(values) end union(a::Extent, ::Nothing; strict=false) = strict ? nothing : a union(::Nothing, b::Extent; strict=false) = strict ? nothing : b @@ -501,6 +506,12 @@ function _shared_keys(ext1::Extent{K1}, ext2::Extent{K2}) where {K1,K2} k in K2 ? (acc..., Val{k}()) : acc end end +# Use NamedTuple merge for combining keys +function _all_keys(ext1::Extent{K1}, ext2::Extent{K2}) where {K1,K2} + ntk1 = NamedTuple{K1}(map(k -> Val{k}(), K1)) + ntk2 = NamedTuple{K2}(map(k -> Val{k}(), K2)) + return values(merge(ntk1, ntk2)) +end @noinline _ext_no_key(key) = throw(ErrorException("Extent has no field $key")) diff --git a/test/runtests.jl b/test/runtests.jl index fed423a..e4affbd 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -57,9 +57,10 @@ end a = E(X=(0.1, 0.5), Y=(1.0, 2.0)) b = E(X=(2.1, 2.5), Y=(3.0, 4.0), Z=(0.0, 1.0)) c = E(Z=(0.2, 2.0)) - @test Extents.union(a, b) == Extents.union(a, b, a) == E(X=(0.1, 2.5), Y=(1.0, 4.0)) + @test Extents.union(a, b) == Extents.union(a, b, a) == E(X=(0.1, 2.5), Y=(1.0, 4.0), Z=(0.0, 1.0)) @test Extents.union(a, b; strict=true) === nothing - @test Extents.union(a, c) === nothing + @test Extents.union(a, c) == E(X=(0.1, 0.5), Y=(1.0, 2.0), Z=(0.2, 2.0)) + @test Extents.union(a, b) == E(X=(0.1, 2.5), Y=(1.0, 4.0), Z=(0.0, 1.0)) # If either argument is nothing, return the other @test Extents.union(a, nothing) === a @@ -69,7 +70,7 @@ end # If both arguments are nothing, return nothing @test Extents.union(nothing, nothing) === nothing @test Extents.union(nothing, nothing; strict=true) === nothing -end +# end @testset "covers" begin # An extent contains itself