bitstring 1.0.0

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.
Files changed (55) hide show
  1. data/CONTRIBUTORS.txt +5 -0
  2. data/Changelog.txt +20 -0
  3. data/LICENCE.txt +202 -0
  4. data/NOTICE.txt +5 -0
  5. data/README.txt +63 -0
  6. data/doc/classes/BitString.html +2479 -0
  7. data/doc/classes/BitString.src/M000001.html +99 -0
  8. data/doc/classes/BitString.src/M000002.html +18 -0
  9. data/doc/classes/BitString.src/M000003.html +20 -0
  10. data/doc/classes/BitString.src/M000004.html +19 -0
  11. data/doc/classes/BitString.src/M000005.html +24 -0
  12. data/doc/classes/BitString.src/M000006.html +44 -0
  13. data/doc/classes/BitString.src/M000007.html +21 -0
  14. data/doc/classes/BitString.src/M000008.html +18 -0
  15. data/doc/classes/BitString.src/M000009.html +18 -0
  16. data/doc/classes/BitString.src/M000010.html +22 -0
  17. data/doc/classes/BitString.src/M000011.html +29 -0
  18. data/doc/classes/BitString.src/M000012.html +22 -0
  19. data/doc/classes/BitString.src/M000013.html +43 -0
  20. data/doc/classes/BitString.src/M000014.html +19 -0
  21. data/doc/classes/BitString.src/M000015.html +40 -0
  22. data/doc/classes/BitString.src/M000016.html +21 -0
  23. data/doc/classes/BitString.src/M000017.html +18 -0
  24. data/doc/classes/BitString.src/M000018.html +18 -0
  25. data/doc/classes/BitString.src/M000019.html +18 -0
  26. data/doc/classes/BitString.src/M000020.html +20 -0
  27. data/doc/classes/BitString.src/M000021.html +24 -0
  28. data/doc/classes/BitString.src/M000022.html +23 -0
  29. data/doc/classes/BitString.src/M000023.html +42 -0
  30. data/doc/classes/BitString.src/M000024.html +61 -0
  31. data/doc/classes/BitString.src/M000025.html +18 -0
  32. data/doc/classes/BitString.src/M000026.html +18 -0
  33. data/doc/classes/BitString.src/M000027.html +20 -0
  34. data/doc/classes/BitString.src/M000028.html +18 -0
  35. data/doc/classes/BitString.src/M000029.html +18 -0
  36. data/doc/classes/BitString.src/M000030.html +18 -0
  37. data/doc/classes/BitString.src/M000031.html +18 -0
  38. data/doc/classes/BitString.src/M000032.html +18 -0
  39. data/doc/created.rid +1 -0
  40. data/doc/files/lib/bitstring/operators_rb.html +122 -0
  41. data/doc/files/lib/bitstring_rb.html +153 -0
  42. data/doc/fr_class_index.html +27 -0
  43. data/doc/fr_file_index.html +28 -0
  44. data/doc/fr_method_index.html +60 -0
  45. data/doc/index.html +24 -0
  46. data/doc/rdoc-style.css +208 -0
  47. data/lib/bitstring.rb +1318 -0
  48. data/lib/bitstring/operators.rb +481 -0
  49. data/test/Rakefile +21 -0
  50. data/test/test_basic.rb +848 -0
  51. data/test/test_data.rb +24 -0
  52. data/test/test_enum.rb +671 -0
  53. data/test/test_helper.rb +3 -0
  54. data/test/test_operators.rb +454 -0
  55. metadata +121 -0
@@ -0,0 +1,481 @@
1
+ #
2
+ # = operators.rb - Operators for the BitString class
3
+ #
4
+ # Author:: Ken Coar
5
+ # Copyright:: Copyright © 2010 Ken Coar
6
+ # License:: Apache Licence 2.0
7
+ #
8
+ # == Description
9
+ #
10
+ # Operator methods for <i>BitString</i> class (<i>e.g.</i>, those consisting
11
+ # of special characters).
12
+ #
13
+ #--
14
+ # Copyright © 2010 Ken Coar
15
+ #
16
+ # Licensed under the Apache License, Version 2.0 (the "License"); you
17
+ # may not use this file except in compliance with the License. You may
18
+ # obtain a copy of the License at
19
+ #
20
+ # http://www.apache.org/licenses/LICENSE-2.0
21
+ #
22
+ # Unless required by applicable law or agreed to in writing, software
23
+ # distributed under the License is distributed on an "AS IS" BASIS,
24
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
25
+ # implied. See the License for the specific language governing
26
+ # permissions and limitations under the License.
27
+ #++
28
+
29
+ #--
30
+ # Re-open the class to add the operator methods
31
+ #++
32
+
33
+ class BitString
34
+
35
+ #
36
+ # === Description
37
+ #
38
+ # Perform a bitwise AND on the entire bitstring, returning a new
39
+ # <i>BitString</i> object. The new bitstring will have the
40
+ # same boundedness as the original.
41
+ #
42
+ # call-seq:
43
+ # bitstring <i>& value</i> => <i>BitString</i>
44
+ # bitstring.&<i>(value)</i> => <i>BitString</i>
45
+ #
46
+ # === Arguments
47
+ # [<i>value</i>] <i>BitString</i>, <i>Integer</i>, or <i>String</i>. Value to AND with the bitstring.
48
+ #
49
+ # === Examples
50
+ # bs = BitString.new('111111111')
51
+ # nbs = bs & '111100011'
52
+ # nbs.to_s
53
+ # => "111100011"
54
+ #
55
+ # bs = BitString.new('10101010101', 11)
56
+ # nbs = bs & '11110001111'
57
+ # nbs.to_s
58
+ # => "10100000101"
59
+ # nbs = bs & '00001110000'
60
+ # nbs.to_s
61
+ # => "00001010000"
62
+ #
63
+ # === Exceptions
64
+ # <i>None</i>.
65
+ #
66
+ def &(val)
67
+ val = _arg2int(val)
68
+ vMask = self.mask
69
+ newval = (@value & val) & vMask
70
+ bounded? ? self.class.new(newval, @length) : self.class.new(newval)
71
+ end # def &
72
+
73
+ #
74
+ # === Description
75
+ #
76
+ # Perform a left-shift on the bitstring, returning a new <i>BitString</i>
77
+ # containing the shifted value. If the bitstring is bounded, bits
78
+ # shifted off the high end are lost.
79
+ #
80
+ # call-seq:
81
+ # bitstring <i>&lt;&lt; bitcount</i> => <i>BitString</i>
82
+ # bitstring.&lt;&lt;<i>(bitcount)</i> => <i>BitString</i>
83
+ #
84
+ # === Arguments
85
+ # [<i>bitcount</i>] <i>Integer</i>. Number of positions by which to left-shift.
86
+ #
87
+ # === Examples
88
+ # bs = BitString.new('1100111')
89
+ # nbs = bs << 2
90
+ # nbs.to_s
91
+ # => "110011100"
92
+ #
93
+ # bs = BitString.new('00010001', 8)
94
+ # nbs = bs << 2
95
+ # nbs.to_s
96
+ # => "01000100"
97
+ # nbs = bs << 4
98
+ # nbs.to_s
99
+ # => "00010000" # High bits shifted off and lost
100
+ #
101
+ # === Exceptions
102
+ # <i>None</i>.
103
+ #
104
+ def <<(bits)
105
+ value = @value * (2**bits.to_i)
106
+ if (bounded?)
107
+ self.class.new(value & self.mask, @length)
108
+ else
109
+ self.class.new(value)
110
+ end
111
+ end # def <<
112
+
113
+ #
114
+ # === Description
115
+ #
116
+ # Right-shift the bitstring (toward the low end) by the specified number
117
+ # of bits. Bits shifted off the end are lost; new bits shifted in at
118
+ # the high end are 0.
119
+ #
120
+ # call-seq:
121
+ # bitstring &gt;&gt; <i>bitcount</i> => <i>BitString</i>
122
+ # bitstring.&gt;&gt;<i>(bitcount)</i> => <i>BitString</i>
123
+ #
124
+ # === Arguments
125
+ # [<i>bitcount</i>] <i>Integer</i>. Number of positions to right-shift by.
126
+ #
127
+ # === Examples
128
+ # bs = BitString.new('1100111')
129
+ # nbs = bs >> 2
130
+ # nbs.to_s
131
+ # => "11001"
132
+ #
133
+ # bs = BitString.new('00010001', 8)
134
+ # nbs = bs >> 2
135
+ # nbs.to_s
136
+ # => "00000100"
137
+ # nbs = bs >> 4
138
+ # nbs.to_s
139
+ # => "00000001"
140
+ #
141
+ # === Exceptions
142
+ # <i>None</i>.
143
+ #
144
+ def >>(bits)
145
+ value = @value / 2**bits.to_i
146
+ if (bounded?)
147
+ self.class.new(value, @length)
148
+ else
149
+ self.class.new(value)
150
+ end
151
+ end # def >>
152
+
153
+ #
154
+ # === Description
155
+ #
156
+ # Extract a particular substring from the bitstring.
157
+ # If we're given a single index, we return an integer; if
158
+ # a range, we return a new BitString.
159
+ #
160
+ # call-seq:
161
+ # bitstring<i>[index]</i> => <i>Integer</i>
162
+ # bitstring<i>[start, length]</i> => <i>BitString</i>
163
+ # bitstring<i>[range]</i> => <i>BitString</i>
164
+ #
165
+ # === Arguments
166
+ # [<i>index</i>] <i>Integer</i>. Single bit position.
167
+ # [<i>start</i>] <i>Integer</i>. Start position of subset.
168
+ # [<i>length</i>] <i>Integer</i>. Length of subset.
169
+ # [<i>range</i>] <i>Range</i>. Subset specified as a range.
170
+ #
171
+ # === Examples
172
+ # bs = BitString.new('110010110')
173
+ # bs[0]
174
+ # => 0
175
+ # bs[1]
176
+ # => 1
177
+ # bs[0..1].to_s # Multi-bit indexing returns a bitsring
178
+ # => "10"
179
+ # bs[0,9].to_s
180
+ # => "110010110"
181
+ # bs[100..102].to_s # Can index 'way past the end for unbounded bitstrings
182
+ # => "000"
183
+ #
184
+ # bs = BitString.new('110010110', 9)
185
+ # bs[100..102].to_s #
186
+ # => exception: "IndexError: index out of range"
187
+ #
188
+ # === Exceptions
189
+ # [<tt>ArgumentError</tt>] If length specified with a range.
190
+ # [<tt>IndexError</tt>] If bitstring is bounded and the substring is illegal.
191
+ #
192
+ def [](pos_p, length_p=nil)
193
+ #
194
+ # Turn a position/length into a range.
195
+ #
196
+ if (pos_p.kind_of?(Integer) && length_p.kind_of?(Integer))
197
+ pos_p = Range.new(pos_p, pos_p + length_p - 1)
198
+ length_p = nil
199
+ end
200
+ if (pos_p.kind_of?(Range))
201
+ unless (length_p.nil?)
202
+ raise ArgumentError.new('length not allowed with range')
203
+ end
204
+ pos_a = pos_p.to_a
205
+ pos_a.reverse! if (pos_a.first < pos_a.last)
206
+ r = pos_a.collect { |pos| self[pos].to_s }
207
+ return self.class.new(r.join(''), r.length)
208
+ end
209
+ pos = pos_p.to_i
210
+ #
211
+ # Blow an error if we were given an index out of range.
212
+ #
213
+ unless ((pos >= 0) &&
214
+ ((! bounded?) || pos.between?(0, @length - 1)))
215
+ _raise(OuttasightIndex, pos)
216
+ end
217
+ (@value & (2**pos)) / (2**pos)
218
+ end # def []
219
+
220
+ #
221
+ # === Description
222
+ #
223
+ # Set a bit or range of bits with a single operation.
224
+ #
225
+ # call-seq:
226
+ # bitstring[<i>pos</i>] = <i>value</i> => <i>value</i>
227
+ # bitstring[<i>start, length</i>] = <i>value</i> => <i>value</i>
228
+ # bitstring[<i>range</i>] = <i>value</i> => <i>value</i>
229
+ #
230
+ # === Arguments
231
+ # [<i>value</i>] <i>Array</i>, <i>BitString</i>, <i>Integer</i>, or <i>String</i>. Value (treated as a stream of bits) used to set the bitstring.
232
+ # [<i>pos</i>] <i>Integer</i>. Single bit position to alter.
233
+ # [<i>start</i>] <i>Integer</i>. First bit position in substring.
234
+ # [<i>length</i>] <i>Integer</i>. Number of bits in substring.
235
+ # [<i>range</i>] <i>Range</i>. Range of bits (<i>e.g.</i>, 5..10) to affect.
236
+ #
237
+ # === Examples
238
+ # bs = BitString.new('110010110')
239
+ # bs[0] = 1
240
+ # => 1
241
+ # bs.to_s
242
+ # => "110010111"
243
+ # bs[1] = 0
244
+ # => 0
245
+ # bs.to_s
246
+ # => "110010101"
247
+ # bs[0..3] = 14 # Multi-bit indexing set a bitsring
248
+ # => "14"
249
+ # bs.to_s
250
+ # => "110011110"
251
+ # bs[12..14] = 5
252
+ # => 5
253
+ # bs.to_s
254
+ # => "101000110011110" # Can index past the end for unbounded bitstrings
255
+ #
256
+ # bs = BitString.new('110010110', 9)
257
+ # bs[1,3] = 4095 # 111111111111, but gets truncated to low 3 bits
258
+ # bs.to_s
259
+ # => "110011110"
260
+ #
261
+ # === Exceptions
262
+ # [<tt>ArgumentError</tt>] Both range and length specified, or value cannot be interpreted as an integer.
263
+ # [<tt>IndexError</tt>] Non-integer or negative index, or beyond the end of the bitstring.
264
+ #
265
+ def []=(*args_p)
266
+ low = high = width = nil
267
+ args = args_p
268
+ if (args.length == 2)
269
+ #
270
+ # [pos]= or [range]=
271
+ #
272
+ if ((r = args[0]).class.eql?(Range))
273
+ #
274
+ # Convert into a [start,length] format to reuse that stream.
275
+ #
276
+ (start, stop) = [r.first, r.last].sort
277
+ width = stop - start + 1
278
+ args = [start, width, args[1]]
279
+ else
280
+ args = [args[0], 1, args[1]]
281
+ end
282
+ elsif (args_p.length != 3)
283
+ _raise(WrongNargs, args_p.length, 3)
284
+ end
285
+ #
286
+ # Special cases of args have now been normalised to [start,length,value].
287
+ # Make sure the values are acceptable.
288
+ #
289
+ (start, nBits, value) = args
290
+ _raise(BogoIndex, start) unless (start.respond_to?(:to_i))
291
+ start = start.to_i unless (start.kind_of?(Integer))
292
+ _raise(BogoIndex, nBits) unless (nBits.respond_to?(:to_i))
293
+ nBits = length.to_i unless (nBits.kind_of?(Integer))
294
+ highpos = start + nBits - 1
295
+ _raise(OuttasightIndex, highpos) if (bounded? && (highpos > @length - 1))
296
+ _raise(BitsRInts, value) unless (value.respond_to?(:to_i))
297
+ value = _arg2int(value)
298
+ #
299
+ # All the checking is done, let's do this thing.
300
+ #
301
+ vMask = 2**nBits - 1
302
+ fvalue = (value &= vMask)
303
+ vMask *= 2**start
304
+ value *= 2**start
305
+
306
+ highpos = self.length
307
+ bValue = @value & ((2**highpos - 1) & ~vMask)
308
+ @value = bValue | value
309
+ return fvalue
310
+ end # def []=
311
+
312
+ #
313
+ # === Description
314
+ #
315
+ # Perform a bitwise exclusive OR (XOR) and return a copy of the
316
+ # result.
317
+ #
318
+ # call-seq:
319
+ # bitstring <i>^ value</i> => <i>BitString</i>
320
+ # bitstring.^<i>(value)</i> => <i>BitString</i>
321
+ #
322
+ # === Arguments
323
+ # [<i>value</i>] <i>Array</i>, <i>BitString</i>, <i>Integer</i>, or <i>String</i>. Value treated as a bitstream and exclusively ORed with the bitstring.
324
+ #
325
+ # === Examples
326
+ # bs = BitString.new('110010110', 9)
327
+ # nbs = bs ^ '001101001'
328
+ # nbs.to_s
329
+ # => "111111111"
330
+ # nbs = bs ^ bs.mask # Equivalent to 'nbs = ~ bs'
331
+ # nbs.to_s
332
+ # => "001101001"
333
+ #
334
+ # === Exceptions
335
+ # <i>None</i>.
336
+ #
337
+ def ^(value)
338
+ value = _arg2int(value)
339
+ value &= self.mask if (bounded?)
340
+ bs = dup
341
+ bs.from_i(value ^ bs.to_i)
342
+ bs
343
+ end # def ^
344
+
345
+ #
346
+ # === Description
347
+ #
348
+ # Perform a bitwise inclusive OR with the current bitstring and
349
+ # return a bitstring containing the result.
350
+ #
351
+ # call-seq:
352
+ # bitstring <i>| value</i> => <i>BitString</i>
353
+ # bitstring.|<i>(value)</i> => <i>BitString</i>
354
+ #
355
+ # === Arguments
356
+ # [<i>value</i>] <i>Array</i>, <i>BitString</i>, <i>Integer</i>, or <i>String</i>. Value treated as a bitstream and inclusively ORed with the bitstring.
357
+ #
358
+ # === Examples
359
+ # bs = BitString.new('110010110')
360
+ # nbs = bs | '11000000000000000'
361
+ # nbs.to_s # Bits cab be ORed in anywhere in an
362
+ # => "11000000110010110" # unbouded string
363
+ #
364
+ # === Exceptions
365
+ # <i>None</i>.
366
+ #
367
+ def |(value)
368
+ value = _arg2int(value)
369
+ value &= self.mask if (bounded?)
370
+ bs = dup
371
+ bs.from_i(value | bs.to_i)
372
+ bs
373
+ end # def |
374
+
375
+ #
376
+ # === Description
377
+ #
378
+ # Perform a one's complement on the current bitstring and return the
379
+ # result in a new one.
380
+ #
381
+ # call-seq:
382
+ # <i>~</i> bitstring => <i>BitString</i>
383
+ # bitstring.~<i>()</i> => <i>BitString</i>
384
+ #
385
+ # === Arguments
386
+ # <i>None</i>.
387
+ #
388
+ # === Examples
389
+ # bs = BitString.new('110010110')
390
+ # nbs = ~ bs
391
+ # nbs.to_s
392
+ # => "1101001" # Leading zeroes stripped when unbounded
393
+ #
394
+ # bs = BitString.new('110010110', 9)
395
+ # nbs = ~ bs
396
+ # nbs.to_s
397
+ # => "001101001"
398
+ #
399
+ # bs = BitString.new('111111111')
400
+ # nbs = ~ bs
401
+ # nbs.to_s
402
+ # => "0"
403
+ #
404
+ # bs = BitString.new('111111111', 9)
405
+ # nbs = ~ bs
406
+ # nbs.to_s
407
+ # => "000000000"
408
+ #
409
+ # === Exceptions
410
+ # <i>None</i>.
411
+ #
412
+ def ~()
413
+ newval = (~ @value) & self.mask
414
+ bounded? ? self.class.new(newval, @length) : self.class.new(newval)
415
+ end # def ~
416
+
417
+ #
418
+ # === Description
419
+ #
420
+ # Perform an equality check against another bitstring or representation
421
+ # of one. The value and the boundedness must both match to be considered
422
+ # equal.
423
+ #
424
+ # call-seq:
425
+ # bitstring == <i>compstring</i> => <i>Boolean</i>
426
+ # bitstring.==<i>(compstring)</i> => <i>Boolean</i>
427
+ #
428
+ # === Arguments
429
+ # [<i>compstring</i>] <i>Array</i>, <i>BitString</i>, <i>Integer</i>, or <i>String</i>. Bitstring (or something representing one) against which to compare.
430
+ #
431
+ # === Examples
432
+ # bs1 = BitString.new('111111111')
433
+ # bs2 = BitString.new('111111111', 9)
434
+ # bs1 == bs2
435
+ # => false # Boundedness doesn't match
436
+ #
437
+ # bs1 = BitString.new('111111111')
438
+ # bs2 = BitString.new('111111111')
439
+ # bs1 == bs2
440
+ # => true # Values and boundedness match
441
+ #
442
+ # bs1 = BitString.new('111111111')
443
+ # bs1 == '111111111'
444
+ # => true # When converted to an unbounded bitstring, it matches
445
+ #
446
+ # bs1 = BitString.new('111111111')
447
+ # bs1 == '0000000111111111'
448
+ # => true # When converted to an unbounded bitstring, it matches
449
+ #
450
+ # bs1 = BitString.new('111111111')
451
+ # bs1 == 511
452
+ # => true # When converted to an unbounded bitstring, it matches
453
+ #
454
+ # bs1 = BitString.new('111111111', 9)
455
+ # bs1 == '1000111111111'
456
+ # => false # When converted to a bounded bitstring (because bs1 is),
457
+ # # lengths and values don't match
458
+ #
459
+ # === Exceptions
460
+ # <i>None</i>.
461
+ #
462
+ def ==(value)
463
+ #
464
+ # Bitstring/bitstring comparison
465
+ #
466
+ unless (value.class == self.class)
467
+ value = _arg2int(value)
468
+ if (self.bounded?)
469
+ bits = [self.length, value.to_s(2).length].max
470
+ value = self.class.new(value, bits)
471
+ else
472
+ value = self.class.new(value)
473
+ end
474
+ end
475
+ ((self.class == value.class) &&
476
+ (self.bounded? == value.bounded?) &&
477
+ (self.length == value.length) &&
478
+ (@value == value.to_i))
479
+ end # def ==
480
+
481
+ end # class BitString