bit-twiddle 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/LICENSE +1 -1
- data/README.md +3 -4
- data/ext/bit_twiddle/Makefile +266 -0
- data/ext/bit_twiddle/bit_twiddle.c +1879 -0
- data/ext/bit_twiddle/bit_twiddle.o +0 -0
- data/ext/bit_twiddle/bit_twiddle.so +0 -0
- data/ext/bit_twiddle/extconf.rb +26 -6
- data/ext/bit_twiddle/mkmf.log +270 -0
- data/ext/bit_twiddle/ruby22/bt_bignum.h +61 -0
- data/ext/bit_twiddle/ruby23/bt_bignum.h +52 -0
- data/ext/bit_twiddle/ruby30/bt_bignum.h +83 -0
- data/lib/bit-twiddle/core_ext.rb +2 -0
- data/lib/bit_twiddle.so +0 -0
- metadata +24 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ea6d4c9db54e566dc5c8a45e8ab95a41fec390f45358092351967501a4248d9c
|
4
|
+
data.tar.gz: f25c14b7aaba7912a12e77e79f1ad4542d6f13d8ac36c2ef85a3f9bc83589908
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 276b6e1717614ef408cc52275612aa78cc3ef17fcb46d77771ff433d0cb6f26f976b30efcb97a9c1fabedd6fbeafa850edbce322e475db512d6d902d9adaefc2
|
7
|
+
data.tar.gz: ce967635d56d3b9425e6036a242cb87da2995a261b703b6c6024776df02a5c1dd30e68d74cc12c28bbbea7672cdd3851eb10af497b302e4ca4306f1fbc2653d2
|
data/LICENSE
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
The program code in the 'bit-twiddle' repository (currently available at https://github.com/alexdowad/bit-twiddle) has been placed in the public domain by its author. You can do anything you want with it, anything at all. You can copy it, sell it, buy it, lease it, rent it out, put it in pawn, or use it as a down payment on a new truck. You can sing it out in the shower, or on a crowded bus. You can even inscribe it on a silk flag, and plant it on Kilimanjaro's snow-covered slopes. The possibilities are endless!
|
2
2
|
|
3
|
-
If
|
3
|
+
If 'public domain' isn't what you like, then you can use this code under a CC0 (creative commons) license. Still no good? Drop the author a note and we'll see how to fix you up.
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
|
1
|
+
Fast bitwise operations for Ruby
|
2
|
+
================================
|
2
3
|
|
3
|
-
Ruby has built-in implementations of the "workhorses" of bit manipulation: bitwise AND, OR, NOT, and XOR operations and bit shifts. This library adds more bitwise operations, which may be useful in implementing some algorithms. All the added operations are implemented in optimized C code (so this is MRI-only).
|
4
|
+
Ruby has built-in implementations of the "workhorses" of bit manipulation: bitwise AND, OR, NOT, and XOR operations and bit shifts. This library adds more bitwise operations, which may be useful in implementing some algorithms. All the added operations are implemented in optimized C code (so this is MRI-only).
|
4
5
|
|
5
6
|
Install this goodness with:
|
6
7
|
|
@@ -22,8 +23,6 @@ require "bit-twiddle/core_ext"
|
|
22
23
|
|
23
24
|
In many cases, `bit-twiddle` operations explicitly work on the low 8, 16, 32, or 64 bits of an integer. (For example, it defines `#bitreverse8`, `#bitreverse16`, `#bitreverse32`, and `#bitreverse64` methods.) If an integer's bit width is larger than the number of bits operated on, the higher-end bits are passed through unchanged.
|
24
25
|
|
25
|
-
All methods automatically convert between `Fixnum` and `Bignum` as is most appropriate to represent their result.
|
26
|
-
|
27
26
|
## Examples
|
28
27
|
|
29
28
|
### Population count
|
@@ -0,0 +1,266 @@
|
|
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
|
+
NULLCMD = :
|
11
|
+
|
12
|
+
#### Start of system configuration section. ####
|
13
|
+
|
14
|
+
srcdir = .
|
15
|
+
topdir = /home/alex/.rbenv/versions/2.7.2/include/ruby-2.7.0
|
16
|
+
hdrdir = $(topdir)
|
17
|
+
arch_hdrdir = /home/alex/.rbenv/versions/2.7.2/include/ruby-2.7.0/x86_64-linux
|
18
|
+
PATH_SEPARATOR = :
|
19
|
+
VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
|
20
|
+
prefix = $(DESTDIR)/home/alex/.rbenv/versions/2.7.2
|
21
|
+
rubysitearchprefix = $(rubylibprefix)/$(sitearch)
|
22
|
+
rubyarchprefix = $(rubylibprefix)/$(arch)
|
23
|
+
rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
|
24
|
+
exec_prefix = $(prefix)
|
25
|
+
vendorarchhdrdir = $(vendorhdrdir)/$(sitearch)
|
26
|
+
sitearchhdrdir = $(sitehdrdir)/$(sitearch)
|
27
|
+
rubyarchhdrdir = $(rubyhdrdir)/$(arch)
|
28
|
+
vendorhdrdir = $(rubyhdrdir)/vendor_ruby
|
29
|
+
sitehdrdir = $(rubyhdrdir)/site_ruby
|
30
|
+
rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME)
|
31
|
+
vendorarchdir = $(vendorlibdir)/$(sitearch)
|
32
|
+
vendorlibdir = $(vendordir)/$(ruby_version)
|
33
|
+
vendordir = $(rubylibprefix)/vendor_ruby
|
34
|
+
sitearchdir = $(sitelibdir)/$(sitearch)
|
35
|
+
sitelibdir = $(sitedir)/$(ruby_version)
|
36
|
+
sitedir = $(rubylibprefix)/site_ruby
|
37
|
+
rubyarchdir = $(rubylibdir)/$(arch)
|
38
|
+
rubylibdir = $(rubylibprefix)/$(ruby_version)
|
39
|
+
sitearchincludedir = $(includedir)/$(sitearch)
|
40
|
+
archincludedir = $(includedir)/$(arch)
|
41
|
+
sitearchlibdir = $(libdir)/$(sitearch)
|
42
|
+
archlibdir = $(libdir)/$(arch)
|
43
|
+
ridir = $(datarootdir)/$(RI_BASE_NAME)
|
44
|
+
mandir = $(datarootdir)/man
|
45
|
+
localedir = $(datarootdir)/locale
|
46
|
+
libdir = $(exec_prefix)/lib
|
47
|
+
psdir = $(docdir)
|
48
|
+
pdfdir = $(docdir)
|
49
|
+
dvidir = $(docdir)
|
50
|
+
htmldir = $(docdir)
|
51
|
+
infodir = $(datarootdir)/info
|
52
|
+
docdir = $(datarootdir)/doc/$(PACKAGE)
|
53
|
+
oldincludedir = $(DESTDIR)/usr/include
|
54
|
+
includedir = $(prefix)/include
|
55
|
+
runstatedir = $(localstatedir)/run
|
56
|
+
localstatedir = $(prefix)/var
|
57
|
+
sharedstatedir = $(prefix)/com
|
58
|
+
sysconfdir = $(prefix)/etc
|
59
|
+
datadir = $(datarootdir)
|
60
|
+
datarootdir = $(prefix)/share
|
61
|
+
libexecdir = $(exec_prefix)/libexec
|
62
|
+
sbindir = $(exec_prefix)/sbin
|
63
|
+
bindir = $(exec_prefix)/bin
|
64
|
+
archdir = $(rubyarchdir)
|
65
|
+
|
66
|
+
|
67
|
+
CC_WRAPPER =
|
68
|
+
CC = gcc
|
69
|
+
CXX = g++
|
70
|
+
LIBRUBY = $(LIBRUBY_SO)
|
71
|
+
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
72
|
+
LIBRUBYARG_SHARED = -Wl,-rpath,$(libdir) -L$(libdir) -l$(RUBY_SO_NAME)
|
73
|
+
LIBRUBYARG_STATIC = -Wl,-rpath,$(libdir) -L$(libdir) -l$(RUBY_SO_NAME)-static $(MAINLIBS)
|
74
|
+
empty =
|
75
|
+
OUTFLAG = -o $(empty)
|
76
|
+
COUTFLAG = -o $(empty)
|
77
|
+
CSRCFLAG = $(empty)
|
78
|
+
|
79
|
+
RUBY_EXTCONF_H =
|
80
|
+
cflags = $(optflags) $(debugflags) $(warnflags)
|
81
|
+
cxxflags =
|
82
|
+
optflags = -O3
|
83
|
+
debugflags = -ggdb3
|
84
|
+
warnflags = -Wall -Wextra -Wdeprecated-declarations -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wwrite-strings -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable
|
85
|
+
cppflags =
|
86
|
+
CCDLFLAGS = -fPIC
|
87
|
+
CFLAGS = $(CCDLFLAGS) $(cflags) -fPIC -Wall -Wno-unknown-warning-option -Wno-unknown-attributes -Wno-ignored-attributes -Werror -O3 -march=native -mtune=native -std=c99 -I./ruby23 $(ARCH_FLAG)
|
88
|
+
INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
|
89
|
+
DEFS =
|
90
|
+
CPPFLAGS = -DSIZEOF_SHORT=2 -DSIZEOF_INT=4 -DSIZEOF_LONG=8 -DSIZEOF_LONG_LONG=8 -DHAVE_TYPE_ULONG -DRSHIFT_IS_ARITH=1 -DHAVE_BSWAP16=1 -I/home/alex/.rbenv/versions/2.7.2/include $(DEFS) $(cppflags)
|
91
|
+
CXXFLAGS = $(CCDLFLAGS) -g -O2 $(ARCH_FLAG)
|
92
|
+
ldflags = -L. -L/home/alex/.rbenv/versions/2.7.2/lib -fstack-protector-strong -rdynamic -Wl,-export-dynamic
|
93
|
+
dldflags = -L/home/alex/.rbenv/versions/2.7.2/lib -Wl,--compress-debug-sections=zlib
|
94
|
+
ARCH_FLAG =
|
95
|
+
DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
|
96
|
+
LDSHARED = $(CC) -shared
|
97
|
+
LDSHAREDXX = $(CXX) -shared
|
98
|
+
AR = ar
|
99
|
+
EXEEXT =
|
100
|
+
|
101
|
+
RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)
|
102
|
+
RUBY_SO_NAME = ruby
|
103
|
+
RUBYW_INSTALL_NAME =
|
104
|
+
RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version)
|
105
|
+
RUBYW_BASE_NAME = rubyw
|
106
|
+
RUBY_BASE_NAME = ruby
|
107
|
+
|
108
|
+
arch = x86_64-linux
|
109
|
+
sitearch = $(arch)
|
110
|
+
ruby_version = 2.7.0
|
111
|
+
ruby = $(bindir)/$(RUBY_BASE_NAME)
|
112
|
+
RUBY = $(ruby)
|
113
|
+
ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h
|
114
|
+
|
115
|
+
RM = rm -f
|
116
|
+
RM_RF = $(RUBY) -run -e rm -- -rf
|
117
|
+
RMDIRS = rmdir --ignore-fail-on-non-empty -p
|
118
|
+
MAKEDIRS = /bin/mkdir -p
|
119
|
+
INSTALL = /usr/bin/install -c
|
120
|
+
INSTALL_PROG = $(INSTALL) -m 0755
|
121
|
+
INSTALL_DATA = $(INSTALL) -m 644
|
122
|
+
COPY = cp
|
123
|
+
TOUCH = exit >
|
124
|
+
|
125
|
+
#### End of system configuration section. ####
|
126
|
+
|
127
|
+
preload =
|
128
|
+
libpath = . $(libdir)
|
129
|
+
LIBPATH = -L. -L$(libdir) -Wl,-rpath,$(libdir)
|
130
|
+
DEFFILE =
|
131
|
+
|
132
|
+
CLEANFILES = mkmf.log
|
133
|
+
DISTCLEANFILES =
|
134
|
+
DISTCLEANDIRS =
|
135
|
+
|
136
|
+
extout =
|
137
|
+
extout_prefix =
|
138
|
+
target_prefix =
|
139
|
+
LOCAL_LIBS =
|
140
|
+
LIBS = $(LIBRUBYARG_SHARED) -lm -lc
|
141
|
+
ORIG_SRCS = bit_twiddle.c
|
142
|
+
SRCS = $(ORIG_SRCS)
|
143
|
+
OBJS = bit_twiddle.o
|
144
|
+
HDRS =
|
145
|
+
LOCAL_HDRS =
|
146
|
+
TARGET = bit_twiddle
|
147
|
+
TARGET_NAME = bit_twiddle
|
148
|
+
TARGET_ENTRY = Init_$(TARGET_NAME)
|
149
|
+
DLLIB = $(TARGET).so
|
150
|
+
EXTSTATIC =
|
151
|
+
STATIC_LIB =
|
152
|
+
|
153
|
+
TIMESTAMP_DIR = .
|
154
|
+
BINDIR = $(bindir)
|
155
|
+
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
156
|
+
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
157
|
+
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
158
|
+
HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
|
159
|
+
ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
|
160
|
+
TARGET_SO_DIR =
|
161
|
+
TARGET_SO = $(TARGET_SO_DIR)$(DLLIB)
|
162
|
+
CLEANLIBS = $(TARGET_SO)
|
163
|
+
CLEANOBJS = *.o *.bak
|
164
|
+
|
165
|
+
all: $(DLLIB)
|
166
|
+
static: $(STATIC_LIB)
|
167
|
+
.PHONY: all install static install-so install-rb
|
168
|
+
.PHONY: clean clean-so clean-static clean-rb
|
169
|
+
|
170
|
+
clean-static::
|
171
|
+
clean-rb-default::
|
172
|
+
clean-rb::
|
173
|
+
clean-so::
|
174
|
+
clean: clean-so clean-static clean-rb-default clean-rb
|
175
|
+
-$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time
|
176
|
+
|
177
|
+
distclean-rb-default::
|
178
|
+
distclean-rb::
|
179
|
+
distclean-so::
|
180
|
+
distclean-static::
|
181
|
+
distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb
|
182
|
+
-$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
|
183
|
+
-$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
184
|
+
-$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true
|
185
|
+
|
186
|
+
realclean: distclean
|
187
|
+
install: install-so install-rb
|
188
|
+
|
189
|
+
install-so: $(DLLIB) $(TIMESTAMP_DIR)/.sitearchdir.time
|
190
|
+
$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
|
191
|
+
clean-static::
|
192
|
+
-$(Q)$(RM) $(STATIC_LIB)
|
193
|
+
install-rb: pre-install-rb do-install-rb install-rb-default
|
194
|
+
install-rb-default: pre-install-rb-default do-install-rb-default
|
195
|
+
pre-install-rb: Makefile
|
196
|
+
pre-install-rb-default: Makefile
|
197
|
+
do-install-rb:
|
198
|
+
do-install-rb-default:
|
199
|
+
pre-install-rb-default:
|
200
|
+
@$(NULLCMD)
|
201
|
+
$(TIMESTAMP_DIR)/.sitearchdir.time:
|
202
|
+
$(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR)
|
203
|
+
$(Q) $(TOUCH) $@
|
204
|
+
|
205
|
+
site-install: site-install-so site-install-rb
|
206
|
+
site-install-so: install-so
|
207
|
+
site-install-rb: install-rb
|
208
|
+
|
209
|
+
.SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S
|
210
|
+
|
211
|
+
.cc.o:
|
212
|
+
$(ECHO) compiling $(<)
|
213
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
|
214
|
+
|
215
|
+
.cc.S:
|
216
|
+
$(ECHO) translating $(<)
|
217
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
|
218
|
+
|
219
|
+
.mm.o:
|
220
|
+
$(ECHO) compiling $(<)
|
221
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
|
222
|
+
|
223
|
+
.mm.S:
|
224
|
+
$(ECHO) translating $(<)
|
225
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
|
226
|
+
|
227
|
+
.cxx.o:
|
228
|
+
$(ECHO) compiling $(<)
|
229
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
|
230
|
+
|
231
|
+
.cxx.S:
|
232
|
+
$(ECHO) translating $(<)
|
233
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
|
234
|
+
|
235
|
+
.cpp.o:
|
236
|
+
$(ECHO) compiling $(<)
|
237
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
|
238
|
+
|
239
|
+
.cpp.S:
|
240
|
+
$(ECHO) translating $(<)
|
241
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
|
242
|
+
|
243
|
+
.c.o:
|
244
|
+
$(ECHO) compiling $(<)
|
245
|
+
$(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
|
246
|
+
|
247
|
+
.c.S:
|
248
|
+
$(ECHO) translating $(<)
|
249
|
+
$(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
|
250
|
+
|
251
|
+
.m.o:
|
252
|
+
$(ECHO) compiling $(<)
|
253
|
+
$(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
|
254
|
+
|
255
|
+
.m.S:
|
256
|
+
$(ECHO) translating $(<)
|
257
|
+
$(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
|
258
|
+
|
259
|
+
$(TARGET_SO): $(OBJS) Makefile
|
260
|
+
$(ECHO) linking shared-object $(DLLIB)
|
261
|
+
-$(Q)$(RM) $(@)
|
262
|
+
$(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
|
263
|
+
|
264
|
+
|
265
|
+
|
266
|
+
$(OBJS): $(HDRS) $(ruby_headers)
|
@@ -0,0 +1,1879 @@
|
|
1
|
+
/* Fast C implementation of additional bitwise operations for Ruby
|
2
|
+
* Hand-crafted with ♥ by Alex Dowad, using ONLY the finest 1s and 0s */
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
#include "bt_bignum.h"
|
6
|
+
|
7
|
+
#ifndef HAVE_TYPE_ULONG
|
8
|
+
typedef unsigned long ulong;
|
9
|
+
#endif
|
10
|
+
#ifndef HAVE_TYPE_UCHAR
|
11
|
+
typedef unsigned char uchar;
|
12
|
+
#endif
|
13
|
+
|
14
|
+
#define fix_zero LONG2FIX(0L)
|
15
|
+
#define BIGNUM_P(x) RB_TYPE_P((x), T_BIGNUM)
|
16
|
+
|
17
|
+
#if SIZEOF_BDIGIT == SIZEOF_LONG
|
18
|
+
|
19
|
+
#define popcount_bdigit __builtin_popcountl
|
20
|
+
#define ffs_bdigit __builtin_ffsl
|
21
|
+
#define clz_bdigit __builtin_clzl
|
22
|
+
|
23
|
+
#elif SIZEOF_BDIGIT == SIZEOF_INT
|
24
|
+
|
25
|
+
#define popcount_bdigit __builtin_popcount
|
26
|
+
#define ffs_bdigit __builtin_ffs
|
27
|
+
#define clz_bdigit __builtin_clz
|
28
|
+
|
29
|
+
#else
|
30
|
+
#error "What is the size of a Ruby Bignum digit on this platform???"
|
31
|
+
#endif
|
32
|
+
|
33
|
+
#if SIZEOF_BDIGIT < 4
|
34
|
+
#error "Sorry, Integer#bswap32 and Integer#arith_rshift32 will not work if sizeof(BDIGIT) < 4. Please report this error."
|
35
|
+
#elif SIZEOF_BDIGIT > 8
|
36
|
+
#error "Sorry, several methods will not work if sizeof(BDIGIT) > 8. Please report this error."
|
37
|
+
#elif SIZEOF_LONG > 8
|
38
|
+
#error "Sorry, Integer#arith_rshift64 will not work if sizeof(long) > 8. Please report this error."
|
39
|
+
#endif
|
40
|
+
|
41
|
+
#if HAVE_BSWAP16 == 0
|
42
|
+
/* stupid bug in GCC 4.7 */
|
43
|
+
static inline uint16_t __builtin_bswap16(uint16_t value)
|
44
|
+
{
|
45
|
+
return (value >> 8) | (value << 8);
|
46
|
+
}
|
47
|
+
#endif
|
48
|
+
|
49
|
+
static int
|
50
|
+
bnum_greater(VALUE bnum, BDIGIT value)
|
51
|
+
{
|
52
|
+
BDIGIT *digits = RBIGNUM_DIGITS(bnum);
|
53
|
+
size_t len = RBIGNUM_LEN(bnum);
|
54
|
+
if (*digits > value)
|
55
|
+
return 1;
|
56
|
+
while (--len)
|
57
|
+
if (*++digits > 0)
|
58
|
+
return 1;
|
59
|
+
return 0;
|
60
|
+
}
|
61
|
+
|
62
|
+
static long
|
63
|
+
value_to_shiftdist(VALUE shiftdist, unsigned int bits)
|
64
|
+
{
|
65
|
+
for (;;) {
|
66
|
+
if (FIXNUM_P(shiftdist)) {
|
67
|
+
return FIX2LONG(shiftdist);
|
68
|
+
} else if (BIGNUM_P(shiftdist)) {
|
69
|
+
long sdist;
|
70
|
+
if (bnum_greater(shiftdist, bits-1))
|
71
|
+
sdist = bits;
|
72
|
+
else
|
73
|
+
sdist = *RBIGNUM_DIGITS(shiftdist);
|
74
|
+
if (RBIGNUM_NEGATIVE_P(shiftdist))
|
75
|
+
sdist = -sdist;
|
76
|
+
return sdist;
|
77
|
+
} else {
|
78
|
+
shiftdist = rb_to_int(shiftdist);
|
79
|
+
}
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
/* 'mask' is 0x7 for 8, 0xF for 16, 0x1F for 32, 0x3F for 64
|
84
|
+
* return value is always positive! */
|
85
|
+
static ulong
|
86
|
+
value_to_rotdist(VALUE rotdist, long bits, long mask)
|
87
|
+
{
|
88
|
+
for (;;) {
|
89
|
+
long rdist;
|
90
|
+
if (FIXNUM_P(rotdist)) {
|
91
|
+
rdist = FIX2LONG(rotdist) % bits;
|
92
|
+
if (rdist < 0)
|
93
|
+
rdist += bits;
|
94
|
+
return (ulong)rdist;
|
95
|
+
} else if (BIGNUM_P(rotdist)) {
|
96
|
+
rdist = *RBIGNUM_DIGITS(rotdist) & mask;
|
97
|
+
if (RBIGNUM_NEGATIVE_P(rotdist))
|
98
|
+
rdist = bits - rdist;
|
99
|
+
return (ulong)rdist;
|
100
|
+
} else {
|
101
|
+
rotdist = rb_to_int(rotdist);
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
static void
|
107
|
+
store_64_into_bnum(VALUE bnum, uint64_t int64)
|
108
|
+
{
|
109
|
+
BDIGIT *dest = RBIGNUM_DIGITS(bnum);
|
110
|
+
size_t len = RBIGNUM_LEN(bnum);
|
111
|
+
|
112
|
+
#if (SIZEOF_BDIGIT == 8)
|
113
|
+
*dest = int64;
|
114
|
+
#else
|
115
|
+
if (len > 1) {
|
116
|
+
*dest = (uint32_t)int64;
|
117
|
+
*(dest+1) = (uint32_t)(int64 >> 32);
|
118
|
+
} else if ((int64 & (0xFFFFFFFFULL << 32)) == 0) {
|
119
|
+
/* the high 4 bytes are zero anyways */
|
120
|
+
*dest = (uint32_t)int64;
|
121
|
+
} else {
|
122
|
+
rb_big_resize(bnum, 2);
|
123
|
+
dest = RBIGNUM_DIGITS(bnum); /* may have moved */
|
124
|
+
*dest = (uint32_t)int64;
|
125
|
+
*(dest+1) = (uint32_t)(int64 >> 32);
|
126
|
+
}
|
127
|
+
#endif
|
128
|
+
}
|
129
|
+
|
130
|
+
static uint64_t
|
131
|
+
load_64_from_bignum(VALUE bnum)
|
132
|
+
{
|
133
|
+
BDIGIT *src = RBIGNUM_DIGITS(bnum);
|
134
|
+
size_t len = RBIGNUM_LEN(bnum);
|
135
|
+
uint64_t result = *src;
|
136
|
+
|
137
|
+
if (SIZEOF_BDIGIT == 4 && len > 1)
|
138
|
+
result += ((uint64_t)*(src+1)) << 32;
|
139
|
+
|
140
|
+
return result;
|
141
|
+
}
|
142
|
+
|
143
|
+
static VALUE
|
144
|
+
modify_lo8_in_bignum(VALUE bnum, uint8_t lo8)
|
145
|
+
{
|
146
|
+
VALUE result;
|
147
|
+
|
148
|
+
if (lo8 == (uint8_t)*RBIGNUM_DIGITS(bnum))
|
149
|
+
return bnum;
|
150
|
+
|
151
|
+
result = rb_big_clone(bnum);
|
152
|
+
*RBIGNUM_DIGITS(result) = (*RBIGNUM_DIGITS(bnum) & ~0xFFL) | lo8;
|
153
|
+
return result;
|
154
|
+
}
|
155
|
+
|
156
|
+
static VALUE
|
157
|
+
modify_lo16_in_bignum(VALUE bnum, uint16_t lo16)
|
158
|
+
{
|
159
|
+
VALUE result;
|
160
|
+
|
161
|
+
if (lo16 == (uint16_t)*RBIGNUM_DIGITS(bnum))
|
162
|
+
return bnum;
|
163
|
+
|
164
|
+
result = rb_big_clone(bnum);
|
165
|
+
*RBIGNUM_DIGITS(result) = (*RBIGNUM_DIGITS(bnum) & ~0xFFFFL) | lo16;
|
166
|
+
return result;
|
167
|
+
}
|
168
|
+
|
169
|
+
static VALUE
|
170
|
+
modify_lo32_in_bignum(VALUE bnum, uint32_t lo32)
|
171
|
+
{
|
172
|
+
BDIGIT value;
|
173
|
+
VALUE result;
|
174
|
+
|
175
|
+
if (lo32 == (uint32_t)*RBIGNUM_DIGITS(bnum))
|
176
|
+
return bnum;
|
177
|
+
|
178
|
+
if (SIZEOF_BDIGIT == 4)
|
179
|
+
value = lo32;
|
180
|
+
else
|
181
|
+
value = (*RBIGNUM_DIGITS(bnum) & ~0xFFFFFFFFL) | lo32;
|
182
|
+
|
183
|
+
#if SIZEOF_LONG == 4
|
184
|
+
/* if a 'long' is only 4 bytes, a 32-bit number could be promoted to Bignum
|
185
|
+
* then modifying the low 32 bits could make it fixable again */
|
186
|
+
if (RBIGNUM_LEN(bnum) == 1 && FIXABLE(value))
|
187
|
+
return LONG2FIX(value);
|
188
|
+
#endif
|
189
|
+
|
190
|
+
result = rb_big_clone(bnum);
|
191
|
+
*RBIGNUM_DIGITS(result) = value;
|
192
|
+
return result;
|
193
|
+
}
|
194
|
+
|
195
|
+
static VALUE
|
196
|
+
modify_lo64_in_bignum(VALUE bnum, uint64_t lo64)
|
197
|
+
{
|
198
|
+
VALUE result;
|
199
|
+
|
200
|
+
if (RBIGNUM_LEN(bnum) <= (8/SIZEOF_BDIGIT)) {
|
201
|
+
if (RBIGNUM_POSITIVE_P(bnum)) {
|
202
|
+
if (POSFIXABLE(lo64))
|
203
|
+
return LONG2FIX((long)lo64);
|
204
|
+
} else if (lo64 <= -FIXNUM_MIN) {
|
205
|
+
return LONG2FIX(-(long)lo64);
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
result = rb_big_clone(bnum);
|
210
|
+
store_64_into_bnum(result, lo64);
|
211
|
+
return result;
|
212
|
+
}
|
213
|
+
|
214
|
+
/* Now start defining implementations of actual Ruby methods
|
215
|
+
* First two helper macros: */
|
216
|
+
#define def_int_method(name) \
|
217
|
+
static VALUE int_ ## name(VALUE integer) { \
|
218
|
+
if (FIXNUM_P(integer)) \
|
219
|
+
return fnum_ ## name(integer); \
|
220
|
+
else \
|
221
|
+
return bnum_ ## name(integer); \
|
222
|
+
}
|
223
|
+
#define def_int_method_with_arg(name) \
|
224
|
+
static VALUE int_ ## name(VALUE integer, VALUE arg) { \
|
225
|
+
if (FIXNUM_P(integer)) \
|
226
|
+
return fnum_ ## name(integer, arg); \
|
227
|
+
else \
|
228
|
+
return bnum_ ## name(integer, arg); \
|
229
|
+
}
|
230
|
+
|
231
|
+
static VALUE
|
232
|
+
fnum_popcount(VALUE fnum)
|
233
|
+
{
|
234
|
+
long value = FIX2LONG(fnum);
|
235
|
+
if (value < 0)
|
236
|
+
rb_raise(rb_eRangeError, "can't take popcount of a negative number");
|
237
|
+
return LONG2FIX(__builtin_popcountl((ulong)value));
|
238
|
+
}
|
239
|
+
|
240
|
+
static VALUE
|
241
|
+
bnum_popcount(VALUE bnum)
|
242
|
+
{
|
243
|
+
BDIGIT *digits = RBIGNUM_DIGITS(bnum);
|
244
|
+
size_t length = RBIGNUM_LEN(bnum);
|
245
|
+
long bits = 0;
|
246
|
+
|
247
|
+
if (RBIGNUM_NEGATIVE_P(bnum))
|
248
|
+
rb_raise(rb_eRangeError, "can't take popcount of a negative number");
|
249
|
+
|
250
|
+
while (length--) {
|
251
|
+
bits += popcount_bdigit(*digits);
|
252
|
+
digits++;
|
253
|
+
}
|
254
|
+
|
255
|
+
return LONG2FIX(bits);
|
256
|
+
}
|
257
|
+
|
258
|
+
/* Document-method: Integer#popcount
|
259
|
+
* Return the number of 1 bits in this integer.
|
260
|
+
*
|
261
|
+
* If the receiver is negative, raise `RangeError`.
|
262
|
+
*
|
263
|
+
* @example
|
264
|
+
* 7.popcount # => 3
|
265
|
+
* 255.popcount # => 8
|
266
|
+
* @return [Integer]
|
267
|
+
*/
|
268
|
+
def_int_method(popcount);
|
269
|
+
|
270
|
+
/* Return the number of 1 bits in all the bytes of this `String`.
|
271
|
+
* @example
|
272
|
+
* "abc".popcount # => 10
|
273
|
+
* @return [Integer]
|
274
|
+
*/
|
275
|
+
static VALUE
|
276
|
+
str_popcount(VALUE str)
|
277
|
+
{
|
278
|
+
uchar *p = (uchar*)RSTRING_PTR(str);
|
279
|
+
long length = RSTRING_LEN(str);
|
280
|
+
long bits = 0;
|
281
|
+
|
282
|
+
/* This could be made faster by processing 4/8 bytes at a time */
|
283
|
+
|
284
|
+
while (length--)
|
285
|
+
bits += __builtin_popcount(*p++);
|
286
|
+
|
287
|
+
return LONG2FIX(bits);
|
288
|
+
}
|
289
|
+
|
290
|
+
static VALUE
|
291
|
+
fnum_lo_bit(VALUE fnum)
|
292
|
+
{
|
293
|
+
/* We raise an error on a negative number because the internal representation
|
294
|
+
* used for negative numbers is different between Fixnum and Bignum, so the
|
295
|
+
* results would not be consistent (running a program on a different computer,
|
296
|
+
* or with a Ruby interpreter compiled by a different compiler, could yield
|
297
|
+
* different results.)
|
298
|
+
* The alternative would be to _pretend_ that both Fixnums/Bignums use 2's
|
299
|
+
* complement notation and compute the answer accordingly.
|
300
|
+
* I don't think it's worth the trouble! */
|
301
|
+
long value = FIX2LONG(fnum);
|
302
|
+
if (value < 0)
|
303
|
+
rb_raise(rb_eRangeError, "can't find lowest 1 bit in a negative number");
|
304
|
+
return LONG2FIX(__builtin_ffsl(value));
|
305
|
+
}
|
306
|
+
|
307
|
+
static VALUE
|
308
|
+
bnum_lo_bit(VALUE bnum)
|
309
|
+
{
|
310
|
+
BDIGIT *digit = RBIGNUM_DIGITS(bnum);
|
311
|
+
long bits = 0;
|
312
|
+
|
313
|
+
if (RBIGNUM_NEGATIVE_P(bnum))
|
314
|
+
rb_raise(rb_eRangeError, "can't find lowest 1 bit in a negative number");
|
315
|
+
|
316
|
+
while (!*digit) {
|
317
|
+
digit++;
|
318
|
+
bits += (sizeof(BDIGIT) * 8);
|
319
|
+
}
|
320
|
+
|
321
|
+
bits += ffs_bdigit(*digit);
|
322
|
+
return LONG2FIX(bits);
|
323
|
+
}
|
324
|
+
|
325
|
+
/* Document-method: Integer#lo_bit
|
326
|
+
* Return the index of the lowest 1 bit, where the least-significant bit is index 1.
|
327
|
+
* If the receiver is 0, return 0.
|
328
|
+
*
|
329
|
+
* If the receiver is negative, raise `RangeError`.
|
330
|
+
*
|
331
|
+
* @example
|
332
|
+
* 1.lo_bit # => 1
|
333
|
+
* 128.lo_bit # => 8
|
334
|
+
* @return [Integer]
|
335
|
+
*/
|
336
|
+
def_int_method(lo_bit);
|
337
|
+
|
338
|
+
static VALUE
|
339
|
+
fnum_hi_bit(VALUE fnum)
|
340
|
+
{
|
341
|
+
long value = FIX2LONG(fnum);
|
342
|
+
if (value == 0)
|
343
|
+
return fix_zero;
|
344
|
+
else if (value < 0)
|
345
|
+
rb_raise(rb_eRangeError, "can't find highest 1 bit in a negative number");
|
346
|
+
return LONG2FIX((sizeof(long) * 8) - __builtin_clzl(value));
|
347
|
+
}
|
348
|
+
|
349
|
+
static VALUE
|
350
|
+
bnum_hi_bit(VALUE bnum)
|
351
|
+
{
|
352
|
+
BDIGIT *digit = RBIGNUM_DIGITS(bnum) + (RBIGNUM_LEN(bnum)-1);
|
353
|
+
ulong bits = (sizeof(BDIGIT) * 8) * RBIGNUM_LEN(bnum);
|
354
|
+
|
355
|
+
if (RBIGNUM_NEGATIVE_P(bnum))
|
356
|
+
rb_raise(rb_eRangeError, "can't find highest 1 bit in a negative number");
|
357
|
+
|
358
|
+
while (!*digit) {
|
359
|
+
digit--;
|
360
|
+
bits -= (sizeof(BDIGIT) * 8);
|
361
|
+
}
|
362
|
+
|
363
|
+
bits -= clz_bdigit(*digit);
|
364
|
+
return LONG2FIX(bits);
|
365
|
+
}
|
366
|
+
|
367
|
+
/* Document-method: Integer#hi_bit
|
368
|
+
* Return the index of the highest 1 bit, where the least-significant bit is index 1.
|
369
|
+
* If the receiver is 0, return 0.
|
370
|
+
*
|
371
|
+
* If the receiver is negative, raise `RangeError`.
|
372
|
+
*
|
373
|
+
* @example
|
374
|
+
* 1.hi_bit # => 1
|
375
|
+
* 255.hi_bit # => 8
|
376
|
+
* @return [Integer]
|
377
|
+
*/
|
378
|
+
def_int_method(hi_bit);
|
379
|
+
|
380
|
+
static VALUE
|
381
|
+
fnum_bswap16(VALUE fnum)
|
382
|
+
{
|
383
|
+
long value = FIX2LONG(fnum);
|
384
|
+
if (value < 0)
|
385
|
+
rb_raise(rb_eRangeError, "can't swap bytes in a negative number");
|
386
|
+
return LONG2FIX(((ulong)value & ~0xFFFFUL) | __builtin_bswap16((uint16_t)value));
|
387
|
+
}
|
388
|
+
|
389
|
+
static VALUE
|
390
|
+
bnum_bswap16(VALUE bnum)
|
391
|
+
{
|
392
|
+
if (RBIGNUM_POSITIVE_P(bnum))
|
393
|
+
return modify_lo16_in_bignum(bnum, __builtin_bswap16((uint16_t)*RBIGNUM_DIGITS(bnum)));
|
394
|
+
else
|
395
|
+
rb_raise(rb_eRangeError, "can't swap bytes in a negative number");
|
396
|
+
}
|
397
|
+
|
398
|
+
/* Document-method: Integer#bswap16
|
399
|
+
* Reverse the least-significant and second least-significant bytes of this integer.
|
400
|
+
*
|
401
|
+
* If the receiver is negative, raise `RangeError`.
|
402
|
+
*
|
403
|
+
* @example
|
404
|
+
* 0xFF00.bswap16 # => 255
|
405
|
+
* 0x00FF.bswap16 # => 65280
|
406
|
+
* @return [Integer]
|
407
|
+
*/
|
408
|
+
def_int_method(bswap16);
|
409
|
+
|
410
|
+
static VALUE
|
411
|
+
fnum_bswap32(VALUE fnum)
|
412
|
+
{
|
413
|
+
long value = FIX2LONG(fnum);
|
414
|
+
if (value < 0)
|
415
|
+
rb_raise(rb_eRangeError, "can't swap bytes in a negative number");
|
416
|
+
|
417
|
+
if (SIZEOF_LONG == 4)
|
418
|
+
/* the size of a Fixnum is always the same as 'long'
|
419
|
+
* and the C standard guarantees 'long' is at least 32 bits
|
420
|
+
* but a couple bits are used for tagging, so the usable precision could
|
421
|
+
* be less than 32 bits...
|
422
|
+
* That is why we have to use a '2NUM' function, not '2FIX' */
|
423
|
+
return ULONG2NUM(__builtin_bswap32(FIX2LONG(fnum)));
|
424
|
+
else
|
425
|
+
return LONG2FIX(((ulong)value & ~0xFFFFFFFFUL) | __builtin_bswap32((uint32_t)value));
|
426
|
+
}
|
427
|
+
|
428
|
+
static VALUE
|
429
|
+
bnum_bswap32(VALUE bnum)
|
430
|
+
{
|
431
|
+
if (RBIGNUM_POSITIVE_P(bnum))
|
432
|
+
return modify_lo32_in_bignum(bnum, __builtin_bswap32(*RBIGNUM_DIGITS(bnum)));
|
433
|
+
else
|
434
|
+
rb_raise(rb_eRangeError, "can't swap bytes in a negative number");
|
435
|
+
}
|
436
|
+
|
437
|
+
/* Document-method: Integer#bswap32
|
438
|
+
* Reverse the least-significant 4 bytes of this integer.
|
439
|
+
*
|
440
|
+
* Does not reverse bits within each byte. This can be used to swap endianness
|
441
|
+
* of a 32-bit integer. If the receiver is negative, raise `RangeError`.
|
442
|
+
*
|
443
|
+
* @example
|
444
|
+
* 0xaabbccdd.bswap32.to_s(16) # => "ddccbbaa"
|
445
|
+
*
|
446
|
+
* @return [Integer]
|
447
|
+
*/
|
448
|
+
def_int_method(bswap32);
|
449
|
+
|
450
|
+
static VALUE
|
451
|
+
fnum_bswap64(VALUE fnum)
|
452
|
+
{
|
453
|
+
long value = FIX2LONG(fnum);
|
454
|
+
if (value < 0)
|
455
|
+
rb_raise(rb_eRangeError, "can't swap bytes in a negative number");
|
456
|
+
return ULL2NUM(__builtin_bswap64((uint64_t)value));
|
457
|
+
}
|
458
|
+
|
459
|
+
static VALUE
|
460
|
+
bnum_bswap64(VALUE bnum)
|
461
|
+
{
|
462
|
+
if (RBIGNUM_POSITIVE_P(bnum))
|
463
|
+
return modify_lo64_in_bignum(bnum, __builtin_bswap64(load_64_from_bignum(bnum)));
|
464
|
+
else
|
465
|
+
rb_raise(rb_eRangeError, "can't swap bytes in a negative number");
|
466
|
+
}
|
467
|
+
|
468
|
+
/* Document-method: Integer#bswap64
|
469
|
+
* Reverse the least-significant 8 bytes of this integer.
|
470
|
+
*
|
471
|
+
* Does not reverse bits within each byte. This can be used to swap endianness
|
472
|
+
* of a 64-bit integer. If the receiver is negative, raise `RangeError`.
|
473
|
+
*
|
474
|
+
* @example
|
475
|
+
* 0xaabbccdd.bswap64.to_s(16) # => "ddccbbaa00000000"
|
476
|
+
*
|
477
|
+
* @return [Integer]
|
478
|
+
*/
|
479
|
+
def_int_method(bswap64);
|
480
|
+
|
481
|
+
#define def_rot_helpers(bits) \
|
482
|
+
static inline uint##bits##_t rrot##bits(uint##bits##_t value, VALUE rotdist) { \
|
483
|
+
ulong rotd = value_to_rotdist(rotdist, bits, bits-1); \
|
484
|
+
return (value >> rotd) | (value << (-rotd & (bits-1))); \
|
485
|
+
} \
|
486
|
+
static inline uint##bits##_t lrot##bits(uint##bits##_t value, VALUE rotdist) { \
|
487
|
+
ulong rotd = value_to_rotdist(rotdist, bits, bits-1); \
|
488
|
+
return (value << rotd) | (value >> (-rotd & (bits-1))); \
|
489
|
+
}
|
490
|
+
|
491
|
+
def_rot_helpers(8);
|
492
|
+
def_rot_helpers(16);
|
493
|
+
def_rot_helpers(32);
|
494
|
+
def_rot_helpers(64);
|
495
|
+
|
496
|
+
static VALUE
|
497
|
+
fnum_rrot8(VALUE fnum, VALUE rotdist)
|
498
|
+
{
|
499
|
+
long value = FIX2LONG(fnum);
|
500
|
+
return LONG2FIX(((ulong)value & ~0xFFUL) | rrot8((uint8_t)value, rotdist));
|
501
|
+
}
|
502
|
+
|
503
|
+
static VALUE
|
504
|
+
bnum_rrot8(VALUE bnum, VALUE rotdist)
|
505
|
+
{
|
506
|
+
return modify_lo8_in_bignum(bnum, rrot8((uint8_t)*RBIGNUM_DIGITS(bnum), rotdist));
|
507
|
+
}
|
508
|
+
|
509
|
+
/* Document-method: Integer#rrot8
|
510
|
+
* Right-rotation ("circular shift") of the low 8 bits in this integer.
|
511
|
+
*
|
512
|
+
* If the rotate distance is negative, the bit rotation will be to the left
|
513
|
+
* instead.
|
514
|
+
*
|
515
|
+
* @example
|
516
|
+
* 0b01110001.rrot8(1).to_s(2) # => "10111000"
|
517
|
+
* 0b01110001.rrot8(3).to_s(2) # => "101110"
|
518
|
+
*
|
519
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
520
|
+
* @return [Integer]
|
521
|
+
*/
|
522
|
+
def_int_method_with_arg(rrot8);
|
523
|
+
|
524
|
+
static VALUE
|
525
|
+
fnum_rrot16(VALUE fnum, VALUE rotdist)
|
526
|
+
{
|
527
|
+
long value = FIX2LONG(fnum);
|
528
|
+
return LONG2FIX(((ulong)value & ~0xFFFFUL) | rrot16((uint16_t)value, rotdist));
|
529
|
+
}
|
530
|
+
|
531
|
+
static VALUE
|
532
|
+
bnum_rrot16(VALUE bnum, VALUE rotdist)
|
533
|
+
{
|
534
|
+
return modify_lo16_in_bignum(bnum, rrot16((uint16_t)*RBIGNUM_DIGITS(bnum), rotdist));
|
535
|
+
}
|
536
|
+
|
537
|
+
/* Document-method: Integer#rrot16
|
538
|
+
* Right-rotation ("circular shift") of the low 16 bits in this integer.
|
539
|
+
*
|
540
|
+
* If the rotate distance is negative, the bit rotation will be to the left
|
541
|
+
* instead.
|
542
|
+
*
|
543
|
+
* @example
|
544
|
+
* 0b0111000101110001.rrot16(1).to_s(2) # => "1011100010111000"
|
545
|
+
* 0b0111000101110001.rrot16(3).to_s(2) # => "10111000101110"
|
546
|
+
*
|
547
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
548
|
+
* @return [Integer]
|
549
|
+
*/
|
550
|
+
def_int_method_with_arg(rrot16);
|
551
|
+
|
552
|
+
static VALUE
|
553
|
+
fnum_rrot32(VALUE fnum, VALUE rotdist)
|
554
|
+
{
|
555
|
+
long value = FIX2LONG(fnum);
|
556
|
+
if (SIZEOF_LONG == 8)
|
557
|
+
return LONG2FIX(((ulong)value & ~0xFFFFFFFFUL) | rrot32((uint32_t)value, rotdist));
|
558
|
+
else
|
559
|
+
return ULONG2NUM(rrot32((uint32_t)value, rotdist));
|
560
|
+
}
|
561
|
+
|
562
|
+
static VALUE
|
563
|
+
bnum_rrot32(VALUE bnum, VALUE rotdist)
|
564
|
+
{
|
565
|
+
return modify_lo32_in_bignum(bnum, rrot32((uint32_t)*RBIGNUM_DIGITS(bnum), rotdist));
|
566
|
+
}
|
567
|
+
|
568
|
+
/* Document-method: Integer#rrot32
|
569
|
+
* Right-rotation ("circular shift") of the low 32 bits in this integer.
|
570
|
+
*
|
571
|
+
* If the rotate distance is negative, the bit rotation will be to the left
|
572
|
+
* instead.
|
573
|
+
*
|
574
|
+
* @example
|
575
|
+
* 0xaabbccdd.rrot32(4).to_s(16) # => "daabbccd"
|
576
|
+
*
|
577
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
578
|
+
* @return [Integer]
|
579
|
+
*/
|
580
|
+
def_int_method_with_arg(rrot32);
|
581
|
+
|
582
|
+
static VALUE
|
583
|
+
fnum_rrot64(VALUE fnum, VALUE rotdist)
|
584
|
+
{
|
585
|
+
return ULL2NUM(rrot64(FIX2ULONG(fnum), rotdist));
|
586
|
+
}
|
587
|
+
|
588
|
+
static VALUE
|
589
|
+
bnum_rrot64(VALUE bnum, VALUE rotdist)
|
590
|
+
{
|
591
|
+
return modify_lo64_in_bignum(bnum, rrot64(load_64_from_bignum(bnum), rotdist));
|
592
|
+
}
|
593
|
+
|
594
|
+
/* Document-method: Integer#rrot64
|
595
|
+
* Right-rotation ("circular shift") of the low 64 bits in this integer.
|
596
|
+
*
|
597
|
+
* If the rotate distance is negative, the bit rotation will be to the left
|
598
|
+
* instead.
|
599
|
+
*
|
600
|
+
* @example
|
601
|
+
* 0x11223344aabbccdd.rrot64(4).to_s(16) # => "d11223344aabbccd"
|
602
|
+
*
|
603
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
604
|
+
* @return [Integer]
|
605
|
+
*/
|
606
|
+
def_int_method_with_arg(rrot64);
|
607
|
+
|
608
|
+
static VALUE
|
609
|
+
fnum_lrot8(VALUE fnum, VALUE rotdist)
|
610
|
+
{
|
611
|
+
long value = FIX2LONG(fnum);
|
612
|
+
return LONG2FIX(((ulong)value & ~0xFFUL) | lrot8((uint8_t)value, rotdist));
|
613
|
+
}
|
614
|
+
|
615
|
+
static VALUE
|
616
|
+
bnum_lrot8(VALUE bnum, VALUE rotdist)
|
617
|
+
{
|
618
|
+
return modify_lo8_in_bignum(bnum, lrot8((uint8_t)*RBIGNUM_DIGITS(bnum), rotdist));
|
619
|
+
}
|
620
|
+
|
621
|
+
/* Document-method: Integer#lrot8
|
622
|
+
* Left-rotation ("circular shift") of the low 8 bits in this integer.
|
623
|
+
*
|
624
|
+
* If the rotate distance is negative, the bit rotation will be to the right
|
625
|
+
* instead.
|
626
|
+
*
|
627
|
+
* @example
|
628
|
+
* 0b01110001.lrot8(1).to_s(2) # => "11100010"
|
629
|
+
* 0b01110001.lrot8(3).to_s(2) # => "10001011"
|
630
|
+
*
|
631
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
632
|
+
* @return [Integer]
|
633
|
+
*/
|
634
|
+
def_int_method_with_arg(lrot8);
|
635
|
+
|
636
|
+
static VALUE
|
637
|
+
fnum_lrot16(VALUE fnum, VALUE rotdist)
|
638
|
+
{
|
639
|
+
long value = FIX2LONG(fnum);
|
640
|
+
return LONG2FIX(((ulong)value & ~0xFFFFUL) | lrot16((uint16_t)value, rotdist));
|
641
|
+
}
|
642
|
+
|
643
|
+
static VALUE
|
644
|
+
bnum_lrot16(VALUE bnum, VALUE rotdist)
|
645
|
+
{
|
646
|
+
return modify_lo16_in_bignum(bnum, lrot16((uint16_t)*RBIGNUM_DIGITS(bnum), rotdist));
|
647
|
+
}
|
648
|
+
|
649
|
+
/* Document-method: Integer#lrot16
|
650
|
+
* Left-rotation ("circular shift") of the low 16 bits in this integer.
|
651
|
+
*
|
652
|
+
* If the rotate distance is negative, the bit rotation will be to the right
|
653
|
+
* instead.
|
654
|
+
*
|
655
|
+
* @example
|
656
|
+
* 0b0111000101110001.lrot16(1).to_s(2) # => "1110001011100010"
|
657
|
+
* 0b0111000101110001.lrot16(3).to_s(2) # => "1000101110001011"
|
658
|
+
*
|
659
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
660
|
+
* @return [Integer]
|
661
|
+
*/
|
662
|
+
def_int_method_with_arg(lrot16);
|
663
|
+
|
664
|
+
static VALUE
|
665
|
+
fnum_lrot32(VALUE fnum, VALUE rotdist)
|
666
|
+
{
|
667
|
+
long value = FIX2LONG(fnum);
|
668
|
+
return LONG2FIX(((ulong)value & ~0xFFFFFFFFUL) | lrot32((uint32_t)value, rotdist));
|
669
|
+
}
|
670
|
+
|
671
|
+
static VALUE
|
672
|
+
bnum_lrot32(VALUE bnum, VALUE rotdist)
|
673
|
+
{
|
674
|
+
return modify_lo32_in_bignum(bnum, lrot32((uint32_t)*RBIGNUM_DIGITS(bnum), rotdist));
|
675
|
+
}
|
676
|
+
|
677
|
+
/* Document-method: Integer#lrot32
|
678
|
+
* Left-rotation ("circular shift") of the low 32 bits in this integer.
|
679
|
+
*
|
680
|
+
* If the rotate distance is negative, the bit rotation will be to the right
|
681
|
+
* instead.
|
682
|
+
*
|
683
|
+
* @example
|
684
|
+
* 0xaabbccdd.lrot32(4).to_s(16) # => "abbccdda"
|
685
|
+
*
|
686
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
687
|
+
* @return [Integer]
|
688
|
+
*/
|
689
|
+
def_int_method_with_arg(lrot32);
|
690
|
+
|
691
|
+
static VALUE
|
692
|
+
fnum_lrot64(VALUE fnum, VALUE rotdist)
|
693
|
+
{
|
694
|
+
return ULL2NUM(lrot64(FIX2ULONG(fnum), rotdist));
|
695
|
+
}
|
696
|
+
|
697
|
+
static VALUE
|
698
|
+
bnum_lrot64(VALUE bnum, VALUE rotdist)
|
699
|
+
{
|
700
|
+
return modify_lo64_in_bignum(bnum, lrot64(load_64_from_bignum(bnum), rotdist));
|
701
|
+
}
|
702
|
+
|
703
|
+
/* Document-method: Integer#lrot64
|
704
|
+
* Left-rotation ("circular shift") of the low 64 bits in this integer.
|
705
|
+
*
|
706
|
+
* If the rotate distance is negative, the bit rotation will be to the right
|
707
|
+
* instead.
|
708
|
+
*
|
709
|
+
* @example
|
710
|
+
* 0x11223344aabbccdd.lrot64(4).to_s(16) # => "1223344aabbccdd1"
|
711
|
+
*
|
712
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
713
|
+
* @return [Integer]
|
714
|
+
*/
|
715
|
+
def_int_method_with_arg(lrot64);
|
716
|
+
|
717
|
+
#define def_shift_helpers(bits) \
|
718
|
+
static uint##bits##_t lshift##bits(uint##bits##_t value, VALUE shiftdist) { \
|
719
|
+
long sdist = value_to_shiftdist(shiftdist, bits); \
|
720
|
+
if (sdist >= bits || sdist <= -bits) return 0; \
|
721
|
+
else if (sdist < 0) return value >> ((uint)-sdist); \
|
722
|
+
else return value << (uint)sdist; \
|
723
|
+
} \
|
724
|
+
static uint##bits##_t rshift##bits(uint##bits##_t value, VALUE shiftdist) { \
|
725
|
+
long sdist = value_to_shiftdist(shiftdist, bits); \
|
726
|
+
if (sdist >= bits || sdist <= -bits) return 0; \
|
727
|
+
else if (sdist < 0) return value << ((uint)-sdist); \
|
728
|
+
else return value >> (uint)sdist; \
|
729
|
+
} \
|
730
|
+
static uint##bits##_t arith_rshift##bits(uint##bits##_t value, VALUE shiftdist) { \
|
731
|
+
long sdist = value_to_shiftdist(shiftdist, bits); \
|
732
|
+
if (sdist >= bits) { \
|
733
|
+
if ((((uint##bits##_t)1 << (bits - 1)) & value) != 0) \
|
734
|
+
return ~0; \
|
735
|
+
else \
|
736
|
+
return 0; \
|
737
|
+
} else if (sdist <= -bits) { \
|
738
|
+
return 0; \
|
739
|
+
} else if (sdist < 0) { \
|
740
|
+
return value << ((uint)-sdist); \
|
741
|
+
} else if (RSHIFT_IS_ARITH) { \
|
742
|
+
return (int##bits##_t)value >> (int)sdist; \
|
743
|
+
} else if ((((uint##bits##_t)1 << (bits - 1)) & value) != 0) { \
|
744
|
+
return (value >> sdist) | ~(((uint##bits##_t)~0) >> sdist); \
|
745
|
+
} else { \
|
746
|
+
return value >> sdist; \
|
747
|
+
} \
|
748
|
+
}
|
749
|
+
|
750
|
+
def_shift_helpers(8);
|
751
|
+
def_shift_helpers(16);
|
752
|
+
def_shift_helpers(32);
|
753
|
+
def_shift_helpers(64);
|
754
|
+
|
755
|
+
static VALUE
|
756
|
+
fnum_lshift8(VALUE fnum, VALUE shiftdist)
|
757
|
+
{
|
758
|
+
long value = FIX2LONG(fnum);
|
759
|
+
if (shiftdist == fix_zero)
|
760
|
+
return fnum;
|
761
|
+
else
|
762
|
+
return LONG2FIX(((ulong)value & ~0xFFUL) | lshift8((uint8_t)value, shiftdist));
|
763
|
+
}
|
764
|
+
|
765
|
+
static VALUE
|
766
|
+
bnum_lshift8(VALUE bnum, VALUE shiftdist)
|
767
|
+
{
|
768
|
+
if (shiftdist == fix_zero)
|
769
|
+
return bnum;
|
770
|
+
else
|
771
|
+
return modify_lo8_in_bignum(bnum, lshift8((uint8_t)*RBIGNUM_DIGITS(bnum), shiftdist));
|
772
|
+
}
|
773
|
+
|
774
|
+
/* Document-method: Integer#lshift8
|
775
|
+
* Left-shift of the low 8 bits in this integer.
|
776
|
+
*
|
777
|
+
* If the shift distance is negative, a right shift will be performed instead.
|
778
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
779
|
+
* more than 7 or less than -7, the low 8 bits will all be zeroed.
|
780
|
+
*
|
781
|
+
* @example
|
782
|
+
* 0x11223344.lshift8(1).to_s(16) # => "11223388"
|
783
|
+
* 0x11223344.lshift8(2).to_s(16) # => "11223310"
|
784
|
+
*
|
785
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
786
|
+
* @return [Integer]
|
787
|
+
*/
|
788
|
+
def_int_method_with_arg(lshift8);
|
789
|
+
|
790
|
+
static VALUE
|
791
|
+
fnum_lshift16(VALUE fnum, VALUE shiftdist)
|
792
|
+
{
|
793
|
+
long value = FIX2LONG(fnum);
|
794
|
+
if (shiftdist == fix_zero)
|
795
|
+
return fnum;
|
796
|
+
else
|
797
|
+
return LONG2FIX(((ulong)value & ~0xFFFFUL) | lshift16((uint16_t)value, shiftdist));
|
798
|
+
}
|
799
|
+
|
800
|
+
static VALUE
|
801
|
+
bnum_lshift16(VALUE bnum, VALUE shiftdist)
|
802
|
+
{
|
803
|
+
if (shiftdist == fix_zero)
|
804
|
+
return bnum;
|
805
|
+
else
|
806
|
+
return modify_lo16_in_bignum(bnum, lshift16((uint16_t)*RBIGNUM_DIGITS(bnum), shiftdist));
|
807
|
+
}
|
808
|
+
|
809
|
+
/* Document-method: Integer#lshift16
|
810
|
+
* Left-shift of the low 16 bits in this integer.
|
811
|
+
*
|
812
|
+
* If the shift distance is negative, a right shift will be performed instead.
|
813
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
814
|
+
* more than 15 or less than -15, the low 16 bits will all be zeroed.
|
815
|
+
*
|
816
|
+
* @example
|
817
|
+
* 0x11223344.lshift16(1).to_s(16) # => "11226688"
|
818
|
+
* 0x11223344.lshift16(2).to_s(16) # => "1122cd10"
|
819
|
+
*
|
820
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
821
|
+
* @return [Integer]
|
822
|
+
*/
|
823
|
+
def_int_method_with_arg(lshift16);
|
824
|
+
|
825
|
+
static VALUE
|
826
|
+
fnum_lshift32(VALUE fnum, VALUE shiftdist)
|
827
|
+
{
|
828
|
+
long value = FIX2LONG(fnum);
|
829
|
+
if (shiftdist == fix_zero)
|
830
|
+
return fnum;
|
831
|
+
else
|
832
|
+
return LONG2FIX(((ulong)value & ~0xFFFFFFFFUL) | lshift32((uint32_t)value, shiftdist));
|
833
|
+
}
|
834
|
+
|
835
|
+
static VALUE
|
836
|
+
bnum_lshift32(VALUE bnum, VALUE shiftdist)
|
837
|
+
{
|
838
|
+
if (shiftdist == fix_zero)
|
839
|
+
return bnum;
|
840
|
+
else
|
841
|
+
return modify_lo32_in_bignum(bnum, lshift32((uint32_t)*RBIGNUM_DIGITS(bnum), shiftdist));
|
842
|
+
}
|
843
|
+
|
844
|
+
/* Document-method: Integer#lshift32
|
845
|
+
* Left-shift of the low 32 bits in this integer.
|
846
|
+
*
|
847
|
+
* If the shift distance is negative, a right shift will be performed instead.
|
848
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
849
|
+
* more than 31 or less than -31, the low 32 bits will all be zeroed.
|
850
|
+
*
|
851
|
+
* @example
|
852
|
+
* 0x11223344.lshift32(1).to_s(16) # => "22446688"
|
853
|
+
* 0x11223344.lshift32(2).to_s(16) # => "4488cd10"
|
854
|
+
*
|
855
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
856
|
+
* @return [Integer]
|
857
|
+
*/
|
858
|
+
def_int_method_with_arg(lshift32);
|
859
|
+
|
860
|
+
static VALUE
|
861
|
+
fnum_lshift64(VALUE fnum, VALUE shiftdist)
|
862
|
+
{
|
863
|
+
long sdist = value_to_shiftdist(shiftdist, 64);
|
864
|
+
|
865
|
+
if (sdist == 0)
|
866
|
+
return fnum;
|
867
|
+
else if (sdist >= 64 || sdist <= -64)
|
868
|
+
return fix_zero;
|
869
|
+
else if (sdist < 0)
|
870
|
+
return LONG2FIX(FIX2ULONG(fnum) >> ((ulong)-sdist));
|
871
|
+
else
|
872
|
+
return ULL2NUM(FIX2ULONG(fnum) << ((ulong)sdist));
|
873
|
+
}
|
874
|
+
|
875
|
+
static VALUE
|
876
|
+
bnum_lshift64(VALUE bnum, VALUE shiftdist)
|
877
|
+
{
|
878
|
+
if (shiftdist == fix_zero)
|
879
|
+
return bnum;
|
880
|
+
else
|
881
|
+
return modify_lo64_in_bignum(bnum, lshift64(load_64_from_bignum(bnum), shiftdist));
|
882
|
+
}
|
883
|
+
|
884
|
+
/* Document-method: Integer#lshift64
|
885
|
+
* Left-shift of the low 64 bits in this integer.
|
886
|
+
*
|
887
|
+
* If the shift distance is negative, a right shift will be performed instead.
|
888
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
889
|
+
* more than 63 or less than -63, the low 64 bits will all be zeroed.
|
890
|
+
*
|
891
|
+
* @example
|
892
|
+
* 0x1122334411223344.lshift64(1).to_s(16) # => "2244668822446688"
|
893
|
+
* 0x1122334411223344.lshift64(2).to_s(16) # => "4488cd104488cd10"
|
894
|
+
*
|
895
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
896
|
+
* @return [Integer]
|
897
|
+
*/
|
898
|
+
def_int_method_with_arg(lshift64);
|
899
|
+
|
900
|
+
static VALUE
|
901
|
+
fnum_rshift8(VALUE fnum, VALUE shiftdist)
|
902
|
+
{
|
903
|
+
long value = FIX2LONG(fnum);
|
904
|
+
if (shiftdist == fix_zero)
|
905
|
+
return fnum;
|
906
|
+
else
|
907
|
+
return LONG2FIX(((ulong)value & ~0xFFUL) | rshift8((uint8_t)value, shiftdist));
|
908
|
+
}
|
909
|
+
|
910
|
+
static VALUE
|
911
|
+
bnum_rshift8(VALUE bnum, VALUE shiftdist)
|
912
|
+
{
|
913
|
+
if (shiftdist == fix_zero)
|
914
|
+
return bnum;
|
915
|
+
else
|
916
|
+
return modify_lo8_in_bignum(bnum, rshift8((uint8_t)*RBIGNUM_DIGITS(bnum), shiftdist));
|
917
|
+
}
|
918
|
+
|
919
|
+
/* Document-method: Integer#rshift8
|
920
|
+
* Right-shift of the low 8 bits in this integer.
|
921
|
+
*
|
922
|
+
* If the shift distance is negative, a left shift will be performed instead.
|
923
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
924
|
+
* more than 7 or less than -7, the low 8 bits will all be zeroed.
|
925
|
+
*
|
926
|
+
* @example
|
927
|
+
* 0x11223344.rshift8(1).to_s(16) # => "11223322"
|
928
|
+
* 0x11223344.rshift8(2).to_s(16) # => "11223311"
|
929
|
+
*
|
930
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
931
|
+
* @return [Integer]
|
932
|
+
*/
|
933
|
+
def_int_method_with_arg(rshift8);
|
934
|
+
|
935
|
+
static VALUE
|
936
|
+
fnum_rshift16(VALUE fnum, VALUE shiftdist)
|
937
|
+
{
|
938
|
+
long value = FIX2LONG(fnum);
|
939
|
+
if (shiftdist == fix_zero)
|
940
|
+
return fnum;
|
941
|
+
else
|
942
|
+
return LONG2FIX(((ulong)value & ~0xFFFFUL) | rshift16((uint16_t)value, shiftdist));
|
943
|
+
}
|
944
|
+
|
945
|
+
static VALUE
|
946
|
+
bnum_rshift16(VALUE bnum, VALUE shiftdist)
|
947
|
+
{
|
948
|
+
if (shiftdist == fix_zero)
|
949
|
+
return bnum;
|
950
|
+
else
|
951
|
+
return modify_lo16_in_bignum(bnum, rshift16((uint16_t)*RBIGNUM_DIGITS(bnum), shiftdist));
|
952
|
+
}
|
953
|
+
|
954
|
+
/* Document-method: Integer#rshift16
|
955
|
+
* Right-shift of the low 16 bits in this integer.
|
956
|
+
*
|
957
|
+
* If the shift distance is negative, a left shift will be performed instead.
|
958
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
959
|
+
* more than 15 or less than -15, the low 16 bits will all be zeroed.
|
960
|
+
*
|
961
|
+
* @example
|
962
|
+
* 0x11223344.rshift16(1).to_s(16) # => "112219a2"
|
963
|
+
* 0x11223344.rshift16(2).to_s(16) # => "11220cd1"
|
964
|
+
*
|
965
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
966
|
+
* @return [Integer]
|
967
|
+
*/
|
968
|
+
def_int_method_with_arg(rshift16);
|
969
|
+
|
970
|
+
static VALUE
|
971
|
+
fnum_rshift32(VALUE fnum, VALUE shiftdist)
|
972
|
+
{
|
973
|
+
long value = FIX2LONG(fnum);
|
974
|
+
if (shiftdist == fix_zero)
|
975
|
+
return fnum;
|
976
|
+
else
|
977
|
+
return LONG2FIX(((ulong)value & ~0xFFFFFFFFUL) | rshift32((uint32_t)value, shiftdist));
|
978
|
+
}
|
979
|
+
|
980
|
+
static VALUE
|
981
|
+
bnum_rshift32(VALUE bnum, VALUE shiftdist)
|
982
|
+
{
|
983
|
+
if (shiftdist == fix_zero)
|
984
|
+
return bnum;
|
985
|
+
else
|
986
|
+
return modify_lo32_in_bignum(bnum, rshift32(*RBIGNUM_DIGITS(bnum), shiftdist));
|
987
|
+
}
|
988
|
+
|
989
|
+
/* Document-method: Integer#rshift32
|
990
|
+
* Right-shift of the low 32 bits in this integer.
|
991
|
+
*
|
992
|
+
* If the shift distance is negative, a left shift will be performed instead.
|
993
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
994
|
+
* more than 31 or less than -31, the low 32 bits will all be zeroed.
|
995
|
+
*
|
996
|
+
* @example
|
997
|
+
* 0x11223344.rshift32(1).to_s(16) # => "89119a2"
|
998
|
+
* 0x11223344.rshift32(2).to_s(16) # => "4488cd1"
|
999
|
+
*
|
1000
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1001
|
+
* @return [Integer]
|
1002
|
+
*/
|
1003
|
+
def_int_method_with_arg(rshift32);
|
1004
|
+
|
1005
|
+
static VALUE
|
1006
|
+
fnum_rshift64(VALUE fnum, VALUE shiftdist)
|
1007
|
+
{
|
1008
|
+
long sdist = value_to_shiftdist(shiftdist, 64);
|
1009
|
+
|
1010
|
+
if (sdist == 0)
|
1011
|
+
return fnum;
|
1012
|
+
else if (sdist >= 64 || sdist <= -64)
|
1013
|
+
return fix_zero;
|
1014
|
+
else if (sdist < 0)
|
1015
|
+
return ULL2NUM(FIX2ULONG(fnum) << ((ulong)-sdist));
|
1016
|
+
else
|
1017
|
+
return LONG2FIX(FIX2ULONG(fnum) >> ((ulong)sdist));
|
1018
|
+
}
|
1019
|
+
|
1020
|
+
static VALUE
|
1021
|
+
bnum_rshift64(VALUE bnum, VALUE shiftdist)
|
1022
|
+
{
|
1023
|
+
if (shiftdist == fix_zero)
|
1024
|
+
return bnum;
|
1025
|
+
else
|
1026
|
+
return modify_lo64_in_bignum(bnum, rshift64(load_64_from_bignum(bnum), shiftdist));
|
1027
|
+
}
|
1028
|
+
|
1029
|
+
/* Document-method: Integer#rshift64
|
1030
|
+
* Right-shift of the low 64 bits in this integer.
|
1031
|
+
*
|
1032
|
+
* If the shift distance is negative, a left shift will be performed instead.
|
1033
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
1034
|
+
* more than 63 or less than -63, the low 64 bits will all be zeroed.
|
1035
|
+
*
|
1036
|
+
* @example
|
1037
|
+
* 0x1122334411223344.rshift64(1).to_s(16) # => "89119a2089119a2"
|
1038
|
+
* 0x1122334411223344.rshift64(2).to_s(16) # => "4488cd104488cd1"
|
1039
|
+
*
|
1040
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1041
|
+
* @return [Integer]
|
1042
|
+
*/
|
1043
|
+
def_int_method_with_arg(rshift64);
|
1044
|
+
|
1045
|
+
static VALUE
|
1046
|
+
fnum_arith_rshift8(VALUE fnum, VALUE shiftdist)
|
1047
|
+
{
|
1048
|
+
long value = FIX2LONG(fnum);
|
1049
|
+
if (shiftdist == fix_zero)
|
1050
|
+
return fnum;
|
1051
|
+
else
|
1052
|
+
return LONG2FIX(((ulong)value & ~0xFFUL) | arith_rshift8((uint8_t)value, shiftdist));
|
1053
|
+
}
|
1054
|
+
|
1055
|
+
static VALUE
|
1056
|
+
bnum_arith_rshift8(VALUE bnum, VALUE shiftdist)
|
1057
|
+
{
|
1058
|
+
if (shiftdist == fix_zero)
|
1059
|
+
return bnum;
|
1060
|
+
else
|
1061
|
+
return modify_lo8_in_bignum(bnum, arith_rshift8((uint8_t)*RBIGNUM_DIGITS(bnum), shiftdist));
|
1062
|
+
}
|
1063
|
+
|
1064
|
+
/* Document-method: Integer#arith_rshift8
|
1065
|
+
* Arithmetic right-shift of the low 8 bits in this integer.
|
1066
|
+
*
|
1067
|
+
* If bit 8 is a 1, the vacated bit positions will be filled with 1s. Otherwise,
|
1068
|
+
* they will be filled with 0s. Or, if the shift distance is negative, a left shift
|
1069
|
+
* will be performed instead, and the vacated bit positions will be filled with 0s.
|
1070
|
+
*
|
1071
|
+
* @example
|
1072
|
+
* 0xaabbccdd.arith_rshift8(1).to_s(16) # => "aabbccee"
|
1073
|
+
* 0xaabbccdd.arith_rshift8(2).to_s(16) # => "aabbccf7"
|
1074
|
+
*
|
1075
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1076
|
+
* @return [Integer]
|
1077
|
+
*/
|
1078
|
+
def_int_method_with_arg(arith_rshift8);
|
1079
|
+
|
1080
|
+
static VALUE
|
1081
|
+
fnum_arith_rshift16(VALUE fnum, VALUE shiftdist)
|
1082
|
+
{
|
1083
|
+
long value = FIX2LONG(fnum);
|
1084
|
+
if (shiftdist == fix_zero)
|
1085
|
+
return fnum;
|
1086
|
+
else
|
1087
|
+
return LONG2FIX(((ulong)value & ~0xFFFFUL) | arith_rshift16((uint16_t)value, shiftdist));
|
1088
|
+
}
|
1089
|
+
|
1090
|
+
static VALUE
|
1091
|
+
bnum_arith_rshift16(VALUE bnum, VALUE shiftdist)
|
1092
|
+
{
|
1093
|
+
if (shiftdist == fix_zero)
|
1094
|
+
return bnum;
|
1095
|
+
else
|
1096
|
+
return modify_lo16_in_bignum(bnum, arith_rshift16((uint16_t)*RBIGNUM_DIGITS(bnum), shiftdist));
|
1097
|
+
}
|
1098
|
+
|
1099
|
+
/* Document-method: Integer#arith_rshift16
|
1100
|
+
* Arithmetic right-shift of the low 16 bits in this integer.
|
1101
|
+
*
|
1102
|
+
* If bit 16 is a 1, the vacated bit positions will be filled with 1s. Otherwise,
|
1103
|
+
* they will be filled with 0s. Or, if the shift distance is negative, a left shift
|
1104
|
+
* will be performed instead, and the vacated bit positions will be filled with 0s.
|
1105
|
+
*
|
1106
|
+
* @example
|
1107
|
+
* 0xaabbccdd.arith_rshift16(1).to_s(16) # => "aabbe66e"
|
1108
|
+
* 0xaabbccdd.arith_rshift16(2).to_s(16) # => "aabbf337"
|
1109
|
+
*
|
1110
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1111
|
+
* @return [Integer]
|
1112
|
+
*/
|
1113
|
+
def_int_method_with_arg(arith_rshift16);
|
1114
|
+
|
1115
|
+
static VALUE
|
1116
|
+
fnum_arith_rshift32(VALUE fnum, VALUE shiftdist)
|
1117
|
+
{
|
1118
|
+
long value = FIX2LONG(fnum);
|
1119
|
+
if (shiftdist == fix_zero)
|
1120
|
+
return fnum;
|
1121
|
+
else
|
1122
|
+
return LONG2FIX(((ulong)value & ~0xFFFFFFFFUL) | arith_rshift32((uint32_t)value, shiftdist));
|
1123
|
+
}
|
1124
|
+
|
1125
|
+
static VALUE
|
1126
|
+
bnum_arith_rshift32(VALUE bnum, VALUE shiftdist)
|
1127
|
+
{
|
1128
|
+
if (shiftdist == fix_zero)
|
1129
|
+
return bnum;
|
1130
|
+
else
|
1131
|
+
return modify_lo32_in_bignum(bnum, arith_rshift32(*RBIGNUM_DIGITS(bnum), shiftdist));
|
1132
|
+
}
|
1133
|
+
|
1134
|
+
/* Document-method: Integer#arith_rshift32
|
1135
|
+
* Arithmetic right-shift of the low 32 bits in this integer.
|
1136
|
+
*
|
1137
|
+
* If bit 32 is a 1, the vacated bit positions will be filled with 1s. Otherwise,
|
1138
|
+
* they will be filled with 0s. Or, if the shift distance is negative, a left shift
|
1139
|
+
* will be performed instead, and the vacated bit positions will be filled with 0s.
|
1140
|
+
*
|
1141
|
+
* @example
|
1142
|
+
* 0xaabbccddaabbccdd.arith_rshift32(1).to_s(16) # => "d55de66e"
|
1143
|
+
* 0xaabbccddaabbccdd.arith_rshift32(2).to_s(16) # => "eaaef337"
|
1144
|
+
*
|
1145
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1146
|
+
* @return [Integer]
|
1147
|
+
*/
|
1148
|
+
def_int_method_with_arg(arith_rshift32);
|
1149
|
+
|
1150
|
+
static VALUE
|
1151
|
+
fnum_arith_rshift64(VALUE fnum, VALUE shiftdist)
|
1152
|
+
{
|
1153
|
+
if (shiftdist == fix_zero)
|
1154
|
+
return fnum;
|
1155
|
+
else
|
1156
|
+
return ULONG2NUM(arith_rshift64((uint64_t)FIX2LONG(fnum), shiftdist));
|
1157
|
+
}
|
1158
|
+
|
1159
|
+
static VALUE
|
1160
|
+
bnum_arith_rshift64(VALUE bnum, VALUE shiftdist)
|
1161
|
+
{
|
1162
|
+
if (shiftdist == fix_zero)
|
1163
|
+
return bnum;
|
1164
|
+
else
|
1165
|
+
return modify_lo64_in_bignum(bnum, arith_rshift64(load_64_from_bignum(bnum), shiftdist));
|
1166
|
+
}
|
1167
|
+
|
1168
|
+
/* Document-method: Integer#arith_rshift64
|
1169
|
+
* Arithmetic right-shift of the low 64 bits in this integer.
|
1170
|
+
*
|
1171
|
+
* If bit 64 is a 1, the vacated bit positions will be filled with 1s. Otherwise,
|
1172
|
+
* they will be filled with 0s. Or, if the shift distance is negative, a left shift
|
1173
|
+
* will be performed instead, and the vacated bit positions will be filled with 0s.
|
1174
|
+
*
|
1175
|
+
* @example
|
1176
|
+
* 0xaabbccddaabbccdd.arith_rshift64(1).to_s(16) # => "d55de66ed55de66e"
|
1177
|
+
* 0xaabbccddaabbccdd.arith_rshift64(2).to_s(16) # => "eaaef3376aaef337"
|
1178
|
+
*
|
1179
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1180
|
+
* @return [Integer]
|
1181
|
+
*/
|
1182
|
+
def_int_method_with_arg(arith_rshift64);
|
1183
|
+
|
1184
|
+
static const uint8_t bitreverse_table[] =
|
1185
|
+
{
|
1186
|
+
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
|
1187
|
+
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
|
1188
|
+
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
|
1189
|
+
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
|
1190
|
+
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
|
1191
|
+
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
|
1192
|
+
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
|
1193
|
+
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
|
1194
|
+
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
|
1195
|
+
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
|
1196
|
+
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
|
1197
|
+
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
|
1198
|
+
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
|
1199
|
+
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
|
1200
|
+
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
|
1201
|
+
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
|
1202
|
+
};
|
1203
|
+
|
1204
|
+
static inline uint8_t reverse8(uint8_t value)
|
1205
|
+
{
|
1206
|
+
if (SIZEOF_LONG == 8)
|
1207
|
+
/* 64-bit CPU
|
1208
|
+
* Thanks to the Bit Twiddling Hacks page:
|
1209
|
+
* http://graphics.stanford.edu/~seander/bithacks.html */
|
1210
|
+
return (uint8_t)((value * 0x0202020202UL & 0x010884422010UL) % 1023);
|
1211
|
+
else
|
1212
|
+
/* 32-bit CPU */
|
1213
|
+
return bitreverse_table[value];
|
1214
|
+
}
|
1215
|
+
|
1216
|
+
static inline uint16_t reverse16(uint16_t value)
|
1217
|
+
{
|
1218
|
+
return (uint16_t)(bitreverse_table[value & 0xFF] << 8) | bitreverse_table[value >> 8];
|
1219
|
+
}
|
1220
|
+
|
1221
|
+
static inline uint32_t reverse32(uint32_t value)
|
1222
|
+
{
|
1223
|
+
return ((uint32_t)reverse16((uint16_t)value) << 16) | reverse16(value >> 16);
|
1224
|
+
}
|
1225
|
+
|
1226
|
+
static inline uint64_t reverse64(uint64_t value)
|
1227
|
+
{
|
1228
|
+
return ((uint64_t)reverse32((uint32_t)value) << 32) | reverse32(value >> 32);
|
1229
|
+
}
|
1230
|
+
|
1231
|
+
static VALUE
|
1232
|
+
fnum_bitreverse8(VALUE fnum)
|
1233
|
+
{
|
1234
|
+
long value = FIX2LONG(fnum);
|
1235
|
+
if (value < 0)
|
1236
|
+
rb_raise(rb_eRangeError, "can't reverse bits in a negative number");
|
1237
|
+
return LONG2FIX((value & ~0xFFL) | reverse8((uint8_t)value));
|
1238
|
+
}
|
1239
|
+
|
1240
|
+
static VALUE
|
1241
|
+
bnum_bitreverse8(VALUE bnum)
|
1242
|
+
{
|
1243
|
+
if (RBIGNUM_NEGATIVE_P(bnum))
|
1244
|
+
rb_raise(rb_eRangeError, "can't reverse bits in a negative number");
|
1245
|
+
return modify_lo8_in_bignum(bnum, reverse8((uint8_t)*RBIGNUM_DIGITS(bnum)));
|
1246
|
+
}
|
1247
|
+
|
1248
|
+
/* Document-method: Integer#bitreverse8
|
1249
|
+
* Reverse the low 8 bits in this integer.
|
1250
|
+
*
|
1251
|
+
* If the receiver is negative, raise `RangeError`.
|
1252
|
+
*
|
1253
|
+
* @example
|
1254
|
+
* 0b01101011.bitreverse8.to_s(2) # => "11010110"
|
1255
|
+
*
|
1256
|
+
* @return [Integer]
|
1257
|
+
*/
|
1258
|
+
def_int_method(bitreverse8);
|
1259
|
+
|
1260
|
+
static VALUE
|
1261
|
+
fnum_bitreverse16(VALUE fnum)
|
1262
|
+
{
|
1263
|
+
long value = FIX2LONG(fnum);
|
1264
|
+
if (value < 0)
|
1265
|
+
rb_raise(rb_eRangeError, "can't reverse bits in a negative number");
|
1266
|
+
return LONG2FIX((value & ~0xFFFFL) | reverse16((uint16_t)value));
|
1267
|
+
}
|
1268
|
+
|
1269
|
+
static VALUE
|
1270
|
+
bnum_bitreverse16(VALUE bnum)
|
1271
|
+
{
|
1272
|
+
if (RBIGNUM_NEGATIVE_P(bnum))
|
1273
|
+
rb_raise(rb_eRangeError, "can't reverse bits in a negative number");
|
1274
|
+
return modify_lo16_in_bignum(bnum, reverse16((uint16_t)*RBIGNUM_DIGITS(bnum)));
|
1275
|
+
}
|
1276
|
+
|
1277
|
+
/* Document-method: Integer#bitreverse16
|
1278
|
+
* Reverse the low 16 bits in this integer.
|
1279
|
+
*
|
1280
|
+
* If the receiver is negative, raise `RangeError`.
|
1281
|
+
*
|
1282
|
+
* @example
|
1283
|
+
* 0b0110101100001011.bitreverse16.to_s(2) # => "1101000011010110"
|
1284
|
+
*
|
1285
|
+
* @return [Integer]
|
1286
|
+
*/
|
1287
|
+
def_int_method(bitreverse16);
|
1288
|
+
|
1289
|
+
static VALUE
|
1290
|
+
fnum_bitreverse32(VALUE fnum)
|
1291
|
+
{
|
1292
|
+
long value = FIX2LONG(fnum);
|
1293
|
+
uint32_t lo32 = (uint32_t)value;
|
1294
|
+
if (value < 0)
|
1295
|
+
rb_raise(rb_eRangeError, "can't reverse bits in a negative number");
|
1296
|
+
else if (SIZEOF_LONG == 4)
|
1297
|
+
return ULONG2NUM(reverse32(lo32));
|
1298
|
+
else
|
1299
|
+
return LONG2FIX((value & ~0xFFFFFFFFL) | reverse32(lo32));
|
1300
|
+
}
|
1301
|
+
|
1302
|
+
static VALUE
|
1303
|
+
bnum_bitreverse32(VALUE bnum)
|
1304
|
+
{
|
1305
|
+
if (RBIGNUM_NEGATIVE_P(bnum))
|
1306
|
+
rb_raise(rb_eRangeError, "can't reverse bits in a negative number");
|
1307
|
+
return modify_lo32_in_bignum(bnum, reverse32(*RBIGNUM_DIGITS(bnum)));
|
1308
|
+
}
|
1309
|
+
|
1310
|
+
/* Document-method: Integer#bitreverse32
|
1311
|
+
* Reverse the low 32 bits in this integer.
|
1312
|
+
*
|
1313
|
+
* If the receiver is negative, raise `RangeError`.
|
1314
|
+
*
|
1315
|
+
* @example
|
1316
|
+
* 0x12341234.bitreverse32.to_s(16) # => "2c482c48"
|
1317
|
+
*
|
1318
|
+
* @return [Integer]
|
1319
|
+
*/
|
1320
|
+
def_int_method(bitreverse32);
|
1321
|
+
|
1322
|
+
static VALUE
|
1323
|
+
fnum_bitreverse64(VALUE fnum)
|
1324
|
+
{
|
1325
|
+
long value = FIX2LONG(fnum);
|
1326
|
+
if (value < 0)
|
1327
|
+
rb_raise(rb_eRangeError, "can't reverse bits in a negative number");
|
1328
|
+
return ULL2NUM(reverse64((uint64_t)value));
|
1329
|
+
}
|
1330
|
+
|
1331
|
+
static VALUE
|
1332
|
+
bnum_bitreverse64(VALUE bnum)
|
1333
|
+
{
|
1334
|
+
if (RBIGNUM_NEGATIVE_P(bnum))
|
1335
|
+
rb_raise(rb_eRangeError, "can't reverse bits in a negative number");
|
1336
|
+
return modify_lo64_in_bignum(bnum, reverse64(load_64_from_bignum(bnum)));
|
1337
|
+
}
|
1338
|
+
|
1339
|
+
/* Document-method: Integer#bitreverse64
|
1340
|
+
* Reverse the low 64 bits in this integer.
|
1341
|
+
*
|
1342
|
+
* If the receiver is negative, raise `RangeError`.
|
1343
|
+
*
|
1344
|
+
* @example
|
1345
|
+
* 0xabcd1234abcd1234.bitreverse64.to_s(16) # => "2c48b3d52c48b3d5"
|
1346
|
+
*
|
1347
|
+
* @return [Integer]
|
1348
|
+
*/
|
1349
|
+
def_int_method(bitreverse64);
|
1350
|
+
|
1351
|
+
/* Document-class: Integer
|
1352
|
+
* Ruby's good old Integer.
|
1353
|
+
*
|
1354
|
+
* `require "bit-twiddle/core_ext"` before trying to use any of the below methods.
|
1355
|
+
*/
|
1356
|
+
/* Document-class: String
|
1357
|
+
* Ruby's good old String.
|
1358
|
+
*
|
1359
|
+
* `require "bit-twiddle/core_ext"` before trying to use any of the below methods.
|
1360
|
+
*/
|
1361
|
+
|
1362
|
+
/* Add all `bit-twiddle` methods directly to `Integer`. */
|
1363
|
+
static void init_core_extensions()
|
1364
|
+
{
|
1365
|
+
rb_define_method(rb_cInteger, "popcount", int_popcount, 0);
|
1366
|
+
rb_define_method(rb_cString, "popcount", str_popcount, 0);
|
1367
|
+
|
1368
|
+
rb_define_method(rb_cInteger, "lo_bit", int_lo_bit, 0);
|
1369
|
+
rb_define_method(rb_cInteger, "hi_bit", int_hi_bit, 0);
|
1370
|
+
|
1371
|
+
rb_define_method(rb_cInteger, "bswap16", int_bswap16, 0);
|
1372
|
+
rb_define_method(rb_cInteger, "bswap32", int_bswap32, 0);
|
1373
|
+
rb_define_method(rb_cInteger, "bswap64", int_bswap64, 0);
|
1374
|
+
|
1375
|
+
rb_define_method(rb_cInteger, "rrot8", int_rrot8, 1);
|
1376
|
+
rb_define_method(rb_cInteger, "rrot16", int_rrot16, 1);
|
1377
|
+
rb_define_method(rb_cInteger, "rrot32", int_rrot32, 1);
|
1378
|
+
rb_define_method(rb_cInteger, "rrot64", int_rrot64, 1);
|
1379
|
+
|
1380
|
+
rb_define_method(rb_cInteger, "lrot8", int_lrot8, 1);
|
1381
|
+
rb_define_method(rb_cInteger, "lrot16", int_lrot16, 1);
|
1382
|
+
rb_define_method(rb_cInteger, "lrot32", int_lrot32, 1);
|
1383
|
+
rb_define_method(rb_cInteger, "lrot64", int_lrot64, 1);
|
1384
|
+
|
1385
|
+
rb_define_method(rb_cInteger, "lshift8", int_lshift8, 1);
|
1386
|
+
rb_define_method(rb_cInteger, "lshift16", int_lshift16, 1);
|
1387
|
+
rb_define_method(rb_cInteger, "lshift32", int_lshift32, 1);
|
1388
|
+
rb_define_method(rb_cInteger, "lshift64", int_lshift64, 1);
|
1389
|
+
|
1390
|
+
rb_define_method(rb_cInteger, "rshift8", int_rshift8, 1);
|
1391
|
+
rb_define_method(rb_cInteger, "rshift16", int_rshift16, 1);
|
1392
|
+
rb_define_method(rb_cInteger, "rshift32", int_rshift32, 1);
|
1393
|
+
rb_define_method(rb_cInteger, "rshift64", int_rshift64, 1);
|
1394
|
+
|
1395
|
+
rb_define_method(rb_cInteger, "arith_rshift8", int_arith_rshift8, 1);
|
1396
|
+
rb_define_method(rb_cInteger, "arith_rshift16", int_arith_rshift16, 1);
|
1397
|
+
rb_define_method(rb_cInteger, "arith_rshift32", int_arith_rshift32, 1);
|
1398
|
+
rb_define_method(rb_cInteger, "arith_rshift64", int_arith_rshift64, 1);
|
1399
|
+
|
1400
|
+
rb_define_method(rb_cInteger, "bitreverse8", int_bitreverse8, 0);
|
1401
|
+
rb_define_method(rb_cInteger, "bitreverse16", int_bitreverse16, 0);
|
1402
|
+
rb_define_method(rb_cInteger, "bitreverse32", int_bitreverse32, 0);
|
1403
|
+
rb_define_method(rb_cInteger, "bitreverse64", int_bitreverse64, 0);
|
1404
|
+
}
|
1405
|
+
|
1406
|
+
static VALUE
|
1407
|
+
bt_add_core_extensions(VALUE self)
|
1408
|
+
{
|
1409
|
+
/* this is so Yardoc can find method definitions */
|
1410
|
+
init_core_extensions();
|
1411
|
+
return Qnil;
|
1412
|
+
}
|
1413
|
+
|
1414
|
+
/* Wrapper functions are used for methods on BitTwiddle module */
|
1415
|
+
#define def_wrapper(name) \
|
1416
|
+
static VALUE bt_ ## name(VALUE self, VALUE num) \
|
1417
|
+
{ \
|
1418
|
+
retry: \
|
1419
|
+
switch (TYPE(num)) { \
|
1420
|
+
case T_FIXNUM: return fnum_ ## name(num); \
|
1421
|
+
case T_BIGNUM: return bnum_ ## name(num); \
|
1422
|
+
default: num = rb_to_int(num); goto retry; \
|
1423
|
+
} \
|
1424
|
+
}
|
1425
|
+
#define def_wrapper_with_arg(name) \
|
1426
|
+
static VALUE bt_ ## name(VALUE self, VALUE num, VALUE arg) \
|
1427
|
+
{ \
|
1428
|
+
retry: \
|
1429
|
+
switch (TYPE(num)) { \
|
1430
|
+
case T_FIXNUM: return fnum_ ## name(num, arg); \
|
1431
|
+
case T_BIGNUM: return bnum_ ## name(num, arg); \
|
1432
|
+
default: num = rb_to_int(num); goto retry; \
|
1433
|
+
} \
|
1434
|
+
}
|
1435
|
+
|
1436
|
+
def_wrapper(popcount);
|
1437
|
+
def_wrapper(lo_bit);
|
1438
|
+
def_wrapper(hi_bit);
|
1439
|
+
def_wrapper(bswap16);
|
1440
|
+
def_wrapper(bswap32);
|
1441
|
+
def_wrapper(bswap64);
|
1442
|
+
def_wrapper_with_arg(lrot8);
|
1443
|
+
def_wrapper_with_arg(lrot16);
|
1444
|
+
def_wrapper_with_arg(lrot32);
|
1445
|
+
def_wrapper_with_arg(lrot64);
|
1446
|
+
def_wrapper_with_arg(rrot8);
|
1447
|
+
def_wrapper_with_arg(rrot16);
|
1448
|
+
def_wrapper_with_arg(rrot32);
|
1449
|
+
def_wrapper_with_arg(rrot64);
|
1450
|
+
def_wrapper_with_arg(lshift8);
|
1451
|
+
def_wrapper_with_arg(lshift16);
|
1452
|
+
def_wrapper_with_arg(lshift32);
|
1453
|
+
def_wrapper_with_arg(lshift64);
|
1454
|
+
def_wrapper_with_arg(rshift8);
|
1455
|
+
def_wrapper_with_arg(rshift16);
|
1456
|
+
def_wrapper_with_arg(rshift32);
|
1457
|
+
def_wrapper_with_arg(rshift64);
|
1458
|
+
def_wrapper_with_arg(arith_rshift8);
|
1459
|
+
def_wrapper_with_arg(arith_rshift16);
|
1460
|
+
def_wrapper_with_arg(arith_rshift32);
|
1461
|
+
def_wrapper_with_arg(arith_rshift64);
|
1462
|
+
def_wrapper(bitreverse8);
|
1463
|
+
def_wrapper(bitreverse16);
|
1464
|
+
def_wrapper(bitreverse32);
|
1465
|
+
def_wrapper(bitreverse64);
|
1466
|
+
|
1467
|
+
void Init_bit_twiddle(void)
|
1468
|
+
{
|
1469
|
+
VALUE rb_mBitTwiddle = rb_define_module("BitTwiddle");
|
1470
|
+
|
1471
|
+
rb_define_singleton_method(rb_mBitTwiddle, "add_core_extensions", bt_add_core_extensions, 0);
|
1472
|
+
|
1473
|
+
/* Return the number of 1 bits in `int`.
|
1474
|
+
* @example
|
1475
|
+
* BitTwiddle.popcount(7) # => 3
|
1476
|
+
* BitTwiddle.popcount(255) # => 8
|
1477
|
+
*
|
1478
|
+
* If `int` is negative, raise `RangeError`.
|
1479
|
+
*
|
1480
|
+
* @param int [Integer] The integer to operate on
|
1481
|
+
* @return [Integer]
|
1482
|
+
*/
|
1483
|
+
rb_define_singleton_method(rb_mBitTwiddle, "popcount", bt_popcount, 1);
|
1484
|
+
/* Return the index of the lowest 1 bit, where the least-significant bit is index 1.
|
1485
|
+
* If this integer is 0, return 0.
|
1486
|
+
* @example
|
1487
|
+
* BitTwiddle.lo_bit(1) # => 1
|
1488
|
+
* BitTwiddle.lo_bit(128) # => 8
|
1489
|
+
*
|
1490
|
+
* If `int` is negative, raise `RangeError`.
|
1491
|
+
*
|
1492
|
+
* @param int [Integer] The integer to operate on
|
1493
|
+
* @return [Integer]
|
1494
|
+
*/
|
1495
|
+
rb_define_singleton_method(rb_mBitTwiddle, "lo_bit", bt_lo_bit, 1);
|
1496
|
+
/* Return the index of the highest 1 bit, where the least-significant bit is index 1.
|
1497
|
+
* If `int` is 0, return 0.
|
1498
|
+
* @example
|
1499
|
+
* BitTwiddle.hi_bit(1) # => 1
|
1500
|
+
* BitTwiddle.hi_bit(255) # => 8
|
1501
|
+
*
|
1502
|
+
* If `int` is negative, raise `RangeError`.
|
1503
|
+
*
|
1504
|
+
* @param int [Integer] The integer to operate on
|
1505
|
+
* @return [Integer]
|
1506
|
+
*/
|
1507
|
+
rb_define_singleton_method(rb_mBitTwiddle, "hi_bit", bt_hi_bit, 1);
|
1508
|
+
/* Reverse the least-significant and second least-significant bytes of `int`.
|
1509
|
+
* @example
|
1510
|
+
* BitTwiddle.bswap16(0xFF00) # => 255
|
1511
|
+
* BitTwiddle.bswap16(0x00FF) # => 65280
|
1512
|
+
*
|
1513
|
+
* If `int` is negative, raise `RangeError`.
|
1514
|
+
*
|
1515
|
+
* @param int [Integer] The integer to operate on
|
1516
|
+
* @return [Integer]
|
1517
|
+
*/
|
1518
|
+
rb_define_singleton_method(rb_mBitTwiddle, "bswap16", bt_bswap16, 1);
|
1519
|
+
/* Reverse the least-significant 4 bytes of `int`.
|
1520
|
+
*
|
1521
|
+
* Does not reverse bits within each byte. This can be used to swap endianness
|
1522
|
+
* of a 32-bit integer.
|
1523
|
+
*
|
1524
|
+
* @example
|
1525
|
+
* BitTwiddle.bswap32(0xaabbccdd).to_s(16) # => "ddccbbaa"
|
1526
|
+
*
|
1527
|
+
* If `int` is negative, raise `RangeError`.
|
1528
|
+
*
|
1529
|
+
* @param int [Integer] The integer to operate on
|
1530
|
+
* @return [Integer]
|
1531
|
+
*/
|
1532
|
+
rb_define_singleton_method(rb_mBitTwiddle, "bswap32", bt_bswap32, 1);
|
1533
|
+
/* Reverse the least-significant 8 bytes of `int`.
|
1534
|
+
*
|
1535
|
+
* Does not reverse bits within each byte. This can be used to swap endianness
|
1536
|
+
* of a 64-bit integer.
|
1537
|
+
*
|
1538
|
+
* @example
|
1539
|
+
* BitTwiddle.bswap64(0xaabbccdd).to_s(16) # => "ddccbbaa00000000"
|
1540
|
+
*
|
1541
|
+
* If `int` is negative, raise `RangeError`.
|
1542
|
+
*
|
1543
|
+
* @param int [Integer] The integer to operate on
|
1544
|
+
* @return [Integer]
|
1545
|
+
*/
|
1546
|
+
rb_define_singleton_method(rb_mBitTwiddle, "bswap64", bt_bswap64, 1);
|
1547
|
+
/* Left-rotation ("circular shift") of the low 8 bits in `int`.
|
1548
|
+
*
|
1549
|
+
* If the rotate distance is negative, the bit rotation will be to the right
|
1550
|
+
* instead.
|
1551
|
+
*
|
1552
|
+
* @example
|
1553
|
+
* BitTwiddle.lrot8(0b01110001, 1).to_s(2) # => "11100010"
|
1554
|
+
* BitTwiddle.lrot8(0b01110001, 3).to_s(2) # => "10001011"
|
1555
|
+
*
|
1556
|
+
* @param int [Integer] The integer to operate on
|
1557
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
1558
|
+
* @return [Integer]
|
1559
|
+
*/
|
1560
|
+
rb_define_singleton_method(rb_mBitTwiddle, "lrot8", bt_lrot8, 2);
|
1561
|
+
/* Left-rotation ("circular shift") of the low 16 bits in `int`.
|
1562
|
+
*
|
1563
|
+
* If the rotate distance is negative, the bit rotation will be to the right
|
1564
|
+
* instead.
|
1565
|
+
*
|
1566
|
+
* @example
|
1567
|
+
* BitTwiddle.lrot16(0b0111000101110001, 1).to_s(2) # => "1110001011100010"
|
1568
|
+
* BitTwiddle.lrot16(0b0111000101110001, 3).to_s(2) # => "1000101110001011"
|
1569
|
+
*
|
1570
|
+
* @param int [Integer] The integer to operate on
|
1571
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
1572
|
+
* @return [Integer]
|
1573
|
+
*/
|
1574
|
+
rb_define_singleton_method(rb_mBitTwiddle, "lrot16", bt_lrot16, 2);
|
1575
|
+
/* Left-rotation ("circular shift") of the low 32 bits in `int`.
|
1576
|
+
*
|
1577
|
+
* If the rotate distance is negative, the bit rotation will be to the right
|
1578
|
+
* instead.
|
1579
|
+
*
|
1580
|
+
* @example
|
1581
|
+
* BitTwiddle.lrot32(0xaabbccdd, 4).to_s(16) # => "abbccdda"
|
1582
|
+
*
|
1583
|
+
* @param int [Integer] The integer to operate on
|
1584
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
1585
|
+
* @return [Integer]
|
1586
|
+
*/
|
1587
|
+
rb_define_singleton_method(rb_mBitTwiddle, "lrot32", bt_lrot32, 2);
|
1588
|
+
/* Left-rotation ("circular shift") of the low 64 bits in `int`.
|
1589
|
+
*
|
1590
|
+
* If the rotate distance is negative, the bit rotation will be to the right
|
1591
|
+
* instead.
|
1592
|
+
*
|
1593
|
+
* @example
|
1594
|
+
* BitTwiddle.lrot64(0x11223344aabbccdd, 4).to_s(16) # => "1223344aabbccdd1"
|
1595
|
+
*
|
1596
|
+
* @param int [Integer] The integer to operate on
|
1597
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
1598
|
+
* @return [Integer]
|
1599
|
+
*/
|
1600
|
+
rb_define_singleton_method(rb_mBitTwiddle, "lrot64", bt_lrot64, 2);
|
1601
|
+
/* Right-rotation ("circular shift") of the low 8 bits in `int`.
|
1602
|
+
*
|
1603
|
+
* If the rotate distance is negative, the bit rotation will be to the left
|
1604
|
+
* instead.
|
1605
|
+
*
|
1606
|
+
* @example
|
1607
|
+
* BitTwiddle.rrot8(0b01110001, 1).to_s(2) # => "10111000"
|
1608
|
+
* BitTwiddle.rrot8(0b01110001, 3).to_s(2) # => "101110"
|
1609
|
+
*
|
1610
|
+
* @param int [Integer] The integer to operate on
|
1611
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
1612
|
+
* @return [Integer]
|
1613
|
+
*/
|
1614
|
+
rb_define_singleton_method(rb_mBitTwiddle, "rrot8", bt_rrot8, 2);
|
1615
|
+
/* Right-rotation ("circular shift") of the low 16 bits in `int`.
|
1616
|
+
*
|
1617
|
+
* If the rotate distance is negative, the bit rotation will be to the left
|
1618
|
+
* instead.
|
1619
|
+
*
|
1620
|
+
* @example
|
1621
|
+
* BitTwiddle.rrot16(0b0111000101110001, 1).to_s(2) # => "1011100010111000"
|
1622
|
+
* BitTwiddle.rrot16(0b0111000101110001, 3).to_s(2) # => "10111000101110"
|
1623
|
+
*
|
1624
|
+
* @param int [Integer] The integer to operate on
|
1625
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
1626
|
+
* @return [Integer]
|
1627
|
+
*/
|
1628
|
+
rb_define_singleton_method(rb_mBitTwiddle, "rrot16", bt_rrot16, 2);
|
1629
|
+
/* Right-rotation ("circular shift") of the low 32 bits in `int`.
|
1630
|
+
*
|
1631
|
+
* If the rotate distance is negative, the bit rotation will be to the left
|
1632
|
+
* instead.
|
1633
|
+
*
|
1634
|
+
* @example
|
1635
|
+
* BitTwiddle.rrot32(0xaabbccdd, 4).to_s(16) # => "daabbccd"
|
1636
|
+
*
|
1637
|
+
* @param int [Integer] The integer to operate on
|
1638
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
1639
|
+
* @return [Integer]
|
1640
|
+
*/
|
1641
|
+
rb_define_singleton_method(rb_mBitTwiddle, "rrot32", bt_rrot32, 2);
|
1642
|
+
/* Right-rotation ("circular shift") of the low 64 bits in `int`.
|
1643
|
+
*
|
1644
|
+
* If the rotate distance is negative, the bit rotation will be to the left
|
1645
|
+
* instead.
|
1646
|
+
*
|
1647
|
+
* @example
|
1648
|
+
* BitTwiddle.rrot64(0x11223344aabbccdd, 4).to_s(16) # => "d11223344aabbccd"
|
1649
|
+
*
|
1650
|
+
* @param int [Integer] The integer to operate on
|
1651
|
+
* @param rotdist [Integer] Number of bit positions to rotate by
|
1652
|
+
* @return [Integer]
|
1653
|
+
*/
|
1654
|
+
rb_define_singleton_method(rb_mBitTwiddle, "rrot64", bt_rrot64, 2);
|
1655
|
+
/* Left-shift of the low 8 bits in `int`.
|
1656
|
+
*
|
1657
|
+
* If the shift distance is negative, a right shift will be performed instead.
|
1658
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
1659
|
+
* more than 7 or less than -7, the low 8 bits will all be zeroed.
|
1660
|
+
*
|
1661
|
+
* @example
|
1662
|
+
* BitTwiddle.lshift8(0x11223344, 1).to_s(16) # => "11223388"
|
1663
|
+
* BitTwiddle.lshift8(0x11223344, 2).to_s(16) # => "11223310"
|
1664
|
+
*
|
1665
|
+
* @param int [Integer] The integer to operate on
|
1666
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1667
|
+
* @return [Integer]
|
1668
|
+
*/
|
1669
|
+
rb_define_singleton_method(rb_mBitTwiddle, "lshift8", bt_lshift8, 2);
|
1670
|
+
/* Left-shift of the low 16 bits in `int`.
|
1671
|
+
*
|
1672
|
+
* If the shift distance is negative, a right shift will be performed instead.
|
1673
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
1674
|
+
* more than 15 or less than -15, the low 16 bits will all be zeroed.
|
1675
|
+
*
|
1676
|
+
* @example
|
1677
|
+
* BitTwiddle.lshift16(0x11223344, 1).to_s(16) # => "11226688"
|
1678
|
+
* BitTwiddle.lshift16(0x11223344, 2).to_s(16) # => "1122cd10"
|
1679
|
+
*
|
1680
|
+
* @param int [Integer] The integer to operate on
|
1681
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1682
|
+
* @return [Integer]
|
1683
|
+
*/
|
1684
|
+
rb_define_singleton_method(rb_mBitTwiddle, "lshift16", bt_lshift16, 2);
|
1685
|
+
/* Left-shift of the low 32 bits in `int`.
|
1686
|
+
*
|
1687
|
+
* If the shift distance is negative, a right shift will be performed instead.
|
1688
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
1689
|
+
* more than 31 or less than -31, the low 32 bits will all be zeroed.
|
1690
|
+
*
|
1691
|
+
* @example
|
1692
|
+
* BitTwiddle.lshift32(0x11223344, 1).to_s(16) # => "22446688"
|
1693
|
+
* BitTwiddle.lshift32(0x11223344, 2).to_s(16) # => "4488cd10"
|
1694
|
+
*
|
1695
|
+
* @param int [Integer] The integer to operate on
|
1696
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1697
|
+
* @return [Integer]
|
1698
|
+
*/
|
1699
|
+
rb_define_singleton_method(rb_mBitTwiddle, "lshift32", bt_lshift32, 2);
|
1700
|
+
/* Left-shift of the low 64 bits in `int`.
|
1701
|
+
*
|
1702
|
+
* If the shift distance is negative, a right shift will be performed instead.
|
1703
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
1704
|
+
* more than 63 or less than -63, the low 64 bits will all be zeroed.
|
1705
|
+
*
|
1706
|
+
* @example
|
1707
|
+
* BitTwiddle.lshift64(0x1122334411223344, 1).to_s(16) # => "2244668822446688"
|
1708
|
+
* BitTwiddle.lshift64(0x1122334411223344, 2).to_s(16) # => "4488cd104488cd10"
|
1709
|
+
*
|
1710
|
+
* @param int [Integer] The integer to operate on
|
1711
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1712
|
+
* @return [Integer]
|
1713
|
+
*/
|
1714
|
+
rb_define_singleton_method(rb_mBitTwiddle, "lshift64", bt_lshift64, 2);
|
1715
|
+
/* Right-shift of the low 8 bits in `int`.
|
1716
|
+
*
|
1717
|
+
* If the shift distance is negative, a left shift will be performed instead.
|
1718
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
1719
|
+
* more than 7 or less than -7, the low 8 bits will all be zeroed.
|
1720
|
+
*
|
1721
|
+
* @example
|
1722
|
+
* BitTwiddle.rshift8(0x11223344, 1).to_s(16) # => "11223322"
|
1723
|
+
* BitTwiddle.rshift8(0x11223344, 2).to_s(16) # => "11223311"
|
1724
|
+
*
|
1725
|
+
* @param int [Integer] The integer to operate on
|
1726
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1727
|
+
* @return [Integer]
|
1728
|
+
*/
|
1729
|
+
rb_define_singleton_method(rb_mBitTwiddle, "rshift8", bt_rshift8, 2);
|
1730
|
+
/* Right-shift of the low 16 bits in `int`.
|
1731
|
+
*
|
1732
|
+
* If the shift distance is negative, a left shift will be performed instead.
|
1733
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
1734
|
+
* more than 15 or less than -15, the low 16 bits will all be zeroed.
|
1735
|
+
*
|
1736
|
+
* @example
|
1737
|
+
* BitTwiddle.rshift16(0x11223344, 1).to_s(16) # => "112219a2"
|
1738
|
+
* BitTwiddle.rshift16(0x11223344, 2).to_s(16) # => "11220cd1"
|
1739
|
+
*
|
1740
|
+
* @param int [Integer] The integer to operate on
|
1741
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1742
|
+
* @return [Integer]
|
1743
|
+
*/
|
1744
|
+
rb_define_singleton_method(rb_mBitTwiddle, "rshift16", bt_rshift16, 2);
|
1745
|
+
/* Right-shift of the low 32 bits in `int`.
|
1746
|
+
*
|
1747
|
+
* If the shift distance is negative, a left shift will be performed instead.
|
1748
|
+
* The vacated bit positions will be filled with 0 bits. If shift distance is
|
1749
|
+
* more than 31 or less than -31, the low 32 bits will all be zeroed.
|
1750
|
+
*
|
1751
|
+
* @example
|
1752
|
+
* BitTwiddle.rshift32(0x11223344, 1).to_s(16) # => "89119a2"
|
1753
|
+
* BitTwiddle.rshift32(0x11223344, 2).to_s(16) # => "4488cd1"
|
1754
|
+
*
|
1755
|
+
* @param int [Integer] The integer to operate on
|
1756
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1757
|
+
* @return [Integer]
|
1758
|
+
*/
|
1759
|
+
rb_define_singleton_method(rb_mBitTwiddle, "rshift32", bt_rshift32, 2);
|
1760
|
+
/* Arithmetic right-shift of the low 64 bits in `int`.
|
1761
|
+
*
|
1762
|
+
* If bit 64 is a 1, the vacated bit positions will be filled with 1s. Otherwise,
|
1763
|
+
* they will be filled with 0s. Or, if the shift distance is negative, a left shift
|
1764
|
+
* will be performed instead, and the vacated bit positions will be filled with 0s.
|
1765
|
+
*
|
1766
|
+
* @example
|
1767
|
+
* BitTwiddle.arith_rshift64(0xaabbccddaabbccdd, 1).to_s(16) # => "d55de66ed55de66e"
|
1768
|
+
* BitTwiddle.arith_rshift64(0xaabbccddaabbccdd, 2).to_s(16) # => "eaaef3376aaef337"
|
1769
|
+
*
|
1770
|
+
* @param int [Integer] The integer to operate on
|
1771
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1772
|
+
* @return [Integer]
|
1773
|
+
*/
|
1774
|
+
rb_define_singleton_method(rb_mBitTwiddle, "rshift64", bt_rshift64, 2);
|
1775
|
+
/* Arithmetic right-shift of the low 8 bits in `int`.
|
1776
|
+
*
|
1777
|
+
* If bit 8 is a 1, the vacated bit positions will be filled with 1s. Otherwise,
|
1778
|
+
* they will be filled with 0s. Or, if the shift distance is negative, a left shift
|
1779
|
+
* will be performed instead, and the vacated bit positions will be filled with 0s.
|
1780
|
+
*
|
1781
|
+
* @example
|
1782
|
+
* BitTwiddle.arith_rshift8(0xaabbccdd, 1).to_s(16) # => "aabbccee"
|
1783
|
+
* BitTwiddle.arith_rshift8(0xaabbccdd, 2).to_s(16) # => "aabbccf7"
|
1784
|
+
*
|
1785
|
+
* @param int [Integer] The integer to operate on
|
1786
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1787
|
+
* @return [Integer]
|
1788
|
+
*/
|
1789
|
+
rb_define_singleton_method(rb_mBitTwiddle, "arith_rshift8", bt_arith_rshift8, 2);
|
1790
|
+
/* Arithmetic right-shift of the low 16 bits in `int`.
|
1791
|
+
*
|
1792
|
+
* If bit 16 is a 1, the vacated bit positions will be filled with 1s. Otherwise,
|
1793
|
+
* they will be filled with 0s. Or, if the shift distance is negative, a left shift
|
1794
|
+
* will be performed instead, and the vacated bit positions will be filled with 0s.
|
1795
|
+
*
|
1796
|
+
* @example
|
1797
|
+
* BitTwiddle.arith_rshift16(0xaabbccdd, 1).to_s(16) # => "aabbe66e"
|
1798
|
+
* BitTwiddle.arith_rshift16(0xaabbccdd, 2).to_s(16) # => "aabbf337"
|
1799
|
+
*
|
1800
|
+
* @param int [Integer] The integer to operate on
|
1801
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1802
|
+
* @return [Integer]
|
1803
|
+
*/
|
1804
|
+
rb_define_singleton_method(rb_mBitTwiddle, "arith_rshift16", bt_arith_rshift16, 2);
|
1805
|
+
/* Arithmetic right-shift of the low 32 bits in `int`.
|
1806
|
+
*
|
1807
|
+
* If bit 32 is a 1, the vacated bit positions will be filled with 1s. Otherwise,
|
1808
|
+
* they will be filled with 0s. Or, if the shift distance is negative, a left shift
|
1809
|
+
* will be performed instead, and the vacated bit positions will be filled with 0s.
|
1810
|
+
*
|
1811
|
+
* @example
|
1812
|
+
* BitTwiddle.arith_rshift32(0xaabbccddaabbccdd, 1).to_s(16) # => "d55de66e"
|
1813
|
+
* BitTwiddle.arith_rshift32(0xaabbccddaabbccdd, 2).to_s(16) # => "eaaef337"
|
1814
|
+
*
|
1815
|
+
* @param int [Integer] The integer to operate on
|
1816
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1817
|
+
* @return [Integer]
|
1818
|
+
*/
|
1819
|
+
rb_define_singleton_method(rb_mBitTwiddle, "arith_rshift32", bt_arith_rshift32, 2);
|
1820
|
+
/* Arithmetic right-shift of the low 64 bits in `int`.
|
1821
|
+
*
|
1822
|
+
* If bit 64 is a 1, the vacated bit positions will be filled with 1s. Otherwise,
|
1823
|
+
* they will be filled with 0s. Or, if the shift distance is negative, a left shift
|
1824
|
+
* will be performed instead, and the vacated bit positions will be filled with 0s.
|
1825
|
+
*
|
1826
|
+
* @example
|
1827
|
+
* BitTwiddle.arith_rshift64(0xaabbccddaabbccdd, 1).to_s(16) # => "d55de66ed55de66e"
|
1828
|
+
* BitTwiddle.arith_rshift64(0xaabbccddaabbccdd, 2).to_s(16) # => "eaaef3376aaef337"
|
1829
|
+
*
|
1830
|
+
* @param int [Integer] The integer to operate on
|
1831
|
+
* @param shiftdist [Integer] Number of bit positions to shift by
|
1832
|
+
* @return [Integer]
|
1833
|
+
*/
|
1834
|
+
rb_define_singleton_method(rb_mBitTwiddle, "arith_rshift64", bt_arith_rshift64, 2);
|
1835
|
+
/* Reverse the low 8 bits in `int`.
|
1836
|
+
*
|
1837
|
+
* @example
|
1838
|
+
* BitTwiddle.bitreverse8(0b01101011).to_s(2) # => "11010110"
|
1839
|
+
*
|
1840
|
+
* If `int` is negative, raise `RangeError`.
|
1841
|
+
*
|
1842
|
+
* @param int [Integer] The integer to operate on
|
1843
|
+
* @return [Integer]
|
1844
|
+
*/
|
1845
|
+
rb_define_singleton_method(rb_mBitTwiddle, "bitreverse8", bt_bitreverse8, 1);
|
1846
|
+
/* Reverse the low 16 bits in `int`.
|
1847
|
+
*
|
1848
|
+
* @example
|
1849
|
+
* BitTwiddle.bitreverse16(0b0110101100001011).to_s(2) # => "1101000011010110"
|
1850
|
+
*
|
1851
|
+
* If `int` is negative, raise `RangeError`.
|
1852
|
+
*
|
1853
|
+
* @param int [Integer] The integer to operate on
|
1854
|
+
* @return [Integer]
|
1855
|
+
*/
|
1856
|
+
rb_define_singleton_method(rb_mBitTwiddle, "bitreverse16", bt_bitreverse16, 1);
|
1857
|
+
/* Reverse the low 32 bits in `int`.
|
1858
|
+
*
|
1859
|
+
* @example
|
1860
|
+
* BitTwiddle.bitreverse32(0x12341234).to_s(16) # => "2c482c48"
|
1861
|
+
*
|
1862
|
+
* If `int` is negative, raise `RangeError`.
|
1863
|
+
*
|
1864
|
+
* @param int [Integer] The integer to operate on
|
1865
|
+
* @return [Integer]
|
1866
|
+
*/
|
1867
|
+
rb_define_singleton_method(rb_mBitTwiddle, "bitreverse32", bt_bitreverse32, 1);
|
1868
|
+
/* Reverse the low 64 bits in `int`.
|
1869
|
+
*
|
1870
|
+
* @example
|
1871
|
+
* BitTwiddle.bitreverse64(0xabcd1234abcd1234).to_s(16) # => "2c48b3d52c48b3d5"
|
1872
|
+
*
|
1873
|
+
* If `int` is negative, raise `RangeError`.
|
1874
|
+
*
|
1875
|
+
* @param int [Integer] The integer to operate on
|
1876
|
+
* @return [Integer]
|
1877
|
+
*/
|
1878
|
+
rb_define_singleton_method(rb_mBitTwiddle, "bitreverse64", bt_bitreverse64, 1);
|
1879
|
+
}
|