blob: c167a8eb8fdc3aa6a0a333898a10905ab2d7c4f5 [file] [log] [blame]
Elad Alond95b0a22018-11-09 15:38:541/*
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
19namespace 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.
24uint32_t ConvertPacketLossFractionToProtoFormat(float packet_loss_fraction);
25bool ParsePacketLossFractionFromProtoFormat(uint32_t proto_packet_loss_fraction,
26 float* output);
27
28} // namespace webrtc
29
30namespace 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))
35template <typename T>
36uint64_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 Titovaf9a3c62021-07-30 12:22:5558// Assuming x = ToUnsigned(y), return `y`.
Elad Alond95b0a22018-11-09 15:38:5459// 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.
63template <typename T>
64bool 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 Titovaf9a3c62021-07-30 12:22:5577 return false; // `x` cannot be represented using a T.
Elad Alond95b0a22018-11-09 15:38:5478 }
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_