Class: Philiprehberger::BitField::Base
- Inherits:
-
Object
- Object
- Philiprehberger::BitField::Base
- Includes:
- Comparable
- Defined in:
- lib/philiprehberger/bit_field.rb
Overview
Named bit flags with symbolic access, set operations, and serialization
Class Method Summary collapse
-
.flag(name, position) ⇒ void
Define a named flag at the given bit position.
-
.flags ⇒ Array<Symbol>
Return all defined flag names.
- .flags_map ⇒ Object private
-
.from_h(hash) ⇒ Base
Create an instance from a hash.
-
.from_i(value) ⇒ Base
Create an instance from an integer value.
-
.from_json(json_string) ⇒ Base
Create an instance from a JSON string.
-
.group(name, flag_names) ⇒ void
Define a named group of flags.
-
.groups ⇒ Hash{Symbol => Array<Symbol>}
Return all defined group definitions.
- .groups_map ⇒ Object private
- .inherited(subclass) ⇒ Object private
-
.strict(*initial_flags) ⇒ Base
Create an instance that raises on unknown flag names.
Instance Method Summary collapse
-
#&(other) ⇒ Base
Bitwise AND.
-
#<=>(other) ⇒ Integer?
Compare by integer value.
-
#==(other) ⇒ Boolean
(also: #eql?)
Equality check.
-
#^(other) ⇒ Base
Bitwise XOR.
-
#added_flags(other) ⇒ Array<Symbol>
Return flags set in self but not in other.
-
#clear(flag) ⇒ self
Clear a flag.
-
#clear_all ⇒ self
Clear all defined flags.
-
#clear_flags(*flag_names) ⇒ self
Clear multiple specific flags at once.
-
#clear_group(group_name) ⇒ self
Clear all flags in a group.
-
#count_clear ⇒ Integer
Return the number of flags currently clear.
-
#count_set ⇒ Integer
Return the number of flags currently set.
-
#flag_clear?(flag) ⇒ Boolean
Check if a flag is clear (not set).
-
#flag_set?(flag) ⇒ Boolean
Check if a flag is set.
-
#flags ⇒ Array<Symbol>
Return all defined flag names.
-
#group_any_set?(group_name) ⇒ Boolean
Check if any flag in a group is set.
-
#group_none_set?(group_name) ⇒ Boolean
Check if no flags in a group are set.
-
#group_set?(group_name) ⇒ Boolean
Check if all flags in a group are set.
-
#hash ⇒ Integer
Hash code for use in Hash keys.
-
#initialize(*initial_flags) ⇒ Base
constructor
Create a new bit field with the given flags set.
-
#removed_flags(other) ⇒ Array<Symbol>
Return flags set in other but not in self.
-
#set(flag) ⇒ self
Set a flag.
-
#set_all ⇒ self
Set all defined flags.
-
#set_flags(*flag_names) ⇒ self
Set multiple specific flags at once.
-
#set_group(group_name) ⇒ self
Set all flags in a group.
-
#to_a ⇒ Array<Symbol>
Return an array of set flag names.
-
#to_h ⇒ Hash{Symbol => Object}
Return a hash representation.
-
#to_i ⇒ Integer
Return the integer representation.
-
#to_json(*_args) ⇒ String
Return a JSON string representation.
-
#toggle(flag) ⇒ self
Toggle a flag.
-
#|(other) ⇒ Base
Bitwise OR.
Constructor Details
#initialize(*initial_flags) ⇒ Base
Create a new bit field with the given flags set
139 140 141 142 |
# File 'lib/philiprehberger/bit_field.rb', line 139 def initialize(*initial_flags) @value = 0 initial_flags.each { |f| set(f) } end |
Class Method Details
.flag(name, position) ⇒ void
This method returns an undefined value.
Define a named flag at the given bit position
31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/philiprehberger/bit_field.rb', line 31 def flag(name, position) raise Error, 'position must be a non-negative integer' unless position.is_a?(Integer) && position >= 0 raise Error, "flag #{name} already defined" if flags_map.key?(name) raise Error, "position #{position} already used" if flags_map.any? { |_, p| p == position } flags_map[name] = position define_method(:"#{name}?") do flag_set?(name) end end |
.flags ⇒ Array<Symbol>
Return all defined flag names
61 62 63 |
# File 'lib/philiprehberger/bit_field.rb', line 61 def flags flags_map.keys end |
.flags_map ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
118 119 120 |
# File 'lib/philiprehberger/bit_field.rb', line 118 def flags_map @flags_map ||= {} end |
.from_h(hash) ⇒ Base
Create an instance from a hash
110 111 112 113 114 115 |
# File 'lib/philiprehberger/bit_field.rb', line 110 def from_h(hash) value = hash[:value] || hash['value'] raise Error, 'hash must include a value key' if value.nil? from_i(value) end |
.from_i(value) ⇒ Base
Create an instance from an integer value
89 90 91 92 93 94 95 |
# File 'lib/philiprehberger/bit_field.rb', line 89 def from_i(value) raise Error, 'value must be a non-negative integer' unless value.is_a?(Integer) && value >= 0 instance = new instance.instance_variable_set(:@value, value) instance end |
.from_json(json_string) ⇒ Base
Create an instance from a JSON string
101 102 103 104 |
# File 'lib/philiprehberger/bit_field.rb', line 101 def from_json(json_string) data = JSON.parse(json_string) from_h(data) end |
.group(name, flag_names) ⇒ void
This method returns an undefined value.
Define a named group of flags
48 49 50 51 52 53 54 55 56 |
# File 'lib/philiprehberger/bit_field.rb', line 48 def group(name, flag_names) raise Error, "group #{name} already defined" if groups_map.key?(name) flag_names.each do |f| raise Error, "unknown flag #{f} in group #{name}" unless flags_map.key?(f) end groups_map[name] = flag_names.dup.freeze end |
.groups ⇒ Hash{Symbol => Array<Symbol>}
Return all defined group definitions
68 69 70 |
# File 'lib/philiprehberger/bit_field.rb', line 68 def groups groups_map.dup end |
.groups_map ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
123 124 125 |
# File 'lib/philiprehberger/bit_field.rb', line 123 def groups_map @groups_map ||= {} end |
.inherited(subclass) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
128 129 130 131 132 |
# File 'lib/philiprehberger/bit_field.rb', line 128 def inherited(subclass) super subclass.instance_variable_set(:@flags_map, flags_map.dup) subclass.instance_variable_set(:@groups_map, groups_map.dup) end |
Instance Method Details
#&(other) ⇒ Base
Bitwise AND
330 331 332 333 334 |
# File 'lib/philiprehberger/bit_field.rb', line 330 def &(other) raise Error, 'cannot combine different bit field types' unless other.is_a?(self.class) self.class.from_i(@value & other.to_i) end |
#<=>(other) ⇒ Integer?
Compare by integer value
350 351 352 353 354 |
# File 'lib/philiprehberger/bit_field.rb', line 350 def <=>(other) return nil unless other.is_a?(self.class) @value <=> other.to_i end |
#==(other) ⇒ Boolean Also known as: eql?
Equality check
360 361 362 |
# File 'lib/philiprehberger/bit_field.rb', line 360 def ==(other) other.is_a?(self.class) && @value == other.to_i end |
#^(other) ⇒ Base
Bitwise XOR
340 341 342 343 344 |
# File 'lib/philiprehberger/bit_field.rb', line 340 def ^(other) raise Error, 'cannot combine different bit field types' unless other.is_a?(self.class) self.class.from_i(@value ^ other.to_i) end |
#added_flags(other) ⇒ Array<Symbol>
Return flags set in self but not in other
375 376 377 378 379 |
# File 'lib/philiprehberger/bit_field.rb', line 375 def added_flags(other) raise Error, 'cannot compare different bit field types' unless other.is_a?(self.class) self.class.flags.select { |f| flag_set?(f) && !other.flag_set?(f) } end |
#clear(flag) ⇒ self
Clear a flag
189 190 191 192 193 |
# File 'lib/philiprehberger/bit_field.rb', line 189 def clear(flag) pos = position_for(flag) @value &= ~(1 << pos) self end |
#clear_all ⇒ self
Clear all defined flags
216 217 218 219 |
# File 'lib/philiprehberger/bit_field.rb', line 216 def clear_all @value = 0 self end |
#clear_flags(*flag_names) ⇒ self
Clear multiple specific flags at once
234 235 236 237 |
# File 'lib/philiprehberger/bit_field.rb', line 234 def clear_flags(*flag_names) flag_names.each { |f| clear(f) } self end |
#clear_group(group_name) ⇒ self
Clear all flags in a group
252 253 254 255 |
# File 'lib/philiprehberger/bit_field.rb', line 252 def clear_group(group_name) group_flags(group_name).each { |f| clear(f) } self end |
#count_clear ⇒ Integer
Return the number of flags currently clear
171 172 173 |
# File 'lib/philiprehberger/bit_field.rb', line 171 def count_clear self.class.flags.size - count_set end |
#count_set ⇒ Integer
Return the number of flags currently set
164 165 166 |
# File 'lib/philiprehberger/bit_field.rb', line 164 def count_set self.class.flags.count { |f| flag_set?(f) } end |
#flag_clear?(flag) ⇒ Boolean
Check if a flag is clear (not set)
157 158 159 |
# File 'lib/philiprehberger/bit_field.rb', line 157 def flag_clear?(flag) !flag_set?(flag) end |
#flag_set?(flag) ⇒ Boolean
Check if a flag is set
148 149 150 151 |
# File 'lib/philiprehberger/bit_field.rb', line 148 def flag_set?(flag) pos = position_for(flag) @value.anybits?(1 << pos) end |
#flags ⇒ Array<Symbol>
Return all defined flag names
298 299 300 |
# File 'lib/philiprehberger/bit_field.rb', line 298 def flags self.class.flags end |
#group_any_set?(group_name) ⇒ Boolean
Check if any flag in a group is set
269 270 271 |
# File 'lib/philiprehberger/bit_field.rb', line 269 def group_any_set?(group_name) group_flags(group_name).any? { |f| flag_set?(f) } end |
#group_none_set?(group_name) ⇒ Boolean
Check if no flags in a group are set
277 278 279 |
# File 'lib/philiprehberger/bit_field.rb', line 277 def group_none_set?(group_name) group_flags(group_name).none? { |f| flag_set?(f) } end |
#group_set?(group_name) ⇒ Boolean
Check if all flags in a group are set
261 262 263 |
# File 'lib/philiprehberger/bit_field.rb', line 261 def group_set?(group_name) group_flags(group_name).all? { |f| flag_set?(f) } end |
#hash ⇒ Integer
Hash code for use in Hash keys
367 368 369 |
# File 'lib/philiprehberger/bit_field.rb', line 367 def hash [self.class, @value].hash end |
#removed_flags(other) ⇒ Array<Symbol>
Return flags set in other but not in self
385 386 387 388 389 |
# File 'lib/philiprehberger/bit_field.rb', line 385 def removed_flags(other) raise Error, 'cannot compare different bit field types' unless other.is_a?(self.class) self.class.flags.select { |f| !flag_set?(f) && other.flag_set?(f) } end |
#set(flag) ⇒ self
Set a flag
179 180 181 182 183 |
# File 'lib/philiprehberger/bit_field.rb', line 179 def set(flag) pos = position_for(flag) @value |= (1 << pos) self end |
#set_all ⇒ self
Set all defined flags
208 209 210 211 |
# File 'lib/philiprehberger/bit_field.rb', line 208 def set_all self.class.flags.each { |f| set(f) } self end |
#set_flags(*flag_names) ⇒ self
Set multiple specific flags at once
225 226 227 228 |
# File 'lib/philiprehberger/bit_field.rb', line 225 def set_flags(*flag_names) flag_names.each { |f| set(f) } self end |
#set_group(group_name) ⇒ self
Set all flags in a group
243 244 245 246 |
# File 'lib/philiprehberger/bit_field.rb', line 243 def set_group(group_name) group_flags(group_name).each { |f| set(f) } self end |
#to_a ⇒ Array<Symbol>
Return an array of set flag names
291 292 293 |
# File 'lib/philiprehberger/bit_field.rb', line 291 def to_a self.class.flags.select { |f| flag_set?(f) } end |
#to_h ⇒ Hash{Symbol => Object}
Return a hash representation
305 306 307 |
# File 'lib/philiprehberger/bit_field.rb', line 305 def to_h { flags: to_a, value: @value } end |
#to_i ⇒ Integer
Return the integer representation
284 285 286 |
# File 'lib/philiprehberger/bit_field.rb', line 284 def to_i @value end |
#to_json(*_args) ⇒ String
Return a JSON string representation
312 313 314 |
# File 'lib/philiprehberger/bit_field.rb', line 312 def to_json(*_args) { flags: to_a.map(&:to_s), value: @value }.to_json end |
#toggle(flag) ⇒ self
Toggle a flag
199 200 201 202 203 |
# File 'lib/philiprehberger/bit_field.rb', line 199 def toggle(flag) pos = position_for(flag) @value ^= (1 << pos) self end |