class QuartzTorrent::Bitfield

A bitfield that allows querying and setting individual bits, as well as serializing and unserializing.

Attributes

length[R]

Length of the Bitfield in bits.

Public Class Methods

new(length) click to toggle source

Create a bitfield of length ‘length’ in bits.

# File lib/quartz_torrent/bitfield.rb, line 43
def initialize(length)
  @length = length
  if @length == 0
    @data = Array.new(0)
  else
    @data = Array.new((length-1)/8+1, 0)
  end
end

Public Instance Methods

allClear?() click to toggle source

Are all bits in the Bitfield clear?

# File lib/quartz_torrent/bitfield.rb, line 114
def allClear?
  # Check all but last byte quickly
  (@data.length-1).times do |i|
    return false if @data[i] != 0
  end
  # Check last byte slowly
  toCheck = @length % 8
  toCheck = 8 if toCheck == 0
  ((@length-toCheck)..(@length-1)).each do |i|
    return false if set?(i)
  end
  true
end
allSet?() click to toggle source

Are all bits in the Bitfield set?

# File lib/quartz_torrent/bitfield.rb, line 99
def allSet?
  # Check all but last byte quickly
  (@data.length-1).times do |i|
    return false if @data[i] != 0xff
  end
  # Check last byte slowly
  toCheck = @length % 8
  toCheck = 8 if toCheck == 0
  ((@length-toCheck)..(@length-1)).each do |i|
    return false if ! set?(i)
  end
  true
end
byteLength() click to toggle source

Length of the Bitfield in bytes.

# File lib/quartz_torrent/bitfield.rb, line 68
def byteLength
  @data.length
end
clear(bit) click to toggle source

Clear the bit at index ‘bit’ to 0.

# File lib/quartz_torrent/bitfield.rb, line 83
def clear(bit)
  quotient = bit >> 3
  remainder = bit & 0x7
  mask = ~(0x80 >> remainder)
  
  raise "Bit #{bit} out of range of bitfield with length #{length}" if quotient >= @data.length
  @data[quotient] &= mask
end
clearAll() click to toggle source

Clear all bits in the field to 0.

# File lib/quartz_torrent/bitfield.rb, line 134
def clearAll
  @data.fill(0x00)
end
compliment() click to toggle source

Calculate the compliment of this bitfield, and return the result as a new bitfield.

# File lib/quartz_torrent/bitfield.rb, line 184
def compliment
  bitfield = Bitfield.new(length)
  bitfield.copyFrom(self)
  bitfield.compliment!
end
compliment!() click to toggle source

Update this bitfield to be the compliment of itself.

# File lib/quartz_torrent/bitfield.rb, line 191
def compliment!
  @data.collect!{ |e| ~e }
  self
end
copyFrom(bitfield) click to toggle source

Set the contents of this bitfield to be the same as the passed bitfield. An exception is thrown if the passed bitfield is smaller than this.

# File lib/quartz_torrent/bitfield.rb, line 175
def copyFrom(bitfield)
  raise "Source bitfield is too small (#{bitfield.length} < #{length})" if bitfield.length < length
  (@data.length).times do |i|
    @data[i] = bitfield.data[i]
  end
end
countSet() click to toggle source

Count the number of bits that are set.

# File lib/quartz_torrent/bitfield.rb, line 218
def countSet
  @data.reduce(0){ |memo, v| memo + @@bitsSetInByteLookup[v] }
end
intersection(bitfield) click to toggle source

Calculate the intersection of this bitfield and the passed bitfield, and return the result as a new bitfield.

# File lib/quartz_torrent/bitfield.rb, line 153
def intersection(bitfield)
  raise "That's not a bitfield" if ! bitfield.is_a?(Bitfield)
  raise "bitfield lengths must be equal" if ! bitfield.length == length

  newbitfield = Bitfield.new(length)
  newbitfield.copyFrom(self)
  newbitfield.intersection!(bitfield)
end
intersection!(bitfield) click to toggle source

Update this bitfield to be the intersection of this bitfield and the passed bitfield.

# File lib/quartz_torrent/bitfield.rb, line 163
def intersection!(bitfield)
  raise "That's not a bitfield" if ! bitfield.is_a?(Bitfield)
  raise "bitfield lengths must be equal" if ! bitfield.length == length
    
  (@data.length).times do |i|
    @data[i] = @data[i] & bitfield.data[i]
  end
  self
end
length=(l) click to toggle source

Adjust the length of the bitfield. This might be necessary if we had to unserialize the bitfield from a serialized array of bytes.

# File lib/quartz_torrent/bitfield.rb, line 57
def length=(l)
  byteLen = 0
  byteLen = (l-1)/8+1 if l > 0

  raise "Length adjustment would change size of underlying array" if byteLen != byteLength

  @length = l
end
serialize() click to toggle source

Serialize this bitfield as a string.

# File lib/quartz_torrent/bitfield.rb, line 197
def serialize
  @data.pack "C*"
end
set(bit) click to toggle source

Set the bit at index ‘bit’ to 1.

# File lib/quartz_torrent/bitfield.rb, line 73
def set(bit)
  quotient = bit >> 3
  remainder = bit & 0x7
  mask = 0x80 >> remainder

  raise "Bit #{bit} out of range of bitfield with length #{length}" if quotient >= @data.length
  @data[quotient] |= mask
end
set?(bit) click to toggle source

Returns true if the bit is set, false otherwise.

# File lib/quartz_torrent/bitfield.rb, line 93
def set?(bit)
  #raise "Bit #{bit} out of range of bitfield with length #{length}" if quotient >= @data.length
  (@data[bit >> 3] << (bit & 0x7)) & 0x80 > 0
end
setAll() click to toggle source

Set all bits in the field to 1.

# File lib/quartz_torrent/bitfield.rb, line 129
def setAll
  @data.fill(0xff)
end
to_s(groupsOf = 8) click to toggle source

Return a display string representing the bitfield.

# File lib/quartz_torrent/bitfield.rb, line 207
def to_s(groupsOf = 8)
  groupsOf = 8 if groupsOf == 0
  s = ""
  length.times do |i|
    s << (set?(i) ? "1" : "0")
    s << " " if i % groupsOf == 0
  end
  s
end
union(bitfield) click to toggle source

Calculate the union of this bitfield and the passed bitfield, and return the result as a new bitfield.

# File lib/quartz_torrent/bitfield.rb, line 140
def union(bitfield)
  raise "That's not a bitfield" if ! bitfield.is_a?(Bitfield)
  raise "bitfield lengths must be equal" if ! bitfield.length == length

  result = Bitfield.new(length)
  (@data.length).times do |i|
    result.data[i] = @data[i] | bitfield.data[i]
  end
  result
end
unserialize(s) click to toggle source

Unserialize this bitfield from a string.

# File lib/quartz_torrent/bitfield.rb, line 202
def unserialize(s)
  @data = s.unpack "C*"
end

Protected Instance Methods

data() click to toggle source
# File lib/quartz_torrent/bitfield.rb, line 223
def data
  @data
end