bitpack 0.1

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.
data/ext/bitpack_ext.c ADDED
@@ -0,0 +1,662 @@
1
+ #include "ruby.h"
2
+ #include "string.h"
3
+ #include "bitpack.h"
4
+
5
+ /* the BitPack class object */
6
+ static VALUE cBitPack;
7
+
8
+ /* mapping of BitPack error codes to ruby exceptions */
9
+ static VALUE bp_exceptions[6];
10
+
11
+ /*
12
+ * call-seq:
13
+ * BitPack.new -> a new BitPack object
14
+ * BitPack.new(n) -> a new BitPack object
15
+ *
16
+ * Creates a new BitPack object. The number of bytes used internally
17
+ * to store the bit string can optionally be set to +n+.
18
+ *
19
+ */
20
+ static VALUE bp_new(int argc, VALUE *argv, VALUE class)
21
+ {
22
+ VALUE bp_obj;
23
+ bitpack_t bp;
24
+
25
+ if (argc == 0) {
26
+ bp = bitpack_init_default();
27
+ }
28
+ else {
29
+ bp = bitpack_init(NUM2ULONG(argv[0]));
30
+ }
31
+
32
+ if (bp == NULL) {
33
+ rb_raise(bp_exceptions[BITPACK_ERR_MALLOC_FAILED], "malloc() failed");
34
+ }
35
+
36
+ bp_obj = Data_Wrap_Struct(class, 0, bitpack_destroy, bp);
37
+
38
+ return bp_obj;
39
+ }
40
+
41
+ /*
42
+ * call-seq:
43
+ * BitPack.from_bytes(string) -> a new BitPack object
44
+ *
45
+ * Creates a new BitPack object that is initialzed with the contents
46
+ * of +string+.
47
+ *
48
+ * === Example
49
+ *
50
+ * >> bp = BitPack.from_bytes("ruby")
51
+ * => 01110010011101010110001001111001
52
+ * >> 4.times { p bp.read_bits(8).chr }
53
+ * "r"
54
+ * "u"
55
+ * "b"
56
+ * "y"
57
+ * => 4
58
+ */
59
+ static VALUE bp_from_bytes(VALUE class, VALUE bytes_str)
60
+ {
61
+ VALUE bp_obj;
62
+ VALUE str;;
63
+ bitpack_t bp;
64
+
65
+ str = StringValue(bytes_str);
66
+
67
+ bp = bitpack_init_from_bytes((unsigned char *)RSTRING(str)->ptr, RSTRING(str)->len);
68
+
69
+ if (bp == NULL) {
70
+ rb_raise(bp_exceptions[BITPACK_ERR_MALLOC_FAILED], "malloc() failed");
71
+ }
72
+
73
+ bp_obj = Data_Wrap_Struct(class, 0, bitpack_destroy, bp);
74
+
75
+ return bp_obj;
76
+ }
77
+
78
+ /*
79
+ * call-seq:
80
+ * bp.size -> Integer
81
+ *
82
+ * Access the current size of the BitPack object in bits.
83
+ */
84
+ static VALUE bp_size(VALUE self)
85
+ {
86
+ bitpack_t bp;
87
+ unsigned long size;
88
+
89
+ Data_Get_Struct(self, struct _bitpack_t, bp);
90
+
91
+ size = bitpack_size(bp);
92
+
93
+ return ULONG2NUM(size);
94
+ }
95
+
96
+ /*
97
+ * call-seq:
98
+ * bp.data_size -> Integer
99
+ *
100
+ * Access the number of bytes of memory currently allocated to this
101
+ * BitPack object.
102
+ */
103
+ static VALUE bp_data_size(VALUE self)
104
+ {
105
+ bitpack_t bp;
106
+ unsigned long data_size;
107
+
108
+ Data_Get_Struct(self, struct _bitpack_t, bp);
109
+
110
+ data_size = bitpack_data_size(bp);
111
+
112
+ return ULONG2NUM(data_size);
113
+ }
114
+
115
+ /*
116
+ * call-seq:
117
+ * bp.read_pos -> Integer
118
+ *
119
+ * Access the current read position of this BitPack object.
120
+ *
121
+ * === Example
122
+ *
123
+ * >> bp = BitPack.from_bytes("test")
124
+ * => 01110100011001010111001101110100
125
+ * >> bp.read_pos
126
+ * => 0
127
+ * >> bp.read_bits(8)
128
+ * => 116
129
+ * >> bp.read_pos
130
+ * => 8
131
+ */
132
+ static VALUE bp_read_pos(VALUE self)
133
+ {
134
+ bitpack_t bp;
135
+ unsigned long read_pos;
136
+
137
+ Data_Get_Struct(self, struct _bitpack_t, bp);
138
+
139
+ read_pos = bitpack_read_pos(bp);
140
+
141
+ return ULONG2NUM(read_pos);
142
+ }
143
+
144
+ /*
145
+ * call-seq:
146
+ * bp.reset_read_pos
147
+ *
148
+ * Reset the current read position to the beginning of this BitPack
149
+ * object.
150
+ */
151
+ static VALUE bp_reset_read_pos(VALUE self)
152
+ {
153
+ bitpack_t bp;
154
+
155
+ Data_Get_Struct(self, struct _bitpack_t, bp);
156
+
157
+ bitpack_reset_read_pos(bp);
158
+
159
+ return self;
160
+ }
161
+
162
+ /*
163
+ * call-seq:
164
+ * bp.on(i)
165
+ *
166
+ * Sets the bit at index +i+. If +i+ is greater than the current
167
+ * size of the BitPack object, then the size is expanded and the
168
+ * current append position is set to this index.
169
+ *
170
+ * === Example
171
+ *
172
+ * >> bp = BitPack.new
173
+ * =>
174
+ * >> bp.on(0)
175
+ * => 1
176
+ * >> bp.on(2)
177
+ * => 101
178
+ * >> bp.on(7)
179
+ * => 10100001
180
+ * >> bp.on(6)
181
+ * => 10100011
182
+ */
183
+ static VALUE bp_on(VALUE self, VALUE index)
184
+ {
185
+ bitpack_t bp;
186
+
187
+ Data_Get_Struct(self, struct _bitpack_t, bp);
188
+
189
+ if (!bitpack_on(bp, NUM2ULONG(index))) {
190
+ rb_raise(bp_exceptions[bitpack_get_error(bp)],
191
+ bitpack_get_error_str(bp));
192
+ }
193
+
194
+ return self;
195
+ }
196
+
197
+ /*
198
+ * call-seq:
199
+ * bp.off(i)
200
+ *
201
+ * Unsets the bit at index +i+. If +i+ is greater than the current
202
+ * size of the BitPack object, then the size is expanded and the
203
+ * current append position is set to this index.
204
+ */
205
+ static VALUE bp_off(VALUE self, VALUE index)
206
+ {
207
+ bitpack_t bp;
208
+
209
+ Data_Get_Struct(self, struct _bitpack_t, bp);
210
+
211
+ if (!bitpack_off(bp, NUM2ULONG(index))) {
212
+ rb_raise(bp_exceptions[bitpack_get_error(bp)],
213
+ bitpack_get_error_str(bp));
214
+ }
215
+
216
+ return self;
217
+ }
218
+
219
+ /*
220
+ * call-seq:
221
+ * bp.get(i) -> 0 or 1
222
+ *
223
+ * Access the value of the bit at index +i+.
224
+ */
225
+ static VALUE bp_get(VALUE self, VALUE index)
226
+ {
227
+ bitpack_t bp;
228
+ unsigned char bit;
229
+
230
+ Data_Get_Struct(self, struct _bitpack_t, bp);
231
+
232
+ if (!bitpack_get(bp, NUM2ULONG(index), &bit)) {
233
+ rb_raise(bp_exceptions[bitpack_get_error(bp)],
234
+ bitpack_get_error_str(bp));
235
+ }
236
+
237
+ return INT2FIX(bit);
238
+ }
239
+
240
+ /*
241
+ * call-seq:
242
+ * bp.set_bits(value, num_bits, i) -> self
243
+ *
244
+ * Sets the specified range of bits in a BitPack object.
245
+ *
246
+ * Packs the Integer +value+ into +num_bits+ bits starting at index
247
+ * +i+. The number of bits required to represent +value+ is checked
248
+ * against the size of the range. If <tt>i + num_bits</tt> is greater
249
+ * than the current size of the BitPack, then the size is adjusted
250
+ * appropriately.
251
+ *
252
+ * === Example
253
+ *
254
+ * >> bp = BitPack.new
255
+ * =>
256
+ * >> bp.set_bits(0xff, 8, 0)
257
+ * => 11111111
258
+ * >> bp.set_bits(0xaa, 8, 8)
259
+ * => 1111111110101010
260
+ */
261
+ static VALUE bp_set_bits(VALUE self, VALUE value, VALUE num_bits, VALUE index)
262
+ {
263
+ bitpack_t bp;
264
+
265
+ Data_Get_Struct(self, struct _bitpack_t, bp);
266
+
267
+ if (!bitpack_set_bits(bp, NUM2ULONG(value), NUM2ULONG(num_bits), NUM2ULONG(index))) {
268
+ rb_raise(bp_exceptions[bitpack_get_error(bp)],
269
+ bitpack_get_error_str(bp));
270
+ }
271
+
272
+ return self;
273
+ }
274
+
275
+ /*
276
+ * call-seq:
277
+ * bp.set_bytes(string, i)
278
+ *
279
+ * Sets the specified range of bytes in a BitPack object.
280
+ *
281
+ * Packs +string+ into the BitPack object starting at index +i+. The
282
+ * size of the BitPack object is adjusted appropriately if necessary.
283
+ *
284
+ * === Example
285
+ *
286
+ * >> bp = BitPack.new
287
+ * =>
288
+ * >> bp.set_bytes("ruby", 0)
289
+ * => 01110010011101010110001001111001
290
+ * >> 4.times { p bp.read_bits(8).chr }
291
+ * "r"
292
+ * "u"
293
+ * "b"
294
+ * "y"
295
+ * => 4
296
+ */
297
+ static VALUE bp_set_bytes(VALUE self, VALUE bytes, VALUE index)
298
+ {
299
+ bitpack_t bp;
300
+ VALUE str;
301
+
302
+ Data_Get_Struct(self, struct _bitpack_t, bp);
303
+
304
+ str = StringValue(bytes);
305
+
306
+ if (!bitpack_set_bytes(bp, (unsigned char *)RSTRING(str)->ptr,
307
+ RSTRING(str)->len, NUM2ULONG(index))) {
308
+ rb_raise(bp_exceptions[bitpack_get_error(bp)],
309
+ bitpack_get_error_str(bp));
310
+ }
311
+
312
+ return self;
313
+ }
314
+
315
+ /*
316
+ * call-seq:
317
+ * bp.get_bits(num_bits, i) -> Integer
318
+ *
319
+ * Access the value stored in a range of bits starting at index +i+.
320
+ *
321
+ * Unpacks +num_bits+ starting from index +i+ and returns the Integer
322
+ * value.
323
+ *
324
+ * === Example
325
+ *
326
+ * >> bp = BitPack.new
327
+ * =>
328
+ * >> bp.append_bits(1, 4)
329
+ * => 0001
330
+ * >> bp.append_bits(2, 4)
331
+ * => 00010010
332
+ * >> bp.append_bits(3, 4)
333
+ * => 000100100011
334
+ * >> bp.append_bits(4, 4)
335
+ * => 0001001000110100
336
+ * >> bp.get_bits(4, 0)
337
+ * => 1
338
+ * >> bp.get_bits(4, 4)
339
+ * => 2
340
+ * >> bp.get_bits(4, 8)
341
+ * => 3
342
+ * >> bp.get_bits(4, 12)
343
+ * => 4
344
+ */
345
+ static VALUE bp_get_bits(VALUE self, VALUE num_bits, VALUE index)
346
+ {
347
+ bitpack_t bp;
348
+ unsigned long value;
349
+
350
+ Data_Get_Struct(self, struct _bitpack_t, bp);
351
+
352
+ if (!bitpack_get_bits(bp, NUM2ULONG(num_bits), NUM2ULONG(index), &value)) {
353
+ rb_raise(bp_exceptions[bitpack_get_error(bp)],
354
+ bitpack_get_error_str(bp));
355
+ }
356
+
357
+ return ULONG2NUM(value);
358
+ }
359
+
360
+ /*
361
+ * call-seq:
362
+ * bp.get_bytes(num_bytes, i) -> String
363
+ *
364
+ * Access the value stored in a range of bytes starting at index +i+.
365
+ *
366
+ * Unpacks +num_bytes+ starting from bit index +i+ and returns the String
367
+ * value.
368
+ *
369
+ * === Example
370
+ *
371
+ * >> bp = BitPack.from_bytes("foobar")
372
+ * => 011001100110111101101111011000100110000101110010
373
+ * >> bp.get_bytes(3, 24)
374
+ * => "bar"
375
+ */
376
+ static VALUE bp_get_bytes(VALUE self, VALUE num_bytes, VALUE index)
377
+ {
378
+ bitpack_t bp;
379
+ unsigned char *bytes;
380
+ VALUE str;
381
+
382
+ Data_Get_Struct(self, struct _bitpack_t, bp);
383
+
384
+ if (!bitpack_get_bytes(bp, NUM2ULONG(num_bytes), NUM2ULONG(index), &bytes)) {
385
+ rb_raise(bp_exceptions[bitpack_get_error(bp)],
386
+ bitpack_get_error_str(bp));
387
+ }
388
+
389
+ str = rb_str_new((char *)bytes, NUM2ULONG(num_bytes));
390
+
391
+ free(bytes);
392
+
393
+ return str;
394
+ }
395
+
396
+ /*
397
+ * call-seq:
398
+ * bp.append_bits(value, num_bits)
399
+ *
400
+ * Append the Integer +value+ to the end of a BitPack object.
401
+ *
402
+ * Packs +num_bits+ bits at the end of a BitPack object. The size of
403
+ * the BitPack object is increased by +num_bits+ as a result.
404
+ *
405
+ * === Example
406
+ *
407
+ * >> bp = BitPack.new
408
+ * =>
409
+ * >> bp.append_bits(1, 3)
410
+ * => 001
411
+ * >> bp.append_bits(3, 3)
412
+ * => 001011
413
+ * >> bp.append_bits(7, 3)
414
+ * => 001011111
415
+ */
416
+ static VALUE bp_append_bits(VALUE self, VALUE value, VALUE num_bits)
417
+ {
418
+ bitpack_t bp;
419
+
420
+ Data_Get_Struct(self, struct _bitpack_t, bp);
421
+
422
+ if (!bitpack_append_bits(bp, NUM2ULONG(value), NUM2ULONG(num_bits))) {
423
+ rb_raise(bp_exceptions[bitpack_get_error(bp)],
424
+ bitpack_get_error_str(bp));
425
+ }
426
+
427
+ return self;
428
+ }
429
+
430
+ /*
431
+ * call-seq:
432
+ * bp.append_bytes(string)
433
+ *
434
+ * Append +string+ to the end of a BitPack object.
435
+ *
436
+ * Packs +string+ at the end of a BitPack object. The size of the
437
+ * BitPack object is increased by the length of +string+ as a result.
438
+ *
439
+ * === Example
440
+ *
441
+ * >> bp = BitPack.new
442
+ * =>
443
+ * >> bp.append_bytes("bit")
444
+ * => 011000100110100101110100
445
+ * >> bp.append_bytes("pack")
446
+ * => 01100010011010010111010001110000011000010110001101101011
447
+ * >> 7.times { p bp.read_bits(8).chr }
448
+ * "b"
449
+ * "i"
450
+ * "t"
451
+ * "p"
452
+ * "a"
453
+ * "c"
454
+ * "k"
455
+ * => 7
456
+ */
457
+ static VALUE bp_append_bytes(VALUE self, VALUE value)
458
+ {
459
+ bitpack_t bp;
460
+ VALUE str;
461
+
462
+ Data_Get_Struct(self, struct _bitpack_t, bp);
463
+
464
+ str = StringValue(value);
465
+
466
+ if (!bitpack_append_bytes(bp, (unsigned char *)RSTRING(str)->ptr,
467
+ RSTRING(str)->len)) {
468
+ rb_raise(bp_exceptions[bitpack_get_error(bp)],
469
+ bitpack_get_error_str(bp));
470
+ }
471
+
472
+ return self;
473
+ }
474
+
475
+ /*
476
+ * call-seq:
477
+ * bp.read_bits(num_bits) -> Integer
478
+ *
479
+ * Access the value of a range of bits at the current read position.
480
+ *
481
+ * Unpacks +num_bits+ bits starting at the current read position (see
482
+ * Bitpack#read_pos) and returns the integer value. The current read
483
+ * position is advanced by +num_bits+ bits.
484
+ *
485
+ * === Example
486
+ *
487
+ * >> bp = BitPack.from_bytes("ruby")
488
+ * => 01110010011101010110001001111001
489
+ * >> 4.times { p bp.read_bits(8).chr }
490
+ * "r"
491
+ * "u"
492
+ * "b"
493
+ * "y"
494
+ * => 4
495
+ */
496
+ static VALUE bp_read_bits(VALUE self, VALUE num_bits)
497
+ {
498
+ bitpack_t bp;
499
+ unsigned long value;
500
+
501
+ Data_Get_Struct(self, struct _bitpack_t, bp);
502
+
503
+ if (!bitpack_read_bits(bp, NUM2ULONG(num_bits), &value)) {
504
+ rb_raise(bp_exceptions[bitpack_get_error(bp)],
505
+ bitpack_get_error_str(bp));
506
+ }
507
+
508
+ return ULONG2NUM(value);
509
+ }
510
+
511
+ /*
512
+ * call-seq:
513
+ * bp.read_bytes(num_bytes) -> String
514
+ *
515
+ * Access the value of a range of bytes at the current read position.
516
+ *
517
+ * Unpacks +num_bytes+ bytes starting at the current read position (see
518
+ * Bitpack#read_pos) and returns the String value. The current read
519
+ * position is advanced by <tt>num_bytes * 8</tt> bits.
520
+ *
521
+ * === Example
522
+ *
523
+ * >> bp = BitPack.from_bytes("foobar")
524
+ * => 011001100110111101101111011000100110000101110010
525
+ * >> bp.read_bytes(3)
526
+ * => "foo"
527
+ * >> bp.read_bytes(3)
528
+ * => "bar"
529
+ */
530
+ static VALUE bp_read_bytes(VALUE self, VALUE num_bytes)
531
+ {
532
+ bitpack_t bp;
533
+ unsigned char *value;
534
+ VALUE str;
535
+
536
+ Data_Get_Struct(self, struct _bitpack_t, bp);
537
+
538
+ if (!bitpack_read_bytes(bp, NUM2ULONG(num_bytes), &value)) {
539
+ rb_raise(bp_exceptions[bitpack_get_error(bp)],
540
+ bitpack_get_error_str(bp));
541
+ }
542
+
543
+ str = rb_str_new((char *)value, NUM2ULONG(num_bytes));
544
+
545
+ free(value);
546
+
547
+ return str;
548
+ }
549
+
550
+ /*
551
+ * call-seq:
552
+ * bp.to_bin -> String
553
+ *
554
+ * Converts the BitPack object to a string of 1s and 0s.
555
+ */
556
+ static VALUE bp_to_bin(VALUE self)
557
+ {
558
+ bitpack_t bp;
559
+ char *s;
560
+ VALUE str;
561
+
562
+ Data_Get_Struct(self, struct _bitpack_t, bp);
563
+
564
+ if (!bitpack_to_bin(bp, &s)) {
565
+ rb_raise(bp_exceptions[bitpack_get_error(bp)],
566
+ bitpack_get_error_str(bp));
567
+ }
568
+
569
+ str = rb_str_new2(s);
570
+
571
+ free(s);
572
+
573
+ return str;
574
+ }
575
+
576
+ /*
577
+ * call-seq:
578
+ * bp.to_bytes -> String
579
+ *
580
+ * Converts the BitPack object to a string of bytes. If the current
581
+ * size of the BitPack object is not a multiple of 8, the last byte
582
+ * in the returned String will be padded with the appropriate number
583
+ * of 0 bits.
584
+ *
585
+ * === Example
586
+ *
587
+ * >> bp = BitPack.new
588
+ * =>
589
+ * >> bp.append_bits(?r, 8)
590
+ * => 01110010
591
+ * >> bp.append_bits(?u, 8)
592
+ * => 0111001001110101
593
+ * >> bp.append_bits(?b, 8)
594
+ * => 011100100111010101100010
595
+ * >> bp.append_bits(?y, 8)
596
+ * => 01110010011101010110001001111001
597
+ * >> bp.to_bytes
598
+ * => "ruby"
599
+ */
600
+ static VALUE bp_to_bytes(VALUE self)
601
+ {
602
+ bitpack_t bp;
603
+ unsigned char *s;
604
+ unsigned long num_bytes;
605
+ VALUE str;
606
+
607
+ Data_Get_Struct(self, struct _bitpack_t, bp);
608
+
609
+ if (!bitpack_to_bytes(bp, &s, &num_bytes)) {
610
+ rb_raise(bp_exceptions[bitpack_get_error(bp)],
611
+ bitpack_get_error_str(bp));
612
+ }
613
+
614
+ str = rb_str_new((char *)s, num_bytes);
615
+
616
+ free(s);
617
+
618
+ return str;
619
+ }
620
+
621
+ /*
622
+ * A library for easily packing and unpacking binary strings with fields of
623
+ * arbitrary bit lengths.
624
+ */
625
+ void Init_bitpack()
626
+ {
627
+ cBitPack = rb_define_class("BitPack", rb_cObject);
628
+
629
+ rb_define_singleton_method(cBitPack, "new", bp_new, -1);
630
+ rb_define_singleton_method(cBitPack, "from_bytes", bp_from_bytes, 1);
631
+
632
+ rb_define_method(cBitPack, "size", bp_size, 0);
633
+ rb_define_method(cBitPack, "data_size", bp_data_size, 0);
634
+ rb_define_method(cBitPack, "read_pos", bp_read_pos, 0);
635
+ rb_define_method(cBitPack, "reset_read_pos", bp_reset_read_pos, 0);
636
+ rb_define_method(cBitPack, "on", bp_on, 1);
637
+ rb_define_method(cBitPack, "off", bp_off, 1);
638
+ rb_define_method(cBitPack, "get", bp_get, 1);
639
+ rb_define_method(cBitPack, "[]", bp_get, 1);
640
+ rb_define_method(cBitPack, "set_bits", bp_set_bits, 3);
641
+ rb_define_method(cBitPack, "get_bits", bp_get_bits, 2);
642
+ rb_define_method(cBitPack, "set_bytes", bp_set_bytes, 2);
643
+ rb_define_method(cBitPack, "get_bytes", bp_get_bytes, 2);
644
+ rb_define_method(cBitPack, "append_bits", bp_append_bits, 2);
645
+ rb_define_method(cBitPack, "append_bytes", bp_append_bytes, 1);
646
+ rb_define_method(cBitPack, "read_bits", bp_read_bits, 1);
647
+ rb_define_method(cBitPack, "read_bytes", bp_read_bytes, 1);
648
+ rb_define_method(cBitPack, "to_bin", bp_to_bin, 0);
649
+ rb_define_method(cBitPack, "to_s", bp_to_bin, 0);
650
+ rb_define_method(cBitPack, "to_bytes", bp_to_bytes, 0);
651
+
652
+ bp_exceptions[BITPACK_ERR_MALLOC_FAILED] = rb_eNoMemError;
653
+ bp_exceptions[BITPACK_ERR_INVALID_INDEX] = rb_eRangeError;
654
+ bp_exceptions[BITPACK_ERR_VALUE_TOO_BIG] = rb_eArgError;
655
+ bp_exceptions[BITPACK_ERR_RANGE_TOO_BIG] = rb_eRangeError;
656
+ bp_exceptions[BITPACK_ERR_READ_PAST_END] = rb_eRangeError;
657
+ bp_exceptions[BITPACK_ERR_EMPTY] = rb_eRangeError;
658
+
659
+ /* require the pure ruby methods */
660
+ rb_require("lib/bitpack.rb");
661
+ }
662
+
data/ext/extconf.rb ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby -Ks
2
+
3
+ require "mkmf"
4
+
5
+ $CFLAGS << ' -W -Wall'
6
+
7
+ create_makefile("bitpack")
8
+
data/lib/bitpack.rb ADDED
@@ -0,0 +1,53 @@
1
+
2
+ class BitPack
3
+ # Element Assignment. Sets the bit at +index+, or the range of bits indicated
4
+ # by the Range object +range+, or the range specified by +index+ and +length+.
5
+ #
6
+ # :call-seq:
7
+ # bp[index] = value -> value
8
+ # bp[range] = value -> value
9
+ # bp[index, length] = value -> value
10
+ #
11
+ # === Example
12
+ #
13
+ # >> bp[0] = 1
14
+ # => 1
15
+ # >> bp[1] = 0
16
+ # => 0
17
+ # >> bp[2] = 1
18
+ # => 1
19
+ # >> bp.to_bin
20
+ # => "101"
21
+ # >> bp[0..7] = 0xff
22
+ # => 255
23
+ # >> bp.to_bin
24
+ # => "11111111"
25
+ # >> bp[8, 16] = 0xf0f0
26
+ # => 61680
27
+ # >> bp.to_bin
28
+ # => "111111111111000011110000"
29
+ #
30
+ def []=(a, b, c = nil)
31
+ if c.nil?
32
+ # only two arguments, so it must be one of the following formats:
33
+ # bp[index] = value
34
+ # bp[range] = value
35
+ if a.kind_of? Integer
36
+ self.set_bits(b, 1, a)
37
+ elsif a.kind_of? Range
38
+ if a.exclude_end?
39
+ self.set_bits(b, a.end - a.begin, a.begin)
40
+ else
41
+ self.set_bits(b, a.end - a.begin + 1, a.begin)
42
+ end
43
+ else
44
+ raise ArgumentError, "index must be an Integer or Range"
45
+ end
46
+ else
47
+ # this must the following format:
48
+ # bp[index, length] = value
49
+ self.set_bits(c, b, a)
50
+ end
51
+ end
52
+ end
53
+