# runtests.jl
include("./dot_dot_list.jl")
using DotDotList
using Base.Test
tests = ["dot_dot_list_test"]
if VERSION >= v"0.5.0-dev+5239"
push!(tests, "dot_dot_list_v5_test")
end
for t in tests
println("testing $t ...")
@time include("$t.jl")
end
# dot_dot_list.jl
# (1,..) / (1,3,..) Notations for Infinite List
# Inspired by: EllipsisNotation.jl (https://github.com/ChrisRackauckas/EllipsisNotation.jl)
# 2018/03/28: Fix for Julia v0.6.x or greater
module DotDotList
import Base.eltype, Base.length, Base.start, Base.done, Base.next, Base.show
const DotDot = Val{:..}
const .. = DotDot()
const DotDotInf1{T} = Tuple{T,DotDot}
const DotDotInf2{T} = Tuple{T,T,DotDot}
const DotDotInf{T} = Union{DotDotInf1{T}, DotDotInf2{T}}
@inline eltype(::DotDotInf{T}) where {T} = T
@inline eltype(::Type{DotDotInf1{T}}) where {T} = T
@inline eltype(::Type{DotDotInf2{T}}) where {T} = T
@inline length(it::DotDotInf{T}) where {T} = typemax(Int)
@inline Base.iteratorsize(::DotDotInf{T}) where {T} = Base.IsInfinite()
@inline start(it::DotDotInf1{T}) where {T<:Number} = (it[1], one(T))
@inline start(it::DotDotInf1{Char}) = (it[1], 1)
@inline start(it::DotDotInf1{Bool}) = (it[1], 1)
@inline start(it::DotDotInf2{T}) where {T} = (it[1], it[2]-it[1])
@inline done(::DotDotInf{Int}, ::NTuple{2,Int}) = false
@inline done(::DotDotInf{T}, ::NTuple{2,T}) where {T<:Number} = false
@inline done(::DotDotInf{T}, ::Tuple{T,Int}) where {T} = false
@inline next(::DotDotInf{T}, t::NTuple{2,T}) where {T<:Number} = ((n,s)=t;(n,(n+s,s)))
@inline next(::DotDotInf{Char}, t::Tuple{Char,Int}) = ((n,s)=t;(n,(n+s,s)))
@inline next(::DotDotInf{Bool}, t::Tuple{Bool,Int}) = ((n,s)=t;(n,((n+s)%Bool,s)))
@inline function show(io::IO, it::DotDotInf1{T}) where {T}
print(io, '(')
show(io, it[1])
print(io, ",..)")
end
@inline function show(io::IO, it::DotDotInf2{T}) where {T}
print(io, '(')
show(io, it[1])
print(io, ',')
show(io, it[2])
print(io, ",..)")
end
# Special for DotDotInf2{T<:AbstractFloat}
function start(it::DotDotInf2{T}) where {T<:AbstractFloat}
if _seemsrational(it[1]) && _seemsrational(it[2])
s = rationalize(it[1])
t = rationalize(it[2]) - s
d = convert(T, lcm(denominator(s), denominator(t)))
(s*d, t*d, d)
else
(it[1], it[2] - it[1])
end
end
@inline done(::DotDotInf{T}, ::NTuple{3,T}) where {T<:AbstractFloat} = false
@inline next(::DotDotInf{T}, t::NTuple{3,T}) where {T<:AbstractFloat} = ((n,s,d)=t;(n/d,(n+s,s,d)))
@inline _seemsrational(v::T) where {T<:AbstractFloat} = convert(T, rationalize(v)) == v
export .., eltype, length, start, done, next, show
end # module
# dot_dot_list_test.jl
# 2018/03/28: Fix for Julia v0.6.x or greater
# include("./dot_dot_list.jl")
# using DotDotList
# using Base.Test
nats = (1,..)
# # io = IOBuffer()
# # print(io, nats)
# # @test "(1,..)" == takebuf_string(io)
# v- shorthand of -^
@test "(1,..)" == "$nats"
@test Int == eltype(nats)
@test [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] == collect(Iterators.take(nats, 10))
odds = (1,3,..)
@test "(1,3,..)" == "$odds"
@test Int == eltype(odds)
@test [1, 3, 5, 7, 9, 11, 13, 15, 17 ,19] == collect(Iterators.take(odds, 10))
issq(n::Int) = isqrt(n)^2 == n
@test [1, 9, 25, 49, 81, 121, 169, 225, 289, 361] == collect(Int, Iterators.take(Iterators.filter(issq, odds), 10))
floats = (1.5,..)
@test "(1.5,..)" == "$floats"
@test Float64 == eltype(floats)
@test Float64[1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5] == collect(Iterators.take(floats, 10))
@test 60.0 == sum(Iterators.take(floats, 10))
floats2 = (1.0,1.1,..)
@test "(1.0,1.1,..)" == "$floats2"
@test Float64 == eltype(floats2)
@test Float64[1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0] == collect(Iterators.take(floats2, 11))
@test 16.5 == sum(Iterators.take(floats2, 11))
floats3 = (1.0,4.0/3.0,..)
# @test "(1.0,1.3333333333333333,..)" == "$floats3"
@test ismatch(r"\(1\.0,1\.33333+,\.\.\)", "$floats3")
@test Float64 == eltype(floats3)
@test Float64[1.0, 4.0/3.0, 5.0/3.0, 2.0, 7.0/3.0, 8.0/3.0, 3.0, 10.0/3.0, 11.0/3.0, 4.0] == collect(Iterators.take(floats3, 10))
@test 25.0 == sum(Iterators.take(floats3, 10))
rationals = (1//1,9//10,..)
@test "(1//1,9//10,..)" == "$rationals"
@test Rational{Int} == eltype(rationals)
@test Rational{Int}[1//1, 9//10, 4//5, 7//10, 3//5, 1//2, 2//5, 3//10, 1//5, 1//10] == collect(Iterators.take(rationals, 10))
bools1 = (false,..)
@test "(false,..)" == "$bools1"
@test Bool == eltype(bools1)
@test Bool[false, true, false, true, false] == collect(Iterators.take(bools1, 5))
bools2 = (true,false,..)
@test "(true,false,..)" == "$bools2"
@test Bool == eltype(bools2)
@test Bool[true, false, true, false, true] == collect(Iterators.take(bools2, 5))
trues = (true,true,..)
@test "(true,true,..)" == "$trues"
@test Bool == eltype(trues)
@test Bool[true, true, true, true, true] == collect(Iterators.take(trues, 5))
chars = ('A',..)
@test "('A',..)" == "$chars"
@test Char == eltype(chars)
@test Char['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'] == collect(Iterators.take(chars, 10))
odd_chars = ('A','C',..)
@test "('A','C',..)" == "$odd_chars"
@test Char == eltype(odd_chars)
@test Char['A', 'C', 'E', 'G', 'I', 'K', 'M', 'O', 'Q', 'S'] == collect(Iterators.take(odd_chars, 10))
# dot_dot_list_v5_test.jl
# 2018/03/28: Fix for Julia v0.6.x or greater
# include("./dot_dot_list.jl")
# using DotDotList
# using Base.Test
evens = (2n for n=(1,..))
@test [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] == collect(Int, Iterators.take(evens, 10))
odd_squares = (n^2 for n=(1,3,..))
@test [1, 9, 25, 49, 81, 121, 169, 225, 289, 361] == collect(Int, Iterators.take(odd_squares, 10))
powers = (2^n for n=(1,..))
@test [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] == collect(Int, Iterators.take(powers, 10))