Skip to content

Instantly share code, notes, and snippets.

@straight-shoota
Created January 8, 2021 17:56
Show Gist options
  • Save straight-shoota/9671508dc0c3aaf9cd96d49531a2a0a4 to your computer and use it in GitHub Desktop.
Save straight-shoota/9671508dc0c3aaf9cd96d49531a2a0a4 to your computer and use it in GitHub Desktop.
[Crystal] Descending range
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