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 +7 -0
- data/.gemtest +0 -0
- data/README.md +52 -0
- data/Rakefile +55 -0
- data/ext/bit_vector/Makefile +238 -0
- data/ext/bit_vector/bit_vector.bundle +0 -0
- data/ext/bit_vector/bit_vector.c +1019 -0
- data/ext/bit_vector/bit_vector.o +0 -0
- data/ext/bit_vector/extconf.rb +8 -0
- data/lib/bit_vector/version.rb +3 -0
- data/test/benchmark.rb +496 -0
- data/test/encoding.rb +26 -0
- data/test/spec.rb +309 -0
- data/test/test.rb +585 -0
- metadata +78 -0
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
|
+
}
|