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.
- data/CONTRIBUTORS.txt +5 -0
- data/Changelog.txt +20 -0
- data/LICENCE.txt +202 -0
- data/NOTICE.txt +5 -0
- data/README.txt +63 -0
- data/doc/classes/BitString.html +2479 -0
- data/doc/classes/BitString.src/M000001.html +99 -0
- data/doc/classes/BitString.src/M000002.html +18 -0
- data/doc/classes/BitString.src/M000003.html +20 -0
- data/doc/classes/BitString.src/M000004.html +19 -0
- data/doc/classes/BitString.src/M000005.html +24 -0
- data/doc/classes/BitString.src/M000006.html +44 -0
- data/doc/classes/BitString.src/M000007.html +21 -0
- data/doc/classes/BitString.src/M000008.html +18 -0
- data/doc/classes/BitString.src/M000009.html +18 -0
- data/doc/classes/BitString.src/M000010.html +22 -0
- data/doc/classes/BitString.src/M000011.html +29 -0
- data/doc/classes/BitString.src/M000012.html +22 -0
- data/doc/classes/BitString.src/M000013.html +43 -0
- data/doc/classes/BitString.src/M000014.html +19 -0
- data/doc/classes/BitString.src/M000015.html +40 -0
- data/doc/classes/BitString.src/M000016.html +21 -0
- data/doc/classes/BitString.src/M000017.html +18 -0
- data/doc/classes/BitString.src/M000018.html +18 -0
- data/doc/classes/BitString.src/M000019.html +18 -0
- data/doc/classes/BitString.src/M000020.html +20 -0
- data/doc/classes/BitString.src/M000021.html +24 -0
- data/doc/classes/BitString.src/M000022.html +23 -0
- data/doc/classes/BitString.src/M000023.html +42 -0
- data/doc/classes/BitString.src/M000024.html +61 -0
- data/doc/classes/BitString.src/M000025.html +18 -0
- data/doc/classes/BitString.src/M000026.html +18 -0
- data/doc/classes/BitString.src/M000027.html +20 -0
- data/doc/classes/BitString.src/M000028.html +18 -0
- data/doc/classes/BitString.src/M000029.html +18 -0
- data/doc/classes/BitString.src/M000030.html +18 -0
- data/doc/classes/BitString.src/M000031.html +18 -0
- data/doc/classes/BitString.src/M000032.html +18 -0
- data/doc/created.rid +1 -0
- data/doc/files/lib/bitstring/operators_rb.html +122 -0
- data/doc/files/lib/bitstring_rb.html +153 -0
- data/doc/fr_class_index.html +27 -0
- data/doc/fr_file_index.html +28 -0
- data/doc/fr_method_index.html +60 -0
- data/doc/index.html +24 -0
- data/doc/rdoc-style.css +208 -0
- data/lib/bitstring.rb +1318 -0
- data/lib/bitstring/operators.rb +481 -0
- data/test/Rakefile +21 -0
- data/test/test_basic.rb +848 -0
- data/test/test_data.rb +24 -0
- data/test/test_enum.rb +671 -0
- data/test/test_helper.rb +3 -0
- data/test/test_operators.rb +454 -0
- metadata +121 -0
data/lib/bitstring.rb
ADDED
@@ -0,0 +1,1318 @@
|
|
1
|
+
#
|
2
|
+
# = bitstring.rb - Bounded and unbounded bit strings
|
3
|
+
#
|
4
|
+
# Author:: Ken Coar
|
5
|
+
# Copyright:: Copyright © 2010 Ken Coar
|
6
|
+
# License:: Apache Licence 2.0
|
7
|
+
#
|
8
|
+
# == Synopsis
|
9
|
+
#
|
10
|
+
# require 'rubygems'
|
11
|
+
# require 'bitstring'
|
12
|
+
# bString = BitString.new([initial-value], [bitcount])
|
13
|
+
# bString = BitString.new(bitcount) { |index| block }
|
14
|
+
#
|
15
|
+
# Bug/feature trackers, code, and mailing lists are available at
|
16
|
+
# http://rubyforge.org/projects/bitstring.
|
17
|
+
#
|
18
|
+
# Class and method documentation is online at
|
19
|
+
# http://bitstring.rubyforge.org/rdoc/
|
20
|
+
#
|
21
|
+
# == Description
|
22
|
+
#
|
23
|
+
# The <i>BitString</i> package provides a class for handling a series
|
24
|
+
# of bits as an array-like structure. Bits are addressable individually
|
25
|
+
# or as subranges.
|
26
|
+
#
|
27
|
+
# BitString objects can be either bounded or unbounded. Bounded bitstrings
|
28
|
+
# have a specific number of bits, and operations that would affect bits
|
29
|
+
# outside those limits will raise exceptions. Unbounded bitstrings can
|
30
|
+
# grow to arbitrary lengths, but some operations (like rotation) cannot
|
31
|
+
# be performed on them.
|
32
|
+
#--
|
33
|
+
# Copyright © 2010 Ken Coar
|
34
|
+
#
|
35
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
36
|
+
# may not use this file except in compliance with the License. You may
|
37
|
+
# obtain a copy of the License at
|
38
|
+
#
|
39
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
40
|
+
#
|
41
|
+
# Unless required by applicable law or agreed to in writing, software
|
42
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
43
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
44
|
+
# implied. See the License for the specific language governing
|
45
|
+
# permissions and limitations under the License.
|
46
|
+
#++
|
47
|
+
|
48
|
+
require 'rubygems'
|
49
|
+
require 'versionomy'
|
50
|
+
|
51
|
+
require 'bitstring/operators'
|
52
|
+
|
53
|
+
#
|
54
|
+
# It's sort of like a fake a subclass of Integer solely to
|
55
|
+
# differentiate bitstrings.
|
56
|
+
#
|
57
|
+
class BitString
|
58
|
+
|
59
|
+
#
|
60
|
+
# Versionomy object for the class, recording the current version.
|
61
|
+
#
|
62
|
+
Version = Versionomy.parse('1.0.0')
|
63
|
+
|
64
|
+
#
|
65
|
+
# Version number as a simple readable string.
|
66
|
+
#
|
67
|
+
VERSION = Version.to_s
|
68
|
+
|
69
|
+
#
|
70
|
+
# Other constants:
|
71
|
+
#
|
72
|
+
|
73
|
+
#
|
74
|
+
# Identifer specifying the least significant (low) end of the bitstring
|
75
|
+
# (used by <i>grow</i>, <i>shrink</i>, and <i>mask</i>).
|
76
|
+
#
|
77
|
+
LOW_END = :low
|
78
|
+
#
|
79
|
+
# Identifer specifying the most significant (high) end of the bitstring
|
80
|
+
# (used by <i>grow</i>, <i>shrink</i>, and <i>mask</i>).
|
81
|
+
#
|
82
|
+
HIGH_END = :high
|
83
|
+
|
84
|
+
# :stopdoc:
|
85
|
+
#
|
86
|
+
# These classes are part of our internal error condition handling
|
87
|
+
# mechanism, and aren't intended to be used externally.
|
88
|
+
#
|
89
|
+
class InternalError < Exception
|
90
|
+
#
|
91
|
+
# Used internally only -- except for internal consistency errors.
|
92
|
+
#
|
93
|
+
end # class InternalError
|
94
|
+
|
95
|
+
class BadDigit < InternalError
|
96
|
+
#
|
97
|
+
# Turned into an ArgumentError.
|
98
|
+
#
|
99
|
+
end # class BadDigit
|
100
|
+
|
101
|
+
class BitsRInts < InternalError
|
102
|
+
#
|
103
|
+
# Turned into an ArgumentError.
|
104
|
+
#
|
105
|
+
end # class BitsRInts
|
106
|
+
|
107
|
+
class BogoIndex < InternalError
|
108
|
+
#
|
109
|
+
# Turned into an IndexError.
|
110
|
+
#
|
111
|
+
end # class BogoIndex
|
112
|
+
|
113
|
+
class NeedGPS < InternalError
|
114
|
+
#
|
115
|
+
# Turned into an ArgumentError.
|
116
|
+
#
|
117
|
+
end # class NeedGPS
|
118
|
+
|
119
|
+
class NoDeficitBits < InternalError
|
120
|
+
#
|
121
|
+
# Turned into an IndexError.
|
122
|
+
#
|
123
|
+
end # class NoDeficitBits
|
124
|
+
|
125
|
+
class OuttasightIndex < InternalError
|
126
|
+
#
|
127
|
+
# Turned into an IndexError.
|
128
|
+
#
|
129
|
+
end # class OuttasightIndex
|
130
|
+
|
131
|
+
class UnboundedNonsense < InternalError
|
132
|
+
#
|
133
|
+
# Turned into a RuntimeError.
|
134
|
+
#
|
135
|
+
end # class UnboundedNonsense
|
136
|
+
|
137
|
+
class UnInterable < InternalError
|
138
|
+
#
|
139
|
+
# Turned into a RuntimeError.
|
140
|
+
#
|
141
|
+
end # class UnInterable
|
142
|
+
|
143
|
+
class WrongNargs < InternalError
|
144
|
+
#
|
145
|
+
# Turned into an ArgumentError.
|
146
|
+
#
|
147
|
+
end # class WrongNargs
|
148
|
+
|
149
|
+
# :startdoc:
|
150
|
+
#
|
151
|
+
# We want a bunch of Enumerable's methods..
|
152
|
+
#
|
153
|
+
include Enumerable
|
154
|
+
|
155
|
+
#
|
156
|
+
# ..but not all of them. Some just don't make sense for bitstrings.
|
157
|
+
# (.zip makes sense, but I'm going to defer it until I have a test for it.)
|
158
|
+
#
|
159
|
+
undef :grep, :sort, :sort_by, :zip
|
160
|
+
|
161
|
+
#
|
162
|
+
# <i>Boolean</i>. Whether or not the bitstring is bounded and limited
|
163
|
+
# to a specific length. Read-only; set at object creation.
|
164
|
+
#
|
165
|
+
attr_reader :bounded
|
166
|
+
|
167
|
+
#
|
168
|
+
# <i>Integer</i>. Length of the bitstring. Only meaningful for bounded
|
169
|
+
# strings. Read-only; set at object creation.
|
170
|
+
#
|
171
|
+
#attr_reader :length
|
172
|
+
|
173
|
+
#
|
174
|
+
# === Description
|
175
|
+
#
|
176
|
+
# Create a new <i>BitString</i> object. By default, it will be unbounded and
|
177
|
+
# all bits clear.
|
178
|
+
#
|
179
|
+
# :call-seq:
|
180
|
+
# new<i>([val], [bitcount])</i> => <i>BitString</i>
|
181
|
+
# new<i>(length) {|index| block }</i> => <i>BitString</i>
|
182
|
+
#
|
183
|
+
# === Arguments
|
184
|
+
# [<i>val</i>] <i>Array</i>, <i>Integer</i>, <i>String</i>, or <i>BitString</i>. Initial value for the bitstring. If a <i>String</i>, the value must contain only '0' and '1' characters; if an <i>Array</i>, all elements must be 0 or 1. Default 0.
|
185
|
+
# [<i>bitcount</i>] <i>Integer</i>. Optional length (number of bits) for a bounded bitstring.
|
186
|
+
#
|
187
|
+
# === Examples
|
188
|
+
# bs = BitString.new(4095)
|
189
|
+
# bs.to_s
|
190
|
+
# => "111111111111"
|
191
|
+
# bs.bounded?
|
192
|
+
# => false
|
193
|
+
#
|
194
|
+
# bs = BitString.new('110000010111', 12)
|
195
|
+
# bs.bounded?
|
196
|
+
# => true
|
197
|
+
# bs.to_i
|
198
|
+
# => 3095
|
199
|
+
#
|
200
|
+
# bs = BitString.new(12) { |pos| pos % 2 }
|
201
|
+
# bs.to_s
|
202
|
+
# => "101010101010"
|
203
|
+
#
|
204
|
+
# === Exceptions
|
205
|
+
# [<tt>RangeError</tt>] <i>val</i> is a string, but contains non-binary digits.
|
206
|
+
#
|
207
|
+
def initialize(*args_p, &block)
|
208
|
+
#
|
209
|
+
# Two constructor scenarios:
|
210
|
+
#
|
211
|
+
# 1. With a block and an optional length (defaults to 1)
|
212
|
+
# 2. No block, and with value and length both optional.
|
213
|
+
#
|
214
|
+
# We don't do any type-checking on the arguments until later.
|
215
|
+
#
|
216
|
+
unless (block.nil?)
|
217
|
+
#
|
218
|
+
# We got a block; set up the constraints. Bitstrings constructed
|
219
|
+
# this way are bounded.
|
220
|
+
#
|
221
|
+
unless (args_p.length < 2)
|
222
|
+
raise ArgumentError.new('only bitstring length ' +
|
223
|
+
'may be specified with a block')
|
224
|
+
end
|
225
|
+
@bounded = true
|
226
|
+
@length = args_p.length > 0 ? args_p[0] : 1
|
227
|
+
else
|
228
|
+
#
|
229
|
+
# Get value and possibly length from the argument list.
|
230
|
+
#
|
231
|
+
unless (args_p.length < 3)
|
232
|
+
raise ArgumentError.new('wrong number of arguments ' +
|
233
|
+
'(must be 2 or fewer)')
|
234
|
+
end
|
235
|
+
val = args_p[0] || 0
|
236
|
+
@length = args_p[1] if (@bounded = ! args_p[1].nil?)
|
237
|
+
end
|
238
|
+
#
|
239
|
+
# Now do some validation on the arguments.
|
240
|
+
#
|
241
|
+
if (@bounded)
|
242
|
+
unless ((@length = @length.to_i) > 0)
|
243
|
+
raise ArgumentError.new('bitstring length must be greater than 0')
|
244
|
+
end
|
245
|
+
end
|
246
|
+
if (block.nil?)
|
247
|
+
#
|
248
|
+
# We weren't passed a block, so get the info directly from the argument
|
249
|
+
# list.
|
250
|
+
#
|
251
|
+
@value = _arg2int(val)
|
252
|
+
else
|
253
|
+
#
|
254
|
+
# We were passed a block, so invoke it for each bit position to
|
255
|
+
# determine that bit's value from the LSB of the result.
|
256
|
+
#
|
257
|
+
@value = 0
|
258
|
+
@length.times { |i| self[i] = block.call(i).to_i & 1 }
|
259
|
+
end
|
260
|
+
end # def initialize
|
261
|
+
|
262
|
+
#
|
263
|
+
# === Description
|
264
|
+
#
|
265
|
+
# Convert a value from some representation into an integer. Possibly
|
266
|
+
# acceptable inputs are:
|
267
|
+
#
|
268
|
+
# o An <i>Array</i> containing only 0 and 1 values.
|
269
|
+
# o An existing <i>BitString</i> object
|
270
|
+
# o An <i>Integer</i> or descendent binary value
|
271
|
+
# o A <i>String</i> containing only '0' and '1' characters
|
272
|
+
#
|
273
|
+
# Any other inputs will raise an exception.
|
274
|
+
#
|
275
|
+
# :call-seq:
|
276
|
+
# _arg2int<i>(value)</i> => <i>Integer</i>
|
277
|
+
#
|
278
|
+
# === Arguments
|
279
|
+
# [<i>value</i>] <i>Array</i>, <i>BitString</i>, <i>Integer</i>, <i>String</i>. The value to be converted to an integer.
|
280
|
+
# [<i>msg</i>] <i>String</i>. Message to use if we don't have a canned one.
|
281
|
+
#
|
282
|
+
# === Examples
|
283
|
+
# _arg2int(23)
|
284
|
+
# => 23
|
285
|
+
# _arg2int('110000010111')
|
286
|
+
# => 3095
|
287
|
+
# _arg2int([1,1,0,0,0,0,0,1,0,1,1,1])
|
288
|
+
# => 3095
|
289
|
+
# _arg2int('alpha')
|
290
|
+
# => exception: "ArgumentError: value ('alpha':String) contains invalid digits"
|
291
|
+
#
|
292
|
+
# === Exceptions
|
293
|
+
# [<tt>ArgumentError</tt>] Can't reduce the argument to a binary integer.
|
294
|
+
#
|
295
|
+
def _arg2int(val_p) # :nodoc:
|
296
|
+
if (val_p.class.eql?(BitString))
|
297
|
+
#
|
298
|
+
# If we were passed a bitstring, convert it.
|
299
|
+
#
|
300
|
+
val = val_p.to_i
|
301
|
+
elsif (val_p.class.eql?(String))
|
302
|
+
#
|
303
|
+
# If we were given a String for the value, it must consist of valid
|
304
|
+
# binary digits.
|
305
|
+
#
|
306
|
+
_raise(BadDigit, nil, val_p) unless (val_p.gsub(/[01]/, '').empty?)
|
307
|
+
val = val_p.to_i(2)
|
308
|
+
elsif (val_p.class.eql?(Array))
|
309
|
+
#
|
310
|
+
# If we were given an array, make sure that all the values are
|
311
|
+
# integers and either 1 or 0.
|
312
|
+
#
|
313
|
+
_raise(BadDigit, nil, val_p) unless ((val_p - [0, 1]).empty?)
|
314
|
+
val = val_p.collect { |bit| bit.to_s(2) }.join('').to_i(2)
|
315
|
+
elsif (val_p.kind_of?(Integer))
|
316
|
+
val = val_p
|
317
|
+
else
|
318
|
+
#
|
319
|
+
# Let's try to convert it to an integer from whatever class we
|
320
|
+
# were passed.
|
321
|
+
#
|
322
|
+
unless (val_p.respond_to?(:to_i))
|
323
|
+
raise ArgumentError.new('unable to determine bitstring value from ' +
|
324
|
+
"\"#{val_p.to_s}\":#{val_p.class.name}")
|
325
|
+
end
|
326
|
+
end
|
327
|
+
val
|
328
|
+
end # def _arg2int
|
329
|
+
|
330
|
+
#
|
331
|
+
# === Description
|
332
|
+
#
|
333
|
+
# Raise a standard exception.
|
334
|
+
#
|
335
|
+
# :call-seq:
|
336
|
+
# _raise<i>(exc, [msg])</i> => Exception raised
|
337
|
+
#
|
338
|
+
# === Arguments
|
339
|
+
# [<i>exc</i>] <i>Exception</i>. One of our 'known' repeated exceptions.
|
340
|
+
# [<i>msg</i>] <i>String</i>. Message to use if we don't have a canned one.
|
341
|
+
#
|
342
|
+
# === Examples
|
343
|
+
# _raise(BadDigit, nil, bogusvalue)
|
344
|
+
# _raise(OuttasightIndex, 'you are kidding, right?')
|
345
|
+
#
|
346
|
+
# === Exceptions
|
347
|
+
# [<tt>InternalError</tt>] Called with something other than an exception.
|
348
|
+
# [<i>other</I>] As indicated.
|
349
|
+
#
|
350
|
+
def _raise(*args) # :nodoc:
|
351
|
+
exc = args.shift
|
352
|
+
unless (exc.ancestors.include?(Exception))
|
353
|
+
raise InternalError.new('asked to raise non-exception')
|
354
|
+
end
|
355
|
+
begin
|
356
|
+
raise InternalError
|
357
|
+
rescue InternalError => e
|
358
|
+
if (args[0].kind_of?(String) && args[0].match(/%/))
|
359
|
+
msg = sprintf(*args)
|
360
|
+
args = []
|
361
|
+
elsif (args[0].kind_of?(String))
|
362
|
+
msg = args.shift
|
363
|
+
else
|
364
|
+
msg = nil
|
365
|
+
end
|
366
|
+
|
367
|
+
mName = e.backtrace[1].match(/in \`(\S*)'/).captures[0]
|
368
|
+
case exc.name.sub(/^.*::/, '')
|
369
|
+
when 'BadDigit'
|
370
|
+
if (msg.nil?)
|
371
|
+
val = args[1].respond_to?(:to_s) ? args[1].to_s : args[1].inspect
|
372
|
+
msg = "value ('#{val}':#{args[1].class.name}) contains invalid digits"
|
373
|
+
end
|
374
|
+
raise ArgumentError.new(msg)
|
375
|
+
when 'BitsRInts'
|
376
|
+
raise ArgumentError.new(msg || 'bitcount must be an integer')
|
377
|
+
when 'BogoIndex'
|
378
|
+
if (msg.nil?)
|
379
|
+
val = args[0]
|
380
|
+
msg = "illegal index value #{val.inspect}"
|
381
|
+
end
|
382
|
+
raise IndexError.new(msg)
|
383
|
+
when 'NeedGPS'
|
384
|
+
raise ArgumentError.new(msg ||
|
385
|
+
'invalid direction for operation')
|
386
|
+
when 'NoDeficitBits'
|
387
|
+
raise IndexError.new(msg || 'bitcount must be positive')
|
388
|
+
when 'NotImplementedError'
|
389
|
+
raise NotImplementedError.new(msg ||
|
390
|
+
"method '#{mName}' not yet implemented")
|
391
|
+
when 'OuttasightIndex'
|
392
|
+
if (msg.kind_of?(Integer))
|
393
|
+
msg = "index out of range: '#{msg.to_s}'"
|
394
|
+
end
|
395
|
+
raise IndexError.new(msg ||
|
396
|
+
'index out of range')
|
397
|
+
when 'UnboundedNonsense'
|
398
|
+
raise RuntimeError.new(msg ||
|
399
|
+
'operation only meaningful for ' +
|
400
|
+
'bounded bitstrings')
|
401
|
+
when 'UnInterable'
|
402
|
+
if (msg.nil?)
|
403
|
+
val = args[0].respond_to?(to_s) ? args[0].to_s : args[0].inspect
|
404
|
+
msg = "unable to reduce '#{val}':#{args[0].class.name} " +
|
405
|
+
"to a binary value"
|
406
|
+
end
|
407
|
+
raise ArgumentError.new(msg)
|
408
|
+
when 'WrongNargs'
|
409
|
+
if (msg.nil?)
|
410
|
+
val = args[0].respond_to?(:to_i) ? args[0].to_i : args[0].inspect
|
411
|
+
req = args[1].respond_to?(:to_i) ? args[1].to_i : args[1].inspect
|
412
|
+
msg = "wrong number of arguments (#{val} for #{req})"
|
413
|
+
end
|
414
|
+
raise ArgumentError.new(msg)
|
415
|
+
else
|
416
|
+
raise exc.new(msg)
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end # def _raise
|
420
|
+
|
421
|
+
#
|
422
|
+
# === Description
|
423
|
+
#
|
424
|
+
# Return a binary string representation of the value, zero filled
|
425
|
+
# or left-truncated to the specified length.
|
426
|
+
#
|
427
|
+
# :call-seq:
|
428
|
+
# _zfill<i>(value, length)</i> => <i>String</i>
|
429
|
+
#
|
430
|
+
# === Arguments
|
431
|
+
# [<i>val</i>] <i>Integer</i> or <i>String</i>. Value to be represented as a string of binary digits.
|
432
|
+
# [<i>length</i>] <i>Integer</i>. Length of output string to return.
|
433
|
+
#
|
434
|
+
# === Examples
|
435
|
+
# _zfill(0, 12)
|
436
|
+
# => "000000000000"
|
437
|
+
#
|
438
|
+
# _zfill(3095, 4)
|
439
|
+
# => "0111"
|
440
|
+
#
|
441
|
+
# _zfill(3095, 15)
|
442
|
+
# => "000110000010111"
|
443
|
+
#
|
444
|
+
# === Exceptions
|
445
|
+
# <i>None</i>.
|
446
|
+
#
|
447
|
+
def _zfill(val_p, length_p) # :nodoc:
|
448
|
+
sVal = val_p.kind_of?(String) ? val_p : val_p.to_s(2)
|
449
|
+
return sVal if (length_p.to_i <= 0)
|
450
|
+
if (length_p > sVal.length)
|
451
|
+
('0' * (length_p - sVal.length)) + sVal
|
452
|
+
elsif (length_p < sVal.length)
|
453
|
+
sVal[-length_p, length_p]
|
454
|
+
else
|
455
|
+
sVal
|
456
|
+
end
|
457
|
+
end # def _zfill
|
458
|
+
|
459
|
+
#
|
460
|
+
# === Description
|
461
|
+
#
|
462
|
+
# Return a Boolean indicating whether the bitstring has a fixed length
|
463
|
+
# (is bounded) or not.
|
464
|
+
#
|
465
|
+
# :call-seq:
|
466
|
+
# bitstring.bounded?()
|
467
|
+
#
|
468
|
+
# === Arguments
|
469
|
+
# <i>None</i>.
|
470
|
+
#
|
471
|
+
# === Examples
|
472
|
+
# bs = BitString.new(3095)
|
473
|
+
# bs.bounded?
|
474
|
+
# => false
|
475
|
+
#
|
476
|
+
# bs = BitString.new(3095, 12)
|
477
|
+
# bs.bounded?
|
478
|
+
# => true
|
479
|
+
#
|
480
|
+
# === Exceptions
|
481
|
+
# <i>None</i>.
|
482
|
+
#
|
483
|
+
def bounded?()
|
484
|
+
@bounded
|
485
|
+
end # def bounded?()
|
486
|
+
|
487
|
+
#
|
488
|
+
# === Description
|
489
|
+
#
|
490
|
+
# Return a duplicate of the current bitstring -- with all bits cleared.
|
491
|
+
#
|
492
|
+
# :call-seq:
|
493
|
+
# bitstring.clear<i>()</i> => <i>BitString</i>
|
494
|
+
#
|
495
|
+
# === Arguments
|
496
|
+
# <i>None</i>.
|
497
|
+
#
|
498
|
+
# === Examples
|
499
|
+
# bs = BitString.new(3095)
|
500
|
+
# nbs = bs.clear
|
501
|
+
# bs.to_s
|
502
|
+
# => "110000010111"
|
503
|
+
# nbs.to_s
|
504
|
+
# => "0"
|
505
|
+
#
|
506
|
+
# === Exceptions
|
507
|
+
# <i>None</i>.
|
508
|
+
#
|
509
|
+
def clear()
|
510
|
+
bs = dup
|
511
|
+
bs.from_i(0)
|
512
|
+
bs
|
513
|
+
end # def clear()
|
514
|
+
|
515
|
+
#
|
516
|
+
# === Description
|
517
|
+
#
|
518
|
+
# Clear all the bits in the bitstring.
|
519
|
+
#
|
520
|
+
# :call-seq:
|
521
|
+
# bitstring.clear!<i>()</i> => <i>BitString</i>
|
522
|
+
#
|
523
|
+
# === Arguments
|
524
|
+
# <i>None</i>.
|
525
|
+
#
|
526
|
+
# === Examples
|
527
|
+
# bs = BitString.new(3095, 12)
|
528
|
+
# bs.to_s
|
529
|
+
# => "110000010111"
|
530
|
+
# bs.clear!
|
531
|
+
# bs.to_s
|
532
|
+
# => "000000000000"
|
533
|
+
#
|
534
|
+
# === Exceptions
|
535
|
+
# <i>None</i>.
|
536
|
+
#
|
537
|
+
def clear!()
|
538
|
+
@value = 0
|
539
|
+
self
|
540
|
+
end # def clear!()
|
541
|
+
|
542
|
+
#
|
543
|
+
# === Description
|
544
|
+
#
|
545
|
+
# Execute a block for each bit in the bitstring.
|
546
|
+
#
|
547
|
+
# :call-seq:
|
548
|
+
# bitstring.<i>each</i> { |<i>bitval</i>| <i>block</i> } => <i>BitString</i>
|
549
|
+
#
|
550
|
+
# === Arguments
|
551
|
+
# [<i>block</i>] <i>Proc</i>. Block to be called for each bit in the string. The block is passed the bit value.
|
552
|
+
#
|
553
|
+
# === Examples
|
554
|
+
# bs = BitString.new('100101')
|
555
|
+
# bs.each { |bitval| puts bitval }
|
556
|
+
# 1
|
557
|
+
# 0
|
558
|
+
# 1
|
559
|
+
# 0
|
560
|
+
# 0
|
561
|
+
# 1
|
562
|
+
#
|
563
|
+
# === Exceptions
|
564
|
+
# <i>None</i>.
|
565
|
+
#
|
566
|
+
def each(&block)
|
567
|
+
self.length.times { |bit| block.call(self[bit]) }
|
568
|
+
self
|
569
|
+
end # def each
|
570
|
+
|
571
|
+
#
|
572
|
+
# === Description
|
573
|
+
#
|
574
|
+
# Treat the bitstring as an Integer and store its entire value at
|
575
|
+
# once.
|
576
|
+
#
|
577
|
+
# :call-seq:
|
578
|
+
# bitstring.from_i<i>(newval)</i> => <i>BitString</i>
|
579
|
+
#
|
580
|
+
# === Arguments
|
581
|
+
# [<i>newval</i>] <i>Integer</i>. Value from which bits will be copied to the bitstring.
|
582
|
+
#
|
583
|
+
# === Examples
|
584
|
+
# bs = BitString.new(0, 12)
|
585
|
+
# bs.to_s
|
586
|
+
# => "000000000000"
|
587
|
+
# bs.from_i(3095)
|
588
|
+
# bs.to_s
|
589
|
+
# => "110000010111"
|
590
|
+
#
|
591
|
+
# === Exceptions
|
592
|
+
# <i>None</i>.
|
593
|
+
#
|
594
|
+
def from_i(newval)
|
595
|
+
unless (newval.respond_to?(:to_i))
|
596
|
+
what = newval.respond_to?(:to_s) ? newval.to_s : newval.inspect
|
597
|
+
_raise(UnInterable, newval)
|
598
|
+
end
|
599
|
+
newval = newval.to_i
|
600
|
+
newval &= 2**@length - 1 if (bounded?)
|
601
|
+
@value = newval
|
602
|
+
self
|
603
|
+
end # def from_i()
|
604
|
+
|
605
|
+
#
|
606
|
+
# === Description
|
607
|
+
#
|
608
|
+
# Return a new bitstring based on the current one, grown (made longer)
|
609
|
+
# in one direction (toward the least significant bits) or the other.
|
610
|
+
# Growing an unbounded string toward the high end is a no-op.
|
611
|
+
#
|
612
|
+
# Bits added are set to <i>defval</i> (default 0).
|
613
|
+
#
|
614
|
+
# :call-seq:
|
615
|
+
# bitstring.grow<i>(bits, [defval], [direction])</i> => <i>BitString</i>
|
616
|
+
#
|
617
|
+
# === Arguments
|
618
|
+
# [<i>bits</i>] <i>Integer</i>. Number of bits to add.
|
619
|
+
# [<i>defval</i>] <i>Integer</i>. Value to which added bits should be set.
|
620
|
+
# [<i>direction</i>] <i>Constant</i>. Either <tt>BitString::HIGH_END</tt> (the default) or <tt>BitString::LOW_END</t>. Indicates whether bits are added at the least or most significant end. Growing with <tt>BitString::LOW_END</tt> results in the bitstring being shifted left.
|
621
|
+
#
|
622
|
+
# === Examples
|
623
|
+
# bs = BitString(5, 3)
|
624
|
+
# bs.to_s
|
625
|
+
# => "101"
|
626
|
+
# nbs = bs.grow(3)
|
627
|
+
# nbs.to_s
|
628
|
+
# => "000101"
|
629
|
+
# nbs = bs.grow(3, 1)
|
630
|
+
# nbs.to_s
|
631
|
+
# => "111101"
|
632
|
+
# nbs = bs.grow(3, 0, BitString::LOW_END)
|
633
|
+
# nbs.to_s
|
634
|
+
# => "101000"
|
635
|
+
#
|
636
|
+
# === Exceptions
|
637
|
+
# [<tt>ArgumentError</tt>] <i>bits</i> isn't an integer, <i>defval</i> can't be reduced to a binary value, or <i>direction</i> isn't one of the defined values.
|
638
|
+
# [<tt>IndexError</tt>] <i>bits</i> is negative or meaningless.
|
639
|
+
# [<tt>RuntimeError</tt>] Can't grow an unbounded string at the high end.
|
640
|
+
#
|
641
|
+
def grow(bits=1, defval=0, direction=HIGH_END)
|
642
|
+
unless (bits.kind_of?(Integer))
|
643
|
+
_raise(BitsRInts)
|
644
|
+
end
|
645
|
+
unless (defval.respond_to?(:to_i))
|
646
|
+
what = defval.respond_to?(:to_s) ? defval.to_s : defval.inspect
|
647
|
+
_raise(UnInterable, defval)
|
648
|
+
end
|
649
|
+
unless ([HIGH_END, LOW_END].include?(direction))
|
650
|
+
_raise(NeedGPS)
|
651
|
+
end
|
652
|
+
unless (bits >= 0)
|
653
|
+
_raise(NoDeficitBits)
|
654
|
+
end
|
655
|
+
unless ((direction == LOW_END) || bounded?)
|
656
|
+
_raise(UnboundedNonsense)
|
657
|
+
end
|
658
|
+
return dup if (bits == 0)
|
659
|
+
|
660
|
+
value = @value
|
661
|
+
vMask = 2**bits - 1
|
662
|
+
if (direction == HIGH_END)
|
663
|
+
vMask *= 2**@length if (bounded?)
|
664
|
+
elsif (direction == LOW_END)
|
665
|
+
value *= (2**bits)
|
666
|
+
end
|
667
|
+
value |= vMask if (defval == 1)
|
668
|
+
bounded? ? self.class.new(value, @length + bits) : self.class.new(value)
|
669
|
+
end # def grow
|
670
|
+
|
671
|
+
#
|
672
|
+
# === Description
|
673
|
+
#
|
674
|
+
# As #grow, except that the current bitstring is changed rather
|
675
|
+
# than a new one returned.
|
676
|
+
#
|
677
|
+
# Bits added are set to <i>defval</i> (default 0).
|
678
|
+
#
|
679
|
+
# :call-seq:
|
680
|
+
# bitstring.grow!<i>(bits, [defval], [direction])</i> => <i>BitString</i>
|
681
|
+
#
|
682
|
+
# === Arguments
|
683
|
+
# [<i>bits</i>] <i>Integer</i> Number of bits to add.
|
684
|
+
# [<i>defval</i>] <i>Integer</i> Value to which added bits should be set.
|
685
|
+
# [<i>direction</i>] <i>Constant</i>. Either <tt>BitString::HIGH_END</tt> (the default) or <tt>BitString::LOW_END</tt>. Indicates whether bits are added at the least or most significant end. Growing with <tt>BitString::LOW_END</tt> results in the bitstring being shifted left.
|
686
|
+
#
|
687
|
+
# === Examples
|
688
|
+
# bs = BitString.new(5, 3)
|
689
|
+
# bs.to_s
|
690
|
+
# => "101"
|
691
|
+
# bs.grow!(3)
|
692
|
+
# bs.to_s
|
693
|
+
# => "000101"
|
694
|
+
# bs.grow!(3, 1, BitString::LOW_END)
|
695
|
+
# bs.to_s
|
696
|
+
# => "000101111"
|
697
|
+
#
|
698
|
+
# === Exceptions
|
699
|
+
# [<tt>ArgumentError</tt>] <i>bits</i> isn't an integer, <i>defval</i> can't be reduced to a binary value, or <i>direction</i> isn't one of the defined values.
|
700
|
+
# [<tt>IndexError</tt>] <i>bits</i> is negative or meaningless.
|
701
|
+
# [<tt>RuntimeError</tt>] Can't grow an unbounded string at the high end.
|
702
|
+
#
|
703
|
+
def grow!(bits=1, defval=0, direction=HIGH_END)
|
704
|
+
bs = grow(bits, defval, direction)
|
705
|
+
@length = bs.length if (bs.bounded?)
|
706
|
+
@value = bs.to_i
|
707
|
+
self
|
708
|
+
end # def grow!
|
709
|
+
|
710
|
+
#
|
711
|
+
# === Description
|
712
|
+
#
|
713
|
+
# Return the length of the bitstring. If it's bounded, the fixed size
|
714
|
+
# is returned, otherwise the number of significant binary digits.
|
715
|
+
#
|
716
|
+
# :call-seq:
|
717
|
+
# bitstring.length()
|
718
|
+
#
|
719
|
+
# === Arguments
|
720
|
+
# <i>None</i>.
|
721
|
+
#
|
722
|
+
# === Examples
|
723
|
+
# bs = BitString.new('101', 3)
|
724
|
+
# bs.length
|
725
|
+
# => 3
|
726
|
+
#
|
727
|
+
# bs = BitString.new('00101', 5)
|
728
|
+
# bs.length
|
729
|
+
# => 5
|
730
|
+
#
|
731
|
+
# bs = BitString.new('00101')
|
732
|
+
# bs.length
|
733
|
+
# => 3
|
734
|
+
#
|
735
|
+
# === Exceptions
|
736
|
+
# <i>None</i>.
|
737
|
+
#
|
738
|
+
def length()
|
739
|
+
bounded? ? @length : @value.to_s(2).length
|
740
|
+
end # def length()
|
741
|
+
|
742
|
+
#
|
743
|
+
# === Description
|
744
|
+
#
|
745
|
+
# Return the value of the least significant (low) bit.
|
746
|
+
#
|
747
|
+
# :call-seq:
|
748
|
+
# bitstring.lsb()
|
749
|
+
#
|
750
|
+
# === Arguments
|
751
|
+
# <i>None</i>.
|
752
|
+
#
|
753
|
+
# === Examples
|
754
|
+
# bs = BitString.new('101')
|
755
|
+
# bs.lsb
|
756
|
+
# => 1
|
757
|
+
#
|
758
|
+
# bs = BitString.new('010')
|
759
|
+
# bs.lsb
|
760
|
+
# => 0
|
761
|
+
#
|
762
|
+
# === Exceptions
|
763
|
+
# <i>None</i>.
|
764
|
+
#
|
765
|
+
def lsb()
|
766
|
+
self[0]
|
767
|
+
end # def lsb()
|
768
|
+
|
769
|
+
#
|
770
|
+
# === Description
|
771
|
+
#
|
772
|
+
# Return an integer with bits set to mask the specified portion of the
|
773
|
+
# bitstring.
|
774
|
+
#
|
775
|
+
# If you want to create a mask wider than the bitstring, use the class
|
776
|
+
# method <i>BitString.mask()</i> instead.
|
777
|
+
#
|
778
|
+
# :call-seq:
|
779
|
+
# bitstring.mask<i>([bitcount], [direction])</i> => <i>Integer</i>
|
780
|
+
#
|
781
|
+
# === Arguments
|
782
|
+
# [<i>bitcount</i>] <i>Integer</i>. Number of bits to set in the mask.
|
783
|
+
# [<i>direction</i>] <i>Constant</i>. <tt>BitString::HIGH_END</tt> (the default) or <tt>BitString::LOW_END</tt>. Specifies the end of the bitstring from which the mask starts.
|
784
|
+
#
|
785
|
+
# === Examples
|
786
|
+
# bs = BitString.new(0, 12)
|
787
|
+
# bs.mask.to_s(2)
|
788
|
+
# => "111111111111"
|
789
|
+
# bs.mask(5).to_s(2)
|
790
|
+
# => "111110000000"
|
791
|
+
# bs.mask(5, BitString::LOW_END).to_s(2)
|
792
|
+
# => "11111"
|
793
|
+
# BitString.new(bs.mask(5, BitString::LOW_END), 12).to_s
|
794
|
+
# => "000000011111"
|
795
|
+
#
|
796
|
+
# === Exceptions
|
797
|
+
# [<tt>IndexError</tt>] Raised if <i>bitcount</i> is negative or grater than the bitstring length.
|
798
|
+
#
|
799
|
+
def mask(bits=self.length, direction=HIGH_END)
|
800
|
+
_raise(OuttasightIndex, bits) if (bits > self.length)
|
801
|
+
_raise(NoDeficitBits) if (bits < 0)
|
802
|
+
vMask = 2**bits - 1
|
803
|
+
vMask *= 2**(self.length - bits) if (direction == HIGH_END)
|
804
|
+
vMask
|
805
|
+
end # def mask()
|
806
|
+
|
807
|
+
#
|
808
|
+
# === Description
|
809
|
+
#
|
810
|
+
# Class method to return an integer value with the specified number
|
811
|
+
# of bits (starting at position 0) all set to 1.
|
812
|
+
#
|
813
|
+
# :call-seq:
|
814
|
+
# BitString.mask<i>(bitcount)</i> => <i>Integer</i>
|
815
|
+
#
|
816
|
+
# === Arguments
|
817
|
+
# [<i>bitcount</i>] <i>Integer</i>. Number of bits to set in the mask.
|
818
|
+
#
|
819
|
+
# === Examples
|
820
|
+
# BitString.mask(5).to_s(2)
|
821
|
+
# => "11111"
|
822
|
+
#
|
823
|
+
# === Exceptions
|
824
|
+
# <i>None</i>.
|
825
|
+
#
|
826
|
+
def self.mask(bits=1)
|
827
|
+
new._raise(NoDeficitBits) if (bits < 0)
|
828
|
+
vMask = 2**bits - 1
|
829
|
+
end # def self.mask
|
830
|
+
|
831
|
+
#
|
832
|
+
# === Description
|
833
|
+
#
|
834
|
+
# Return the value of the most significant (high) bit.
|
835
|
+
# Only meaningful for bounded bitstrings.
|
836
|
+
#
|
837
|
+
# :call-seq:
|
838
|
+
# bitstring.msb()
|
839
|
+
#
|
840
|
+
# === Arguments
|
841
|
+
# <i>None</i>.
|
842
|
+
#
|
843
|
+
# === Examples
|
844
|
+
# bs = BitString.new('0101')
|
845
|
+
# bs.msb
|
846
|
+
# => 1 # Leading zeroes stripped in unbouded bitstrings
|
847
|
+
#
|
848
|
+
# bs = BitString.new('0101', 4)
|
849
|
+
# bs.msb
|
850
|
+
# => 0
|
851
|
+
#
|
852
|
+
# === Exceptions
|
853
|
+
# [<tt>RuntimeError</tt>] There is no 'MSB' for an unbounded bitstring.
|
854
|
+
#
|
855
|
+
def msb()
|
856
|
+
unless (bounded?)
|
857
|
+
_raise(UnboundedNonsense,
|
858
|
+
'most significant bit only applies to bounded bitstrings')
|
859
|
+
end
|
860
|
+
self[@length - 1]
|
861
|
+
end # def msb()
|
862
|
+
|
863
|
+
#
|
864
|
+
# === Description
|
865
|
+
#
|
866
|
+
# Return the number of bits in the bitstring that are either set (1)
|
867
|
+
# or clear (0). Leading zeroes on unbounded bitstrings are ignored.
|
868
|
+
#
|
869
|
+
# :call-seq:
|
870
|
+
# bitstring.population<i>(testval)</i> => <i>Integer</i>
|
871
|
+
#
|
872
|
+
# === Arguments
|
873
|
+
# [<i>testval</i>] <i>Array</i>, <i>BitString</i>, <i>Integer</i>, or <i>String</i> whose low bit is used for the test.
|
874
|
+
#
|
875
|
+
# === Examples
|
876
|
+
# bs = BitString.new('0001111001010')
|
877
|
+
# bs.population(0)
|
878
|
+
# => 4
|
879
|
+
# bs.population(1)
|
880
|
+
# => 6
|
881
|
+
#
|
882
|
+
# bs = BitString.new('0001111001010', 13)
|
883
|
+
# bs.population(0)
|
884
|
+
# => 7
|
885
|
+
# bs.population(1)
|
886
|
+
# => 6
|
887
|
+
#
|
888
|
+
# === Exceptions
|
889
|
+
# [<tt>ArgumentError</tt>] The argument cannot be reduced to a binary digit.
|
890
|
+
#
|
891
|
+
def population(val)
|
892
|
+
val = _arg2int(val) & 1
|
893
|
+
self.select { |bval| bval == val }.length
|
894
|
+
end # def population
|
895
|
+
|
896
|
+
#
|
897
|
+
# === Description
|
898
|
+
#
|
899
|
+
# Return a copy of the bitstring resized to the specified number of bits,
|
900
|
+
# resulting in truncation or growth. Bits are added to, or removed from,
|
901
|
+
# the high (more significant) end. Resizing an unbounded bitstring
|
902
|
+
# makes it bounded.
|
903
|
+
#
|
904
|
+
# :call-seq:
|
905
|
+
# bitstring.resize<i>(bits)</i> => <i>BitString</i>
|
906
|
+
#
|
907
|
+
# === Arguments
|
908
|
+
# [<i>bits</i>] Width of the resulting bitstring.
|
909
|
+
#
|
910
|
+
# === Examples
|
911
|
+
# bs = BitString.new('101')
|
912
|
+
# bs.bounded?
|
913
|
+
# => false
|
914
|
+
# nbs = bs.resize(5)
|
915
|
+
# nbs.bounded?
|
916
|
+
# => true
|
917
|
+
# nbs.length
|
918
|
+
# => 5
|
919
|
+
# nbs.to_s
|
920
|
+
# => "00101"
|
921
|
+
# nbs = bs.resize(7)
|
922
|
+
# nbs.to_s
|
923
|
+
# => "0000101"
|
924
|
+
#
|
925
|
+
# === Exceptions
|
926
|
+
# [<tt>IndexError</tt>] <i>bits</i> is negative or meaningless.
|
927
|
+
#
|
928
|
+
def resize(bits)
|
929
|
+
unless (bits.kind_of?(Integer))
|
930
|
+
_raise(BitsRInts)
|
931
|
+
end
|
932
|
+
unless (bits > 0)
|
933
|
+
_raise(NoDeficitBits)
|
934
|
+
end
|
935
|
+
value = @value
|
936
|
+
length = self.length
|
937
|
+
bs = self.class.new(value, length)
|
938
|
+
diffbits = bits - length
|
939
|
+
diffbits < 0 ? bs.shrink!(-diffbits) : bs.grow!(diffbits)
|
940
|
+
end # def resize
|
941
|
+
|
942
|
+
#
|
943
|
+
# === Description
|
944
|
+
#
|
945
|
+
# As #resize except it's the current bitstring that gets resized.
|
946
|
+
#
|
947
|
+
# :call-seq:
|
948
|
+
# bitstring.resize!<i>(bits)</i> => <i>BitString</i>
|
949
|
+
#
|
950
|
+
# === Arguments
|
951
|
+
# [<i>bits</i>] Width of the resulting bitstring.
|
952
|
+
#
|
953
|
+
# === Examples
|
954
|
+
# bs = BitString.new('101')
|
955
|
+
# bs.bounded?
|
956
|
+
# => false
|
957
|
+
# bs.resize!(5)
|
958
|
+
# bs.bounded?
|
959
|
+
# => true
|
960
|
+
# bs.length
|
961
|
+
# => 5
|
962
|
+
# bs.to_s
|
963
|
+
# => "00101"
|
964
|
+
# bs.resize!(7)
|
965
|
+
# bs.to_s
|
966
|
+
# => "0000101"
|
967
|
+
#
|
968
|
+
# === Exceptions
|
969
|
+
# [<tt>IndexError</tt>] <i>bits</i> is negative or meaningless.
|
970
|
+
#
|
971
|
+
def resize!(bits)
|
972
|
+
bs = resize(bits)
|
973
|
+
@bounded = true
|
974
|
+
@length = bs.length
|
975
|
+
@value = bs.to_i
|
976
|
+
self
|
977
|
+
end # def resize!
|
978
|
+
|
979
|
+
#
|
980
|
+
# === Description
|
981
|
+
#
|
982
|
+
# Rotate the bitstring, taking bits from one end and shifting them
|
983
|
+
# in at the other. Only makes sense with bounded strings.
|
984
|
+
#
|
985
|
+
# A negative value rotates left; a positive one rotates to the right.
|
986
|
+
#
|
987
|
+
# :call-seq:
|
988
|
+
# bistring.rotate<i>(bits)</i> => <i>BitString</i>
|
989
|
+
#
|
990
|
+
# === Arguments
|
991
|
+
# [<i>bits</i>] <i>Integer</i>. Number of positions to rotate left (negative) or right (positive). Bits rotated off one end are rotated in on the other.
|
992
|
+
#
|
993
|
+
# === Examples
|
994
|
+
# bs = BitString.new('000000011111', 12)
|
995
|
+
# bs.rotate(3).to_s
|
996
|
+
# => "000011111000"
|
997
|
+
# bs.rotate(-4).to_s
|
998
|
+
# => "100000001111"
|
999
|
+
#
|
1000
|
+
# === Exceptions
|
1001
|
+
# [<tt>RuntimeError</tt>] Can't rotate an unbounded bitstring.
|
1002
|
+
#
|
1003
|
+
def rotate(bits_p)
|
1004
|
+
unless (bounded?)
|
1005
|
+
_raise(UnboundedNonsense,
|
1006
|
+
'rotation only applies to bounded bitstrings')
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
value = @value
|
1010
|
+
length = @length
|
1011
|
+
bits = bits_p.to_i.abs % length
|
1012
|
+
vMask = (mult = 2**bits) - 1
|
1013
|
+
ldiff = length - bits
|
1014
|
+
if (bits_p > 0)
|
1015
|
+
#
|
1016
|
+
# Rotate right (toward the LSB)
|
1017
|
+
#
|
1018
|
+
residue = value & vMask
|
1019
|
+
value /= mult
|
1020
|
+
value |= residue * 2**ldiff
|
1021
|
+
elsif (bits_p < 0)
|
1022
|
+
#
|
1023
|
+
# Rotate left (toward the MSB)
|
1024
|
+
#
|
1025
|
+
vMask *= 2**ldiff
|
1026
|
+
residue = value & vMask
|
1027
|
+
value = ((value & ~vMask) * mult) | (residue / 2**ldiff)
|
1028
|
+
end
|
1029
|
+
self.class.new(value, @length)
|
1030
|
+
end # def rotate
|
1031
|
+
|
1032
|
+
#
|
1033
|
+
# === Description
|
1034
|
+
#
|
1035
|
+
# Same as #rotate except that the result is stored back into the
|
1036
|
+
# current object.
|
1037
|
+
#
|
1038
|
+
# :call-seq:
|
1039
|
+
# bitstring.rotate!<i>(bits)</i> => <i>BitString</i>
|
1040
|
+
#
|
1041
|
+
# === Arguments
|
1042
|
+
# [<i>bits</i>] <i>Integer</i>. Number of positions to rotate left (negative) or right (positive). Bits rotated off one end are rotated in on the other.
|
1043
|
+
#
|
1044
|
+
# === Examples
|
1045
|
+
# bs = BitString.new('000000011111', 12)
|
1046
|
+
# bs.rotate!(3)
|
1047
|
+
# bs.to_s
|
1048
|
+
# => "000011111000"
|
1049
|
+
# bs.rotate!(-4)
|
1050
|
+
# bs.to_s
|
1051
|
+
# => "100000001111"
|
1052
|
+
#
|
1053
|
+
# === Exceptions
|
1054
|
+
# <i>None</i>.
|
1055
|
+
#
|
1056
|
+
def rotate!(bits_p)
|
1057
|
+
@value = rotate(bits_p).to_i
|
1058
|
+
self
|
1059
|
+
end # def rotate!
|
1060
|
+
|
1061
|
+
#
|
1062
|
+
# === Description
|
1063
|
+
#
|
1064
|
+
# Iterate through all the bits, invoking the specified block with the
|
1065
|
+
# value of each in turn. If the block returns a true value, the
|
1066
|
+
# bit value is added to the result array.
|
1067
|
+
#
|
1068
|
+
# :call-seq:
|
1069
|
+
# bitstring.select { <i>|bit| block</i> } => <i>Array</i>
|
1070
|
+
#
|
1071
|
+
# === Arguments
|
1072
|
+
# [<i>bit</i>] <i>Integer</i>. The value (0 or 1) of the current bit.
|
1073
|
+
# [<i>block</i>] <i>Proc</i>. The block of code to execute.
|
1074
|
+
#
|
1075
|
+
# === Examples
|
1076
|
+
# bs = BitString.new('11001110001')
|
1077
|
+
# bs.select { |bit| bit == 1}
|
1078
|
+
# => [1, 1, 1, 1, 1, 1]
|
1079
|
+
#
|
1080
|
+
# bs = BitString.new('0011001110001')
|
1081
|
+
# bs.select { |bit| bit == 0}
|
1082
|
+
# => [0, 0, 0, 0, 0] # because unbounded leadings zeroes are dropped
|
1083
|
+
#
|
1084
|
+
# bs = BitString.new('0011001110001', 13)
|
1085
|
+
# bs.select { |bit| bit == 0}
|
1086
|
+
# => [0, 0, 0, 0, 0, 0, 0]
|
1087
|
+
#
|
1088
|
+
# === Exceptions
|
1089
|
+
# <i>None</i>.
|
1090
|
+
#
|
1091
|
+
def select(&block)
|
1092
|
+
result = []
|
1093
|
+
self.each do |val|
|
1094
|
+
result.push(val) if (block.call(val))
|
1095
|
+
end
|
1096
|
+
result
|
1097
|
+
end # def select
|
1098
|
+
|
1099
|
+
#
|
1100
|
+
# === Description
|
1101
|
+
#
|
1102
|
+
# Shrink the bitstring (make it shorter) by truncating bits from
|
1103
|
+
# one end or the other. Shrinking to fewer than 1 bits raises
|
1104
|
+
# an exception.
|
1105
|
+
#
|
1106
|
+
# :call-seq:
|
1107
|
+
# bitstring.shrink<i>(bits, [direction])</i>
|
1108
|
+
#
|
1109
|
+
# === Arguments
|
1110
|
+
# [<i>bits</i>] <i>Integer</i>. Number of bits to truncate.
|
1111
|
+
# [<i>direction</i>] <i>Constant</i>. Either <tt>BitString::HIGH_END</tt> (the default) or <tt>BitString::LOW_END</tt>.
|
1112
|
+
#
|
1113
|
+
# === Examples
|
1114
|
+
# bs = BitString.new(3095) # 110000010111
|
1115
|
+
# nbs = bs.shrink(5)
|
1116
|
+
# nbs.to_s
|
1117
|
+
# => "10111" # Unbounded leading zeroes aren't significant
|
1118
|
+
# nbs = nbs.shrink(2, BitString::LOW_END)
|
1119
|
+
# nbs.to_s
|
1120
|
+
# => "101"
|
1121
|
+
#
|
1122
|
+
# bs = BitString.new(3095, 12) # 110000010111
|
1123
|
+
# nbs = bs.shrink(5)
|
1124
|
+
# nbs.to_s
|
1125
|
+
# => "0010111"
|
1126
|
+
#
|
1127
|
+
# === Exceptions
|
1128
|
+
# [<tt>ArgumentError</tt>] <i>bitcount</i> isn't an integer or <i>direction</i> isn't one of the defined values.
|
1129
|
+
# [<tt>IndexError</tt>] <i>bits</i> is negative or meaningless.
|
1130
|
+
#
|
1131
|
+
def shrink(bits=1, direction=HIGH_END)
|
1132
|
+
unless (bits.kind_of?(Integer))
|
1133
|
+
_raise(BitsRInts)
|
1134
|
+
end
|
1135
|
+
unless (bits >= 0)
|
1136
|
+
_raise(NoDeficitBits)
|
1137
|
+
end
|
1138
|
+
unless ([HIGH_END, LOW_END].include?(direction))
|
1139
|
+
_raise(NeedGPS)
|
1140
|
+
end
|
1141
|
+
return dup if (bits == 0)
|
1142
|
+
|
1143
|
+
if (bounded? && (bits >= @length))
|
1144
|
+
_raise(RuntimeError, 'shrink count greater than bitstring size')
|
1145
|
+
end
|
1146
|
+
value = @value
|
1147
|
+
length = bounded? ? @length - bits : nil
|
1148
|
+
if (direction == LOW_END)
|
1149
|
+
value /= 2**bits
|
1150
|
+
else
|
1151
|
+
_raise(UnboundedNonsense) unless (bounded?)
|
1152
|
+
value &= 2**length - 1
|
1153
|
+
end
|
1154
|
+
bounded? ? self.class.new(value, length) : self.class.new(value)
|
1155
|
+
end # def shrink
|
1156
|
+
|
1157
|
+
#
|
1158
|
+
# === Description
|
1159
|
+
#
|
1160
|
+
# As #shrink except that the current bitstring is modified rather than
|
1161
|
+
# a copy being made and altered.
|
1162
|
+
#
|
1163
|
+
# :call-seq:
|
1164
|
+
# bitstring.shrink!<i>(bits, [direction])</i>
|
1165
|
+
#
|
1166
|
+
# === Arguments
|
1167
|
+
# [<i>bits</i>] <i>Integer</i>. Number of bits to truncate.
|
1168
|
+
# [<i>direction</i>] <i>Constant</i>. <tt>BitString::HIGH_END</tt> (the default) or <tt>BitString::LOW_END</tt>.
|
1169
|
+
#
|
1170
|
+
# === Examples
|
1171
|
+
# bs = BitString.new(3095) # 110000010111
|
1172
|
+
# bs.shrink!(5)
|
1173
|
+
# bs.to_s
|
1174
|
+
# => "10111" # Unbounded leading zeroes aren't significant
|
1175
|
+
# bs.shrink!(2, BitString::LOW_END)
|
1176
|
+
# bs.to_s
|
1177
|
+
# => "101"
|
1178
|
+
#
|
1179
|
+
# bs = BitString.new(3095, 12) # 110000010111
|
1180
|
+
# bs.shrink!(5)
|
1181
|
+
# bs.to_s
|
1182
|
+
# => "0010111"
|
1183
|
+
#
|
1184
|
+
# === Exceptions
|
1185
|
+
# [<tt>ArgumentError</tt>] <i>bitcount</i> isn't an integer or <i>direction</i> isn't one of the defined values.
|
1186
|
+
# [<tt>IndexError</tt>] <i>bits</i> is negative or meaningless.
|
1187
|
+
#
|
1188
|
+
def shrink!(bits=1, direction=HIGH_END)
|
1189
|
+
bs = shrink(bits, direction)
|
1190
|
+
@length = bs.length if (bs.bounded?)
|
1191
|
+
@value = bs.to_i
|
1192
|
+
self
|
1193
|
+
end # def shrink!
|
1194
|
+
|
1195
|
+
#
|
1196
|
+
# === Description
|
1197
|
+
#
|
1198
|
+
# Extract a subset from the bitstring. See the description of
|
1199
|
+
# the <tt>[]</tt> method.
|
1200
|
+
#
|
1201
|
+
# :call-seq:
|
1202
|
+
# bitstring.slice<i>(index)</i> => <i>Integer</i>
|
1203
|
+
# bitstring.slice<i>(start, length)</i> => <i>BitString</i>
|
1204
|
+
# bitstring.slice<i>(range)</i> => <i>BitString</i>
|
1205
|
+
#
|
1206
|
+
# === Arguments
|
1207
|
+
# [<i>index</i>] <i>Integer</i>. Single bit position.
|
1208
|
+
# [<i>start</i>] <i>Integer</i>. Start position of subset.
|
1209
|
+
# [<i>length</i>] <i>Integer</i>. Length of subset.
|
1210
|
+
# [<i>range</i>] <i>Range</i>. Subset specified as a range.
|
1211
|
+
#
|
1212
|
+
# === Exceptions
|
1213
|
+
# [<tt>ArgumentError</tt>] If length specified with a range.
|
1214
|
+
# [<tt>IndexError</tt>] If bounded bitstring and substring is illegal.
|
1215
|
+
#
|
1216
|
+
def slice(*args)
|
1217
|
+
self[*args]
|
1218
|
+
end # def slice
|
1219
|
+
|
1220
|
+
#
|
1221
|
+
# === Description
|
1222
|
+
#
|
1223
|
+
# Select the specified bits from the bitstring, and remake it using
|
1224
|
+
# only those bits. If bounded, the size will be adjusted to match
|
1225
|
+
# the number of bits selected. This is an alternative way to change
|
1226
|
+
# the size and value of an existing bitstring (see the grow!(), shrink!(),
|
1227
|
+
# and resize!() methods.)
|
1228
|
+
#
|
1229
|
+
# :call-seq:
|
1230
|
+
# bitstring.slice!<i>(index)</i> => <i>Integer</i>
|
1231
|
+
# bitstring.slice!<i>(start, length)</i> => <i>BitString</i>
|
1232
|
+
# bitstring.slice!<i>(range)</i> => <i>BitString</i>
|
1233
|
+
#
|
1234
|
+
# === Arguments
|
1235
|
+
# [<i>index</i>] <i>Integer</i>. Single bit position.
|
1236
|
+
# [<i>start</i>] <i>Integer</i>. Start position of subset.
|
1237
|
+
# [<i>length</i>] <i>Integer</i>. Length of subset.
|
1238
|
+
# [<i>range</i>] <i>Range</i>. Subset specified as a range.
|
1239
|
+
#
|
1240
|
+
# === Examples
|
1241
|
+
# bs = BitString.new(3095, 12)
|
1242
|
+
# bs.to_s
|
1243
|
+
# => "110000010111"
|
1244
|
+
# bs.slice!(4..10)
|
1245
|
+
# bs.to_s
|
1246
|
+
# => "1000001"
|
1247
|
+
#
|
1248
|
+
# === Exceptions
|
1249
|
+
# [<tt>ArgumentError</tt>] If length specified with a range.
|
1250
|
+
# [<tt>IndexError</tt>] If bounded bitstring and substring is illegal.
|
1251
|
+
#
|
1252
|
+
def slice!(*args)
|
1253
|
+
bs = self[*args]
|
1254
|
+
@value = bs.to_i
|
1255
|
+
@bounded = bs.bounded?
|
1256
|
+
@length = bs.length if (bs.bounded?)
|
1257
|
+
self
|
1258
|
+
end # def slice!
|
1259
|
+
|
1260
|
+
#
|
1261
|
+
# === Description
|
1262
|
+
#
|
1263
|
+
# Return the full value of the bitstring represented as an integer.
|
1264
|
+
#
|
1265
|
+
# :call-seq:
|
1266
|
+
# bitstring.to_i<i>()</i> => <i>Integer</i>
|
1267
|
+
#
|
1268
|
+
# === Arguments
|
1269
|
+
# <i>None</i>.
|
1270
|
+
#
|
1271
|
+
# === Examples
|
1272
|
+
# bs = BitString.new('110000010111')
|
1273
|
+
# bs.to_i
|
1274
|
+
# => 3095
|
1275
|
+
#
|
1276
|
+
# === Exceptions
|
1277
|
+
# <i>None</i>.
|
1278
|
+
#
|
1279
|
+
def to_i()
|
1280
|
+
@value.to_i
|
1281
|
+
end # def to_i()
|
1282
|
+
|
1283
|
+
#
|
1284
|
+
# === Description
|
1285
|
+
#
|
1286
|
+
# Return the bitlist as a <i>String</i> object consisting of '0' and '1'
|
1287
|
+
# characters. If the bitstring is bounded, the <i>String</i> will
|
1288
|
+
# be zero-filled on the left (high end).
|
1289
|
+
#
|
1290
|
+
# :call-seq:
|
1291
|
+
# bitstring.to_s<i>()</i> => <i>String</i>
|
1292
|
+
#
|
1293
|
+
# === Arguments
|
1294
|
+
# <i>None</i>.
|
1295
|
+
#
|
1296
|
+
# === Examples
|
1297
|
+
# bs = BitString.new(3095)
|
1298
|
+
# bs.to_s
|
1299
|
+
# => "110000010111"
|
1300
|
+
#
|
1301
|
+
# bs = BitString.new(3095, 14)
|
1302
|
+
# bs.to_s
|
1303
|
+
# => "00110000010111"
|
1304
|
+
#
|
1305
|
+
# === Exceptions
|
1306
|
+
# <i>None</i>.
|
1307
|
+
#
|
1308
|
+
def to_s()
|
1309
|
+
_zfill(@value, @length)
|
1310
|
+
end # def to_s()
|
1311
|
+
|
1312
|
+
#
|
1313
|
+
# List visibility alterations here, since the directive effects persist
|
1314
|
+
# past the next definition.
|
1315
|
+
#
|
1316
|
+
protected(:_arg2int, :_raise, :_zfill)
|
1317
|
+
|
1318
|
+
end # class BitString
|