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>
ToUnsigned(T y)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
58 // Assuming x = ToUnsigned(y), return `y`.
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>
ToSigned(uint64_t x,T * y)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)) {
77 return false; // `x` cannot be represented using a T.
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_
94