class IntervalSet
IntervalSet
implements a set of sorted non-overlapping ranges. A range's start is always interpreted as inclusive while the end is exclusive
Constants
- VERSION
Public Class Methods
Builds a new IntervalSet
from the supplied ranges. Overlapping ranges will be merged.
IntervalSet[] # -> [] IntervalSet[0...1] # -> [0...1] IntervalSet[0...1, 2...3] # -> [0...1, 2...3] IntervalSet[0...1, 1...2] # -> [0...2] array = [0...1, 2...3] IntervalSet[*array] # -> [0...1, 2...3]
@param ranges [Range a list of ranges to be added to the new IntervalSet
@return [IntervalSet] a new IntervalSet
containing the supplied ranges.
# File lib/interval_set.rb, line 20 def self.[](*ranges) IntervalSet.new.tap do |interval_set| ranges.each {|range| interval_set << range} end end
Returns an empty instance of IntervalSet
.
# File lib/interval_set.rb, line 27 def initialize @range_map = TreeMap.new end
Private Class Methods
# File lib/interval_set.rb, line 1021 def self.normalize_range(range) range.exclude_end? ? range : range.first...range.last end
# File lib/interval_set.rb, line 1017 def self.range_empty?(range) range.first >= range.last end
# File lib/interval_set.rb, line 1025 def self.unexpected_object(object) raise ArgumentError.new("unexpected object #{object}") end
Public Instance Methods
Adds the other object's elements to this IntervalSet
. The result is stored in this IntervalSet
.
IntervalSet.new.add(0...1) # -> [0...1] IntervalSet.new << (0...1) # -> [0...1] i = IntervalSet.new # -> [] i << (0...1) # -> [0...1] i << (2...3) # -> [0...1, 2...3] i << (1...2) # -> [0...3] i << (-1...4) # -> [-1...4]
@param other [Range, IntervalSet] the other object. @return [IntervalSet] self.
# File lib/interval_set.rb, line 324 def add(other) case other when Range add_range(other) when IntervalSet add_interval_set(other) else IntervalSet.unexpected_object(other) end end
Returns the bounds of this IntervalSet
.
IntervalSet[0...1, 2...3].bounds # -> 0...3 IntervalSet[].bounds # -> nil
@return [Range] a range from lower to upper bound or nil
if empty.
# File lib/interval_set.rb, line 71 def bounds empty? ? nil : min...max end
Returns true
if the given range has common elements with the bounding range of this IntervalSet
.
IntervalSet[1...2].bounds_intersected_by?(2...3) # -> false IntervalSet[1...2, 5...6].bounds_intersected_by?(3...4) # -> true
@param range [Range]
# File lib/interval_set.rb, line 247 def bounds_intersected_by?(range) return false if IntervalSet.range_empty?(range) !empty? && range.first < max && range.last > min end
Returns true
if the given range has common elements with the bounding range or the bounds of this IntervalSet
.
IntervalSet[1...2].bounds_intersected_or_touched_by?(2...3) # -> true IntervalSet[1...2].bounds_intersected_or_touched_by?(3...4) # -> false IntervalSet[1...2, 5...6].bounds_intersected_or_touched_by?(3...4) # -> true
@param range [Range]
# File lib/interval_set.rb, line 261 def bounds_intersected_or_touched_by?(range) return false if IntervalSet.range_empty?(range) !empty? && range.first <= max && range.last >= min end
Buffers this IntervalSet
by adding a left and right margin to each range. The result is stored in a new IntervalSet
.
IntervalSet[1...2].buffer(1, 2) # -> [0...4] # negative values will shrink the ranges IntervalSet[0...4].buffer(-1, -2) # -> [1...2] IntervalSet[1...2].buffer(-0.5, -0.5) # -> []
@param left [Object] margin added to the left side of each range. @param right [Object] margin added to the right side of each range. @return [IntervalSet] a new IntervalSet
containing the buffered ranges.
# File lib/interval_set.rb, line 607 def buffer(left, right) clone.buffer!(left, right) end
Buffers this IntervalSet
by adding a left and right margin to each range. The result is stored in this IntervalSet
.
IntervalSet[1...2].buffer!(1, 2) # -> [0...4] # negative values will shrink the ranges IntervalSet[0...4].buffer!(-1, -2) # -> [1...2] IntervalSet[1...2].buffer!(-0.5, -0.5) # -> []
@param left [Object] margin added to the left side of each range. @param right [Object] margin added to the right side of each range. @return [IntervalSet] self.
# File lib/interval_set.rb, line 582 def buffer!(left, right) ranges = map do |range| range.first - left...range.last + right end.select do |range| range.first < range.last end clear ranges.each {|r| add_range(r)} self end
Removes all elements from this IntervalSet
. @return [IntervalSet] self.
# File lib/interval_set.rb, line 613 def clear @range_map.clear @min = nil @max = nil self end
Returns a new IntervalSet
instance containing all ranges of this IntervalSet
. @return [IntervalSet] the clone.
# File lib/interval_set.rb, line 631 def clone IntervalSet.new.copy(self) end
Convolves the other object's elements with this IntervalSet
. The result is stored in a new IntervalSet
.
The result will contain all elements which can be obtained by adding any pair of elements from both sets. A ∗ B = { a + b | a ∈ A ∧ b ∈ B }
# Convolve with a range (effectively buffers the set) IntervalSet[0...4] * (-1...2) # -> [-1...6] # Convolving with empty or reversed ranges result in an empty set. IntervalSet[0...4] * (0...0) # -> [] IntervalSet[0...4] * (1...0) # -> [] # Convolve with a interval set IntervalSet[0...1, 10...12] * IntervalSet[-2...1, 1...2] # -> [-2...3, 8...14]
@param other [Range | IntervalSet] the other object. @return [IntervalSet] a new IntervalSet
containing the convolution.
# File lib/interval_set.rb, line 531 def convolve(other) clone.convolve!(other) end
Convolves the other object's elements with this IntervalSet
. The result is stored in this IntervalSet
.
The result will contain all elements which can be obtained by adding any pair of elements from both sets. A ∗ B = { a + b | a ∈ A ∧ b ∈ B }
# Convolve with a range (effectively buffers the set) IntervalSet[0...4].convolve!(-1...2) # -> [-1...6] # Convolving with empty or reversed ranges result in an empty set. IntervalSet[0...4].convolve!(0...0) # -> [] IntervalSet[0...4].convolve!(1...0) # -> [] # Convolve with a interval set IntervalSet[0...1, 10...12].convolve!(IntervalSet[-2...1, 1...2]) # -> [-2...3, 8...14]
@param other [Range | IntervalSet] the other object. @return [IntervalSet] self
# File lib/interval_set.rb, line 502 def convolve!(other) case other when Range convolve_range!(other) when IntervalSet convolve_interval_set!(other) else IntervalSet.unexpected_object(other) end end
Replaces the content of this IntervalSet
by the content of the given IntervalSet
. @param interval_set [IntervalSet] the other IntervalSet
to be copied @return [IntervalSet] self.
# File lib/interval_set.rb, line 638 def copy(interval_set) clear interval_set.each {|range| put(range)} @min = interval_set.min @max = interval_set.max self end
Counts the number of ranges contained by this IntervalSet
.
i = IntervalSet[] # -> [] i.count # -> 0 i << (0...1) # -> [0...1] i.count # -> 1 i << (2...3) # -> [0...1, 2...3] i.count # -> 2 i << (1...2) # -> [0...3] i.count # -> 1
@return [Fixnum] the number of ranges.
# File lib/interval_set.rb, line 306 def count @range_map.count end
Subtracts the other object's elements from this IntervalSet
. The result is stored in a new IntervalSet
.
IntervalSet[0...2, 3...5] - IntervalSet[1...4, 5...6] # -> [0...1, 4...5]
Note that using remove
or difference!
is more efficient than -=
.
@param other [Range, IntervalSet] the other object. @return [IntervalSet] a new IntervalSet
containing the difference.
# File lib/interval_set.rb, line 436 def difference(other) case other when Range difference_range(other) when IntervalSet difference_interval_set(other) else IntervalSet.unexpected_object(other) end end
Iterates over all ranges of this set in ascending order. @yield all ranges. @yieldparam [Range] range. @return [void]
# File lib/interval_set.rb, line 625 def each @range_map.each_node {|node| yield node.value} end
Returns true
if this IntervalSet
contains no ranges.
# File lib/interval_set.rb, line 41 def empty? @range_map.empty? end
Returns true
if two IntervalSets are equal.
IntervalSet[0...1] == IntervalSet[0...1] # -> true IntervalSet[0...1] == IntervalSet[1...2] # -> false
@param other [Object] the other object.
# File lib/interval_set.rb, line 81 def eql?(other) return false if other.nil? || !other.is_a?(IntervalSet) || count != other.count || bounds != other.bounds lhs_iter = enum_for rhs_iter = other.enum_for count.times.all? {lhs_iter.next == rhs_iter.next} end
Returns true
if the other object represents a equal set of ranges as this IntervalSet
.
IntervalSet[1...2].eql_set?(1...2) # -> true IntervalSet[1...2].eql_set?(IntervalSet[1...2]) # -> true
@param other [Range | IntervalSet] the other object.
# File lib/interval_set.rb, line 99 def eql_set?(other) case other when Range eql_range?(other) when IntervalSet eql?(other) else IntervalSet.unexpected_object(other) end end
Returns true
if this IntervalSet
contains the given element.
i = IntervalSet[0...1] # -> [0...1] i.include?(0) # -> true i.include?(0.5) # -> true i.include?(1) # -> false ; a range's end is exclusive
Note that the given element must be comparable to elements already in this set. Otherwise, the behavior is undefined.
@param element [Object]
# File lib/interval_set.rb, line 122 def include?(element) return false if element.nil? floor_entry = @range_map.floor_entry(element) !floor_entry.nil? && floor_entry.value.last > element end
Returns true
if the closure of this IntervalSet
contains the given element.
The closure of a set S
is defined as the set containing all elements of S
but also its limit points.
It will always return true
if include?
returns true
but in addition it will also return true
if the exclusive end of a range is included.
i = IntervalSet[0...1] # -> [0...1] i.include_or_limit?(0) # -> true i.include_or_limit?(0.5) # -> true i.include_or_limit?(1) # -> true
Note that the given element must be comparable to elements already in this set. Otherwise, the behavior is undefined.
@param element [Object]
# File lib/interval_set.rb, line 150 def include_or_limit?(element) return false if element.nil? floor_entry = @range_map.floor_entry(element) !floor_entry.nil? && floor_entry.value.last >= element end
Intersects the other object's elements with this IntervalSet
. The result is stored in this IntervalSet
.
i = IntervalSet[0...2, 3...5].intersect(1...5) # -> [1...2, 3...5] i # -> [1...2, 3...5]
@param other [Range, IntervalSet] the other object. @return [IntervalSet] self.
# File lib/interval_set.rb, line 369 def intersect(other) case other when Range intersect_range(other) when IntervalSet intersect_interval_set(other) else IntervalSet.unexpected_object(other) end end
Returns true
if the given object has any common elements with this IntervalSet
.
i = IntervalSet[0...1] # -> [0...1] # Ranges only need a single common element with the interval set i.intersect?(0...1) # -> true i.intersect?(0...2) # -> true i.intersect?(1...2) # -> false ; the start of a range is inclusive but the end exclusive # The same applies for interval sets i.intersect?(IntervalSet[0...1]) # -> true i.intersect?(IntervalSet[0...1, 2...3]) # -> true i.intersect?(IntervalSet[2...3]) # -> false
@param other [Range | IntervalSet] the other object.
# File lib/interval_set.rb, line 283 def intersect?(other) case other when Range intersect_range?(other) when IntervalSet intersect_interval_set?(other) else IntervalSet.unexpected_object(other) end end
Intersects the other object's elements with this IntervalSet
. The result is stored in a new IntervalSet
.
IntervalSet[0...2, 3...5] & IntervalSet[1...4, 5...6] # -> [1...2, 3...4]
@param other [Range, IntervalSet] the other object. @return [IntervalSet] a new IntervalSet
containing the intersection.
# File lib/interval_set.rb, line 389 def intersection(other) case other when Range intersection_range(other) when IntervalSet intersection_interval_set(other) else IntervalSet.unexpected_object(other) end end
# File lib/interval_set.rb, line 31 def marshal_dump to_a end
# File lib/interval_set.rb, line 35 def marshal_load(ranges) initialize ranges.each {|range| add(range)} end
Returns the upper bound of this IntervalSet
.
IntervalSet[0...1, 2...3].max # -> 3 IntervalSet[].max # -> nil
@return the upper bound or nil
if empty.
# File lib/interval_set.rb, line 61 def max @max end
Returns the lower bound of this IntervalSet
.
IntervalSet[0...1, 2...3].min # -> 0 IntervalSet[].min # -> nil
@return the lower bound or nil
if empty.
# File lib/interval_set.rb, line 51 def min @min end
Return true
if this IntervalSet
is a proper subset of the other.
IntervalSet[0...1] < IntervalSet[0...2] # -> true IntervalSet[1...3] < IntervalSet[0...2] # -> false IntervalSet[1...3] < IntervalSet[0...2] # -> false # Compare to ranges IntervalSet[1...2].subset?(0...3) # -> false
@param other [Range | IntervalSet] the other object.
# File lib/interval_set.rb, line 234 def proper_subset?(other) !eql_set?(other) && subset?(other) end
Returns true
if this IntervalSet
is a proper superset of the other.
IntervalSet[0...2] > IntervalSet[0...1] # -> true IntervalSet[0...2] > IntervalSet[0...2] # -> false IntervalSet[0...2] > IntervalSet[1...3] # -> false # Compare to ranges IntervalSet[0...3].superset?(1...2) # -> true
@param other [Range | IntervalSet] the other object.
# File lib/interval_set.rb, line 218 def proper_superset?(other) !eql_set?(other) && superset?(other) end
Removes the other object's elements from this IntervalSet
. The result is stored in this IntervalSet
.
i = IntervalSet[0...10] # -> [0...10] i.remove(0...2) # -> [8...10] i >> (2...8) # -> [0...2, 8...10]
@param other [Range, IntervalSet] the other object. @return [IntervalSet] self.
# File lib/interval_set.rb, line 347 def remove(other) case other when Range remove_range(other) when IntervalSet remove_interval_set(other) else IntervalSet.unexpected_object(other) end end
Shifts this IntervalSet
by the given amount. The result is stored in a new IntervalSet
.
IntervalSet[0...1].shift!(1) # -> [1...2]
Note that +shift!(0)+ will not be optimized since IntervalSet
does not assume numbers as element type.
@param amount [Object] @return [IntervalSet] a new IntervalSet
shifted by amount
.
# File lib/interval_set.rb, line 566 def shift(amount) clone.shift!(amount) end
Shifts this IntervalSet
by the given amount. The result is stored in this IntervalSet
.
IntervalSet[0...1].shift(1) # -> [1...2]
Note that +shift(0)+ will not be optimized since IntervalSet
does not assume numbers as element type.
@param amount [Object] @return [IntervalSet] self.
# File lib/interval_set.rb, line 547 def shift!(amount) ranges = map {|range| range.first + amount...range.last + amount} clear ranges.each {|range| put(range)} update_bounds self end
Returns true
if all elements of this IntervalSet
are included by the other object.
IntervalSet[0...1] <= IntervalSet[0...1] # -> true IntervalSet[0...1] <= IntervalSet[0...1, 2...3] # -> true IntervalSet[0...1, 2...3] <= IntervalSet[0...1] # -> false IntervalSet[0...1, 2...3] <= IntervalSet[0...3] # -> true # You can also supply ranges IntervalSet[0...1, 2...3].subset?(0...3) # -> true
@param other [Range | IntervalSet] the other object.
# File lib/interval_set.rb, line 195 def subset?(other) case other when Range subset_range?(other) when IntervalSet other.superset_interval_set?(self) else IntervalSet.unexpected_object(other) end end
Returns true
if this IntervalSet
includes all elements of the other object.
IntervalSet[0...1] >= IntervalSet[0...1] # -> true IntervalSet[0...2] >= IntervalSet[0...1] # -> true IntervalSet[0...1] >= IntervalSet[0...1, 2...3] # -> false IntervalSet[0...3] >= IntervalSet[0...1, 2...3] # -> true # You can also supply ranges IntervalSet[0...2].superset?(0...1) # -> true
@param other [Range | IntervalSet] the other object.
# File lib/interval_set.rb, line 170 def superset?(other) case other when Range superset_range?(other) when IntervalSet superset_interval_set?(other) else IntervalSet.unexpected_object(other) end end
Returns a String representation of this IntervalSet
.
IntervalSet[].to_s # -> "[]" IntervalSet[0...1].to_s # -> "[0...1]" IntervalSet[0...1, 2...3].to_s # -> "[0...1, 2...3]"
@return [String] the String representation.
# File lib/interval_set.rb, line 654 def to_s string_io = StringIO.new last_index = count - 1 string_io << '[' each_with_index do |range, i| string_io << range string_io << ', ' if i < last_index end string_io << ']' string_io.string end
Joins the other object's elements with this IntervalSet
. The result is stored in a new IntervalSet
.
IntervalSet[0...1, 2...3] | IntervalSet[1...2, 4...5] # -> [0...3, 4...5]
Note that using add
or union!
is more efficient than +=
or |=
.
@param other [Range, IntervalSet] the other object. @return [IntervalSet] a new IntervalSet
containing the union.
# File lib/interval_set.rb, line 412 def union(other) case other when Range union_range(other) when IntervalSet union_interval_set(other) else IntervalSet.unexpected_object(other) end end
Calculates a new IntervalSet
which only contains elements exclusively from either this or the given object.
This operation is equivalent to (self | other) - (self & other)
IntervalSet[0...1] ^ IntervalSet[1...2] # -> [0...2] IntervalSet[0...2, 4...6] ^ IntervalSet[1...5, 7...8] # -> [0...1, 2...4, 5...6, 7...8] IntervalSet[0...1] ^ IntervalSet[0...1] # -> []
@param other [Range, IntervalSet] @return [IntervalSet] a new IntervalSet
containing the exclusive set.
# File lib/interval_set.rb, line 460 def xor(other) clone.xor!(other) end
Calculates the set which contains elements exclusively from either this or the given object. The result of this operation is stored in this set.
The resulting set is equivalent to (self | other) - (self & other)
IntervalSet[0...1].xor!(IntervalSet[1...2]) # -> [0...2] IntervalSet[0...2, 4...6].xor!(IntervalSet[1...5, 7...8]) # -> [0...1, 2...4, 5...6, 7...8] IntervalSet[0...1].xor!(IntervalSet[0...1]) # -> []
@param other [Range, IntervalSet] @return [IntervalSet] a new IntervalSet
containing the exclusive set.
# File lib/interval_set.rb, line 478 def xor!(other) intersection = self & other add(other).remove(intersection) end
Protected Instance Methods
# File lib/interval_set.rb, line 835 def add_interval_set(interval_set) return self if interval_set == self || interval_set.empty? interval_set.each {|range| add_range(range)} self end
# File lib/interval_set.rb, line 778 def add_range(range) # ignore empty or reversed ranges return self if IntervalSet.range_empty?(range) # short cut unless bounds_intersected_or_touched_by?(range) put_and_update_bounds(range) return self end # short cut if subset_range?(range) clear put_and_update_bounds(range) return self end # range.first <= core.min <= range.last core = @range_map.sub_map(range.first, true, range.last, true) # short cut if range already included if !core.empty? && core.first_entry == core.last_entry core_range = core.first_entry.value return self if core_range.first == range.first && core_range.last == range.last end # left.min < range.first left_entry = @range_map.lower_entry(range.first) # right.min <= range.last right_entry = core.empty? ? left_entry : core.last_entry # determine boundaries # left.max >= range.first include_left = !left_entry.nil? && left_entry.value.last >= range.first # right.max > range.last include_right = !right_entry.nil? && right_entry.value.last > range.last left_boundary = include_left ? left_entry.key : range.first right_boundary = include_right ? right_entry.value.last : range.last @range_map.remove(left_boundary) if include_left core.keys.each {|key| @range_map.remove(key)} # add range if !include_left && !include_right put_and_update_bounds(range) else put_and_update_bounds(left_boundary...right_boundary) end self end
# File lib/interval_set.rb, line 997 def convolve_interval_set!(interval_set) interval_sets = interval_set.map {|range| clone.convolve_range!(range)} clear interval_sets.each {|rs| add_interval_set(rs)} self end
# File lib/interval_set.rb, line 989 def convolve_range!(range) if IntervalSet.range_empty?(range) clear else buffer!(-range.first, range.last) end end
# File lib/interval_set.rb, line 960 def difference_interval_set(interval_set) new_interval_set = IntervalSet.new return new_interval_set if interval_set == self || empty? new_interval_set.copy(self) new_interval_set.remove_interval_set(interval_set) if !interval_set.empty? && bounds_intersected_by?(interval_set.bounds) new_interval_set end
# File lib/interval_set.rb, line 947 def difference_range(range) new_interval_set = IntervalSet.new return new_interval_set if subset_range?(range) return new_interval_set.copy(self) unless bounds_intersected_by?(range) unless IntervalSet.range_empty?(range) new_interval_set.add_interval_set(head_set(range.first)) new_interval_set.add_interval_set(tail_set(range.last)) new_interval_set.remove_range(range) end end
# File lib/interval_set.rb, line 740 def eql_range?(range) return true if empty? && IntervalSet.range_empty?(range) count == 1 && bounds == range end
# File lib/interval_set.rb, line 759 def head_set(value) head_map = @range_map.head_map(value) IntervalSet.allocate.initialize_with_range_map(head_map) end
# File lib/interval_set.rb, line 673 def initialize_with_range_map(range_map) @range_map = range_map update_bounds self end
# File lib/interval_set.rb, line 912 def intersect_interval_set(interval_set) return self if interval_set == self if interval_set.empty? || !bounds_intersected_by?(interval_set.bounds) clear return self end intersection = interval_set.sub_set(bounds).map do |range| IntervalSet.new.tap do |interval_set_item| interval_set_item.add_interval_set(sub_set(range)) interval_set_item.intersect_range(range) end end.reduce(IntervalSet.new) do |acc, interval_set_item| acc.add_interval_set(interval_set_item); acc end @range_map = intersection.range_map @min = intersection.min @max = intersection.max self end
# File lib/interval_set.rb, line 734 def intersect_interval_set?(interval_set) return false if empty? || !bounds_intersected_by?(interval_set.bounds) sub_set(interval_set.bounds).any? {|range| intersect_range?(range)} end
# File lib/interval_set.rb, line 879 def intersect_range(range) unless bounds_intersected_by?(range) clear return self end return self if subset_range?(range) # left_map.min < range.first left_map = @range_map.head_map(range.first, false) # right_map.min >= range.last right_map = @range_map.tail_map(range.last, true) # left.min < range.first left_entry = left_map.last_entry # right.min < range.last right_entry = @range_map.lower_entry(range.last) # left.max > range.first include_left = !left_entry.nil? && left_entry.value.last > range.first # right.max > right.max include_right = !right_entry.nil? && right_entry.value.last > range.last left_map.keys.each {|key| @range_map.remove(key)} right_map.keys.each {|key| @range_map.remove(key)} put(range.first...[left_entry.value.last, range.last].min) if include_left put([right_entry.key, range.first].max...range.last) if include_right update_bounds self end
# File lib/interval_set.rb, line 724 def intersect_range?(range) return false unless bounds_intersected_by?(range) # left.min < range.last left_entry = @range_map.lower_entry(range.last) # left.max > range.first !left_entry.nil? && left_entry.value.last > range.first end
# File lib/interval_set.rb, line 980 def intersection_interval_set(interval_set) new_interval_set = IntervalSet.new return new_interval_set if interval_set.empty? || !bounds_intersected_by?(interval_set.bounds) new_interval_set.add_interval_set(self) new_interval_set.intersect_interval_set(interval_set) end
# File lib/interval_set.rb, line 970 def intersection_range(range) new_interval_set = IntervalSet.new return new_interval_set unless bounds_intersected_by?(range) return new_interval_set.copy(self) if subset_range?(range) new_interval_set.add(sub_set(range)) new_interval_set.intersect_range(range) end
# File lib/interval_set.rb, line 683 def put(range) @range_map.put(range.first, IntervalSet.normalize_range(range)) end
# File lib/interval_set.rb, line 687 def put_and_update_bounds(range) put(range) if @min.nil? && @max.nil? @min = range.first @max = range.last else @min = [range.first, @min].min @max = [range.last, @max].max end end
# File lib/interval_set.rb, line 679 def range_map @range_map end
# File lib/interval_set.rb, line 869 def remove_interval_set(interval_set) if interval_set == self clear else interval_set.each {|range| remove_range(range)} end self end
# File lib/interval_set.rb, line 843 def remove_range(range) return self unless bounds_intersected_by?(range) # range.first <= core.min <= range.last core = @range_map.sub_map(range.first, true, range.last, false) # left.min < range.first left_entry = @range_map.lower_entry(range.first) # right.min < range.last right_entry = core.empty? ? left_entry : core.last_entry # left.max > range.to include_left = !left_entry.nil? && left_entry.value.last > range.first # right.max > range.last include_right = !right_entry.nil? && right_entry.value.last > range.last core.keys.each {|key| @range_map.remove(key)} # right first since right might be same as left put(range.last...right_entry.value.last) if include_right put(left_entry.key...range.first) if include_left update_bounds self end
# File lib/interval_set.rb, line 746 def sub_set(range) # left.min < range.first left_entry = @range_map.lower_entry(range.first) # left.max > range.first include_left = !left_entry.nil? && left_entry.value.last > range.first bound_min = include_left ? left_entry.value.first : range.first sub_map = @range_map.sub_map(bound_min, range.last) IntervalSet.allocate.initialize_with_range_map(sub_map) end
# File lib/interval_set.rb, line 717 def subset_range?(range) return true if empty? return false if IntervalSet.range_empty?(range) empty? || (range.first <= min && range.last >= max) end
# File lib/interval_set.rb, line 710 def superset_interval_set?(interval_set) return true if interval_set == self || interval_set.empty? return false if empty? || !interval_set.bounds_intersected_by?(bounds) interval_set.all? {|range| superset_range?(range)} end
# File lib/interval_set.rb, line 699 def superset_range?(range) return true if IntervalSet.range_empty?(range) return false if empty? || !bounds_intersected_by?(range) # left.min <= range.first left_entry = @range_map.floor_entry(range.first) # left.max >= range.last !left_entry.nil? && left_entry.value.last >= range.last end
# File lib/interval_set.rb, line 765 def tail_set(value) # left.min < value left_entry = @range_map.lower_entry(value) # left.max > value include_left = !left_entry.nil? && left_entry.value.last > value bound_min = include_left ? left_entry.value.first : value tail_map = @range_map.tail_map(bound_min) IntervalSet.allocate.initialize_with_range_map(tail_map) end
# File lib/interval_set.rb, line 942 def union_interval_set(interval_set) new_interval_set = clone new_interval_set.add_interval_set(interval_set) end
# File lib/interval_set.rb, line 936 def union_range(range) new_interval_set = IntervalSet.new new_interval_set.add_interval_set(self) unless subset_range?(range) new_interval_set.add_range(range) end
Private Instance Methods
# File lib/interval_set.rb, line 1007 def update_bounds if empty? @min = nil @max = nil else @min = @range_map.first_entry.value.first @max = @range_map.last_entry.value.last end end