1 # Copyright (C) 2012 Martin A. Hansen.
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # http://www.gnu.org/copyleft/gpl.html
19 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
21 # This software is part of the Biopieces framework (www.biopieces.org).
23 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
27 # Error class for all exceptions to do with Base36.
28 class BitMapError < StandardError; end
33 attr_accessor :byte_array
35 def initialize(rows, cols, byte_array = nil)
41 @byte_array_size = (rows * cols.to_f / BitsInChar).ceil
42 @byte_array = "\0" * @byte_array_size
44 @byte_array_size = (rows * cols.to_f / BitsInChar).ceil
45 @byte_array = byte_array
50 rows = rows.first.to_a if rows.first.respond_to? :to_a
51 cols = cols.first.to_a if cols.first.respond_to? :to_a
53 new_byte_array_size = (rows.size * cols.size.to_f / BitsInChar).ceil
54 new_byte_array = "\0" * new_byte_array_size
56 slice_c(new_byte_array, rows, cols)
58 BitMap.new(rows.size, cols.size, new_byte_array)
62 @rows, @cols = @cols, @rows
65 # Method to convert a bit array to a string.
69 (0 ... @size).each do |pos|
77 string.gsub(/.{#{@cols}}/, "\\0#{$/}")
81 builder.add_static "rows", 'rb_intern("@rows")', "ID"
82 builder.add_static "cols", 'rb_intern("@cols")', "ID"
83 builder.add_static "size", 'rb_intern("@size")', "ID"
84 builder.add_static "byte_array_size", 'rb_intern("@byte_array_size")', "ID"
85 builder.add_static "byte_array", 'rb_intern("@byte_array")', "ID"
88 unsigned char bit_count[256] = {
89 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
90 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
91 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
92 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
93 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
94 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
95 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
96 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
97 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
98 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
99 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
100 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
101 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
102 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
103 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
104 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
109 #define COUNT_BITS(c) (bit_count[c])
113 #define BYTE_POS(pos) (pos / CHAR_BIT)
117 #define BIT_POS(pos) (1 << (CHAR_BIT - 1 - (pos % CHAR_BIT)))
123 VALUE _size = rb_ivar_get(self, byte_array_size);
124 VALUE _byte_array = rb_ivar_get(self, byte_array);
125 int size = NUM2INT(_size);
126 unsigned char* byte_array = StringValuePtr(_byte_array);
129 for (i = 0; i < size; i++) byte_array[i] = ~0;
136 VALUE _size = rb_ivar_get(self, byte_array_size);
137 VALUE _byte_array = rb_ivar_get(self, byte_array);
138 int size = NUM2INT(_size);
139 unsigned char* byte_array = StringValuePtr(_byte_array);
142 for (i = 0; i < size; i++) byte_array[i] = 0;
147 void bit_set_c(int row, int col)
149 VALUE _rows = rb_ivar_get(self, rows);
150 VALUE _cols = rb_ivar_get(self, cols);
151 VALUE _byte_array = rb_ivar_get(self, byte_array);
152 int rows = NUM2INT(_rows);
153 int cols = NUM2INT(_cols);
154 unsigned char* byte_array = StringValuePtr(_byte_array);
158 rb_raise(rb_eval_string("BitMapError"), "row out of range: %d >= %d\\n", row, rows);
161 rb_raise(rb_eval_string("BitMapError"), "col out of range: %d >= %d\\n", col, cols);
163 pos = row * cols + col;
165 byte_array[BYTE_POS(pos)] |= BIT_POS(pos);
170 VALUE bit_test_c(int pos)
172 VALUE _byte_array = rb_ivar_get(self, byte_array);
173 unsigned char* byte_array = StringValuePtr(_byte_array);
175 return ((byte_array[BYTE_POS(pos)] & BIT_POS(pos)) != 0);
180 void slice_c(char* new_array, VALUE _new_rows, VALUE _new_cols)
182 VALUE _old_array = rb_ivar_get(self, byte_array);
183 VALUE _old_rows = rb_ivar_get(self, rows);
184 VALUE _old_cols = rb_ivar_get(self, cols);
185 unsigned char* old_array = StringValuePtr(_old_array);
186 int old_rows = NUM2INT(_old_rows);
187 int old_cols = NUM2INT(_old_cols);
189 VALUE *rows_array = RARRAY_PTR(_new_rows);
190 VALUE *cols_array = RARRAY_PTR(_new_cols);
191 int row_count = (int) RARRAY_LEN(_new_rows);
192 int col_count = (int) RARRAY_LEN(_new_cols);
198 for (r = 0; r < row_count; r++)
200 for (c = 0; c < col_count; c++)
202 old_pos = NUM2INT(rows_array[r]) * old_cols + NUM2INT(cols_array[c]);
203 new_pos = r * col_count + c;
205 new_array[BYTE_POS(new_pos)] |= BIT_POS(new_pos) & (old_array[BYTE_POS(old_pos)] & BIT_POS(old_pos));
214 VALUE _size = rb_ivar_get(self, byte_array_size);
215 VALUE _byte_array = rb_ivar_get(self, byte_array);
216 int size = NUM2INT(_size);
217 unsigned char* byte_array = StringValuePtr(_byte_array);
221 for (i = 0; i < size; i++)
222 sum += COUNT_BITS(byte_array[i]);
231 VALUE _rows = rb_ivar_get(self, rows);
232 VALUE _cols = rb_ivar_get(self, cols);
233 VALUE _byte_array = rb_ivar_get(self, byte_array);
234 int rows = NUM2INT(_rows);
235 int cols = NUM2INT(_cols);
236 unsigned char* byte_array = StringValuePtr(_byte_array);
240 VALUE rb_sums = rb_ary_new();
244 for (row = 0; row < rows; row++) sums[row] = 0;
246 for (row = 0; row < rows; row++)
248 for (col = 0; col < cols; col++)
250 pos = row * cols + col;
251 sums[row] += ((byte_array[BYTE_POS(pos)] & BIT_POS(pos)) != 0);
255 for (row = 0; row < rows; row++) rb_ary_push(rb_sums, INT2FIX(sums[row]));
263 alias :sum_rows :sum_rows_c
264 alias :bit_set :bit_set_c
265 alias :bit_set? :bit_test_c
267 alias :empty! :empty_c
268 alias :zero! :empty_c