bit_vector 0.9

Sign up to get free protection for your applications and to get access to all the features.
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
+ }