Class: Ibex::Tables::Compact

Inherits:
Object
  • Object
show all
Defined in:
lib/ibex/tables/compact.rb,
sig/ibex/tables/compact.rbs

Overview

Sparse table represented by per-row offsets and ownership checks.

Direct Known Subclasses

CompactActions

Constant Summary collapse

DENSE_CELL_LIMIT =

Signature:

  • Integer

Returns:

  • (Integer)
1_000_000

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(offsets:, values:, checks:, row_count:, dense_width: nil) ⇒ Compact

Returns a new instance of Compact.

RBS:

  • (offsets: Array[Integer], values: Array[Object?], checks: Array[Integer?], row_count: Integer, ?dense_width: Integer?) -> void

Parameters:

  • offsets: (Array[Integer])
  • values: (Array[Object?])
  • checks: (Array[Integer?])
  • row_count: (Integer)
  • dense_width: (Integer, nil) (defaults to: nil)


130
131
132
133
134
135
136
137
138
# File 'lib/ibex/tables/compact.rb', line 130

def initialize(offsets:, values:, checks:, row_count:, dense_width: nil)
  @offsets = offsets.freeze
  @values = values.freeze
  @checks = checks.freeze
  @row_count = row_count
  @dense_width = dense_width
  @dense_values = dense_layout(dense_width)
  freeze
end

Instance Attribute Details

#checksArray[Integer?] (readonly)

Signature:

  • Array[Integer?]

Returns:

  • (Array[Integer?])


73
74
75
# File 'lib/ibex/tables/compact.rb', line 73

def checks
  @checks
end

#dense_valuesArray[Object?]? (readonly)

Signature:

  • Array[Object?]?

Returns:

  • (Array[Object?], nil)


75
76
77
# File 'lib/ibex/tables/compact.rb', line 75

def dense_values
  @dense_values
end

#dense_widthInteger? (readonly)

Signature:

  • Integer?

Returns:

  • (Integer, nil)


76
77
78
# File 'lib/ibex/tables/compact.rb', line 76

def dense_width
  @dense_width
end

#offsetsArray[Integer] (readonly)

Signature:

  • Array[Integer]

Returns:

  • (Array[Integer])


71
72
73
# File 'lib/ibex/tables/compact.rb', line 71

def offsets
  @offsets
end

#row_countInteger (readonly)

Signature:

  • Integer

Returns:

  • (Integer)


74
75
76
# File 'lib/ibex/tables/compact.rb', line 74

def row_count
  @row_count
end

#valuesArray[Object?] (readonly)

Signature:

  • Array[Object?]

Returns:

  • (Array[Object?])


72
73
74
# File 'lib/ibex/tables/compact.rb', line 72

def values
  @values
end

Class Method Details

.build(rows, dense: true) ⇒ Compact

RBS:

  • (Array[Hash[Integer, Object?]] rows, ?dense: bool) -> Compact

Parameters:

  • rows (Array[Hash[Integer, Object?]])
  • dense: (Boolean) (defaults to: true)

Returns:



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/ibex/tables/compact.rb', line 80

def build(rows, dense: true)
  offsets = Array.new(rows.length, 0)
  values = [] #: Array[Object?]
  checks = [] #: Array[Integer?]
  next_offsets = {} #: Hash[Array[Integer], Integer]
  rows.each_index.sort_by { |row| [-rows[row].length, row] }.each do |row|
    offset = find_offset(rows[row].keys, checks, next_offsets)
    offsets[row] = offset
    rows[row].each do |column, value|
      index = offset + column
      values[index] = value
      checks[index] = row
    end
  end
  dense_width = rows.flat_map(&:keys).max.to_i + 1 if dense
  dense_width = nil if dense_width && (rows.length * dense_width) > DENSE_CELL_LIMIT
  new(
    offsets: offsets, values: values, checks: checks, row_count: rows.length,
    dense_width: dense_width
  )
end

.packed(offsets, values, checks, row_count:, dense_width: nil) ⇒ Compact

RBS:

  • (String offsets, String values, String checks, row_count: Integer, ?dense_width: Integer?) -> Compact

Parameters:

  • offsets (String)
  • values (String)
  • checks (String)
  • row_count: (Integer)
  • dense_width: (Integer, nil) (defaults to: nil)

Returns:



104
105
106
107
108
109
110
111
112
# File 'lib/ibex/tables/compact.rb', line 104

def packed(offsets, values, checks, row_count:, dense_width: nil)
  new(
    offsets: PackedIntegers.decode_required(offsets),
    values: PackedIntegers.decode(values),
    checks: PackedIntegers.decode(checks),
    row_count: row_count,
    dense_width: dense_width
  )
end

Instance Method Details

#dense_layout(dense_width) ⇒ Array[Object?]?

RBS:

  • (Integer? dense_width) -> Array[Object?]?

Parameters:

  • dense_width (Integer, nil)

Returns:

  • (Array[Object?], nil)


170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/ibex/tables/compact.rb', line 170

def dense_layout(dense_width)
  return nil unless dense_width
  raise ArgumentError, "compact dense width must be positive" unless dense_width.positive?
  return nil if (@row_count * dense_width) > DENSE_CELL_LIMIT

  dense = Array.new(@row_count * dense_width) #: Array[Object?]
  @checks.each_index do |index|
    row = @checks[index]
    next unless row

    column = index - @offsets.fetch(row)
    raise ArgumentError, "compact column exceeds the dense row width" unless
      column.between?(0, dense_width - 1)

    dense[(row * dense_width) + column] = @values[index]
  end
  dense.freeze
end

#lookup(row, column) ⇒ Object?

Keep predicate dispatch out of this lookup because every parser action and goto crosses it. rubocop:disable Style/NumericPredicate

RBS:

  • (Integer row, Integer column) -> Object?

Parameters:

  • row (Integer)
  • column (Integer)

Returns:

  • (Object, nil)


144
145
146
147
148
149
150
151
# File 'lib/ibex/tables/compact.rb', line 144

def lookup(row, column)
  return nil if row < 0 || row >= @row_count || column < 0

  index = @offsets[row] + column
  return nil if index < 0 || index >= @checks.length

  @checks[index] == row ? @values[index] : nil
end

#row(row) ⇒ Hash[Integer, Object?]

RBS:

  • (Integer row) -> Hash[Integer, Object?]

Parameters:

  • row (Integer)

Returns:

  • (Hash[Integer, Object?])


155
156
157
158
159
160
161
162
163
164
165
# File 'lib/ibex/tables/compact.rb', line 155

def row(row)
  return {} unless row.between?(0, @row_count - 1)

  result = {} #: Hash[Integer, Object?]
  @checks.each_index do |index|
    next unless @checks[index] == row

    result[index - @offsets[row]] = @values[index]
  end
  result
end