# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
require 'narray'
+require 'pp'
BitsInChar = 8
# Method to set a bit to 1 at a given position in the bit array.
def bit_set(pos)
- raise BitArrayError, "Position #{pos} must be an integer." unless pos.is_a? Fixnum
- raise BitArrayError, "Position #{pos} outside of range: 0 ... #{@size}" unless (0 ... @size ).include? pos
+ raise BitArrayError, "Position #{pos} must be an integer." unless pos.is_a? Fixnum
+ raise BitArrayError, "Position #{pos} outside of range: 0 ... #{@size - 1}" unless (0 ... @size ).include? pos
@byte_array[byte_pos(pos)] = @byte_array[byte_pos(pos)] | bit_pos(pos)
end
# Method to set a bit to 0 at a given position in the bit array.
def bit_unset(pos)
- raise BitArrayError, "Position #{pos} must be an integer." unless pos.is_a? Fixnum
- raise BitArrayError, "Position #{pos} outside of range: 0 ... #{@size}" unless (0 ... @size ).include? pos
+ raise BitArrayError, "Position #{pos} must be an integer." unless pos.is_a? Fixnum
+ raise BitArrayError, "Position #{pos} outside of range: 0 ... #{@size - 1}" unless (0 ... @size ).include? pos
mask = bit_pos(pos)
mask = ~mask
# Method to check if a bit at a given position in the bit array is set.
def bit_set?(pos)
- raise BitArrayError, "Position #{pos} must be an integer." unless pos.is_a? Fixnum
- raise BitArrayError, "Position #{pos} outside of range: 0 ... #{@size}" unless (0 ... @size ).include? pos
+ raise BitArrayError, "Position #{pos} must be an integer." unless pos.is_a? Fixnum
+ raise BitArrayError, "Position #{pos} outside of range: 0 ... #{@size - 1}" unless (0 ... @size ).include? pos
(@byte_array[byte_pos(pos)] & bit_pos(pos)) != 0
end
# Method that returns the number of bits set "on" in a bit array.
- def bits_on
- bits_on = 0
-
- self.byte_array.each do |byte|
- bits_on += @count_array[byte]
- end
-
- bits_on
+ def bits_on
+ index = NArray.sint(*self.byte_array.shape)
+ index[] = self.byte_array
+ NArray.to_na(@count_array)[index].sum
end
# Method that returns the number of bits set "off" in a bit array.
# Method to set the bits to "on" in an interval in a bit array.
# Returns the number of bits set.
def interval_set(start, stop)
- raise BitArrayError, "interval start < 0 (#{start} < 0)" if start < 0
- raise BitArrayError, "interval stop > bit array size (#{stop} > #{self.size})" if stop > self.size
- raise BitArrayError, "interval stop < interval start (#{stop} < #{start})" if stop < start
+ raise BitArrayError, "interval start < 0 (#{start} < 0)" if start < 0
+ raise BitArrayError, "interval stop > bit array size - 1 (#{stop} > #{self.size - 1})" if stop > self.size - 1
+ raise BitArrayError, "interval stop < interval start (#{stop} < #{start})" if stop < start
+
+ byte_start = start / BitsInChar
+ byte_stop = stop / BitsInChar
+
+ bits_start = start % BitsInChar
+ bits_stop = stop % BitsInChar
+
+ mask = (2 ** BitsInChar) - 1 # 11111111
+
+ if byte_start == byte_stop
+ self.byte_array[byte_start] |= ((mask >> bits_start) & (mask << (BitsInChar - bits_stop - 1)))
+ else
+ if bits_start != 0
+ self.byte_array[byte_start] |= (mask >> bits_start)
+ byte_start += 1
+ end
- (start ... stop).each do |pos|
- self.bit_set(pos)
+ self.byte_array[byte_stop] |= (mask << (BitsInChar - bits_stop - 1))
+
+ if byte_start != byte_stop
+ self.byte_array[byte_start ... byte_stop] = mask
+ end
end
- stop - start
+ stop - start + 1
end
# Method to set the bits to "off" in an interval in a bit array.
# Returns the number of bits unset.
def interval_unset(start, stop)
- raise BitArrayError, "interval start < 0 (#{start} < 0)" if start < 0
- raise BitArrayError, "interval stop > bit array size (#{stop} > #{self.size})" if stop > self.size
- raise BitArrayError, "interval stop < interval start (#{stop} < #{start})" if stop < start
+ raise BitArrayError, "interval start < 0 (#{start} < 0)" if start < 0
+ raise BitArrayError, "interval stop > bit array size - 1 (#{stop} > #{self.size - 1})" if stop > self.size - 1
+ raise BitArrayError, "interval stop < interval start (#{stop} < #{start})" if stop < start
+
+ byte_start = start / BitsInChar
+ byte_stop = stop / BitsInChar
+
+ bits_start = start % BitsInChar
+ bits_stop = stop % BitsInChar
- (start ... stop).each do |pos|
- self.bit_unset(pos)
+ mask = (2 ** BitsInChar) - 1 # 11111111
+
+ if byte_start == byte_stop
+ self.byte_array[byte_start] &= ~((mask >> bits_start) & (mask << (BitsInChar - bits_stop - 1)))
+ else
+ if bits_start != 0
+ self.byte_array[byte_start] &= ~(mask >> bits_start)
+ byte_start += 1
+ end
+
+ self.byte_array[byte_stop] &= ~(mask << (BitsInChar - bits_stop - 1))
+
+ if byte_start != byte_stop
+ self.byte_array[byte_start ... byte_stop] = ~mask
+ end
end
- stop - start
+ stop - start + 1
end
# Method to locate intervals of bits set to "on" in a bit array.
# BitArray.each_interval { |start, stop| } -> Fixnum
def each_interval
intervals = []
- start = 0
- stop = 0
+ bit_start = 0
+ bit_stop = 0
- while start < self.size
- if self.bit_set?(start)
- stop = start
+ while bit_start < self.size
+ bit_start += 1 while bit_start < self.size and not self.bit_set?(bit_start)
- while stop < self.size and self.bit_set?(stop)
- stop += 1
- end
+ if bit_start < self.size
+ bit_stop = bit_start
+ bit_stop += 1 while bit_stop < self.size and self.bit_set?(bit_stop)
if block_given?
- yield start, stop
+ yield bit_start, bit_stop - 1
else
- intervals << [start, stop]
+ intervals << [bit_start, bit_stop - 1]
end
- end
- stop > start ? start = stop : start += 1
+ bit_start = bit_stop + 1
+ end
end
return intervals unless block_given?