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(¶ms, 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