Class: RubyTorrent::Covering

Inherits:
Object
  • Object
show all
Defined in:
lib/rubytorrent/package.rb

Overview

a Covering is a set of non-overlapping ranges within a given start point and endpoint.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(domain, ranges = []) ⇒ Covering

‘domain’ should be an AwesomeRange determining the start and end point. ‘ranges’ should be an array of non-overlapping AwesomeRanges sorted by start point.



108
109
110
111
# File 'lib/rubytorrent/package.rb', line 108

def initialize(domain, ranges=[])
  @domain = domain
  @ranges = ranges
end

Instance Attribute Details

#domainObject

Returns the value of attribute domain.



103
104
105
# File 'lib/rubytorrent/package.rb', line 103

def domain
  @domain
end

#rangesObject

Returns the value of attribute ranges.



103
104
105
# File 'lib/rubytorrent/package.rb', line 103

def ranges
  @ranges
end

Instance Method Details

#==(o) ⇒ Object



194
# File 'lib/rubytorrent/package.rb', line 194

def ==(o); o.domain == self.domain && o.ranges == self.ranges; end

#complete!Object



113
# File 'lib/rubytorrent/package.rb', line 113

def complete!; @ranges = [@domain]; self; end

#complete?Boolean

Returns:

  • (Boolean)


114
# File 'lib/rubytorrent/package.rb', line 114

def complete?; @ranges == [@domain]; end

#empty!Object



115
# File 'lib/rubytorrent/package.rb', line 115

def empty!; @ranges = []; self; end

#empty?Boolean

Returns:

  • (Boolean)


116
# File 'lib/rubytorrent/package.rb', line 116

def empty?; @ranges == []; end

#fill(r) ⇒ Object

given a covering of size N and a new range ‘r’, returns a covering of size 0 < s <= N + 1 that also covers the range ‘r’.

Raises:

  • (ArgumentError)


134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/rubytorrent/package.rb', line 134

def fill(r)
  raise ArgumentError, "#{r} outside of domain #@domain" unless @domain.rss? r
  Covering.new(@domain, @ranges.inject([]) do |set, x|
    ## r contains the result of the continuing merge. if r is nil,
    ## then we've already added it, so we just copy x.
    if r.nil? then set + [x] else
      ## otoh, if r is there, we try and merge in the current
      ## element.
      if r.rcont? x
        ## if we can merge, keep the union in r and don't add
        ## anything
        r = r.runion x
        set
      ## if we can't merge it, we'll see if it's time to add it. we
      ## know that r and x don't overlap because r.mergable?(x) was
      ## false, so we can simply compare the start points to see
      ## whether it should come before x.
      elsif r.first < x.first
        s = set + [r, x] # add both 
        r = nil
        s
      else set + [x] ## no merging or adding, so we just copy x.
      end
    end
  ## if 'r' still hasn't been added, it should be the last element,
  ## we add it here.
  end.push(r).compact)
end

#first_gap(domain = @domain) ⇒ Object

given an array of non-overlapping ranges sorted by start point, and a range ‘domain’, returns the first range from ‘domain’ not covered by any range in the array.



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/rubytorrent/package.rb', line 166

def first_gap(domain=@domain)
  start = domain.first
  endd = nil
  excl = nil
  @ranges.each do |r|
    next if r.last < start

    if r.first > start # found a gap
      if r.first < domain.last
        return AwesomeRange.new(start, r.first, false)
      else # r.first >= domain.last, so use domain's exclusion
        return AwesomeRange.new(start, domain.last, domain.exclude_end?)
      end
    else # r.first <= start
      start = r.last unless r.last < start
      break if start > domain.last
    end
  end

  if (start >= domain.last)
    ## entire domain was covered
    nil
  else
    ## tail end of the domain uncovered
    AwesomeRange.new(start, domain.last, domain.exclude_end?)
  end
end

#poke(r) ⇒ Object

given a covering of size N and a new range ‘r’, returns a covering of size 0 <= s <= N + 1 that doesn’t cover the range given by ‘r’.

Raises:

  • (ArgumentError)


121
122
123
124
125
126
127
128
129
130
# File 'lib/rubytorrent/package.rb', line 121

def poke(r)
  raise ArgumentError, "#{r} outside of domain #@domain" unless @domain.rss? r
  Covering.new(@domain, @ranges.inject([]) do |set, x|
    if x.rint(r) != nil
      set + x.rdiff(r)
    else
      set + [x]
    end
  end)
end