-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from mbauman/mb/rename
Use names from base (without extending them)
- Loading branch information
Showing
3 changed files
with
162 additions
and
115 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,14 @@ | ||
module TupleTypes | ||
|
||
import Base: isvatuple | ||
|
||
check(T) = (T===Tuple || T===NTuple) && throw(ArgumentError("parameters of $T are undefined")) | ||
|
||
# Define methods for up to N tuple parameters to be evaluated in the Type domain | ||
const N=4 | ||
ie = :() | ||
for p=0:N | ||
params = ntuple(i->symbol(:P,i), p) | ||
global getpara, concatenate | ||
# Return the whole parameter list as an svec | ||
@eval getpara{$(params...)}(::Type{Tuple{$(params...)}}) = Base.svec($(params...)) | ||
|
||
# Accessing by a constant value | ||
for i=1:p | ||
@eval getpara{$(params...)}(::Type{Tuple{$(params...)}}, ::Type{Val{$i}}) = $(params[i]) | ||
end | ||
@eval getpara{$(params...), n}(t::Type{Tuple{$(params...)}}, ::Type{Val{n}}) = throw(BoundsError(t, n)) | ||
|
||
# Accessing by a non-constant selects the proper value with an ifelse chain | ||
if p == 1 | ||
ie = :(P1) | ||
elseif p > 1 | ||
ie = :(ifelse(i == $p, $(params[p]), $ie)) | ||
end | ||
@eval getpara{$(params...)}(t::Type{Tuple{$(params...)}}, i::Int) = (1 <= i <= $p || throw(BoundsError(t, i)); $ie) | ||
# It'd be nice to simply define the constant `i` computation in the type | ||
# domain instead of relying upon dispatch, but it's not constant-folding: | ||
# @eval getparam{$(params...), i}(t::Type{Tuple{$(params...)}}, ::Type{Val{i}}) = (1 <= i <= $p || throw(BoundsError(t, i)); $ie) | ||
|
||
# concatenation | ||
for q=0:N | ||
qarams = ntuple(i->symbol(:Q,i), q) | ||
@eval concatenate{$(params...), $(qarams...)}(::Type{Tuple{$(params...)}},::Type{Tuple{$(qarams...)}}) = Tuple{$(params...), $(qarams...)} | ||
end | ||
end | ||
|
||
|
||
# Might as well use this for all datatypes | ||
function getpara(T::Type) | ||
check(T) | ||
T.parameters # just return the svec, avoids allocations | ||
end | ||
|
||
function getpara(T::Type, i::Integer) | ||
check(T) | ||
L = length(T.parameters) | ||
if isvatuple(T) && i >= L | ||
T.parameters[end].parameters[1] | ||
else | ||
1 <= i <= L || throw(BoundsError(T, i)) | ||
T.parameters[i] | ||
end | ||
end | ||
|
||
getpara{I<:Integer}(T::Type, is::AbstractVector{I}) = Base.svec([getpara(T,i) for i in is]...) | ||
|
||
function concatenate{T<:Tuple, S<:Tuple}(::Type{T}, ::Type{S}) | ||
check(T); check(S); | ||
isvatuple(T) && throw(ArgumentError("cannot concatenate the varargs tuple $T with $S")) | ||
Tuple{T.parameters..., S.parameters...} | ||
end | ||
|
||
|
||
end # module | ||
baremodule TupleTypes | ||
using Base | ||
|
||
# Since we're defining our own getindex and length methods to operate on types | ||
# separately, it's difficult to then use Base's methods at the same time. | ||
# Instead, we define them as t* within an Implementation module, and reassign | ||
# them to the API names we want to use in this baremodule. | ||
Base.include("implementation.jl") | ||
const getindex = Implementation.tgetindex | ||
const length = Implementation.tlength | ||
const collect = Implementation.tcollect | ||
const concatenate = Implementation.concatenate | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
module Implementation | ||
|
||
import Base: isvatuple | ||
|
||
check(T) = (T===Tuple || T===NTuple) && throw(ArgumentError("parameters of $T are undefined")) | ||
|
||
# Define methods for up to N tuple parameters to be evaluated in the Type domain | ||
const N=4 | ||
ie = :() | ||
for p=0:N | ||
params = ntuple(i->symbol(:P,i), p) | ||
global tgetindex, tlength, concatenate | ||
|
||
# Accessing by a constant value | ||
for i=1:p | ||
@eval tgetindex{$(params...)}(::Type{Tuple{$(params...)}}, ::Type{Val{$i}}) = $(params[i]) | ||
end | ||
@eval tgetindex{$(params...), n}(t::Type{Tuple{$(params...)}}, ::Type{Val{n}}) = throw(BoundsError(t, n)) | ||
|
||
# Accessing by a non-constant selects the proper value with an ifelse chain | ||
if p == 1 | ||
ie = :(P1) | ||
elseif p > 1 | ||
ie = :(ifelse(i == $p, $(params[p]), $ie)) | ||
end | ||
@eval tgetindex{$(params...)}(t::Type{Tuple{$(params...)}}, i::Int) = (1 <= i <= $p || throw(BoundsError(t, i)); $ie) | ||
# It'd be nice to simply define the constant `i` computation in the type | ||
# domain instead of relying upon dispatch, but it's not constant-folding: | ||
# @eval getparam{$(params...), i}(t::Type{Tuple{$(params...)}}, ::Type{Val{i}}) = (1 <= i <= $p || throw(BoundsError(t, i)); $ie) | ||
|
||
# concatenation | ||
for q=0:N | ||
qarams = ntuple(i->symbol(:Q,i), q) | ||
@eval concatenate{$(params...), $(qarams...)}(::Type{Tuple{$(params...)}},::Type{Tuple{$(qarams...)}}) = Tuple{$(params...), $(qarams...)} | ||
end | ||
|
||
# length | ||
@eval tlength{$(params...)}(t::Type{Tuple{$(params...)}}) = $p | ||
end | ||
|
||
|
||
# Fallbacks for the general case | ||
function tcollect(T::Type) | ||
check(T) | ||
T.parameters # just return the svec, avoids allocations | ||
end | ||
|
||
function tlength(T::Type) | ||
check(T) | ||
length(T.parameters) | ||
end | ||
|
||
tgetindex{i}(T::Type, ::Type{Val{i}}) = tgetindex(T, i) | ||
function tgetindex(T::Type, i::Integer) | ||
check(T) | ||
L = length(T.parameters) | ||
if isvatuple(T) && i >= L | ||
T.parameters[end].parameters[1] | ||
else | ||
1 <= i <= L || throw(BoundsError(T, i)) | ||
T.parameters[i] | ||
end | ||
end | ||
|
||
tgetindex{I<:Integer}(T::Type, is::AbstractVector{I}) = Base.svec([tgetindex(T,i) for i in is]...) | ||
|
||
function concatenate{T<:Tuple, S<:Tuple}(::Type{T}, ::Type{S}) | ||
check(T); check(S); | ||
isvatuple(T) && throw(ArgumentError("cannot concatenate the varargs tuple $T with $S")) | ||
Tuple{T.parameters..., S.parameters...} | ||
end | ||
|
||
|
||
end # module |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,87 @@ | ||
using TupleTypes | ||
using Base.Test | ||
|
||
import TupleTypes: getpara, concatenate | ||
|
||
## getpara | ||
|
||
@test getpara(Tuple{}) === Core.svec() | ||
@test getpara(Tuple{1,2,3}) === Core.svec(1,2,3) | ||
@test getpara(Tuple{Int,String}) === Core.svec(Int,String) | ||
@test_throws ArgumentError getpara(Tuple) | ||
@test_throws ArgumentError getpara(NTuple) | ||
#@test_throws ArgumentError getpara(Tuple{Vararg{Int}}) | ||
#@test_throws ArgumentError getpara(Tuple{String,Vararg{Int}}) | ||
|
||
## getpara | ||
@test getpara(Tuple{1,2,3}, 1) === 1 | ||
@test getpara(Tuple{1,2,3}, 2) === 2 | ||
@test getpara(Tuple{1,2,3}, 3) === 3 | ||
@test getpara(Tuple{1,2,3}, 2:3) === Base.svec(2,3) | ||
@test_throws BoundsError getpara(Tuple{1,2,3}, 0) | ||
@test_throws BoundsError getpara(Tuple{1,2,3}, 4) | ||
@test getpara(Tuple{Int, String}, 1) === Int | ||
@test getpara(Tuple{Int, String}, 2) === String | ||
@test getpara(Tuple{Int, String}, [2,1]) === Base.svec(String,Int) | ||
@test_throws BoundsError getpara(Tuple{Int, String}, 0) | ||
@test_throws BoundsError getpara(Tuple{Int, String}, 3) | ||
@test_throws ArgumentError getpara(Tuple, 1) | ||
@test_throws ArgumentError getpara(NTuple, 1) | ||
@test getpara(Tuple{Vararg{Int}}, 1) === Int | ||
@test getpara(Tuple{Vararg{Int}}, 1000) === Int | ||
@test getpara(Tuple{Vararg{Int}}, 10^10) === Int | ||
@test getpara(Tuple{Vararg{Int}}, [10^10, 10^10+1]) === Base.svec(Int,Int) | ||
@test_throws BoundsError getpara(Tuple{Vararg{Int}}, 0) | ||
@test getpara(Tuple{Int, Vararg{String}}, 1) === Int | ||
@test getpara(Tuple{Int, Vararg{String}}, 2) === String | ||
@test getpara(Tuple{Int, Vararg{String}}, 3) === String | ||
@test getpara(Tuple{Int, Vararg{String}}, [1,3]) === Base.svec(Int,String) | ||
@test_throws BoundsError getpara(Tuple{Int, Vararg{String}}, 0) | ||
## TupleTypes.collect | ||
|
||
@test TupleTypes.collect(Tuple{}) === Core.svec() | ||
@test TupleTypes.collect(Tuple{1,2,3}) === Core.svec(1,2,3) | ||
@test TupleTypes.collect(Tuple{Int,String}) === Core.svec(Int,String) | ||
@test_throws ArgumentError TupleTypes.collect(Tuple) | ||
@test_throws ArgumentError TupleTypes.collect(NTuple) | ||
#@test_throws ArgumentError TupleTypes.collect(Tuple{Vararg{Int}}) | ||
#@test_throws ArgumentError TupleTypes.collect(Tuple{String,Vararg{Int}}) | ||
|
||
## TupleTypes.getindex | ||
@test TupleTypes.getindex(Tuple{1,2,3}, 1) === 1 | ||
@test TupleTypes.getindex(Tuple{1,2,3}, 2) === 2 | ||
@test TupleTypes.getindex(Tuple{1,2,3}, 3) === 3 | ||
@test TupleTypes.getindex(Tuple{1,2,3}, Val{1}) === 1 | ||
@test TupleTypes.getindex(Tuple{1,2,3}, Val{2}) === 2 | ||
@test TupleTypes.getindex(Tuple{1,2,3}, Val{3}) === 3 | ||
@test TupleTypes.getindex(Tuple{1,2,3}, 2:3) === Base.svec(2,3) | ||
@test_throws BoundsError TupleTypes.getindex(Tuple{1,2,3}, 0) | ||
@test_throws BoundsError TupleTypes.getindex(Tuple{1,2,3}, 4) | ||
@test_throws BoundsError TupleTypes.getindex(Tuple{1,2,3}, Val{0}) | ||
@test_throws BoundsError TupleTypes.getindex(Tuple{1,2,3}, Val{4}) | ||
@test TupleTypes.getindex(Tuple{Int, String}, 1) === Int | ||
@test TupleTypes.getindex(Tuple{Int, String}, 2) === String | ||
@test TupleTypes.getindex(Tuple{Int, String}, Val{1}) === Int | ||
@test TupleTypes.getindex(Tuple{Int, String}, Val{2}) === String | ||
@test TupleTypes.getindex(Tuple{Int, String}, [2,1]) === Base.svec(String,Int) | ||
@test_throws BoundsError TupleTypes.getindex(Tuple{Int, String}, 0) | ||
@test_throws BoundsError TupleTypes.getindex(Tuple{Int, String}, 3) | ||
@test_throws BoundsError TupleTypes.getindex(Tuple{Int, String}, Val{0}) | ||
@test_throws BoundsError TupleTypes.getindex(Tuple{Int, String}, Val{3}) | ||
@test_throws ArgumentError TupleTypes.getindex(Tuple, 1) | ||
@test_throws ArgumentError TupleTypes.getindex(NTuple, 1) | ||
@test TupleTypes.getindex(Tuple{Vararg{Int}}, Val{1}) === Int | ||
@test TupleTypes.getindex(Tuple{Vararg{Int}}, Val{1000}) === Int | ||
@test TupleTypes.getindex(Tuple{Vararg{Int}}, Val{10^10}) === Int | ||
@test TupleTypes.getindex(Tuple{Vararg{Int}}, [10^10, 10^10+1]) === Base.svec(Int,Int) | ||
@test_throws BoundsError TupleTypes.getindex(Tuple{Vararg{Int}}, 0) | ||
@test_throws BoundsError TupleTypes.getindex(Tuple{Vararg{Int}}, Val{0}) | ||
@test TupleTypes.getindex(Tuple{Int, Vararg{String}}, 1) === Int | ||
@test TupleTypes.getindex(Tuple{Int, Vararg{String}}, 2) === String | ||
@test TupleTypes.getindex(Tuple{Int, Vararg{String}}, 3) === String | ||
@test TupleTypes.getindex(Tuple{Int, Vararg{String}}, Val{1}) === Int | ||
@test TupleTypes.getindex(Tuple{Int, Vararg{String}}, Val{2}) === String | ||
@test TupleTypes.getindex(Tuple{Int, Vararg{String}}, Val{3}) === String | ||
@test TupleTypes.getindex(Tuple{Int, Vararg{String}}, [1,3]) === Base.svec(Int,String) | ||
@test_throws BoundsError TupleTypes.getindex(Tuple{Int, Vararg{String}}, 0) | ||
@test_throws BoundsError TupleTypes.getindex(Tuple{Int, Vararg{String}}, Val{0}) | ||
|
||
# bug in Julia https://github.com/JuliaLang/julia/issues/11725 | ||
f{T<:Integer}(::T, ::T) = 1 | ||
fm = first(methods(f)) | ||
g{I<:Integer}(::I, ::I) = 1 | ||
gm = first(methods(g)) | ||
@test getpara(fm.sig, 1)==fm.sig.parameters[1] | ||
@test getpara(gm.sig, 1)==gm.sig.parameters[1] | ||
@test TupleTypes.getindex(fm.sig, 1)==fm.sig.parameters[1] | ||
@test TupleTypes.getindex(gm.sig, 1)==gm.sig.parameters[1] | ||
|
||
|
||
## Concatenate | ||
|
||
@test concatenate(Tuple{}, Tuple{}) === Tuple{} | ||
@test concatenate(Tuple{Int}, Tuple{}) === Tuple{Int} | ||
@test concatenate(Tuple{}, Tuple{Int}) === Tuple{Int} | ||
@test concatenate(Tuple{Int}, Tuple{String}) === Tuple{Int,String} | ||
@test concatenate(Tuple{1,2,3}, Tuple{4,5,6}) === Tuple{1,2,3,4,5,6} | ||
@test concatenate(Tuple{}, Tuple{Vararg{Int}}) === Tuple{Vararg{Int}} | ||
@test concatenate(Tuple{String}, Tuple{Int, Vararg{String}}) === Tuple{String, Int, Vararg{String}} | ||
@test_throws ArgumentError concatenate(Tuple, Tuple{Int}) | ||
@test_throws ArgumentError concatenate(Tuple{}, Tuple) | ||
@test_throws ArgumentError concatenate(Tuple{Vararg{String}}, Tuple{Int}) | ||
@test TupleTypes.concatenate(Tuple{}, Tuple{}) === Tuple{} | ||
@test TupleTypes.concatenate(Tuple{Int}, Tuple{}) === Tuple{Int} | ||
@test TupleTypes.concatenate(Tuple{}, Tuple{Int}) === Tuple{Int} | ||
@test TupleTypes.concatenate(Tuple{Int}, Tuple{String}) === Tuple{Int,String} | ||
@test TupleTypes.concatenate(Tuple{1,2,3}, Tuple{4,5,6}) === Tuple{1,2,3,4,5,6} | ||
@test TupleTypes.concatenate(Tuple{}, Tuple{Vararg{Int}}) === Tuple{Vararg{Int}} | ||
@test TupleTypes.concatenate(Tuple{String}, Tuple{Int, Vararg{String}}) === Tuple{String, Int, Vararg{String}} | ||
@test_throws ArgumentError TupleTypes.concatenate(Tuple, Tuple{Int}) | ||
@test_throws ArgumentError TupleTypes.concatenate(Tuple{}, Tuple) | ||
@test_throws ArgumentError TupleTypes.concatenate(Tuple{Vararg{String}}, Tuple{Int}) | ||
|
||
|
||
## Length | ||
|
||
@test TupleTypes.length(Tuple{}) === 0 | ||
@test TupleTypes.length(Tuple{Int}) === 1 | ||
@test TupleTypes.length(Tuple{Int8, Int16}) === 2 | ||
@test TupleTypes.length(Tuple{Int8, Int16, Int32}) === 3 | ||
@test TupleTypes.length(Tuple{Int8, Int16, Int32, Int64}) === 4 | ||
@test TupleTypes.length(Tuple{Vararg{String}}) === 1 | ||
@test TupleTypes.length(Tuple{Int,Vararg{String}}) === 2 | ||
@test TupleTypes.length(Tuple{Int8, Int16,Vararg{String}}) === 3 | ||
@test TupleTypes.length(Tuple{Int8, Int16, Int32,Vararg{String}}) === 4 | ||
@test TupleTypes.length(Tuple{Int8, Int16, Int32, Int64,Vararg{String}}) === 5 |