8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
# File 'lib/flexr/codegen/table_packer.rb', line 8
def pack(rows, compression: :rows)
full = compression.to_sym == :full
base = []
default = rows.map { |row| row.tally.max_by { |_value, count| count }&.first }
fallback = full ? Array.new(rows.length) : nil
next_table = []
check = []
occupied = {}
rows.each_with_index do |row, state|
if full
candidate, matches = rows.each_index.take(state).map do |other_state|
[other_state, row.each_index.count { |class_id| row[class_id] == rows[other_state][class_id] }]
end.max_by(&:last)
fallback[state] = candidate if candidate && matches > row.count { |value| value == default[state] }
end
inherited = fallback && fallback[state] ? rows.fetch(fallback.fetch(state)) : nil
entries = row.each_index.reject do |class_id|
row[class_id] == (inherited ? inherited[class_id] : default[state])
end
offset = 0
while entries.any? { |class_id| occupied.key?(offset + class_id) }
offset += 1
end
base[state] = offset
entries.each do |class_id|
index = offset + class_id
next_table[index] = row[class_id]
check[index] = state
occupied[index] = true
end
end
result = { base: base.freeze, default: default.freeze, next: next_table.freeze, check: check.freeze }
result[:fallback] = fallback.freeze if fallback
result.freeze
end
|