Skip to content

Commit 773db6a

Browse files
authored
Create Compat.Iterators; add takewhile, dropwhile and map (#715)
1 parent e1d2225 commit 773db6a

File tree

5 files changed

+143
-0
lines changed

5 files changed

+143
-0
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ changes in `julia`.
5555

5656
## Supported features
5757

58+
* `Compat.Iterators.map` is added. It provides another syntax `Iterators.map(f, iterators...)`
59+
for writing `(f(args...) for args in zip(iterators...))`, i.e. a lazy `map` ([#34352]).
60+
(since Compat 3.14)
61+
62+
* `takewhle` and `dropwhile` are added in `Compat.Iterators` ([#33437]). (since Compat 3.14)
63+
5864
* Curried comparisons `!=(x)`, `>=(x)`, `<=(x)`, `>(x)`, and `<(x)` are defined as, e.g.,
5965
`!=(x) = y -> y != x` ([#30915]). (since Compat 3.14)
6066

@@ -184,3 +190,5 @@ Note that you should specify the correct minimum version for `Compat` in the
184190
[#36360]: https://github.com/JuliaLang/julia/pull/36360
185191
[#35929]: https://github.com/JuliaLang/julia/pull/35929
186192
[#30915]: https://github.com/JuliaLang/julia/pull/30915
193+
[#33437]: https://github.com/JuliaLang/julia/pull/33437
194+
[#34352]: https://github.com/JuliaLang/julia/pull/34352

src/Compat.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ if VERSION < v"1.2.0-DEV.257" # e7e726b3df1991e1306ef0c566d363c0a83b2dea
594594
Base.:(<)(x) = Base.Fix2(<, x)
595595
end
596596

597+
include("iterators.jl")
597598
include("deprecated.jl")
598599

599600
end # module Compat

src/iterators.jl

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
module CompatIterators
2+
# Defining this module with the name `CompatIterators` and define
3+
# `const Iterators = CompatIterators` at the end of this file so that
4+
#
5+
# julia> using Compat.Iterators
6+
#
7+
# julia> Iterators
8+
# Base.Iterators
9+
#
10+
# julia> takewhile
11+
# takewhile (generic function with 1 method)
12+
#
13+
# works without conflict in identifiers in all Julia versions. Users
14+
# still need to explicitly import `Compat.Iterators` via `using
15+
# Compat: Iterators` to use, e.g., `Iterators.map` before Julia 1.6.
16+
# This is the case with and without the `CompatIterators` hack.
17+
18+
using Base: SizeUnknown
19+
20+
# We normally use `Base.f(...) = ...` style for overloading. However,
21+
# we use `import Base: f` style here to make synchronizing the code
22+
# with `Base` easier.
23+
import Base: IteratorEltype, IteratorSize, eltype, iterate
24+
25+
# Import exported APIs
26+
for n in names(Base.Iterators)
27+
n === :Iterators && continue
28+
@eval begin
29+
using Base.Iterators: $n
30+
export $n
31+
end
32+
end
33+
34+
# Import unexported public APIs
35+
using Base.Iterators: filter
36+
37+
# https://github.com/JuliaLang/julia/pull/33437
38+
if VERSION < v"1.4.0-DEV.291" # 5f013d82f92026f7dfbe4234f283658beb1f8a2a
39+
export takewhile, dropwhile
40+
41+
# takewhile
42+
struct TakeWhile{I,P<:Function}
43+
pred::P
44+
xs::I
45+
end
46+
47+
takewhile(pred,xs) = TakeWhile(pred,xs)
48+
49+
function iterate(ibl::TakeWhile, itr...)
50+
y = iterate(ibl.xs,itr...)
51+
y === nothing && return nothing
52+
ibl.pred(y[1]) || return nothing
53+
y
54+
end
55+
56+
IteratorSize(::Type{<:TakeWhile}) = SizeUnknown()
57+
eltype(::Type{TakeWhile{I,P}}) where {I,P} = eltype(I)
58+
IteratorEltype(::Type{TakeWhile{I,P}}) where {I,P} = IteratorEltype(I)
59+
60+
# dropwhile
61+
struct DropWhile{I,P<:Function}
62+
pred::P
63+
xs::I
64+
end
65+
66+
dropwhile(pred,itr) = DropWhile(pred,itr)
67+
68+
iterate(ibl::DropWhile,itr) = iterate(ibl.xs, itr)
69+
function iterate(ibl::DropWhile)
70+
y = iterate(ibl.xs)
71+
while y !== nothing
72+
ibl.pred(y[1]) || break
73+
y = iterate(ibl.xs,y[2])
74+
end
75+
y
76+
end
77+
78+
IteratorSize(::Type{<:DropWhile}) = SizeUnknown()
79+
eltype(::Type{DropWhile{I,P}}) where {I,P} = eltype(I)
80+
IteratorEltype(::Type{DropWhile{I,P}}) where {I,P} = IteratorEltype(I)
81+
end
82+
83+
# https://github.com/JuliaLang/julia/pull/34352
84+
if VERSION < v"1.6.0-DEV.258" # 1f8b44204fafb1caabc6a1cd6ca39458a550e2fc
85+
map(f, args...) = Base.Generator(f, args...)
86+
else
87+
using Base.Iterators: map
88+
end
89+
90+
end # module
91+
92+
const Iterators = CompatIterators

test/iterators.jl

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
module TestIterators
2+
3+
using Compat.Iterators
4+
using Compat: Compat, Iterators
5+
using Test
6+
7+
# https://github.com/JuliaLang/julia/pull/33437
8+
@testset "takewhile" begin
9+
@test collect(takewhile(<(4),1:10)) == [1,2,3]
10+
@test collect(takewhile(<(4),Iterators.countfrom(1))) == [1,2,3]
11+
@test collect(takewhile(<(4),5:10)) == []
12+
@test collect(takewhile(_->true,5:10)) == 5:10
13+
@test collect(takewhile(isodd,[1,1,2,3])) == [1,1]
14+
@test collect(takewhile(<(2), takewhile(<(3), [1,1,2,3]))) == [1,1]
15+
end
16+
17+
# https://github.com/JuliaLang/julia/pull/33437
18+
@testset "dropwhile" begin
19+
@test collect(dropwhile(<(4), 1:10)) == 4:10
20+
@test collect(dropwhile(<(4), 1:10)) isa Vector{Int}
21+
@test isempty(dropwhile(<(4), []))
22+
@test collect(dropwhile(_->false,1:3)) == 1:3
23+
@test isempty(dropwhile(_->true, 1:3))
24+
@test collect(dropwhile(isodd,[1,1,2,3])) == [2,3]
25+
@test collect(dropwhile(iseven,dropwhile(isodd,[1,1,2,3]))) == [3]
26+
end
27+
28+
# https://github.com/JuliaLang/julia/pull/34352
29+
@testset "Iterators.map" begin
30+
@test collect(Iterators.map(string, 1:3)::Base.Generator) == map(string, 1:3)
31+
@test collect(Iterators.map(tuple, 1:3, 4:6)::Base.Generator) == map(tuple, 1:3, 4:6)
32+
end
33+
34+
@testset "Iterators.filter" begin
35+
# `Iterators.filter` already existed in Julia 1.0. We just make
36+
# sure that it is available under `Compat.Iterators` namespace.
37+
@test Compat.Iterators.filter === Base.Iterators.filter
38+
end
39+
40+
end # module

test/runtests.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,4 +545,6 @@ end
545545
@test lt5(4) && !lt5(5)
546546
end
547547

548+
include("iterators.jl")
549+
548550
nothing

0 commit comments

Comments
 (0)