Class: BinData::Array

Inherits:
Base
  • Object
show all
Extended by:
DSLMixin
Includes:
Enumerable
Defined in:
lib/bindata/array.rb

Overview

An Array is a list of data objects of the same type.

require 'bindata'

data = "\x03\x04\x05\x06\x07\x08\x09"

obj = BinData::Array.new(type: :int8, initial_length: 6)
obj.read(data) #=> [3, 4, 5, 6, 7, 8]

obj = BinData::Array.new(type: :int8,
                         read_until: -> { index == 1 })
obj.read(data) #=> [3, 4]

obj = BinData::Array.new(type: :int8,
                         read_until: -> { element >= 6 })
obj.read(data) #=> [3, 4, 5, 6]

obj = BinData::Array.new(type: :int8,
        read_until: -> { array[index] + array[index - 1] == 13 })
obj.read(data) #=> [3, 4, 5, 6, 7]

obj = BinData::Array.new(type: :int8, read_until: :eof)
obj.read(data) #=> [3, 4, 5, 6, 7, 8, 9]

Parameters

Parameters may be provided at initialisation to control the behaviour of an object. These params are:

:type

The symbol representing the data type of the array elements. If the type is to have params passed to it, then it should be provided as [type_symbol, hash_params].

:initial_length

The initial length of the array.

:read_until

While reading, elements are read until this condition is true. This is typically used to read an array until a sentinel value is found. The variables index, element and array are made available to any lambda assigned to this parameter. If the value of this parameter is the symbol :eof, then the array will read as much data from the stream as possible.

Each data object in an array has the variable index made available to any lambda evaluated as a parameter of that data object.

Defined Under Namespace

Modules: InitialLengthPlugin, ReadUntilEOFPlugin, ReadUntilPlugin

Instance Attribute Summary

Attributes inherited from Base

#parent

Instance Method Summary collapse

Methods included from DSLMixin

dsl_parser, method_missing, to_str

Methods inherited from Base

#==, #=~, #abs_offset, arg_processor, auto_call_delayed_io, bindata_name, #clear, #debug_name, #eval_parameter, #get_parameter, #has_parameter?, #initialize_with_warning, #inspect, #lazy_evaluator, #new, #num_bytes, #pretty_print, #read, read, register_subclasses, #rel_offset, #safe_respond_to?, #to_binary_s, #to_hex, #to_s, unregister_self, #write

Methods included from AcceptedParametersPlugin

#accepted_parameters, #default_parameters, #mandatory_parameters, #mutually_exclusive_parameters, #optional_parameters

Methods included from RegisterNamePlugin

included

Methods included from Framework

#bit_aligned?

Instance Method Details

#[](arg1, arg2 = nil) ⇒ Object Also known as: slice

Returns the element at index.



139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/bindata/array.rb', line 139

def [](arg1, arg2 = nil)
  if arg1.respond_to?(:to_int) && arg2.nil?
    slice_index(arg1.to_int)
  elsif arg1.respond_to?(:to_int) && arg2.respond_to?(:to_int)
    slice_start_length(arg1.to_int, arg2.to_int)
  elsif arg1.is_a?(Range) && arg2.nil?
    slice_range(arg1)
  else
    raise TypeError, "can't convert #{arg1} into Integer" unless arg1.respond_to?(:to_int)
    raise TypeError, "can't convert #{arg2} into Integer" unless arg2.respond_to?(:to_int)
  end
end

#[]=(index, value) ⇒ Object

Sets the element at index.



174
175
176
177
# File 'lib/bindata/array.rb', line 174

def []=(index, value)
  extend_array(index)
  elements[index].assign(value)
end

#assign(array) ⇒ Object

Raises:

  • (ArgumentError)


82
83
84
85
86
87
88
# File 'lib/bindata/array.rb', line 82

def assign(array)
  return if self.equal?(array)  # prevent self assignment
  raise ArgumentError, "can't set a nil value for #{debug_name}" if array.nil?

  @elements = []
  concat(array)
end

#at(index) ⇒ Object

Returns the element at index. Unlike slice, if index is out of range the array will not be automatically extended.



169
170
171
# File 'lib/bindata/array.rb', line 169

def at(index)
  elements[index]
end

#clear?Boolean

Returns:

  • (Boolean)


78
79
80
# File 'lib/bindata/array.rb', line 78

def clear?
  @elements.nil? || elements.all?(&:clear?)
end

#concat(array) ⇒ Object



117
118
119
120
# File 'lib/bindata/array.rb', line 117

def concat(array)
  insert(-1, *array.to_ary)
  self
end

#debug_name_of(child) ⇒ Object

:nodoc:



223
224
225
226
# File 'lib/bindata/array.rb', line 223

def debug_name_of(child) # :nodoc:
  index = find_index_of(child)
  "#{debug_name}[#{index}]"
end

#do_num_bytesObject

:nodoc:



239
240
241
# File 'lib/bindata/array.rb', line 239

def do_num_bytes # :nodoc:
  sum_num_bytes_for_all_elements
end

#do_write(io) ⇒ Object

:nodoc:



235
236
237
# File 'lib/bindata/array.rb', line 235

def do_write(io) # :nodoc:
  elements.each { |el| el.do_write(io) }
end

#eachObject



219
220
221
# File 'lib/bindata/array.rb', line 219

def each
  elements.each { |el| yield el }
end

#empty?Boolean

Returns:

  • (Boolean)


210
211
212
# File 'lib/bindata/array.rb', line 210

def empty?
  length.zero?
end

#find_index(obj) ⇒ Object Also known as: index



94
95
96
# File 'lib/bindata/array.rb', line 94

def find_index(obj)
  elements.index(obj)
end

#find_index_of(obj) ⇒ Object

Returns the first index of obj in self.

Uses equal? for the comparator.



102
103
104
# File 'lib/bindata/array.rb', line 102

def find_index_of(obj)
  elements.index { |el| el.equal?(obj) }
end

#first(n = nil) ⇒ Object

Returns the first element, or the first n elements, of the array. If the array is empty, the first form returns nil, and the second form returns an empty array.



182
183
184
185
186
187
188
189
190
191
# File 'lib/bindata/array.rb', line 182

def first(n = nil)
  if n.nil? && empty?
    # explicitly return nil as arrays grow automatically
    nil
  elsif n.nil?
    self[0]
  else
    self[0, n]
  end
end

#initialize_instanceObject



74
75
76
# File 'lib/bindata/array.rb', line 74

def initialize_instance
  @elements = nil
end

#initialize_shared_instanceObject



61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/bindata/array.rb', line 61

def initialize_shared_instance
  @element_prototype = get_parameter(:type)
  if get_parameter(:read_until) == :eof
    extend ReadUntilEOFPlugin
  elsif has_parameter?(:read_until)
    extend ReadUntilPlugin
  elsif has_parameter?(:initial_length)
    extend InitialLengthPlugin
  end

  super
end

#insert(index, *objs) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/bindata/array.rb', line 122

def insert(index, *objs)
  extend_array(index - 1)
  abs_index = (index >= 0) ? index : index + 1 + length

  # insert elements before...
  new_elements = objs.map { new_element }
  elements.insert(index, *new_elements)

  # ...assigning values
  objs.each_with_index do |obj, i|
    self[abs_index + i] = obj
  end

  self
end

#last(n = nil) ⇒ Object

Returns the last element, or the last n elements, of the array. If the array is empty, the first form returns nil, and the second form returns an empty array.



196
197
198
199
200
201
202
203
# File 'lib/bindata/array.rb', line 196

def last(n = nil)
  if n.nil?
    self[-1]
  else
    n = length if n > length
    self[-n, n]
  end
end

#lengthObject Also known as: size



205
206
207
# File 'lib/bindata/array.rb', line 205

def length
  elements.length
end

#offset_of(child) ⇒ Object

:nodoc:



228
229
230
231
232
233
# File 'lib/bindata/array.rb', line 228

def offset_of(child) # :nodoc:
  index = find_index_of(child)
  sum = sum_num_bytes_below_index(index)

  child.bit_aligned? ? sum.floor : sum.ceil
end

#push(*args) ⇒ Object Also known as: <<



106
107
108
109
# File 'lib/bindata/array.rb', line 106

def push(*args)
  insert(-1, *args)
  self
end

#snapshotObject



90
91
92
# File 'lib/bindata/array.rb', line 90

def snapshot
  elements.collect(&:snapshot)
end

#to_aryObject

Allow this object to be used in array context.



215
216
217
# File 'lib/bindata/array.rb', line 215

def to_ary
  collect { |el| el }
end

#unshift(*args) ⇒ Object



112
113
114
115
# File 'lib/bindata/array.rb', line 112

def unshift(*args)
  insert(0, *args)
  self
end