Skip to content

Commit

Permalink
Add keytype+valtype method for AbstractArray and AbstractVector (#…
Browse files Browse the repository at this point in the history
…27749)

* Add keytype method for AbstractArray and AbstractVector

The function `keytype(a)` returns `eltype(keys(a))` for associative
structures; it should do the same for `Abstract{Array, Vector}`.

* Add keytype method for AbstractArray and AbstractVector (part 2)

Now also for the type, not just for objects.

* Add valtype(...) for arrays

Arrays are associative structures in the sense that keys(...)
and values(...) both work on them. When considering them as such, their
valtype should be equal to eltype. (A future version of Julia could
even do `const valtype = eltype`?)

* Implement keytype/valtype for object as keytype(typeof(...

As suggested by @mbauman in code review.

Co-Authored-By: tkluck <tkluck@infty.nl>

* Implement keytype/valtype for ranges

* Add test cases for keytype/valtype(::AbstractArray)

* Add #27749 to NEWS.md

* keytype/valtype for arrays: docs + compat annotation

* keytype/valtype: use String values in examples

this makes the distinction between key and value clearer. Thanks to @StefanKarpinski for suggesting this.

Co-Authored-By: tkluck <tkluck@infty.nl>

* keytype/valtype for arrays: no special treatment for ranges

This was a little red herring in the discussion in #27749:
the `length` of a range may depend on the type of its parameters,
but as it turns out, `eltype(keys(...))` does not.

That's arguably a bug/inconsistency, but it's outside of the
scope of this pull request to fix that.
  • Loading branch information
tkluck authored and mbauman committed Apr 4, 2019
1 parent 0136fa1 commit ce17e05
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 0 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ Standard library changes
* A no-argument construct to `Ptr{T}` has been added which constructs a null pointer ([#30919])
* `strip` now accepts a function argument in the same manner as `lstrip` and `rstrip` ([#31211])
* `mktempdir` now accepts a `prefix` keyword argument to customize the file name ([#31230], [#22922])
* `keytype` and `valtype` now work on `AbstractArray`, and return the `eltype` of `keys(...)` and
`values(...)` respectively ([#27749]).
* `nextfloat(::BigFloat)` and `prevfloat(::BigFloat)` now returns a value with the same precision
as their argument, which means that (in particular) `nextfloat(prevfloat(x)) == x` whereas
previously this could result in a completely different value with a different precision ([#31310])
Expand Down
45 changes: 45 additions & 0 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,51 @@ unsafe_indices(r::AbstractRange) = (OneTo(unsafe_length(r)),) # Ranges use check
keys(a::AbstractArray) = CartesianIndices(axes(a))
keys(a::AbstractVector) = LinearIndices(a)

"""
keytype(T::Type{<:AbstractArray})
keytype(A::AbstractArray)
Return the key type of an array. This is equal to the
`eltype` of the result of `keys(...)`, and is provided
mainly for compatibility with the dictionary interface.
# Examples
```jldoctest
julia> keytype([1, 2, 3]) == Int
true
julia> keytype([1 2; 3 4])
CartesianIndex{2}
```
!!! compat "Julia 1.2"
For arrays, this function requires at least Julia 1.2.
"""
keytype(a::AbstractArray) = keytype(typeof(a))

keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
keytype(A::Type{<:AbstractVector}) = Int

valtype(a::AbstractArray) = valtype(typeof(a))

"""
valtype(T::Type{<:AbstractArray})
valtype(A::AbstractArray)
Return the value type of an array. This is identical to `eltype` and is
provided mainly for compatibility with the dictionary interface.
# Examples
```jldoctest
julia> valtype(["one", "two", "three"])
String
```
!!! compat "Julia 1.2"
For arrays, this function requires at least Julia 1.2.
"""
valtype(A::Type{<:AbstractArray}) = eltype(A)

prevind(::AbstractArray, i::Integer) = Int(i)-1
nextind(::AbstractArray, i::Integer) = Int(i)+1

Expand Down
3 changes: 3 additions & 0 deletions test/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,9 @@ for A in (rand(2), rand(2,3))
@test A[i] == v
end
@test Array(values(A)) == A

@test keytype(A) == eltype(keys(A))
@test valtype(A) == eltype(values(A))
end

# nextind and prevind
Expand Down
31 changes: 31 additions & 0 deletions test/ranges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,37 @@ end
@test length(Char(0):Char(0x001fffff)) == 2097152
@test length(typemax(UInt64)//one(UInt64):1:typemax(UInt64)//one(UInt64)) == 1
end
@testset "keys/values" begin
keytype_is_correct(r) = keytype(r) == eltype(keys(r))
valtype_is_correct(r) = valtype(r) == eltype(values(r))
@test keytype_is_correct(1:3)
@test keytype_is_correct(1:.3:4)
@test keytype_is_correct(.1:.1:.3)
@test keytype_is_correct(Int8(1):Int8(5))
@test keytype_is_correct(Int16(1):Int8(5))
@test keytype_is_correct(Int16(1):Int8(3):Int8(5))
@test keytype_is_correct(Int8(1):Int16(3):Int8(5))
@test keytype_is_correct(Int8(1):Int8(3):Int16(5))
@test keytype_is_correct(Int64(1):Int64(5))
@test keytype_is_correct(Int64(1):Int64(5))
@test keytype_is_correct(Int128(1):Int128(5))
@test keytype_is_correct(Base.OneTo(4))
@test keytype_is_correct(Base.OneTo(Int32(4)))

@test valtype_is_correct(1:3)
@test valtype_is_correct(1:.3:4)
@test valtype_is_correct(.1:.1:.3)
@test valtype_is_correct(Int8(1):Int8(5))
@test valtype_is_correct(Int16(1):Int8(5))
@test valtype_is_correct(Int16(1):Int8(3):Int8(5))
@test valtype_is_correct(Int8(1):Int16(3):Int8(5))
@test valtype_is_correct(Int8(1):Int8(3):Int16(5))
@test valtype_is_correct(Int64(1):Int64(5))
@test valtype_is_correct(Int64(1):Int64(5))
@test valtype_is_correct(Int128(1):Int128(5))
@test valtype_is_correct(Base.OneTo(4))
@test valtype_is_correct(Base.OneTo(Int32(4)))
end
@testset "findall(::Base.Fix2{typeof(in)}, ::Array)" begin
@test findall(in(3:20), [5.2, 3.3]) == findall(in(Vector(3:20)), [5.2, 3.3])

Expand Down

2 comments on commit ce17e05

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Executing the daily benchmark build, I will reply here when finished:

@nanosoldier runbenchmarks(ALL, isdaily = true)

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @ararslan

Please sign in to comment.