Created
January 8, 2021 17:56
-
-
Save straight-shoota/9671508dc0c3aaf9cd96d49531a2a0a4 to your computer and use it in GitHub Desktop.
[Crystal] Descending range
This file contains hidden or 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
struct Range | |
# Iterates over the elements of this range, passing each in turn to the block. | |
# | |
# ``` | |
# (10..15).each { |n| print n, ' ' } | |
# # prints: 10 11 12 13 14 15 | |
# ``` | |
def each : Nil | |
{% if B == Nil %} | |
{% raise "Can't each beginless range" %} | |
{% end %} | |
current = @begin | |
if current.nil? | |
raise ArgumentError.new("Can't each beginless range") | |
end | |
# TODO: This typeof and the macro interpolations are a workaround until #9324 is fixed. | |
typeof(yield current) | |
{% if E == Nil %} | |
while true | |
{{ "yield current".id }} | |
current = current.succ | |
end | |
{% else %} | |
end_value = @end | |
if end_value.nil? | |
while true | |
{{ "yield current".id }} | |
current = current.succ | |
end | |
else | |
if current < end_value | |
while current < end_value | |
{{ "yield current".id }} | |
current = current.succ | |
end | |
else | |
while current > end_value | |
{{ "yield current".id }} | |
current = current.pred | |
end | |
end | |
{{ "yield current".id }} if !@exclusive && (current <=> end_value).zero? | |
end | |
{% end %} | |
end | |
def empty? | |
@begin == @end && [email protected]? && @exclusive | |
end | |
def direction | |
if @begin == @end && [email protected]? | |
0 | |
elsif (from = @begin) && (to = @end) | |
(to <=> from).sign | |
else | |
1 | |
end | |
end | |
# Returns `true` if this range includes the given *value*. | |
# | |
# ``` | |
# (1..10).includes?(4) # => true | |
# (1..10).includes?(10) # => true | |
# (1..10).includes?(11) # => false | |
# | |
# (1...10).includes?(9) # => true | |
# (1...10).includes?(10) # => false | |
# ``` | |
def includes?(value) | |
begin_value = @begin | |
end_value = @end | |
direction = self.direction | |
# begin passes | |
((begin_value.nil? || (value <=> begin_value).sign != -direction) && | |
# end passes | |
(end_value.nil? || | |
(value <=> end_value).sign.in?(@exclusive ? {-direction} : {-direction, 0}))) | |
end | |
private class ItemIterator(B, E) | |
def next | |
return stop if @reached_end | |
end_value = @range.end | |
if end_value.nil? || @current != end_value | |
value = @current | |
if @range.direction == -1 | |
@current = @current.pred | |
else | |
@current = @current.succ | |
end | |
value | |
else | |
@reached_end = true | |
if [email protected]_end? && @current == end_value | |
@current | |
else | |
stop | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment