xref: /aosp_15_r20/external/webrtc/logging/rtc_event_log/encoder/delta_encoding.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "logging/rtc_event_log/encoder/delta_encoding.h"
12 
13 #include <algorithm>
14 #include <limits>
15 #include <memory>
16 #include <utility>
17 
18 #include "absl/memory/memory.h"
19 #include "absl/strings/string_view.h"
20 #include "logging/rtc_event_log/encoder/bit_writer.h"
21 #include "logging/rtc_event_log/encoder/var_int.h"
22 #include "rtc_base/bit_buffer.h"
23 #include "rtc_base/bitstream_reader.h"
24 #include "rtc_base/checks.h"
25 #include "rtc_base/logging.h"
26 #include "rtc_base/numerics/safe_conversions.h"
27 
28 namespace webrtc {
29 namespace {
30 
31 // TODO(eladalon): Only build the decoder in tools and unit tests.
32 
33 bool g_force_unsigned_for_testing = false;
34 bool g_force_signed_for_testing = false;
35 
BitsToBytes(size_t bits)36 size_t BitsToBytes(size_t bits) {
37   return (bits / 8) + (bits % 8 > 0 ? 1 : 0);
38 }
39 
40 // TODO(eladalon): Replace by something more efficient.
UnsignedBitWidth(uint64_t input,bool zero_val_as_zero_width=false)41 uint64_t UnsignedBitWidth(uint64_t input, bool zero_val_as_zero_width = false) {
42   if (zero_val_as_zero_width && input == 0) {
43     return 0;
44   }
45 
46   uint64_t width = 0;
47   do {  // input == 0 -> width == 1
48     width += 1;
49     input >>= 1;
50   } while (input != 0);
51   return width;
52 }
53 
SignedBitWidth(uint64_t max_pos_magnitude,uint64_t max_neg_magnitude)54 uint64_t SignedBitWidth(uint64_t max_pos_magnitude,
55                         uint64_t max_neg_magnitude) {
56   const uint64_t bitwidth_pos = UnsignedBitWidth(max_pos_magnitude, true);
57   const uint64_t bitwidth_neg =
58       (max_neg_magnitude > 0) ? UnsignedBitWidth(max_neg_magnitude - 1, true)
59                               : 0;
60   return 1 + std::max(bitwidth_pos, bitwidth_neg);
61 }
62 
63 // Return the maximum integer of a given bit width.
64 // Examples:
65 // MaxUnsignedValueOfBitWidth(1) = 0x01
66 // MaxUnsignedValueOfBitWidth(6) = 0x3f
67 // MaxUnsignedValueOfBitWidth(8) = 0xff
68 // MaxUnsignedValueOfBitWidth(32) = 0xffffffff
MaxUnsignedValueOfBitWidth(uint64_t bit_width)69 uint64_t MaxUnsignedValueOfBitWidth(uint64_t bit_width) {
70   RTC_DCHECK_GE(bit_width, 1);
71   RTC_DCHECK_LE(bit_width, 64);
72   return (bit_width == 64) ? std::numeric_limits<uint64_t>::max()
73                            : ((static_cast<uint64_t>(1) << bit_width) - 1);
74 }
75 
76 // Computes the delta between `previous` and `current`, under the assumption
77 // that wrap-around occurs after `width` is exceeded.
UnsignedDelta(uint64_t previous,uint64_t current,uint64_t bit_mask)78 uint64_t UnsignedDelta(uint64_t previous, uint64_t current, uint64_t bit_mask) {
79   return (current - previous) & bit_mask;
80 }
81 
82 // Determines the encoding type (e.g. fixed-size encoding).
83 // Given an encoding type, may also distinguish between some variants of it
84 // (e.g. which fields of the fixed-size encoding are explicitly mentioned by
85 // the header, and which are implicitly assumed to hold certain default values).
86 enum class EncodingType {
87   kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt = 0,
88   kFixedSizeSignedDeltasEarlyWrapAndOptSupported = 1,
89   kReserved1 = 2,
90   kReserved2 = 3,
91   kNumberOfEncodingTypes  // Keep last
92 };
93 
94 // The width of each field in the encoding header. Note that this is the
95 // width in case the field exists; not all fields occur in all encoding types.
96 constexpr size_t kBitsInHeaderForEncodingType = 2;
97 constexpr size_t kBitsInHeaderForDeltaWidthBits = 6;
98 constexpr size_t kBitsInHeaderForSignedDeltas = 1;
99 constexpr size_t kBitsInHeaderForValuesOptional = 1;
100 constexpr size_t kBitsInHeaderForValueWidthBits = 6;
101 
102 static_assert(static_cast<size_t>(EncodingType::kNumberOfEncodingTypes) <=
103                   1 << kBitsInHeaderForEncodingType,
104               "Not all encoding types fit.");
105 
106 // Default values for when the encoding header does not specify explicitly.
107 constexpr bool kDefaultSignedDeltas = false;
108 constexpr bool kDefaultValuesOptional = false;
109 constexpr uint64_t kDefaultValueWidthBits = 64;
110 
111 // Parameters for fixed-size delta-encoding/decoding.
112 // These are tailored for the sequence which will be encoded (e.g. widths).
113 class FixedLengthEncodingParameters final {
114  public:
ValidParameters(uint64_t delta_width_bits,bool signed_deltas,bool values_optional,uint64_t value_width_bits)115   static bool ValidParameters(uint64_t delta_width_bits,
116                               bool signed_deltas,
117                               bool values_optional,
118                               uint64_t value_width_bits) {
119     return (1 <= delta_width_bits && delta_width_bits <= 64 &&
120             1 <= value_width_bits && value_width_bits <= 64 &&
121             delta_width_bits <= value_width_bits);
122   }
123 
FixedLengthEncodingParameters(uint64_t delta_width_bits,bool signed_deltas,bool values_optional,uint64_t value_width_bits)124   FixedLengthEncodingParameters(uint64_t delta_width_bits,
125                                 bool signed_deltas,
126                                 bool values_optional,
127                                 uint64_t value_width_bits)
128       : delta_width_bits_(delta_width_bits),
129         signed_deltas_(signed_deltas),
130         values_optional_(values_optional),
131         value_width_bits_(value_width_bits),
132         delta_mask_(MaxUnsignedValueOfBitWidth(delta_width_bits_)),
133         value_mask_(MaxUnsignedValueOfBitWidth(value_width_bits_)) {
134     RTC_DCHECK(ValidParameters(delta_width_bits, signed_deltas, values_optional,
135                                value_width_bits));
136   }
137 
138   // Number of bits necessary to hold the widest(*) of the deltas between the
139   // values in the sequence.
140   // (*) - Widest might not be the largest, if signed deltas are used.
delta_width_bits() const141   uint64_t delta_width_bits() const { return delta_width_bits_; }
142 
143   // Whether deltas are signed.
signed_deltas() const144   bool signed_deltas() const { return signed_deltas_; }
145 
146   // Whether the values of the sequence are optional. That is, it may be
147   // that some of them do not have a value (not even a sentinel value indicating
148   // invalidity).
values_optional() const149   bool values_optional() const { return values_optional_; }
150 
151   // Number of bits necessary to hold the largest value in the sequence.
value_width_bits() const152   uint64_t value_width_bits() const { return value_width_bits_; }
153 
154   // Masks where only the bits relevant to the deltas/values are turned on.
delta_mask() const155   uint64_t delta_mask() const { return delta_mask_; }
value_mask() const156   uint64_t value_mask() const { return value_mask_; }
157 
SetSignedDeltas(bool signed_deltas)158   void SetSignedDeltas(bool signed_deltas) { signed_deltas_ = signed_deltas; }
SetDeltaWidthBits(uint64_t delta_width_bits)159   void SetDeltaWidthBits(uint64_t delta_width_bits) {
160     delta_width_bits_ = delta_width_bits;
161     delta_mask_ = MaxUnsignedValueOfBitWidth(delta_width_bits);
162   }
163 
164  private:
165   uint64_t delta_width_bits_;  // Normally const, but mutable in tests.
166   bool signed_deltas_;         // Normally const, but mutable in tests.
167   const bool values_optional_;
168   const uint64_t value_width_bits_;
169 
170   uint64_t delta_mask_;  // Normally const, but mutable in tests.
171   const uint64_t value_mask_;
172 };
173 
174 // Performs delta-encoding of a single (non-empty) sequence of values, using
175 // an encoding where all deltas are encoded using the same number of bits.
176 // (With the exception of optional elements; those are encoded as a bit vector
177 // with one bit per element, plus a fixed number of bits for every element that
178 // has a value.)
179 class FixedLengthDeltaEncoder final {
180  public:
181   // See webrtc::EncodeDeltas() for general details.
182   // This function return a bit pattern that would allow the decoder to
183   // determine whether it was produced by FixedLengthDeltaEncoder, and can
184   // therefore be decoded by FixedLengthDeltaDecoder, or whether it was produced
185   // by a different encoder.
186   static std::string EncodeDeltas(
187       absl::optional<uint64_t> base,
188       const std::vector<absl::optional<uint64_t>>& values);
189 
190   FixedLengthDeltaEncoder(const FixedLengthDeltaEncoder&) = delete;
191   FixedLengthDeltaEncoder& operator=(const FixedLengthDeltaEncoder&) = delete;
192 
193  private:
194   // Calculate min/max values of unsigned/signed deltas, given the bit width
195   // of all the values in the series.
196   static void CalculateMinAndMaxDeltas(
197       absl::optional<uint64_t> base,
198       const std::vector<absl::optional<uint64_t>>& values,
199       uint64_t bit_width,
200       uint64_t* max_unsigned_delta,
201       uint64_t* max_pos_signed_delta,
202       uint64_t* min_neg_signed_delta);
203 
204   // No effect outside of unit tests.
205   // In unit tests, may lead to forcing signed/unsigned deltas, etc.
206   static void ConsiderTestOverrides(FixedLengthEncodingParameters* params,
207                                     uint64_t delta_width_bits_signed,
208                                     uint64_t delta_width_bits_unsigned);
209 
210   // FixedLengthDeltaEncoder objects are to be created by EncodeDeltas() and
211   // released by it before it returns. They're mostly a convenient way to
212   // avoid having to pass a lot of state between different functions.
213   // Therefore, it was deemed acceptable to let them have a reference to
214   // `values`, whose lifetime must exceed the lifetime of `this`.
215   FixedLengthDeltaEncoder(const FixedLengthEncodingParameters& params,
216                           absl::optional<uint64_t> base,
217                           const std::vector<absl::optional<uint64_t>>& values,
218                           size_t existent_values_count);
219 
220   // Perform delta-encoding using the parameters given to the ctor on the
221   // sequence of values given to the ctor.
222   std::string Encode();
223 
224   // Exact lengths.
225   size_t OutputLengthBytes(size_t existent_values_count) const;
226   size_t HeaderLengthBits() const;
227   size_t EncodedDeltasLengthBits(size_t existent_values_count) const;
228 
229   // Encode the compression parameters into the stream.
230   void EncodeHeader();
231 
232   // Encode a given delta into the stream.
233   void EncodeDelta(uint64_t previous, uint64_t current);
234   void EncodeUnsignedDelta(uint64_t previous, uint64_t current);
235   void EncodeSignedDelta(uint64_t previous, uint64_t current);
236 
237   // The parameters according to which encoding will be done (width of
238   // fields, whether signed deltas should be used, etc.)
239   const FixedLengthEncodingParameters params_;
240 
241   // The encoding scheme assumes that at least one value is transmitted OOB,
242   // so that the first value can be encoded as a delta from that OOB value,
243   // which is `base_`.
244   const absl::optional<uint64_t> base_;
245 
246   // The values to be encoded.
247   // Note: This is a non-owning reference. See comment above ctor for details.
248   const std::vector<absl::optional<uint64_t>>& values_;
249 
250   // Buffer into which encoded values will be written.
251   // This is created dynmically as a way to enforce that the rest of the
252   // ctor has finished running when this is constructed, so that the lower
253   // bound on the buffer size would be guaranteed correct.
254   std::unique_ptr<BitWriter> writer_;
255 };
256 
257 // TODO(eladalon): Reduce the number of passes.
EncodeDeltas(absl::optional<uint64_t> base,const std::vector<absl::optional<uint64_t>> & values)258 std::string FixedLengthDeltaEncoder::EncodeDeltas(
259     absl::optional<uint64_t> base,
260     const std::vector<absl::optional<uint64_t>>& values) {
261   RTC_DCHECK(!values.empty());
262 
263   // As a special case, if all of the elements are identical to the base,
264   // (including, for optional fields, about their existence/non-existence),
265   // the empty string is used to signal that.
266   if (std::all_of(
267           values.cbegin(), values.cend(),
268           [base](absl::optional<uint64_t> val) { return val == base; })) {
269     return std::string();
270   }
271 
272   bool non_decreasing = true;
273   uint64_t max_value_including_base = base.value_or(0u);
274   size_t existent_values_count = 0;
275   {
276     uint64_t previous = base.value_or(0u);
277     for (size_t i = 0; i < values.size(); ++i) {
278       if (!values[i].has_value()) {
279         continue;
280       }
281       ++existent_values_count;
282       non_decreasing &= (previous <= values[i].value());
283       max_value_including_base =
284           std::max(max_value_including_base, values[i].value());
285       previous = values[i].value();
286     }
287   }
288 
289   // If the sequence is non-decreasing, it may be assumed to have width = 64;
290   // there's no reason to encode the actual max width in the encoding header.
291   const uint64_t value_width_bits =
292       non_decreasing ? 64 : UnsignedBitWidth(max_value_including_base);
293 
294   uint64_t max_unsigned_delta;
295   uint64_t max_pos_signed_delta;
296   uint64_t min_neg_signed_delta;
297   CalculateMinAndMaxDeltas(base, values, value_width_bits, &max_unsigned_delta,
298                            &max_pos_signed_delta, &min_neg_signed_delta);
299 
300   const uint64_t delta_width_bits_unsigned =
301       UnsignedBitWidth(max_unsigned_delta);
302   const uint64_t delta_width_bits_signed =
303       SignedBitWidth(max_pos_signed_delta, min_neg_signed_delta);
304 
305   // Note: Preference for unsigned if the two have the same width (efficiency).
306   const bool signed_deltas =
307       delta_width_bits_signed < delta_width_bits_unsigned;
308   const uint64_t delta_width_bits =
309       signed_deltas ? delta_width_bits_signed : delta_width_bits_unsigned;
310 
311   const bool values_optional =
312       !base.has_value() || (existent_values_count < values.size());
313 
314   FixedLengthEncodingParameters params(delta_width_bits, signed_deltas,
315                                        values_optional, value_width_bits);
316 
317   // No effect in production.
318   ConsiderTestOverrides(&params, delta_width_bits_signed,
319                         delta_width_bits_unsigned);
320 
321   FixedLengthDeltaEncoder encoder(params, base, values, existent_values_count);
322   return encoder.Encode();
323 }
324 
CalculateMinAndMaxDeltas(absl::optional<uint64_t> base,const std::vector<absl::optional<uint64_t>> & values,uint64_t bit_width,uint64_t * max_unsigned_delta_out,uint64_t * max_pos_signed_delta_out,uint64_t * min_neg_signed_delta_out)325 void FixedLengthDeltaEncoder::CalculateMinAndMaxDeltas(
326     absl::optional<uint64_t> base,
327     const std::vector<absl::optional<uint64_t>>& values,
328     uint64_t bit_width,
329     uint64_t* max_unsigned_delta_out,
330     uint64_t* max_pos_signed_delta_out,
331     uint64_t* min_neg_signed_delta_out) {
332   RTC_DCHECK(!values.empty());
333   RTC_DCHECK(max_unsigned_delta_out);
334   RTC_DCHECK(max_pos_signed_delta_out);
335   RTC_DCHECK(min_neg_signed_delta_out);
336 
337   const uint64_t bit_mask = MaxUnsignedValueOfBitWidth(bit_width);
338 
339   uint64_t max_unsigned_delta = 0;
340   uint64_t max_pos_signed_delta = 0;
341   uint64_t min_neg_signed_delta = 0;
342 
343   absl::optional<uint64_t> prev = base;
344   for (size_t i = 0; i < values.size(); ++i) {
345     if (!values[i].has_value()) {
346       continue;
347     }
348 
349     if (!prev.has_value()) {
350       // If the base is non-existent, the first existent value is encoded as
351       // a varint, rather than as a delta.
352       RTC_DCHECK(!base.has_value());
353       prev = values[i];
354       continue;
355     }
356 
357     const uint64_t current = values[i].value();
358 
359     const uint64_t forward_delta = UnsignedDelta(*prev, current, bit_mask);
360     const uint64_t backward_delta = UnsignedDelta(current, *prev, bit_mask);
361 
362     max_unsigned_delta = std::max(max_unsigned_delta, forward_delta);
363 
364     if (forward_delta < backward_delta) {
365       max_pos_signed_delta = std::max(max_pos_signed_delta, forward_delta);
366     } else {
367       min_neg_signed_delta = std::max(min_neg_signed_delta, backward_delta);
368     }
369 
370     prev = current;
371   }
372 
373   *max_unsigned_delta_out = max_unsigned_delta;
374   *max_pos_signed_delta_out = max_pos_signed_delta;
375   *min_neg_signed_delta_out = min_neg_signed_delta;
376 }
377 
ConsiderTestOverrides(FixedLengthEncodingParameters * params,uint64_t delta_width_bits_signed,uint64_t delta_width_bits_unsigned)378 void FixedLengthDeltaEncoder::ConsiderTestOverrides(
379     FixedLengthEncodingParameters* params,
380     uint64_t delta_width_bits_signed,
381     uint64_t delta_width_bits_unsigned) {
382   if (g_force_unsigned_for_testing) {
383     params->SetDeltaWidthBits(delta_width_bits_unsigned);
384     params->SetSignedDeltas(false);
385   } else if (g_force_signed_for_testing) {
386     params->SetDeltaWidthBits(delta_width_bits_signed);
387     params->SetSignedDeltas(true);
388   } else {
389     // Unchanged.
390   }
391 }
392 
FixedLengthDeltaEncoder(const FixedLengthEncodingParameters & params,absl::optional<uint64_t> base,const std::vector<absl::optional<uint64_t>> & values,size_t existent_values_count)393 FixedLengthDeltaEncoder::FixedLengthDeltaEncoder(
394     const FixedLengthEncodingParameters& params,
395     absl::optional<uint64_t> base,
396     const std::vector<absl::optional<uint64_t>>& values,
397     size_t existent_values_count)
398     : params_(params), base_(base), values_(values) {
399   RTC_DCHECK(!values_.empty());
400   writer_ =
401       std::make_unique<BitWriter>(OutputLengthBytes(existent_values_count));
402 }
403 
Encode()404 std::string FixedLengthDeltaEncoder::Encode() {
405   EncodeHeader();
406 
407   if (params_.values_optional()) {
408     // Encode which values exist and which don't.
409     for (absl::optional<uint64_t> value : values_) {
410       writer_->WriteBits(value.has_value() ? 1u : 0u, 1);
411     }
412   }
413 
414   absl::optional<uint64_t> previous = base_;
415   for (absl::optional<uint64_t> value : values_) {
416     if (!value.has_value()) {
417       RTC_DCHECK(params_.values_optional());
418       continue;
419     }
420 
421     if (!previous.has_value()) {
422       // If the base is non-existent, the first existent value is encoded as
423       // a varint, rather than as a delta.
424       RTC_DCHECK(!base_.has_value());
425       writer_->WriteBits(EncodeVarInt(value.value()));
426     } else {
427       EncodeDelta(previous.value(), value.value());
428     }
429 
430     previous = value;
431   }
432 
433   return writer_->GetString();
434 }
435 
OutputLengthBytes(size_t existent_values_count) const436 size_t FixedLengthDeltaEncoder::OutputLengthBytes(
437     size_t existent_values_count) const {
438   return BitsToBytes(HeaderLengthBits() +
439                      EncodedDeltasLengthBits(existent_values_count));
440 }
441 
HeaderLengthBits() const442 size_t FixedLengthDeltaEncoder::HeaderLengthBits() const {
443   if (params_.signed_deltas() == kDefaultSignedDeltas &&
444       params_.values_optional() == kDefaultValuesOptional &&
445       params_.value_width_bits() == kDefaultValueWidthBits) {
446     return kBitsInHeaderForEncodingType + kBitsInHeaderForDeltaWidthBits;
447   } else {
448     return kBitsInHeaderForEncodingType + kBitsInHeaderForDeltaWidthBits +
449            kBitsInHeaderForSignedDeltas + kBitsInHeaderForValuesOptional +
450            kBitsInHeaderForValueWidthBits;
451   }
452 }
453 
EncodedDeltasLengthBits(size_t existent_values_count) const454 size_t FixedLengthDeltaEncoder::EncodedDeltasLengthBits(
455     size_t existent_values_count) const {
456   if (!params_.values_optional()) {
457     return values_.size() * params_.delta_width_bits();
458   } else {
459     RTC_DCHECK_EQ(std::count_if(values_.begin(), values_.end(),
460                                 [](absl::optional<uint64_t> val) {
461                                   return val.has_value();
462                                 }),
463                   existent_values_count);
464     // One bit for each delta, to indicate if the value exists, and delta_width
465     // for each existent value, to indicate the delta itself.
466     // If base_ is non-existent, the first value (if any) is encoded as a varint
467     // rather than as a delta.
468     const size_t existence_bitmap_size_bits = 1 * values_.size();
469     const bool first_value_is_varint =
470         !base_.has_value() && existent_values_count >= 1;
471     const size_t first_value_varint_size_bits = 8 * kMaxVarIntLengthBytes;
472     const size_t deltas_count = existent_values_count - first_value_is_varint;
473     const size_t deltas_size_bits = deltas_count * params_.delta_width_bits();
474     return existence_bitmap_size_bits + first_value_varint_size_bits +
475            deltas_size_bits;
476   }
477 }
478 
EncodeHeader()479 void FixedLengthDeltaEncoder::EncodeHeader() {
480   RTC_DCHECK(writer_);
481 
482   const EncodingType encoding_type =
483       (params_.value_width_bits() == kDefaultValueWidthBits &&
484        params_.signed_deltas() == kDefaultSignedDeltas &&
485        params_.values_optional() == kDefaultValuesOptional)
486           ? EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt
487           : EncodingType::kFixedSizeSignedDeltasEarlyWrapAndOptSupported;
488 
489   writer_->WriteBits(static_cast<uint64_t>(encoding_type),
490                      kBitsInHeaderForEncodingType);
491 
492   // Note: Since it's meaningless for a field to be of width 0, when it comes
493   // to fields that relate widths, we encode  width 1 as 0, width 2 as 1,
494 
495   writer_->WriteBits(params_.delta_width_bits() - 1,
496                      kBitsInHeaderForDeltaWidthBits);
497 
498   if (encoding_type == EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt) {
499     return;
500   }
501 
502   writer_->WriteBits(static_cast<uint64_t>(params_.signed_deltas()),
503                      kBitsInHeaderForSignedDeltas);
504   writer_->WriteBits(static_cast<uint64_t>(params_.values_optional()),
505                      kBitsInHeaderForValuesOptional);
506   writer_->WriteBits(params_.value_width_bits() - 1,
507                      kBitsInHeaderForValueWidthBits);
508 }
509 
EncodeDelta(uint64_t previous,uint64_t current)510 void FixedLengthDeltaEncoder::EncodeDelta(uint64_t previous, uint64_t current) {
511   if (params_.signed_deltas()) {
512     EncodeSignedDelta(previous, current);
513   } else {
514     EncodeUnsignedDelta(previous, current);
515   }
516 }
517 
EncodeUnsignedDelta(uint64_t previous,uint64_t current)518 void FixedLengthDeltaEncoder::EncodeUnsignedDelta(uint64_t previous,
519                                                   uint64_t current) {
520   RTC_DCHECK(writer_);
521   const uint64_t delta = UnsignedDelta(previous, current, params_.value_mask());
522   writer_->WriteBits(delta, params_.delta_width_bits());
523 }
524 
EncodeSignedDelta(uint64_t previous,uint64_t current)525 void FixedLengthDeltaEncoder::EncodeSignedDelta(uint64_t previous,
526                                                 uint64_t current) {
527   RTC_DCHECK(writer_);
528 
529   const uint64_t forward_delta =
530       UnsignedDelta(previous, current, params_.value_mask());
531   const uint64_t backward_delta =
532       UnsignedDelta(current, previous, params_.value_mask());
533 
534   uint64_t delta;
535   if (forward_delta <= backward_delta) {
536     delta = forward_delta;
537   } else {
538     // Compute the unsigned representation of a negative delta.
539     // This is the two's complement representation of this negative value,
540     // when deltas are of width params_.delta_mask().
541     RTC_DCHECK_GE(params_.delta_mask(), backward_delta);
542     RTC_DCHECK_LT(params_.delta_mask() - backward_delta, params_.delta_mask());
543     delta = params_.delta_mask() - backward_delta + 1;
544     RTC_DCHECK_LE(delta, params_.delta_mask());
545   }
546 
547   writer_->WriteBits(delta, params_.delta_width_bits());
548 }
549 
550 // Perform decoding of a a delta-encoded stream, extracting the original
551 // sequence of values.
552 class FixedLengthDeltaDecoder final {
553  public:
554   // Checks whether FixedLengthDeltaDecoder is a suitable decoder for this
555   // bitstream. Note that this does NOT imply that stream is valid, and will
556   // be decoded successfully. It DOES imply that all other decoder classes
557   // will fail to decode this input, though.
558   static bool IsSuitableDecoderFor(absl::string_view input);
559 
560   // Assuming that `input` is the result of fixed-size delta-encoding
561   // that took place with the same value to `base` and over `num_of_deltas`
562   // original values, this will return the sequence of original values.
563   // If an error occurs (can happen if `input` is corrupt), an empty
564   // vector will be returned.
565   static std::vector<absl::optional<uint64_t>> DecodeDeltas(
566       absl::string_view input,
567       absl::optional<uint64_t> base,
568       size_t num_of_deltas);
569 
570   FixedLengthDeltaDecoder(const FixedLengthDeltaDecoder&) = delete;
571   FixedLengthDeltaDecoder& operator=(const FixedLengthDeltaDecoder&) = delete;
572 
573  private:
574   // Reads the encoding header in `input` and returns a FixedLengthDeltaDecoder
575   // with the corresponding configuration, that can be used to decode the
576   // values in `input`.
577   // If the encoding header is corrupt (contains an illegal configuration),
578   // nullptr will be returned.
579   // When a valid FixedLengthDeltaDecoder is returned, this does not mean that
580   // the entire stream is free of error. Rather, only the encoding header is
581   // examined and guaranteed.
582   static std::unique_ptr<FixedLengthDeltaDecoder> Create(
583       absl::string_view input,
584       absl::optional<uint64_t> base,
585       size_t num_of_deltas);
586 
587   // FixedLengthDeltaDecoder objects are to be created by DecodeDeltas() and
588   // released by it before it returns. They're mostly a convenient way to
589   // avoid having to pass a lot of state between different functions.
590   // Therefore, it was deemed acceptable that `reader` does not own the buffer
591   // it reads, meaning the lifetime of `this` must not exceed the lifetime
592   // of `reader`'s underlying buffer.
593   FixedLengthDeltaDecoder(BitstreamReader reader,
594                           const FixedLengthEncodingParameters& params,
595                           absl::optional<uint64_t> base,
596                           size_t num_of_deltas);
597 
598   // Perform the decoding using the parameters given to the ctor.
599   std::vector<absl::optional<uint64_t>> Decode();
600 
601   // Add `delta` to `base` to produce the next value in a sequence.
602   // The delta is applied as signed/unsigned depending on the parameters
603   // given to the ctor. Wrap-around is taken into account according to the
604   // values' width, as specified by the aforementioned encoding parameters.
605   uint64_t ApplyDelta(uint64_t base, uint64_t delta) const;
606 
607   // Helpers for ApplyDelta().
608   uint64_t ApplyUnsignedDelta(uint64_t base, uint64_t delta) const;
609   uint64_t ApplySignedDelta(uint64_t base, uint64_t delta) const;
610 
611   // Reader of the input stream to be decoded. Does not own that buffer.
612   // See comment above ctor for details.
613   BitstreamReader reader_;
614 
615   // The parameters according to which encoding will be done (width of
616   // fields, whether signed deltas should be used, etc.)
617   const FixedLengthEncodingParameters params_;
618 
619   // The encoding scheme assumes that at least one value is transmitted OOB,
620   // so that the first value can be encoded as a delta from that OOB value,
621   // which is `base_`.
622   const absl::optional<uint64_t> base_;
623 
624   // The number of values to be known to be decoded.
625   const size_t num_of_deltas_;
626 };
627 
IsSuitableDecoderFor(absl::string_view input)628 bool FixedLengthDeltaDecoder::IsSuitableDecoderFor(absl::string_view input) {
629   BitstreamReader reader(input);
630   uint64_t encoding_type_bits = reader.ReadBits(kBitsInHeaderForEncodingType);
631   if (!reader.Ok()) {
632     return false;
633   }
634 
635   const auto encoding_type = static_cast<EncodingType>(encoding_type_bits);
636   return encoding_type ==
637              EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt ||
638          encoding_type ==
639              EncodingType::kFixedSizeSignedDeltasEarlyWrapAndOptSupported;
640 }
641 
DecodeDeltas(absl::string_view input,absl::optional<uint64_t> base,size_t num_of_deltas)642 std::vector<absl::optional<uint64_t>> FixedLengthDeltaDecoder::DecodeDeltas(
643     absl::string_view input,
644     absl::optional<uint64_t> base,
645     size_t num_of_deltas) {
646   auto decoder = FixedLengthDeltaDecoder::Create(input, base, num_of_deltas);
647   if (!decoder) {
648     return std::vector<absl::optional<uint64_t>>();
649   }
650 
651   return decoder->Decode();
652 }
653 
Create(absl::string_view input,absl::optional<uint64_t> base,size_t num_of_deltas)654 std::unique_ptr<FixedLengthDeltaDecoder> FixedLengthDeltaDecoder::Create(
655     absl::string_view input,
656     absl::optional<uint64_t> base,
657     size_t num_of_deltas) {
658   BitstreamReader reader(input);
659   // Encoding type
660   uint32_t encoding_type_bits = reader.ReadBits(kBitsInHeaderForEncodingType);
661   if (!reader.Ok()) {
662     return nullptr;
663   }
664 
665   const EncodingType encoding = static_cast<EncodingType>(encoding_type_bits);
666   if (encoding != EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt &&
667       encoding !=
668           EncodingType::kFixedSizeSignedDeltasEarlyWrapAndOptSupported) {
669     RTC_LOG(LS_WARNING) << "Unrecognized encoding type.";
670     return nullptr;
671   }
672 
673   // See encoding for +1's rationale.
674   const uint64_t delta_width_bits =
675       reader.ReadBits(kBitsInHeaderForDeltaWidthBits) + 1;
676   RTC_DCHECK_LE(delta_width_bits, 64);
677 
678   // signed_deltas, values_optional, value_width_bits
679   bool signed_deltas;
680   bool values_optional;
681   uint64_t value_width_bits;
682   if (encoding == EncodingType::kFixedSizeUnsignedDeltasNoEarlyWrapNoOpt) {
683     signed_deltas = kDefaultSignedDeltas;
684     values_optional = kDefaultValuesOptional;
685     value_width_bits = kDefaultValueWidthBits;
686   } else {
687     signed_deltas = reader.Read<bool>();
688     values_optional = reader.Read<bool>();
689     // See encoding for +1's rationale.
690     value_width_bits = reader.ReadBits(kBitsInHeaderForValueWidthBits) + 1;
691     RTC_DCHECK_LE(value_width_bits, 64);
692   }
693 
694   if (!reader.Ok()) {
695     return nullptr;
696   }
697 
698   // Note: Because of the way the parameters are read, it is not possible
699   // for illegal values to be read. We check nevertheless, in case the code
700   // changes in the future in a way that breaks this promise.
701   if (!FixedLengthEncodingParameters::ValidParameters(
702           delta_width_bits, signed_deltas, values_optional, value_width_bits)) {
703     RTC_LOG(LS_WARNING) << "Corrupt log; illegal encoding parameters.";
704     return nullptr;
705   }
706 
707   FixedLengthEncodingParameters params(delta_width_bits, signed_deltas,
708                                        values_optional, value_width_bits);
709   return absl::WrapUnique(
710       new FixedLengthDeltaDecoder(reader, params, base, num_of_deltas));
711 }
712 
FixedLengthDeltaDecoder(BitstreamReader reader,const FixedLengthEncodingParameters & params,absl::optional<uint64_t> base,size_t num_of_deltas)713 FixedLengthDeltaDecoder::FixedLengthDeltaDecoder(
714     BitstreamReader reader,
715     const FixedLengthEncodingParameters& params,
716     absl::optional<uint64_t> base,
717     size_t num_of_deltas)
718     : reader_(reader),
719       params_(params),
720       base_(base),
721       num_of_deltas_(num_of_deltas) {
722   RTC_DCHECK(reader_.Ok());
723 }
724 
Decode()725 std::vector<absl::optional<uint64_t>> FixedLengthDeltaDecoder::Decode() {
726   RTC_DCHECK(reader_.Ok());
727   std::vector<bool> existing_values(num_of_deltas_);
728   if (params_.values_optional()) {
729     for (size_t i = 0; i < num_of_deltas_; ++i) {
730       existing_values[i] = reader_.Read<bool>();
731     }
732   } else {
733     std::fill(existing_values.begin(), existing_values.end(), true);
734   }
735 
736   absl::optional<uint64_t> previous = base_;
737   std::vector<absl::optional<uint64_t>> values(num_of_deltas_);
738 
739   for (size_t i = 0; i < num_of_deltas_; ++i) {
740     if (!existing_values[i]) {
741       RTC_DCHECK(params_.values_optional());
742       continue;
743     }
744 
745     if (!previous) {
746       // If the base is non-existent, the first existent value is encoded as
747       // a varint, rather than as a delta.
748       RTC_DCHECK(!base_.has_value());
749       values[i] = DecodeVarInt(reader_);
750     } else {
751       uint64_t delta = reader_.ReadBits(params_.delta_width_bits());
752       values[i] = ApplyDelta(*previous, delta);
753     }
754 
755     previous = values[i];
756   }
757 
758   if (!reader_.Ok()) {
759     values = {};
760   }
761 
762   return values;
763 }
764 
ApplyDelta(uint64_t base,uint64_t delta) const765 uint64_t FixedLengthDeltaDecoder::ApplyDelta(uint64_t base,
766                                              uint64_t delta) const {
767   RTC_DCHECK_LE(base, MaxUnsignedValueOfBitWidth(params_.value_width_bits()));
768   RTC_DCHECK_LE(delta, MaxUnsignedValueOfBitWidth(params_.delta_width_bits()));
769   return params_.signed_deltas() ? ApplySignedDelta(base, delta)
770                                  : ApplyUnsignedDelta(base, delta);
771 }
772 
ApplyUnsignedDelta(uint64_t base,uint64_t delta) const773 uint64_t FixedLengthDeltaDecoder::ApplyUnsignedDelta(uint64_t base,
774                                                      uint64_t delta) const {
775   // Note: May still be used if signed deltas used.
776   RTC_DCHECK_LE(base, MaxUnsignedValueOfBitWidth(params_.value_width_bits()));
777   RTC_DCHECK_LE(delta, MaxUnsignedValueOfBitWidth(params_.delta_width_bits()));
778   return (base + delta) & params_.value_mask();
779 }
780 
ApplySignedDelta(uint64_t base,uint64_t delta) const781 uint64_t FixedLengthDeltaDecoder::ApplySignedDelta(uint64_t base,
782                                                    uint64_t delta) const {
783   RTC_DCHECK(params_.signed_deltas());
784   RTC_DCHECK_LE(base, MaxUnsignedValueOfBitWidth(params_.value_width_bits()));
785   RTC_DCHECK_LE(delta, MaxUnsignedValueOfBitWidth(params_.delta_width_bits()));
786 
787   const uint64_t top_bit = static_cast<uint64_t>(1)
788                            << (params_.delta_width_bits() - 1);
789 
790   const bool positive_delta = ((delta & top_bit) == 0);
791   if (positive_delta) {
792     return ApplyUnsignedDelta(base, delta);
793   }
794 
795   const uint64_t delta_abs = (~delta & params_.delta_mask()) + 1;
796   return (base - delta_abs) & params_.value_mask();
797 }
798 
799 }  // namespace
800 
EncodeDeltas(absl::optional<uint64_t> base,const std::vector<absl::optional<uint64_t>> & values)801 std::string EncodeDeltas(absl::optional<uint64_t> base,
802                          const std::vector<absl::optional<uint64_t>>& values) {
803   // TODO(eladalon): Support additional encodings.
804   return FixedLengthDeltaEncoder::EncodeDeltas(base, values);
805 }
806 
DecodeDeltas(absl::string_view input,absl::optional<uint64_t> base,size_t num_of_deltas)807 std::vector<absl::optional<uint64_t>> DecodeDeltas(
808     absl::string_view input,
809     absl::optional<uint64_t> base,
810     size_t num_of_deltas) {
811   RTC_DCHECK_GT(num_of_deltas, 0);  // Allows empty vector to indicate error.
812 
813   // The empty string is a special case indicating that all values were equal
814   // to the base.
815   if (input.empty()) {
816     std::vector<absl::optional<uint64_t>> result(num_of_deltas);
817     std::fill(result.begin(), result.end(), base);
818     return result;
819   }
820 
821   if (FixedLengthDeltaDecoder::IsSuitableDecoderFor(input)) {
822     return FixedLengthDeltaDecoder::DecodeDeltas(input, base, num_of_deltas);
823   }
824 
825   RTC_LOG(LS_WARNING) << "Could not decode delta-encoded stream.";
826   return std::vector<absl::optional<uint64_t>>();
827 }
828 
SetFixedLengthEncoderDeltaSignednessForTesting(bool signedness)829 void SetFixedLengthEncoderDeltaSignednessForTesting(bool signedness) {
830   g_force_unsigned_for_testing = !signedness;
831   g_force_signed_for_testing = signedness;
832 }
833 
UnsetFixedLengthEncoderDeltaSignednessForTesting()834 void UnsetFixedLengthEncoderDeltaSignednessForTesting() {
835   g_force_unsigned_for_testing = false;
836   g_force_signed_for_testing = false;
837 }
838 
839 }  // namespace webrtc
840