class QuartzTorrent::Bitfield
A bitfield that allows querying and setting individual bits, as well as serializing and unserializing.
Attributes
Length of the Bitfield
in bits.
Public Class Methods
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
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
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
Length of the Bitfield
in bytes.
# File lib/quartz_torrent/bitfield.rb, line 68 def byteLength @data.length end
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
Clear all bits in the field to 0.
# File lib/quartz_torrent/bitfield.rb, line 134 def clearAll @data.fill(0x00) end
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
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
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
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
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
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
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 this bitfield as a string.
# File lib/quartz_torrent/bitfield.rb, line 197 def serialize @data.pack "C*" end
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
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
Set all bits in the field to 1.
# File lib/quartz_torrent/bitfield.rb, line 129 def setAll @data.fill(0xff) end
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
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 this bitfield from a string.
# File lib/quartz_torrent/bitfield.rb, line 202 def unserialize(s) @data = s.unpack "C*" end
Protected Instance Methods
# File lib/quartz_torrent/bitfield.rb, line 223 def data @data end