bit-twiddle 0.0.2 → 0.0.4

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