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