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