bit-twiddle 0.0.2 → 0.0.4

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