Skip to content

Commit 3771c34

Browse files
authored
extend KeyPath to allow CartesianIndex keys (#96)
1 parent 09bf849 commit 3771c34

File tree

2 files changed

+19
-3
lines changed

2 files changed

+19
-3
lines changed

src/keypath.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
using Base: tail
22

3-
KeyT = Union{Symbol, AbstractString, Integer}
3+
KeyT = Union{Symbol, AbstractString, Integer, CartesianIndex}
44

55
"""
66
KeyPath(keys...)
77
88
A type for representing a path of keys to a value in a nested structure.
99
Can be constructed with a sequence of keys, or by concatenating other `KeyPath`s.
10-
Keys can be of type `Symbol`, `String`, or `Int`.
10+
Keys can be of type `Symbol`, `String`, `Int`, or `CartesianIndex`.
1111
1212
For custom types, access through symbol keys is assumed to be done with `getproperty`.
1313
For consistency, the method `Base.propertynames` is used to get the viable property names.
1414
15-
For string and integer keys instead, the access is done with `getindex`.
15+
For string, integer, and cartesian index keys, the access is done with `getindex` instead.
1616
1717
See also [`getkeypath`](@ref), [`haskeypath`](@ref).
1818
@@ -85,18 +85,21 @@ end
8585
keypathstr(kp::KeyPath) = join(kp.keys, ".")
8686

8787
_getkey(x, k::Integer) = x[k]
88+
_getkey(x::AbstractArray, k::CartesianIndex) = x[k]
8889
_getkey(x, k::Symbol) = getproperty(x, k)
8990
_getkey(x::AbstractDict, k::Symbol) = x[k]
9091
_getkey(x, k::AbstractString) = x[k]
9192

9293
_setkey!(x, k::Integer, v) = (x[k] = v)
94+
_setkey!(x::AbstractArray, k::CartesianIndex, v) = (x[k] = v)
9395
_setkey!(x, k::Symbol, v) = setproperty!(x, k, v)
9496
_setkey!(x::AbstractDict, k::Symbol, v) = (x[k] = v)
9597
_setkey!(x, k::AbstractString, v) = (x[k] = v)
9698

9799
_haskey(x, k::Integer) = haskey(x, k)
98100
_haskey(x::Tuple, k::Integer) = 1 <= k <= length(x)
99101
_haskey(x::AbstractArray, k::Integer) = 1 <= k <= length(x) # TODO: extend to generic indexing
102+
_haskey(x::AbstractArray, k::CartesianIndex) = checkbounds(Bool, x, k)
100103
_haskey(x, k::Symbol) = k in propertynames(x)
101104
_haskey(x::AbstractDict, k::Symbol) = haskey(x, k)
102105
_haskey(x, k::AbstractString) = haskey(x, k)

test/keypath.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
kp = KeyPath(:b, :c, 2)
4545
@test getkeypath(x, kp) == 7
4646

47+
x = [(a=1,) (b=2,)]
48+
@test getkeypath(x, KeyPath(CartesianIndex(1, 1), :a)) == 1
49+
@test getkeypath(x, KeyPath(CartesianIndex(1, 2), :b)) == 2
50+
4751
@testset "access through getproperty" begin
4852
x = Tkp(3, Dict(:c => 4, :d => 5), 6);
4953

@@ -65,6 +69,10 @@
6569
kp = KeyPath(:b, :c, 2)
6670
setkeypath!(x, kp, 17)
6771
@test x.b.c[2] == 17
72+
73+
x = [(a=1,) (b=2,)]
74+
setkeypath!(x, KeyPath(CartesianIndex(1, 2)), (c=3,))
75+
@test x[2] == (c=3,)
6876
end
6977

7078
@testset "haskeypath" begin
@@ -75,6 +83,11 @@
7583
@test !haskeypath(x, KeyPath(:b, "d", 4))
7684
@test !haskeypath(x, KeyPath(:b, "e"))
7785

86+
x = [(a=1,) (b=2,)]
87+
@test haskeypath(x, KeyPath(CartesianIndex(1, 1)))
88+
@test haskeypath(x, KeyPath(CartesianIndex(1, 2)))
89+
@test !haskeypath(x, KeyPath(CartesianIndex(1, 3)))
90+
7891
@testset "access through getproperty" begin
7992
x = Tkp(3, Dict(:c => 4, :d => 5), 6);
8093

0 commit comments

Comments
 (0)