From 51065bedb077085e5b9729c630fc41317c9a219f Mon Sep 17 00:00:00 2001 From: Guilherme Andrade <g@gandrade.net> Date: Sat, 16 Mar 2024 21:31:10 +0000 Subject: [PATCH] Further optimise encoding --- src/erlzord.erl | 67 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/src/erlzord.erl b/src/erlzord.erl index 78d04b2..d4ece2f 100644 --- a/src/erlzord.erl +++ b/src/erlzord.erl @@ -96,10 +96,17 @@ -export_type([list_vector/0]). -record(encoding_direction, { - shift_start_offset :: non_neg_integer(), + shift_start :: non_neg_integer(), shift_increment :: +1 | -1 }). +-record(z_builder, { + head :: non_neg_integer(), + head_sz :: non_neg_integer(), + tail_data :: [binary()], + tail_sz :: non_neg_integer() +}). + %% ------------------------------------------------------------------ %% Deprecated Type Definitions %% ------------------------------------------------------------------ @@ -332,46 +339,72 @@ encode_list_(Vector, Dimensions, MinComponent, MaxComponent) -> interleave(NormalizedVector, Dimensions). %, ComponentBitsize). interleave(Values, Dimensions) -> - Direction = #encoding_direction{shift_start_offset = 0, shift_increment = +1}, + Direction = #encoding_direction{shift_start = 0, shift_increment = +1}, AlternateDirection - = #encoding_direction{shift_start_offset = Dimensions - 1, shift_increment = -1}, + = #encoding_direction{shift_start = Dimensions - 1, shift_increment = -1}, - interleave_recur(Values, Direction, AlternateDirection, Dimensions, _BitsizeAcc = 0, _Acc = 0). + Builder = #z_builder{head = 0, head_sz = 0, tail_data = [], tail_sz = 0}, + interleave_recur(Values, Direction, AlternateDirection, Dimensions, Builder). -interleave_recur(Values, Direction, AlternateDirection, Dimensions, BitsizeAcc, Acc) -> - ShiftStart = BitsizeAcc + Direction#encoding_direction.shift_start_offset, - ShiftIncrement = Direction#encoding_direction.shift_increment, +interleave_recur(Values, Direction, AlternateDirection, Dimensions, Builder) -> + #encoding_direction{shift_start = ShiftStart, shift_increment = ShiftIncrement} = Direction, % io:format("INTERLEAVING AFTER ~b bits~n", [BitsizeAcc]), - case interleave_next(Values, ShiftStart, ShiftIncrement, true, [], Acc) of - {RemainingValues, UpdatedAcc} -> - UpdatedBitsizeAcc = BitsizeAcc + Dimensions, + case interleave_next(Values, ShiftStart, ShiftIncrement, true, [], 0) of + {RemainingValues, Slice} -> + UpdatedBuilder = prepend_to_builder(Builder, Slice, Dimensions), interleave_recur(RemainingValues, AlternateDirection, Direction, Dimensions, - UpdatedBitsizeAcc, UpdatedAcc); + UpdatedBuilder); all_zeroes -> - Acc + builder_to_integer(Builder) end. -interleave_next([Value | Next], Shift, ShiftIncrement, AllZeroes, RemainingValuesAcc, Acc) -> +interleave_next([Value | Next], Shift, ShiftIncrement, AllZeroes, RemainingValuesAcc, SliceAcc) -> ValueRemaining = Value bsr 1, ValueMask = (Value band 1) bsl Shift, UpdatedAllZeroes = AllZeroes andalso (Value =:= 0), UpdatedRemainingValuesAcc = [ValueRemaining | RemainingValuesAcc], - UpdatedAcc = Acc bor ValueMask, + UpdatedSliceAcc = SliceAcc bor ValueMask, interleave_next(Next, Shift + ShiftIncrement, ShiftIncrement, UpdatedAllZeroes, - UpdatedRemainingValuesAcc, UpdatedAcc); -interleave_next([], _Shift, _ShiftIncrement, AllZeroes, RemainingValuesAcc, Acc) -> + UpdatedRemainingValuesAcc, UpdatedSliceAcc); +interleave_next([], _Shift, _ShiftIncrement, AllZeroes, RemainingValuesAcc, UpdatedSliceAcc) -> case AllZeroes of false -> - {RemainingValuesAcc, Acc}; + {RemainingValuesAcc, UpdatedSliceAcc}; true -> all_zeroes end. +prepend_to_builder(Builder, Slice, Dimensions) -> + case Builder#z_builder.head_sz + Dimensions of + UpdatedHeadSz when UpdatedHeadSz < 60 -> + UpdatedHead = (Slice bsl Builder#z_builder.head_sz) bor Builder#z_builder.head, + Builder#z_builder{head = UpdatedHead, head_sz = UpdatedHeadSz}; + + TooLarge -> + NewHeadSz = TooLarge rem 32, + <<NewHead:NewHeadSz, MoreTailData/bytes>> = << + Slice:Dimensions, + (Builder#z_builder.head):(Builder#z_builder.head_sz) + >>, + + Builder#z_builder{ + head = NewHead, + head_sz = NewHeadSz, + tail_data = [MoreTailData | Builder#z_builder.tail_data], + tail_sz = Builder#z_builder.tail_sz + bit_size(MoreTailData) + } + end. + +builder_to_integer(Builder) -> + HigherZ = Builder#z_builder.head bsl Builder#z_builder.tail_sz, + LowerZ = binary:decode_unsigned(iolist_to_binary(Builder#z_builder.tail_data)), + HigherZ bor LowerZ. + -spec decode_list_(Z, Dimensions, MinComponent, MaxComponent, Bitsize) -> Vector when Z :: non_neg_integer(),