From: martinahansen Date: Fri, 14 Jan 2011 16:26:18 +0000 (+0000) Subject: added bitarray ruby code X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=706bc94141a46896ebd8b404292526c96000e750;p=biopieces.git added bitarray ruby code git-svn-id: http://biopieces.googlecode.com/svn/trunk@1202 74ccb610-7750-0410-82ae-013aeee3265d --- diff --git a/code_ruby/Maasha/lib/bitarray.rb b/code_ruby/Maasha/lib/bitarray.rb new file mode 100644 index 0000000..5533c52 --- /dev/null +++ b/code_ruby/Maasha/lib/bitarray.rb @@ -0,0 +1,158 @@ +BitsInChar = 8 + +# Error class for all exceptions to do with BitArray. +class BitArrayError < StandardError; end + +# Class containing methods for creating and manipulating a bit array. +class BitArray + attr_reader :size, :byte_array + + # Method to initialize a new bit array of a given size. + def initialize(size) + @size = size + @byte_array = init_byte_array + @count_table = init_count_table + end + + # 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 + + @byte_array[byte_pos(pos)] = (@byte_array[byte_pos(pos)].ord | bit_pos(pos)).chr + end + + # 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 + + (@byte_array[byte_pos(pos)].ord & bit_pos(pos)) != 0 + end + + # Method that returns the number of bits set "on" in a bit array. + def bits_on1 + bits_on = 0 + + (0 ... @size).each do |pos| + bits_on += 1 if bit_set?(pos) + end + + bits_on + end + + # Method that returns the number of bits set "on" in a bit array. + def bits_on + bits_on = 0 + + (0 ... self.byte_array.size).each do |byte| + bits_on += @count_table[byte] + end + + bits_on + end + + # Method that returns the number of bits set "off" in a bit array. + def bits_off + @size - bits_on + end + + # Method to run bitwise AND (&) on two bit arrays and return the + # result in a new bit array. Bits are copied if they exists in BOTH operands. + # 00111100 & 00001101 = 00001100 + def &(ba) + raise BitArrayError, "uneven size of bit arrays: #{self.size} vs #{ba.size}" if self.size != ba.size + + result = BitArray.new(ba.size) + + (0 ... ba.byte_array.size).each do |byte| + result.byte_array[byte] = (self.byte_array[byte].ord & ba.byte_array[byte].ord).chr + end + + result + end + + # Method to run bitwise OR (|) on two bit arrays and return the + # result in a new bit array. Bits are copied if they exists in EITHER operands. + # 00111100 | 00001101 = 00111101 + def |(ba) + raise BitArrayError, "uneven size of bit arrays: #{self.size} vs #{ba.size}" if self.size != ba.size + + result = BitArray.new(ba.size) + + (0 ... ba.byte_array.size).each do |byte| + result.byte_array[byte] = (self.byte_array[byte].ord | ba.byte_array[byte].ord).chr + end + + result + end + + # Method to run bitwise XOR (^) on two bit arrays and return the + # result in a new bit array. Bits are copied if they exists in ONE BUT NOT BOTH operands. + # 00111100 ^ 00001101 = 00110001 + def ^(ba) + raise BitArrayError, "uneven size of bit arrays: #{self.size} vs #{ba.size}" if self.size != ba.size + + result = BitArray.new(ba.size) + + (0 ... ba.byte_array.size).each do |byte| + result.byte_array[byte] = (self.byte_array[byte].ord ^ ba.byte_array[byte].ord).chr + end + + result + end + + # Method to convert a bit array to a string. + def to_s + string = "" + + (0 ... @size).each do |pos| + if self.bit_set? pos + string << "1" + else + string << "0" + end + end + + string + end + + private + + # Method to initialize the byte array (string) that constitutes the bit array. + def init_byte_array + raise BitArrayError, "Size must be an integer, not #{@size}" unless @size.is_a? Fixnum + raise BitArrayError, "Size must be positive, not #{@size}" unless @size > 0 + + byte_array = "" + byte_array << 0.chr * (((@size - 1) / BitsInChar) + 1) + + byte_array + end + + # Method that creates a table with number of bits set. + def init_count_table + count_table = [] + + bits = 0 + + (0 ... BitsInChar).each do |i| + (0 ... BitsInChar).each do |c| + bits += 1 + end + end + + puts bits + end + + # Method that returns the byte position in the byte array for a given bit position. + def byte_pos(pos) + pos / BitsInChar + end + + # Method that returns the bit position in a byte. + def bit_pos(pos) + 1 << (BitsInChar - 1 - (pos % BitsInChar)) + end +end + diff --git a/code_ruby/Maasha/test/test_bitarray.rb b/code_ruby/Maasha/test/test_bitarray.rb new file mode 100755 index 0000000..c077932 --- /dev/null +++ b/code_ruby/Maasha/test/test_bitarray.rb @@ -0,0 +1,116 @@ +#!/usr/bin/env ruby + +require 'bitarray' +require 'test/unit' +require 'pp' + +class TestBitArray < Test::Unit::TestCase + def setup + @ba = BitArray.new(10) + end + + def test_BitArray_initialize_raises_on_bad_sizes + [ -1, 0, 1.1, "a" ].each do |size| + assert_raise(BitArrayError) { BitArray.new(size) } + end + end + + def test_BitArray_initialize_dont_raise_on_ok_sizes + [ 1, 10, 1000 ].each do |size| + assert_nothing_raised { BitArray.new(size) } + end + end + + def test_BitArray_size_returns_correctly + assert_equal(10, @ba.size) + end + + def test_BitArray_to_s_returns_correctly + assert_equal("0000000000", @ba.to_s) + end + + def test_BitArray_bit_set_with_bad_pos_raises + [-1, 10, 1.1].each do |pos| + assert_raise(BitArrayError) { @ba.bit_set(pos) } + end + end + + def test_BitArray_bit_set + str = "0000000000" + + (0.upto 9).each do |pos| + @ba.bit_set(pos) + str[pos] = "1" + assert_equal(str, @ba.to_s) + end + end + + def test_BitArray_bit_set_questionmark_with_bad_pos_raises + [-1, 10, 1.1].each do |pos| + assert_raise(BitArrayError) { @ba.bit_set?(pos) } + end + end + + def test_BitArray_bit_set_questionmark + (0.upto 9).each do |pos| + @ba.bit_set(pos) + assert_equal(true, @ba.bit_set?(pos)) + end + end + + def test_BitArray_bits_on_returns_correctly + @ba.bit_set(4) + assert_equal(1, @ba.bits_on) + end + + def test_BitArray_bits_off_returns_correctly + @ba.bit_set(4) + assert_equal(9, @ba.bits_off) + end + + def test_BitArray_and_with_uneven_sizes_raises + ba = BitArray.new(11) + assert_raise(BitArrayError) { @ba & ba } + end + + def test_BitArray_AND_returns_correctly + ba = BitArray.new(10) + @ba.bit_set(4) + @ba.bit_set(5) + ba.bit_set(5) + ba.bit_set(6) + assert_equal( "0000010000", (@ba & ba).to_s) + end + + def test_BitArray_AND_EQUAL_returns_correctly + ba = BitArray.new(10) + @ba.bit_set(4) + @ba.bit_set(5) + ba.bit_set(5) + ba.bit_set(6) + @ba &= ba + assert_equal( "0000010000", @ba.to_s) + end + + def test_BitArray_OR_returns_correctly + ba = BitArray.new(10) + @ba.bit_set(4) + @ba.bit_set(5) + ba.bit_set(5) + ba.bit_set(6) + assert_equal( "0000111000", (@ba | ba).to_s) + end + + def test_BitArray_XOR_returns_correctly + ba = BitArray.new(10) + @ba.bit_set(4) + @ba.bit_set(5) + ba.bit_set(5) + ba.bit_set(6) + assert_equal( "0000101000", (@ba ^ ba).to_s) + end +end + + +__END__ +