Elad Alon | d95b0a2 | 2018-11-09 15:38:54 | [diff] [blame] | 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 | #ifndef LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_COMMON_H_ |
| 12 | #define LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_COMMON_H_ |
| 13 | |
| 14 | #include <stdint.h> |
| 15 | |
| 16 | #include <limits> |
| 17 | #include <type_traits> |
| 18 | |
| 19 | namespace webrtc { |
| 20 | |
| 21 | // Convert between the packet fraction loss (a floating point number in |
| 22 | // the range [0.0, 1.0]), and a uint32_t with up to a fixed number of bits. |
| 23 | // The latter can be more efficiently stored in a protobuf and/or delta-encoded. |
| 24 | uint32_t ConvertPacketLossFractionToProtoFormat(float packet_loss_fraction); |
| 25 | bool ParsePacketLossFractionFromProtoFormat(uint32_t proto_packet_loss_fraction, |
| 26 | float* output); |
| 27 | |
| 28 | } // namespace webrtc |
| 29 | |
| 30 | namespace webrtc_event_logging { |
| 31 | |
| 32 | // Produce an unsigned representation of a signed integer. On two's complement |
| 33 | // machines, this is equivalent to: |
| 34 | // static_cast<uint64_t>(static_cast<std::make_unsigned<T>>(y)) |
| 35 | template <typename T> |
| 36 | uint64_t ToUnsigned(T y) { |
| 37 | static_assert(std::is_integral<T>::value, ""); |
| 38 | static_assert(std::is_signed<T>::value, ""); |
| 39 | |
| 40 | // Note that a signed integer whose width is N bits, has N-1 digits. |
| 41 | static_assert(std::numeric_limits<T>::digits < 64, ""); |
| 42 | |
| 43 | constexpr T MIN_T = std::numeric_limits<T>::min(); |
| 44 | constexpr T MAX_T = std::numeric_limits<T>::max(); |
| 45 | |
| 46 | static_assert(MAX_T + MIN_T + 1 >= 0, "MAX_T >= abs(MIN_T) - 1"); |
| 47 | |
| 48 | if (y >= 0) { |
| 49 | return static_cast<uint64_t>(y); |
| 50 | } else { |
| 51 | // y is in the range [MIN_T, -1], so (y - MIN_T) is in the |
| 52 | // range [0, abs(MIN_T) - 1]. This is representable in a T |
| 53 | // because MAX_T >= abs(MIN_T) - 1, as per the static_assert above. |
| 54 | return static_cast<uint64_t>(MAX_T) + 1 + static_cast<uint64_t>(y - MIN_T); |
| 55 | } |
| 56 | } |
| 57 | |
Artem Titov | af9a3c6 | 2021-07-30 12:22:55 | [diff] [blame] | 58 | // Assuming x = ToUnsigned(y), return `y`. |
Elad Alon | d95b0a2 | 2018-11-09 15:38:54 | [diff] [blame] | 59 | // Note: static_cast<T>(x) would work on most platforms and compilers, but |
| 60 | // involves undefined behavior. This function is well-defined, and can be |
| 61 | // optimized to a noop for 64 bit types, or a few arithmetic |
| 62 | // instructions and a single conditional jump for narrower types. |
| 63 | template <typename T> |
| 64 | bool ToSigned(uint64_t x, T* y) { |
| 65 | static_assert(std::is_integral<T>::value, ""); |
| 66 | static_assert(std::is_signed<T>::value, ""); |
| 67 | |
| 68 | // Note that a signed integer whose width is N bits, has N-1 digits. |
| 69 | static_assert(std::numeric_limits<T>::digits < 64, ""); |
| 70 | |
| 71 | constexpr T MIN_T = std::numeric_limits<T>::min(); |
| 72 | constexpr T MAX_T = std::numeric_limits<T>::max(); |
| 73 | |
| 74 | using UNSIGNED_T = typename std::make_unsigned<T>::type; |
| 75 | constexpr auto MAX_UNSIGNED_T = std::numeric_limits<UNSIGNED_T>::max(); |
| 76 | if (x > static_cast<uint64_t>(MAX_UNSIGNED_T)) { |
Artem Titov | af9a3c6 | 2021-07-30 12:22:55 | [diff] [blame] | 77 | return false; // `x` cannot be represented using a T. |
Elad Alon | d95b0a2 | 2018-11-09 15:38:54 | [diff] [blame] | 78 | } |
| 79 | |
| 80 | if (x <= static_cast<uint64_t>(MAX_T)) { |
| 81 | // The original value was positive, so it is safe to just static_cast. |
| 82 | *y = static_cast<T>(x); |
| 83 | } else { // x > static_cast<uint64_t>(MAX_T) |
| 84 | const uint64_t neg_x = x - static_cast<uint64_t>(MAX_T) - 1; |
| 85 | *y = static_cast<T>(neg_x) + MIN_T; |
| 86 | } |
| 87 | |
| 88 | return true; |
| 89 | } |
| 90 | |
| 91 | } // namespace webrtc_event_logging |
| 92 | |
| 93 | #endif // LOGGING_RTC_EVENT_LOG_ENCODER_RTC_EVENT_LOG_ENCODER_COMMON_H_ |