bit_vector 0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5f6f928647cf7bd7886a1205e7714ed15f0320bf
4
+ data.tar.gz: 83942ae3820c64df059a0dfffb1dbf8d4e54ab6f
5
+ SHA512:
6
+ metadata.gz: ab7074ab7c7b68ef7668dc9b62d53a350d1c5c2e8825eb84b996e12255d046c284fc94ec28749def0c34d693647d45bab943d245b696d6b33d758c6338578ef7
7
+ data.tar.gz: c5892e896bdec09a219ece110a2a8dbdcdf7193c2c0bde559b4a24f5c14607109f7412b0717eb9262515df86bd5ee91e7a3854687313c6a83d5248a4a20a0329
data/.gemtest ADDED
File without changes
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # bit_vector
2
+
3
+ An implementation of arbitrarily large Bit Vectors in Ruby using C + inline assembler for speed
4
+
5
+ This builds heavily on a much earlier Gem 'bitset' authored by 'MoonWolf' on RAA.
6
+
7
+ # Notes on Bit Vector Lengths
8
+
9
+ Many bit vector operations are only defined if the lengths of the vectors are the same. By
10
+ considering a bit vector to possess any number of high-order zeros most operations
11
+ can be made to work with differently sized operands. When creating this library
12
+ a couple of different approaches to this were considered:
13
+
14
+ * Return a result the size of the first operand,
15
+ * Return the smallest result set (not necessarily normalized),
16
+ * Return a normalized result (the length being the position of the high order bit).
17
+
18
+ Like the original implementor I chose to use the middle strategy.
19
+
20
+ # Bit Vectors in String Format
21
+
22
+ The string format of a bit vector represents the bit positions from least significant to
23
+ most significant with the characters '0,-,f,F,N' representing an un-set bit and all other
24
+ characters interpreted as a set bit.
25
+
26
+ ## `from_bytes` and `to_bytes`
27
+
28
+ These are methods to serialize and de-serialize a bit vector in a platform dependent way.
29
+ They use US-ASCII encoded strings consisting of 8-bit bytes that represents the bit
30
+ vector. It is _not_ the binary representation as a string of 0's and 1's used by `new` and
31
+ `to_s` methods.
32
+
33
+ # Operators and Methods
34
+
35
+ Statements that use binary operators of the form `r = a op b` are computed by
36
+ the Ruby call `a.op(b)`
37
+
38
+ Most operators are obvious, here's some that aren't
39
+
40
+ ## minus
41
+
42
+ This is defined elementwise as: r = a and not b
43
+
44
+ ## bytesize
45
+
46
+ This returns the length in bytes required to store this bitvec
47
+
48
+ ## New
49
+ Called with:
50
+
51
+ * a FixNum to create an empty vector of specified length
52
+ * a String to create a vector from the string in the format described above.
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+ require 'rake/clean'
4
+
5
+ CLEAN << %w{
6
+ ext/bit_vector/Makefile
7
+ ext/bit_vector/bit_vector.o
8
+ ext/bit_vector/mkmf.log
9
+ }
10
+
11
+ CLOBBER << %w{
12
+ ext/bit_vector/bit_vector.so
13
+ ext/bit_vector/bit_vector.bundle
14
+ pkg/
15
+ }
16
+
17
+ # Run the benchmarks with the in-tree gem
18
+ #
19
+ desc "Run the benchmarks using the tree"
20
+ task :benchmark do
21
+ ruby "-Ilib:ext/bit_vector:#{$:.join(':')} test/benchmark.rb"
22
+ end
23
+
24
+ # Now we want to test with the in-tree gem, but Bundler doesn't support binary gems
25
+ # with the :path syntax, so we have to do it ourselves.
26
+ #
27
+ Rake::TestTask.new('test:unit') do |t|
28
+ t.pattern = 'test/test*.rb'
29
+ t.libs << 'ext/bit_vector'
30
+ t.libs << 'lib'
31
+ end
32
+
33
+ Rake::TestTask.new('test:spec') do |t|
34
+ t.test_files = ['test/spec.rb']
35
+ t.libs << 'ext/bit_vector'
36
+ t.libs << 'lib'
37
+ end
38
+
39
+ # Now although we have put the gem in the Gemfile with a :path
40
+ # bundler won't actually compile the extensions, so make it happen...
41
+ #
42
+ desc "Compile the C extensions so we can use in-tree"
43
+ task :compile do
44
+ cd "ext/bit_vector" do
45
+ ruby "extconf.rb"
46
+ sh "make"
47
+ end
48
+ end
49
+ task 'test:unit' => :compile
50
+ task 'test:spec' => :compile
51
+
52
+ task :test => ['test:unit', 'test:spec']
53
+ task :default => :test
54
+
55
+ # vim: ft=ruby sts=2 sw=2 ts=8
@@ -0,0 +1,238 @@
1
+
2
+ SHELL = /bin/sh
3
+
4
+ # V=0 quiet, V=1 verbose. other values don't work.
5
+ V = 0
6
+ Q1 = $(V:1=)
7
+ Q = $(Q1:0=@)
8
+ ECHO1 = $(V:1=@:)
9
+ ECHO = $(ECHO1:0=@echo)
10
+
11
+ #### Start of system configuration section. ####
12
+
13
+ srcdir = .
14
+ topdir = /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/include/ruby-2.0.0
15
+ hdrdir = $(topdir)
16
+ arch_hdrdir = /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/include/ruby-2.0.0/universal-darwin14
17
+ PATH_SEPARATOR = :
18
+ VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
19
+ prefix = /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr
20
+ rubysitearchprefix = $(rubylibprefix)/$(sitearch)
21
+ rubyarchprefix = $(rubylibprefix)/$(arch)
22
+ rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
23
+ exec_prefix = $(prefix)
24
+ vendorarchhdrdir = $(vendorhdrdir)/$(sitearch)
25
+ sitearchhdrdir = $(sitehdrdir)/$(sitearch)
26
+ rubyarchhdrdir = $(rubyhdrdir)/$(arch)
27
+ vendorhdrdir = $(rubyhdrdir)/vendor_ruby
28
+ sitehdrdir = $(rubyhdrdir)/site_ruby
29
+ rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME)
30
+ vendorarchdir = $(vendorlibdir)/$(sitearch)
31
+ vendorlibdir = $(vendordir)/$(ruby_version)
32
+ vendordir = $(rubylibprefix)/vendor_ruby
33
+ sitearchdir = $(sitelibdir)/$(sitearch)
34
+ sitelibdir = $(sitedir)/$(ruby_version)
35
+ sitedir = $(DESTDIR)/Library/Ruby/Site
36
+ rubyarchdir = $(rubylibdir)/$(arch)
37
+ rubylibdir = $(rubylibprefix)/$(ruby_version)
38
+ sitearchincludedir = $(includedir)/$(sitearch)
39
+ archincludedir = $(includedir)/$(arch)
40
+ sitearchlibdir = $(libdir)/$(sitearch)
41
+ archlibdir = $(libdir)/$(arch)
42
+ ridir = $(datarootdir)/$(RI_BASE_NAME)
43
+ mandir = $(DESTDIR)/usr/share/man
44
+ localedir = $(datarootdir)/locale
45
+ libdir = $(exec_prefix)/lib
46
+ psdir = $(docdir)
47
+ pdfdir = $(docdir)
48
+ dvidir = $(docdir)
49
+ htmldir = $(docdir)
50
+ infodir = $(DESTDIR)/usr/share/info
51
+ docdir = $(datarootdir)/doc/$(PACKAGE)
52
+ oldincludedir = /usr/include
53
+ includedir = $(prefix)/include
54
+ localstatedir = $(prefix)/var
55
+ sharedstatedir = $(prefix)/com
56
+ sysconfdir = $(DESTDIR)/Library/Ruby/Site
57
+ datadir = $(datarootdir)
58
+ datarootdir = $(prefix)/share
59
+ libexecdir = $(exec_prefix)/libexec
60
+ sbindir = $(exec_prefix)/sbin
61
+ bindir = $(exec_prefix)/bin
62
+ archdir = $(rubyarchdir)
63
+
64
+
65
+ CC = xcrun clang
66
+ CXX = xcrun clang++
67
+ LIBRUBY = $(LIBRUBY_SO)
68
+ LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
69
+ LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
70
+ LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
71
+ empty =
72
+ OUTFLAG = -o $(empty)
73
+ COUTFLAG = -o $(empty)
74
+
75
+ RUBY_EXTCONF_H =
76
+ cflags = $(optflags) $(debugflags) $(warnflags)
77
+ optflags =
78
+ debugflags = -g
79
+ warnflags =
80
+ CCDLFLAGS =
81
+ CFLAGS = $(CCDLFLAGS) -std=c99 -Wall -Wextra -O0 -ggdb3 $(ARCH_FLAG)
82
+ INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
83
+ DEFS =
84
+ CPPFLAGS = -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT $(DEFS) $(cppflags)
85
+ CXXFLAGS = $(CCDLFLAGS) $(ARCH_FLAG) -g -Os -pipe $(ARCH_FLAG)
86
+ ldflags = -L. -L/usr/local/lib
87
+ dldflags = -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress
88
+ ARCH_FLAG = -arch x86_64
89
+ DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
90
+ LDSHARED = $(CC) -dynamic -bundle
91
+ LDSHAREDXX = $(CXX) -dynamic -bundle
92
+ AR = ar
93
+ EXEEXT =
94
+
95
+ RUBY_INSTALL_NAME = ruby
96
+ RUBY_SO_NAME = ruby.2.0.0
97
+ RUBYW_INSTALL_NAME =
98
+ RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version)
99
+ RUBYW_BASE_NAME = rubyw
100
+ RUBY_BASE_NAME = ruby
101
+
102
+ arch = universal-darwin14
103
+ sitearch = $(arch)
104
+ ruby_version = 2.0.0
105
+ ruby = $(bindir)/ruby
106
+ RUBY = $(ruby)
107
+ ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/defines.h $(arch_hdrdir)/ruby/config.h
108
+
109
+ RM = rm -f
110
+ RM_RF = $(RUBY) -run -e rm -- -rf
111
+ RMDIRS = rmdir -p
112
+ MAKEDIRS = mkdir -p
113
+ INSTALL = /usr/bin/install -c
114
+ INSTALL_PROG = $(INSTALL) -m 0755
115
+ INSTALL_DATA = $(INSTALL) -m 644
116
+ COPY = cp
117
+ TOUCH = exit >
118
+
119
+ #### End of system configuration section. ####
120
+
121
+ preload =
122
+
123
+ libpath = . $(libdir)
124
+ LIBPATH = -L. -L$(libdir)
125
+ DEFFILE =
126
+
127
+ CLEANFILES = mkmf.log
128
+ DISTCLEANFILES =
129
+ DISTCLEANDIRS =
130
+
131
+ extout =
132
+ extout_prefix =
133
+ target_prefix =
134
+ LOCAL_LIBS =
135
+ LIBS = $(LIBRUBYARG_SHARED) -lpthread -ldl -lobjc
136
+ ORIG_SRCS = bit_vector.c
137
+ SRCS = $(ORIG_SRCS)
138
+ OBJS = bit_vector.o
139
+ HDRS =
140
+ TARGET = bit_vector
141
+ TARGET_NAME = bit_vector
142
+ TARGET_ENTRY = Init_$(TARGET_NAME)
143
+ DLLIB = $(TARGET).bundle
144
+ EXTSTATIC =
145
+ STATIC_LIB =
146
+
147
+ BINDIR = $(DESTDIR)$(bindir)
148
+ RUBYCOMMONDIR = $(DESTDIR)$(sitedir)$(target_prefix)
149
+ RUBYLIBDIR = $(DESTDIR)$(sitelibdir)$(target_prefix)
150
+ RUBYARCHDIR = $(DESTDIR)$(sitearchdir)$(target_prefix)
151
+ HDRDIR = $(DESTDIR)$(rubyhdrdir)/ruby$(target_prefix)
152
+ ARCHHDRDIR = $(DESTDIR)$(rubyhdrdir)/$(arch)/ruby$(target_prefix)
153
+
154
+ TARGET_SO = $(DLLIB)
155
+ CLEANLIBS = $(TARGET).bundle
156
+ CLEANOBJS = *.o *.bak
157
+
158
+ all: $(DLLIB)
159
+ static: $(STATIC_LIB)
160
+ .PHONY: all install static install-so install-rb
161
+ .PHONY: clean clean-so clean-static clean-rb
162
+
163
+ clean-static::
164
+ clean-rb-default::
165
+ clean-rb::
166
+ clean-so::
167
+ clean: clean-so clean-static clean-rb-default clean-rb
168
+ -$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time
169
+
170
+ distclean-rb-default::
171
+ distclean-rb::
172
+ distclean-so::
173
+ distclean-static::
174
+ distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb
175
+ -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
176
+ -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
177
+ -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true
178
+
179
+ realclean: distclean
180
+ install: install-so install-rb
181
+
182
+ install-so: $(DLLIB) ./.RUBYARCHDIR.time
183
+ $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
184
+ clean-static::
185
+ -$(Q)$(RM) $(STATIC_LIB)
186
+ install-rb: pre-install-rb install-rb-default
187
+ install-rb-default: pre-install-rb-default
188
+ pre-install-rb: Makefile
189
+ pre-install-rb-default: Makefile
190
+ pre-install-rb-default:
191
+ $(ECHO) installing default bit_vector libraries
192
+ ./.RUBYARCHDIR.time:
193
+ $(Q) $(MAKEDIRS) $(RUBYARCHDIR)
194
+ $(Q) $(TOUCH) $@
195
+
196
+ site-install: site-install-so site-install-rb
197
+ site-install-so: install-so
198
+ site-install-rb: install-rb
199
+
200
+ .SUFFIXES: .c .m .cc .mm .cxx .cpp .C .o
201
+
202
+ .cc.o:
203
+ $(ECHO) compiling $(<)
204
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
205
+
206
+ .mm.o:
207
+ $(ECHO) compiling $(<)
208
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
209
+
210
+ .cxx.o:
211
+ $(ECHO) compiling $(<)
212
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
213
+
214
+ .cpp.o:
215
+ $(ECHO) compiling $(<)
216
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
217
+
218
+ .C.o:
219
+ $(ECHO) compiling $(<)
220
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
221
+
222
+ .c.o:
223
+ $(ECHO) compiling $(<)
224
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
225
+
226
+ .m.o:
227
+ $(ECHO) compiling $(<)
228
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
229
+
230
+ $(DLLIB): $(OBJS) Makefile
231
+ $(ECHO) linking shared-object $(DLLIB)
232
+ -$(Q)$(RM) $(@)
233
+ $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
234
+ $(Q) test -z '$(RUBY_CODESIGN)' || codesign -s '$(RUBY_CODESIGN)' -f $@
235
+
236
+
237
+
238
+ $(OBJS): $(HDRS) $(ruby_headers)
Binary file
@@ -0,0 +1,1019 @@
1
+ /* Taken from an original by 'MoonWolf' on RAA
2
+ * Largely rewritten to use 64 bit allocations and inline assembly for speed
3
+ * by Nick Townsend 2014
4
+ */
5
+ #include "ruby.h"
6
+ #include "string.h"
7
+
8
+ #define BITCOUNTS(s,len) (s->bit_len = len, s->qws_len = (len+63)/64, s->last_bit = len % 64 )
9
+
10
+ static VALUE cBitVector;
11
+ static ID id_new, id_first, id_end;
12
+
13
+ struct BitVector {
14
+ int64_t bit_len; /* in bits */
15
+ int64_t qws_len; /* number of uint64 elements */
16
+ int last_bit; /* number bits used in final element (0 = all) */
17
+ uint64_t *ptr;
18
+ };
19
+
20
+ void bs_resize(struct BitVector *bits, int64_t bit_len) {
21
+
22
+ int64_t qws_len = (bit_len + 63) / 64;
23
+ int last_bit = bit_len % 64;
24
+
25
+ if (bits->bit_len == bit_len) {
26
+ return;
27
+ }
28
+ else if (bits->bit_len > bit_len) {
29
+ bits->ptr = REALLOC_N(bits->ptr, uint64_t, qws_len);
30
+ if (last_bit > 0) {
31
+ bits->ptr[qws_len-1] &= (1<<last_bit)-1;
32
+ }
33
+ }
34
+ else if (bits->bit_len < bit_len) {
35
+ bits->ptr = REALLOC_N(bits->ptr, uint64_t, qws_len);
36
+ memset(bits->ptr+bits->qws_len, 0, qws_len - bits->qws_len);
37
+ }
38
+ bits->bit_len = bit_len;
39
+ bits->qws_len = qws_len;
40
+ bits->last_bit = last_bit;
41
+ }
42
+
43
+ int64_t bs_bytesize(struct BitVector *bits) {
44
+ int64_t byte_len = bits->qws_len*8;
45
+ if (bits->last_bit > 0) {
46
+ byte_len -= 8;
47
+ byte_len += (bits->last_bit+7)/8;
48
+ }
49
+ return byte_len;
50
+ }
51
+
52
+ int bs_get(struct BitVector *bits, int64_t index) {
53
+ int bit;
54
+
55
+ if (index >= bits->bit_len) {
56
+ bit = 0;
57
+ } else {
58
+ __asm ( "mov %2, %%r8 \n"
59
+ "shr $6, %%r8 \n"
60
+ "mov %2, %%r9 \n"
61
+ "and $63, %%r9 \n"
62
+ "mov $0, %0 \n"
63
+ "bt %%r9, (%1, %%r8, 8) \n"
64
+ "jnc get_exit \n"
65
+ "mov $1, %0 \n"
66
+ "get_exit: \n"
67
+ : "=r"(bit) : "r"(bits->ptr), "r"(index) : "cc"
68
+ );
69
+ }
70
+ return bit;
71
+ }
72
+
73
+ void bs_set(struct BitVector *bits, int64_t index, int bit) {
74
+
75
+ if (index >= bits->bit_len) {
76
+ bs_resize(bits, index+1);
77
+ }
78
+
79
+ __asm volatile (
80
+ "mov %1, %%r8 \n"
81
+ "shr $6, %%r8 \n"
82
+ "mov %1, %%r9 \n"
83
+ "and $63, %%r9 \n"
84
+ "cmp $0, %2 \n"
85
+ "je bs_set_zero \n"
86
+ "bts %%r9, (%0,%%r8,8) \n"
87
+ "jmp bs_set_exit \n"
88
+ "bs_set_zero: \n"
89
+ "btr %%r9, (%0,%%r8,8) \n"
90
+ "bs_set_exit: \n"
91
+ : : "r"(bits->ptr), "r"(index), "r"(bit) : "%r8", "%r9", "cc", "memory"
92
+ );
93
+
94
+ }
95
+
96
+ void bs_sets(struct BitVector *bits, int64_t first, int64_t last, int bit) {
97
+ int64_t first_offset;
98
+ int64_t last_offset;
99
+ int64_t first_bit;
100
+ int64_t last_bit;
101
+ int64_t qws;
102
+ int64_t i;
103
+ uint64_t c;
104
+
105
+ if (bits->bit_len < last) {
106
+ bs_resize(bits, last);
107
+ }
108
+
109
+ first_offset = first / 64;
110
+ first_bit = first % 64;
111
+ last_offset = last / 64;
112
+ last_bit = last % 64;
113
+ qws = last_offset - first_offset + 1;
114
+
115
+ if (first_bit==0 && last_bit==63) {
116
+ memset(&bits->ptr[first_offset], bit ? 0xffffffffffffffff : 0x0, qws);
117
+ return;
118
+ }
119
+
120
+ if (last-first < 63) {
121
+ for(i=first; i<=last; i++) {
122
+ bs_set(bits, i, bit);
123
+ }
124
+ return;
125
+ }
126
+
127
+ if (first_bit != 0) {
128
+ c = bits->ptr[first_offset];
129
+ if (bit) {
130
+ c |= ~((1 << first_bit) - 1);
131
+ } else {
132
+ c &= ((1 << first_bit) - 1);
133
+ }
134
+ bits->ptr[first_offset] = c;
135
+ first_offset++;
136
+ qws--;
137
+ }
138
+
139
+ if (last_bit != 63) {
140
+ c = bits->ptr[last_offset];
141
+ if (bit) {
142
+ c |= ((2 << last_bit) - 1);
143
+ } else {
144
+ c &= ~((2 << last_bit) - 1);
145
+ }
146
+ bits->ptr[last_offset] = c;
147
+ qws--;
148
+ }
149
+
150
+ if (qws>0) {
151
+ memset(&bits->ptr[first_offset], bit ? 0xffffffffffffffff : 0x00, qws);
152
+ }
153
+
154
+ return;
155
+ }
156
+
157
+
158
+ void bs_fill(VALUE obj, struct BitVector *bits, int fill) {
159
+ int i;
160
+ VALUE vfirst, vend;
161
+ int64_t first, end;
162
+ switch(TYPE(obj)) {
163
+ case T_FIXNUM:
164
+ bs_set(bits, FIX2LONG(obj), fill);
165
+ break;
166
+ case T_ARRAY:
167
+ for(i=0; i< (RARRAY_LEN(obj)); i++) {
168
+ bs_fill( (RARRAY_PTR(obj)[i]), bits, fill);
169
+ }
170
+ break;
171
+ default:
172
+ if (rb_class_of(obj)==rb_cRange) {
173
+ vfirst = rb_funcall(obj, id_first, 0);
174
+ vend = rb_funcall(obj, id_end, 0);
175
+ Check_Type(vfirst, T_FIXNUM);
176
+ Check_Type(vend, T_FIXNUM);
177
+ first = FIX2LONG(vfirst);
178
+ end = FIX2LONG(vend);
179
+ if (rb_funcall(obj, rb_intern("exclude_end?"), 0) == Qtrue) {
180
+ end--;
181
+ }
182
+ if (first>end || first<0 || end<0) {
183
+ rb_raise(rb_eRangeError, "not valid range");
184
+ }
185
+ bs_sets(bits, first, end, fill);
186
+ } else {
187
+ rb_raise(rb_eTypeError, "not valid index");
188
+ }
189
+ }
190
+ }
191
+
192
+ void bs_or(struct BitVector *bits, struct BitVector *x) {
193
+ uint64_t *ptr, *xptr;
194
+ int64_t i;
195
+
196
+ if (bits->bit_len < x->bit_len) {
197
+ bs_resize(bits, x->bit_len);
198
+ }
199
+
200
+ ptr = bits->ptr;
201
+ xptr = x->ptr;
202
+ for(i=0; i<bits->qws_len; i++) {
203
+ *ptr++ |= *xptr++;
204
+ }
205
+
206
+ }
207
+
208
+ void bs_not(struct BitVector *bits) {
209
+ uint64_t *ptr;
210
+ uint64_t qw;
211
+ int64_t i;
212
+
213
+ ptr = bits->ptr;
214
+ for(i=0; i < bits->qws_len; i++) {
215
+ qw = *ptr;
216
+ *ptr++ = ~qw;
217
+ }
218
+ if (bits->last_bit>0) {
219
+ qw = *--ptr;
220
+ *ptr = qw & ((1<<bits->last_bit)-1);
221
+ }
222
+ }
223
+
224
+ /* Returned bit_vector is the size of the first operand. See README.md */
225
+
226
+ void bs_and(struct BitVector *rbits, struct BitVector *xbits, struct BitVector *ybits) {
227
+ uint64_t *rptr, *xptr, *yptr;
228
+
229
+ *rbits = *xbits;
230
+ rbits->ptr = ALLOC_N(uint64_t, rbits->qws_len);
231
+
232
+ rptr = rbits->ptr;
233
+ xptr = xbits->ptr;
234
+ yptr = ybits->ptr;
235
+
236
+ for (int64_t ix = 0; ix < rbits->qws_len; ix++) {
237
+ *rptr++ = *xptr++ & *yptr++;
238
+ }
239
+ if (rbits->last_bit > 0) {
240
+ *(--rptr) &= (1<<rbits->last_bit)-1;
241
+ }
242
+ }
243
+
244
+ void bs_xor(struct BitVector *bits, struct BitVector *x) {
245
+ uint64_t *ptr, *xptr;
246
+ int64_t i;
247
+
248
+ if (bits->bit_len < x->bit_len) {
249
+ bs_resize(bits, x->bit_len);
250
+ }
251
+
252
+ ptr = bits->ptr;
253
+ xptr = x->ptr;
254
+ for(i=0; i<bits->qws_len; i++) {
255
+ *ptr++ ^= *xptr++;
256
+ }
257
+
258
+ }
259
+
260
+ int64_t bs_max(struct BitVector *bits) {
261
+ int64_t qws;
262
+ int64_t pos;
263
+
264
+ for (qws = bits->qws_len - 1; qws >= 0; qws -= 1) {
265
+ __asm (
266
+ "bsr %1, %0 \n"
267
+ "jnz bs_max_found \n"
268
+ "mov $64, %0 \n"
269
+ "bs_max_found: \n"
270
+ : "=r"(pos) : "m"(bits->ptr[qws]) : "cc", "memory"
271
+ );
272
+ if (pos < 64) {
273
+ return (qws * 64) + pos;
274
+ }
275
+ }
276
+ return -1;
277
+ }
278
+
279
+ int64_t bs_min(struct BitVector *bits) {
280
+ int64_t index;
281
+ int pos;
282
+ uint64_t *ptr, qw;
283
+
284
+ ptr = bits->ptr;
285
+ for(index = 0; index < bits->bit_len; index += 64) {
286
+ qw = *ptr++;
287
+ __asm (
288
+ "bsf %1, %0 \n"
289
+ "jnz bs_min_found \n"
290
+ "mov $64, %0 \n"
291
+ "bs_min_found: \n"
292
+ : "=r"(pos) : "m"(qw) : "cc"
293
+ );
294
+ if (pos < 64) {
295
+ return index + pos;
296
+ }
297
+ }
298
+ return -1;
299
+ }
300
+
301
+ int64_t bs_index(struct BitVector *bits, int bit, int64_t off) {
302
+ int64_t pos;
303
+
304
+ __asm (
305
+ "mov %3, %%r9 \n"
306
+ "shr $6, %%r9 \n" /* r9: loop counter stepping up in qw */
307
+ "mov %2, %%r11 \n"
308
+ "shr $6, %%r11 \n" /* r11: end marker in qw */
309
+ "mov $18446744073709551615, %%r8 \n"
310
+ "mov %3, %%rcx \n"
311
+ "and $63, %%rcx \n" /* rcx: bit offset in first qw */
312
+ "shl %%cl, %%r8 \n"
313
+ "and (%1, %%r9, 8), %%r8 \n"
314
+ "loop: \n"
315
+ " bsf %%r8, %%rax \n"
316
+ " jnz found \n"
317
+ " inc %%r9 \n"
318
+ " cmp %%r11, %%r9 \n"
319
+ " jl next \n"
320
+ " movq $-1, %0 \n"
321
+ " jmp exit \n"
322
+ "next: \n"
323
+ " mov (%1, %%r9, 8), %%r8 \n"
324
+ " jmp loop \n"
325
+ "found: \n"
326
+ " salq $6, %%r9 \n"
327
+ " add %%rax, %%r9 \n"
328
+ " movq %%r9, %0 \n"
329
+ "exit: \n"
330
+ : "=r"(pos) : "r"(bits->ptr), "r"(bits->bit_len), "r"(off), "m"(bit) : "%rax", "%rcx", "%r8", "%r9", "%r11", "cc", "memory"
331
+ );
332
+
333
+ return pos;
334
+ }
335
+ int to_bit(VALUE obj) {
336
+ int bit;
337
+
338
+ switch(TYPE(obj)) {
339
+ case T_NIL:
340
+ case T_FALSE:
341
+ bit = 0;
342
+ break;
343
+ case T_FIXNUM:
344
+ if (FIX2INT(obj)==0) {
345
+ bit = 0;
346
+ } else {
347
+ bit = 1;
348
+ }
349
+ break;
350
+ default:
351
+ bit = 1;
352
+ }
353
+
354
+ return bit;
355
+ }
356
+
357
+ void bits_free(struct BitVector *bits) {
358
+ ruby_xfree(bits->ptr);
359
+ }
360
+
361
+ static VALUE bits_s_new(int argc, VALUE *argv, VALUE self) {
362
+ struct BitVector *bits;
363
+ VALUE arg;
364
+ VALUE obj;
365
+ int bitcnt;
366
+ int64_t len;
367
+ uint64_t qw, *bptr;
368
+ unsigned char *ptr;
369
+
370
+ obj = Data_Make_Struct(self, struct BitVector, NULL, bits_free, bits);
371
+
372
+ switch(argc) {
373
+ case 0:
374
+ arg = INT2FIX(1);
375
+ break;
376
+ case 1:
377
+ arg = argv[0];
378
+ break;
379
+ default:
380
+ arg = INT2FIX(0);
381
+ rb_raise(rb_eArgError, "Too many args");
382
+ }
383
+
384
+ switch(TYPE(arg)) {
385
+
386
+ case T_FIXNUM:
387
+
388
+ BITCOUNTS(bits, FIX2LONG(arg));
389
+ if (bits->bit_len < 1) {
390
+ rb_raise(rb_eArgError, "May not be less than one");
391
+ }
392
+ bits->ptr = ALLOC_N(uint64_t, bits->qws_len);
393
+ memset(bits->ptr, 0, bits->qws_len*8);
394
+ break;
395
+
396
+ case T_STRING:
397
+
398
+ len = RSTRING_LEN(arg);
399
+ BITCOUNTS(bits,len);
400
+ bits->ptr = ALLOC_N(uint64_t, bits->qws_len);
401
+ memset(bits->ptr, 0, bits->qws_len*8);
402
+
403
+ qw = 0;
404
+ bitcnt = 0;
405
+ ptr = (unsigned char *)RSTRING_PTR(arg);
406
+ bptr = bits->ptr;
407
+ while(len--) {
408
+ switch(*ptr++) {
409
+ case '0':
410
+ case '-':
411
+ case 'f':
412
+ case 'F':
413
+ case 'N':
414
+ break;
415
+ default:
416
+ __asm ( "bts %1, %0" : "=g"(qw) : "r"(bitcnt) : "cc","memory");
417
+ }
418
+ bitcnt++;
419
+ if (bitcnt == 64) {
420
+ *bptr++ = qw;
421
+ qw = 0;
422
+ bitcnt = 0;
423
+ }
424
+ }
425
+ if (bitcnt) {
426
+ *bptr++ = qw;
427
+ }
428
+ break;
429
+
430
+ default:
431
+ rb_raise(rb_eArgError, "not valid value");
432
+ }
433
+
434
+ return obj;
435
+ }
436
+
437
+ static VALUE bits_s_from_bytes(VALUE self, VALUE arg) {
438
+ struct BitVector *bits;
439
+ VALUE retobj;
440
+ int64_t len;
441
+
442
+ Check_Type(arg, T_STRING);
443
+
444
+ len = RSTRING_LEN(arg);
445
+ if (len<1) {
446
+ rb_raise(rb_eArgError, "array size");
447
+ }
448
+
449
+ retobj = Data_Make_Struct(self, struct BitVector, NULL, bits_free, bits);
450
+ BITCOUNTS(bits, len*8);
451
+ bits->ptr = ALLOC_N(uint64_t, bits->qws_len);
452
+
453
+ memcpy(bits->ptr, RSTRING_PTR(arg), len);
454
+
455
+ return retobj;
456
+ }
457
+
458
+
459
+ static VALUE bits_length(VALUE self) {
460
+ struct BitVector *bits;
461
+
462
+ Data_Get_Struct(self, struct BitVector, bits);
463
+
464
+ return LONG2FIX(bits->bit_len);
465
+ }
466
+
467
+ static VALUE bits_bytesize(VALUE self) {
468
+ struct BitVector *bits;
469
+
470
+ Data_Get_Struct(self, struct BitVector, bits);
471
+
472
+ return LONG2FIX(bs_bytesize(bits));
473
+ }
474
+
475
+ static VALUE bits_resize(VALUE self, VALUE obj) {
476
+ struct BitVector *bits;
477
+ int64_t len;
478
+
479
+ Check_Type(obj, T_FIXNUM);
480
+ len = FIX2LONG(obj);
481
+ if (len<1) {
482
+ rb_raise(rb_eArgError, "array size");
483
+ }
484
+
485
+ Data_Get_Struct(self, struct BitVector, bits);
486
+ bs_resize(bits, len);
487
+
488
+ return self;
489
+ }
490
+
491
+ static VALUE bits_to_s(VALUE self) {
492
+ struct BitVector *bits;
493
+ unsigned char *ptr;
494
+ int64_t i;
495
+ VALUE str;
496
+
497
+ Data_Get_Struct(self, struct BitVector, bits);
498
+ str = rb_str_new(0, bits->bit_len);
499
+
500
+ ptr = (unsigned char *)RSTRING_PTR(str);
501
+ for(i=0; i<bits->bit_len; i++) {
502
+ *ptr++ = bs_get(bits, i) ? '1' : '0';
503
+ }
504
+
505
+ return str;
506
+ }
507
+
508
+ static VALUE bits_dup(VALUE self) {
509
+ struct BitVector *orig;
510
+ struct BitVector *dups;
511
+ VALUE obj;
512
+
513
+ Data_Get_Struct(self, struct BitVector, orig);
514
+
515
+ obj = Data_Make_Struct(CLASS_OF(self), struct BitVector, NULL, bits_free, dups);
516
+ *dups = *orig;
517
+ dups->ptr = ALLOC_N(uint64_t, dups->qws_len);
518
+ memcpy(dups->ptr, orig->ptr, dups->qws_len*8);
519
+
520
+ return obj;
521
+ }
522
+
523
+ static VALUE bits_clear(VALUE self) {
524
+ struct BitVector *bits;
525
+
526
+ Data_Get_Struct(self, struct BitVector, bits);
527
+ memset(bits->ptr, 0, bits->qws_len*8);
528
+
529
+ return self;
530
+ }
531
+
532
+ static VALUE bits_get(VALUE self, VALUE vidx) {
533
+ struct BitVector *bits;
534
+ int64_t index;
535
+ int bit;
536
+
537
+ Data_Get_Struct(self, struct BitVector, bits);
538
+
539
+ Check_Type(vidx, T_FIXNUM);
540
+
541
+ index = FIX2LONG(vidx);
542
+ if (index<0) {
543
+ rb_raise(rb_eRangeError, "index range");
544
+ }
545
+
546
+ bit = bs_get(bits, index);
547
+
548
+ return INT2FIX(bit);
549
+ }
550
+
551
+
552
+ static VALUE bits_set(VALUE self, VALUE vidx, VALUE vobj) {
553
+ struct BitVector *bits;
554
+ int64_t index;
555
+ int bit;
556
+
557
+ Data_Get_Struct(self, struct BitVector, bits);
558
+
559
+ Check_Type(vidx, T_FIXNUM);
560
+
561
+ index = FIX2LONG(vidx);
562
+ if (index<0) {
563
+ rb_raise(rb_eRangeError, "index range");
564
+ }
565
+
566
+ bit = to_bit(vobj);
567
+
568
+ bs_set(bits, index, bit);
569
+
570
+ return self;
571
+ }
572
+
573
+ /* This method returns the index of the first bit set to the given value */
574
+
575
+ static VALUE bits_index(VALUE self, VALUE vobj, VALUE voff) {
576
+ struct BitVector *bits;
577
+ int64_t pos, off;
578
+ int bit;
579
+
580
+ Data_Get_Struct(self, struct BitVector, bits);
581
+ bit = to_bit(vobj);
582
+ Check_Type(voff, T_FIXNUM);
583
+ off = FIX2LONG(voff);
584
+
585
+ pos = bs_index(bits, bit, off);
586
+
587
+ return (pos == -1) ? Qnil : LONG2FIX(pos);
588
+ }
589
+ /* This method extracts a subset of the bit_vector */
590
+
591
+ static VALUE bits_slice(VALUE self, VALUE vidx) {
592
+ struct BitVector *bits;
593
+ struct BitVector *slis;
594
+ VALUE obj;
595
+ VALUE vfirst, vend;
596
+ int64_t first = 0, end = 0;
597
+ int64_t ix, ox;
598
+
599
+ Data_Get_Struct(self, struct BitVector, bits);
600
+
601
+ /* Validate the range and extract start and end */
602
+
603
+ if (rb_class_of(vidx)==rb_cRange) {
604
+ vfirst = rb_funcall(vidx, id_first, 0);
605
+ vend = rb_funcall(vidx, id_end, 0);
606
+ Check_Type(vfirst, T_FIXNUM);
607
+ Check_Type(vend, T_FIXNUM);
608
+ first = FIX2LONG(vfirst);
609
+ end = FIX2LONG(vend);
610
+ if (rb_funcall(vidx, rb_intern("exclude_end?"), 0) == Qtrue) {
611
+ end--;
612
+ }
613
+ if (first>end || first<0 || end<0) {
614
+ rb_raise(rb_eRangeError, "not valid range");
615
+ }
616
+ } else {
617
+ rb_raise(rb_eTypeError, "not valid index");
618
+ }
619
+
620
+ obj = Data_Make_Struct(CLASS_OF(self), struct BitVector, NULL, bits_free, slis);
621
+ slis->bit_len = end - first + 1;
622
+ slis->qws_len = (slis->bit_len+63)/64;
623
+ slis->last_bit = slis->bit_len % 64;
624
+ slis->ptr = ALLOC_N(uint64_t, slis->qws_len);
625
+
626
+ /* Now copy the bits TBD use __asm */
627
+
628
+ for (ix = first, ox = 0; ix <= end; ix++,ox++) {
629
+ bs_set(slis, ox, bs_get(bits, ix));
630
+ }
631
+ return obj;
632
+ }
633
+
634
+ static VALUE bits_on(int argc, VALUE *argv, VALUE self) {
635
+ struct BitVector *bits;
636
+ int i;
637
+ Data_Get_Struct(self, struct BitVector, bits);
638
+
639
+ for(i=0; i<argc; i++) {
640
+ bs_fill(argv[i], bits, 1);
641
+ }
642
+
643
+ return self;
644
+ }
645
+
646
+ static VALUE bits_off(int argc, VALUE *argv, VALUE self) {
647
+ struct BitVector *bits;
648
+ int i;
649
+
650
+ Data_Get_Struct(self, struct BitVector, bits);
651
+
652
+ for(i=0; i<argc; i++) {
653
+ bs_fill(argv[i], bits, 0);
654
+ }
655
+
656
+ return self;
657
+ }
658
+
659
+ static VALUE bits_or(VALUE self, VALUE other) {
660
+ VALUE obj;
661
+ struct BitVector *bits, *rbits, *xbits;
662
+
663
+ Data_Get_Struct(self, struct BitVector, bits);
664
+
665
+ obj = Data_Make_Struct(CLASS_OF(self), struct BitVector, NULL, bits_free, rbits);
666
+ *rbits = *bits;
667
+ rbits->ptr = ALLOC_N(uint64_t, rbits->qws_len);
668
+ memcpy(rbits->ptr, bits->ptr, rbits->qws_len*8);
669
+
670
+ Data_Get_Struct(other, struct BitVector, xbits);
671
+ bs_or(rbits, xbits);
672
+
673
+ return obj;
674
+ }
675
+
676
+ static VALUE bits_not(VALUE self) {
677
+ VALUE obj;
678
+ struct BitVector *bits, *rbits;
679
+
680
+ Data_Get_Struct(self, struct BitVector, bits);
681
+
682
+ obj = Data_Make_Struct(CLASS_OF(self), struct BitVector, NULL, bits_free, rbits);
683
+ *rbits = *bits;
684
+ rbits->ptr = ALLOC_N(uint64_t, rbits->qws_len);
685
+ memcpy(rbits->ptr, bits->ptr, rbits->qws_len*8);
686
+
687
+ bs_not(rbits);
688
+
689
+ return obj;
690
+ }
691
+
692
+ static VALUE bits_and(VALUE self, VALUE other) {
693
+ VALUE r;
694
+ struct BitVector *rbits, *xbits, *ybits;
695
+
696
+ Data_Get_Struct(self, struct BitVector, xbits);
697
+ Data_Get_Struct(other, struct BitVector, ybits);
698
+
699
+ r = Data_Make_Struct(CLASS_OF(self), struct BitVector, NULL, bits_free, rbits);
700
+
701
+ bs_and(rbits, xbits, ybits);
702
+
703
+ return r;
704
+ }
705
+
706
+ static VALUE bits_xor(VALUE self, VALUE other) {
707
+ VALUE obj;
708
+ struct BitVector *bits, *rbits, *xbits;
709
+
710
+ Data_Get_Struct(self, struct BitVector, bits);
711
+
712
+ obj = Data_Make_Struct(CLASS_OF(self), struct BitVector, NULL, bits_free, rbits);
713
+ *rbits = *bits;
714
+ rbits->ptr = ALLOC_N(uint64_t, rbits->qws_len);
715
+ memcpy(rbits->ptr, bits->ptr, rbits->qws_len*8);
716
+
717
+ Data_Get_Struct(other, struct BitVector, xbits);
718
+ bs_xor(rbits, xbits);
719
+
720
+ return obj;
721
+ }
722
+
723
+ /* r = a and ~b */
724
+ static VALUE bits_minus(VALUE self, VALUE other) {
725
+ VALUE r;
726
+ struct BitVector i;
727
+ struct BitVector *rbits, *xbits, *ybits, *ibits;
728
+
729
+ Data_Get_Struct(self, struct BitVector, xbits);
730
+ Data_Get_Struct(other, struct BitVector, ybits);
731
+ r = Data_Make_Struct(CLASS_OF(self), struct BitVector, NULL, bits_free, rbits);
732
+
733
+ ibits = &i;
734
+ *ibits = *ybits;
735
+ ibits->ptr = ALLOC_N(uint64_t, ibits->qws_len);
736
+ memcpy(ibits->ptr, ybits->ptr, ibits->qws_len*8);
737
+
738
+ if (xbits->bit_len > ybits->bit_len) bs_resize(ibits, xbits->bit_len);
739
+ bs_not(ibits);
740
+ bs_and(rbits, xbits, ibits);
741
+
742
+ return r;
743
+ }
744
+
745
+ static VALUE bits_cmp(VALUE self, VALUE other) {
746
+ struct BitVector *sbits, *obits;
747
+ int64_t smax,omax,qws;
748
+ uint64_t *sptr,*optr, sqw, oqw;
749
+
750
+ Data_Get_Struct(self, struct BitVector, sbits);
751
+ Data_Get_Struct(other, struct BitVector, obits);
752
+
753
+ smax = bs_max(sbits);
754
+ omax = bs_max(obits);
755
+ if (smax < omax) {
756
+ return INT2FIX(-1);
757
+ } else if (smax > omax) {
758
+ return INT2FIX(1);
759
+ }
760
+
761
+ if (smax < 0) {
762
+ return INT2FIX(0);
763
+ }
764
+
765
+ qws = (smax+63)/64;
766
+ sptr = sbits->ptr + qws - 1;
767
+ optr = obits->ptr + qws - 1;
768
+ while(qws--) {
769
+ sqw = *sptr--;
770
+ oqw = *optr--;
771
+ if (sqw < oqw) {
772
+ return INT2FIX(-1);
773
+ } else if (sqw > oqw) {
774
+ return INT2FIX(1);
775
+ }
776
+ }
777
+
778
+ return INT2FIX(0);
779
+ }
780
+
781
+
782
+ static VALUE bits_zero(VALUE self) {
783
+ struct BitVector *bits;
784
+ uint64_t *ptr;
785
+ int64_t i;
786
+
787
+ Data_Get_Struct(self, struct BitVector, bits);
788
+
789
+ ptr = bits->ptr;
790
+ for(i=0 ; i<bits->qws_len; i++) {
791
+ if (*ptr++ != 0) {
792
+ return Qfalse;
793
+ }
794
+ }
795
+
796
+ return Qtrue;
797
+ }
798
+
799
+ static VALUE bits_nonzero(VALUE self) {
800
+ struct BitVector *bits;
801
+ uint64_t *ptr;
802
+ int64_t i;
803
+
804
+ Data_Get_Struct(self, struct BitVector, bits);
805
+
806
+ ptr = bits->ptr;
807
+ for(i=0 ; i<bits->qws_len; i++) {
808
+ if (*ptr++ != 0) {
809
+ return Qtrue;
810
+ }
811
+ }
812
+
813
+ return Qfalse;
814
+ }
815
+
816
+ static VALUE bits_max(VALUE self) {
817
+ struct BitVector *bits;
818
+ int64_t index;
819
+
820
+ Data_Get_Struct(self, struct BitVector, bits);
821
+
822
+ index = bs_max(bits);
823
+
824
+ if (index >= 0) {
825
+ return LONG2FIX(index);
826
+ } else {
827
+ return Qnil;
828
+ }
829
+ }
830
+
831
+ static VALUE bits_min(VALUE self) {
832
+ struct BitVector *bits;
833
+ int64_t index;
834
+
835
+ Data_Get_Struct(self, struct BitVector, bits);
836
+
837
+ index = bs_min(bits);
838
+
839
+ if (index >= 0) {
840
+ return LONG2FIX(index);
841
+ } else {
842
+ return Qnil;
843
+ }
844
+ }
845
+
846
+ static VALUE bits_norm(VALUE self) {
847
+ VALUE obj;
848
+ struct BitVector *bits;
849
+ int64_t index;
850
+
851
+ obj = bits_dup(self);
852
+ Data_Get_Struct(obj, struct BitVector, bits);
853
+
854
+ index = bs_max(bits);
855
+ if (index < 0) {
856
+ index = 1;
857
+ } else {
858
+ index = index + 1;
859
+ }
860
+ bs_resize(bits, index);
861
+
862
+ return obj;
863
+ }
864
+
865
+ static VALUE bits_normx(VALUE self) {
866
+ struct BitVector *bits;
867
+ int64_t index;
868
+
869
+ Data_Get_Struct(self, struct BitVector, bits);
870
+
871
+ index = bs_max(bits);
872
+
873
+ if (index < 0) {
874
+ index = 1;
875
+ } else {
876
+ index = index + 1;
877
+ }
878
+ bs_resize(bits, index);
879
+
880
+ return self;
881
+ }
882
+
883
+ static VALUE bits_to_ary(VALUE self) {
884
+ VALUE ary;
885
+ struct BitVector *bits;
886
+ int64_t from, to, index;
887
+
888
+ Data_Get_Struct(self, struct BitVector, bits);
889
+
890
+ ary = rb_ary_new();
891
+
892
+ for (index = 0; index != -1;) {
893
+ index = bs_index(bits, 1, index);
894
+ if (index < 0) break;
895
+ from = index;
896
+ to = from;
897
+ do {
898
+ index = bs_index(bits, 1, index+1);
899
+ if (index == -1) break;
900
+ if (index == to + 1) to = index;
901
+ } while (index == to);
902
+
903
+ if (from==to) {
904
+ rb_ary_push(ary, LONG2FIX(from));
905
+ } else {
906
+ rb_ary_push(ary, rb_funcall(rb_cRange, id_new, 2, LONG2FIX(from), LONG2FIX(to)));
907
+ }
908
+ }
909
+ return ary;
910
+ }
911
+
912
+ static VALUE bits_to_bytes(VALUE self) {
913
+ struct BitVector *bits;
914
+ VALUE rs;
915
+
916
+ Data_Get_Struct(self, struct BitVector, bits);
917
+
918
+ int64_t len = bs_bytesize(bits);
919
+
920
+ rs = rb_str_new(0, len);
921
+
922
+ memcpy(RSTRING_PTR(rs), bits->ptr, len);
923
+
924
+ return rs;
925
+ }
926
+
927
+ static VALUE bits_each(VALUE self) {
928
+ struct BitVector *bits;
929
+ int64_t idx;
930
+
931
+ Data_Get_Struct(self, struct BitVector, bits);
932
+
933
+ for(idx=0; idx < bits->bit_len; idx++) {
934
+ if (bs_get(bits, idx)) {
935
+ rb_yield(LONG2FIX(idx));
936
+ }
937
+ }
938
+
939
+ return self;
940
+ }
941
+
942
+ static VALUE bits_count(VALUE self) {
943
+ struct BitVector *bits;
944
+ uint64_t *ptr, qw;
945
+ int64_t count;
946
+ int64_t i;
947
+
948
+ Data_Get_Struct(self, struct BitVector, bits);
949
+
950
+ count = 0;
951
+ ptr = bits->ptr;
952
+ for(i = 0 ; i < bits->qws_len; i++) {
953
+ qw = *ptr++;
954
+ __asm ( "mov %1, %%r8 \n"
955
+ "bs_count: \n"
956
+ "bsf %%r8, %%r11 \n"
957
+ "jz bs_count_exit \n"
958
+ "inc %0 \n"
959
+ "btr %%r11, %%r8 \n"
960
+ "jmp bs_count \n"
961
+ "bs_count_exit: \n"
962
+ : "=&r"(count) : "r"(qw) : "%r8", "cc", "memory"
963
+ );
964
+ }
965
+
966
+ return LONG2FIX(count);
967
+ }
968
+
969
+ void Init_bit_vector() {
970
+ cBitVector = rb_define_class("BitVector", rb_cObject);
971
+ rb_include_module(cBitVector, rb_mComparable);
972
+
973
+ rb_define_singleton_method(cBitVector, "new", bits_s_new, -1 );
974
+ rb_define_singleton_method(cBitVector, "from_bytes", bits_s_from_bytes, 1 );
975
+
976
+ rb_define_method(cBitVector, "size", bits_length, 0);
977
+ rb_define_method(cBitVector, "size=", bits_resize, 1);
978
+ rb_define_method(cBitVector, "length", bits_length, 0);
979
+ rb_define_method(cBitVector, "bytesize", bits_bytesize, 0);
980
+ rb_define_method(cBitVector, "to_s", bits_to_s, 0);
981
+ rb_define_method(cBitVector, "dup", bits_dup, 0);
982
+ rb_define_method(cBitVector, "clone", bits_dup, 0);
983
+ rb_define_method(cBitVector, "slice", bits_slice, 1);
984
+ rb_define_method(cBitVector, "index", bits_index, 2);
985
+ rb_define_method(cBitVector, "clear", bits_clear, 0);
986
+ rb_define_method(cBitVector, "get", bits_get, 1);
987
+ rb_define_method(cBitVector, "[]", bits_get, 1);
988
+ rb_define_method(cBitVector, "set", bits_set, 2);
989
+ rb_define_method(cBitVector, "[]=", bits_set, 2);
990
+ rb_define_method(cBitVector, "on", bits_on, -1);
991
+ rb_define_method(cBitVector, "off", bits_off, -1);
992
+
993
+ rb_define_method(cBitVector, "|", bits_or, 1);
994
+ rb_define_method(cBitVector, "~", bits_not, 0);
995
+ rb_define_method(cBitVector, "&", bits_and, 1);
996
+ rb_define_method(cBitVector, "^", bits_xor, 1);
997
+ rb_define_method(cBitVector, "+", bits_or, 1);
998
+ rb_define_method(cBitVector, "-", bits_minus, 1);
999
+ rb_define_method(cBitVector, "*", bits_and, 1);
1000
+ rb_define_method(cBitVector, "<=>", bits_cmp, 1);
1001
+
1002
+ rb_define_method(cBitVector, "zero?", bits_zero, 0);
1003
+ rb_define_method(cBitVector, "nonzero?", bits_nonzero, 0);
1004
+ rb_define_method(cBitVector, "max", bits_max, 0);
1005
+ rb_define_method(cBitVector, "min", bits_min, 0);
1006
+ rb_define_method(cBitVector, "normalize", bits_norm, 0);
1007
+ rb_define_method(cBitVector, "normalize!", bits_normx, 0);
1008
+
1009
+ rb_define_method(cBitVector, "to_ary", bits_to_ary, 0);
1010
+ rb_define_method(cBitVector, "to_bytes", bits_to_bytes, 0);
1011
+ rb_define_method(cBitVector, "count", bits_count, 0);
1012
+
1013
+ rb_define_method(cBitVector, "each", bits_each, 0);
1014
+ /* rb_include_module(cBitVector, rb_mEnumerable); */
1015
+
1016
+ id_new = rb_intern("new");
1017
+ id_first = rb_intern("first");
1018
+ id_end = rb_intern("end");
1019
+ }