OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 24 matching lines...) Expand all Loading... | |
35 // These classes are implemented as recursive templetizations, inteded to make | 35 // These classes are implemented as recursive templetizations, inteded to make |
36 // it easy for the compiler to completely inline the reading/writing. | 36 // it easy for the compiler to completely inline the reading/writing. |
37 | 37 |
38 | 38 |
39 #include <limits> | 39 #include <limits> |
40 | 40 |
41 #include "webrtc/typedefs.h" | 41 #include "webrtc/typedefs.h" |
42 | 42 |
43 namespace webrtc { | 43 namespace webrtc { |
44 | 44 |
45 // According to ISO C standard ISO/IEC 9899, section 6.2.6.2 (2), the three | |
46 // representations of signed integers allowed are two's complement, one's | |
47 // complement and sign/magnitude. We can detect which is used by looking at | |
48 // the two last bits of -1, which will be 11 in two's complement, 10 in one's | |
49 // complement and 01 in sign/magnitude. | |
50 // TODO(sprang): In the unlikely event that we actually need to support a | |
51 // platform that doesn't use two's complement, implement conversion to/from | |
52 // wire format. | |
53 | |
54 namespace { | |
55 inline void AssertTwosComplement() { | |
56 // Assume the if any one signed integer type is two's complement, then all | |
57 // other will be too. | |
58 static_assert( | |
59 (-1 & 0x03) == 0x03, | |
60 "Only two's complement representation of signed integers supported."); | |
61 } | |
62 // Plain const char* won't work for static_assert, use #define instead. | |
63 #define kSizeErrorMsg "Byte size must be less than or equal to data type size." | |
64 } | |
65 | |
66 // Utility class for getting the unsigned equivalent of a signed type. | |
67 template <typename T> | |
68 struct UnsignedOf; | |
69 | |
45 // Class for reading integers from a sequence of bytes. | 70 // Class for reading integers from a sequence of bytes. |
46 // T = type of integer, B = bytes to read, is_signed = true if signed integer | 71 // T = type of integer, B = bytes to read, is_signed = true if signed integer. |
47 // If is_signed is true and B < sizeof(T), sign extension might be needed | 72 // If is_signed is true and B < sizeof(T), sign extension might be needed. |
48 template<typename T, unsigned int B = sizeof(T), | 73 template <typename T, |
49 bool is_signed = std::numeric_limits<T>::is_signed> | 74 unsigned int B = sizeof(T), |
50 class ByteReader { | 75 bool is_signed = std::numeric_limits<T>::is_signed> |
76 class ByteReader; | |
77 | |
78 // Specialization of ByteReader for unsigned types. | |
79 template <typename T, unsigned int B> | |
80 class ByteReader<T, B, false> { | |
51 public: | 81 public: |
52 static T ReadBigEndian(const uint8_t* data) { | 82 static T ReadBigEndian(const uint8_t* data) { |
53 if (is_signed && B < sizeof(T)) { | 83 static_assert(B <= sizeof(T), kSizeErrorMsg); |
54 return SignExtend(InternalReadBigEndian(data)); | |
55 } | |
56 return InternalReadBigEndian(data); | 84 return InternalReadBigEndian(data); |
57 } | 85 } |
58 | 86 |
59 static T ReadLittleEndian(const uint8_t* data) { | 87 static T ReadLittleEndian(const uint8_t* data) { |
60 if (is_signed && B < sizeof(T)) { | 88 static_assert(B <= sizeof(T), kSizeErrorMsg); |
61 return SignExtend(InternalReadLittleEndian(data)); | |
62 } | |
63 return InternalReadLittleEndian(data); | 89 return InternalReadLittleEndian(data); |
64 } | 90 } |
65 | 91 |
66 private: | 92 private: |
67 static T InternalReadBigEndian(const uint8_t* data) { | 93 static T InternalReadBigEndian(const uint8_t* data) { |
68 T val(0); | 94 T val(0); |
69 for (unsigned int i = 0; i < B; ++i) { | 95 for (unsigned int i = 0; i < B; ++i) |
70 val |= static_cast<T>(data[i]) << ((B - 1 - i) * 8); | 96 val |= static_cast<T>(data[i]) << ((B - 1 - i) * 8); |
71 } | |
72 return val; | 97 return val; |
73 } | 98 } |
74 | 99 |
75 static T InternalReadLittleEndian(const uint8_t* data) { | 100 static T InternalReadLittleEndian(const uint8_t* data) { |
76 T val(0); | 101 T val(0); |
77 for (unsigned int i = 0; i < B; ++i) { | 102 for (unsigned int i = 0; i < B; ++i) |
78 val |= static_cast<T>(data[i]) << (i * 8); | 103 val |= static_cast<T>(data[i]) << (i * 8); |
104 return val; | |
105 } | |
106 }; | |
107 | |
108 // Specialization of ByteReader for signed types. | |
109 template <typename T, unsigned int B> | |
110 class ByteReader<T, B, true> { | |
111 public: | |
112 typedef typename UnsignedOf<T>::Type U; | |
113 | |
114 static T ReadBigEndian(const uint8_t* data) { | |
115 U unsigned_val = ByteReader<T, B, false>::ReadBigEndian(data); | |
116 if (B < sizeof(T)) | |
117 unsigned_val = SignExtend(unsigned_val); | |
118 return ReinterpretAsSigned(unsigned_val); | |
119 } | |
120 | |
121 static T ReadLittleEndian(const uint8_t* data) { | |
122 U unsigned_val = ByteReader<T, B, false>::ReadLittleEndian(data); | |
123 if (B < sizeof(T)) | |
124 unsigned_val = SignExtend(unsigned_val); | |
125 return ReinterpretAsSigned(unsigned_val); | |
126 } | |
127 | |
128 private: | |
129 // As a hack to avoid implementation-specific or undefined behavior when | |
130 // bit-shifting or casting signed integers, read as a signed equivalent | |
131 // instead and convert to signed. This is safe since we have asserted that | |
132 // two's complement for is used. | |
133 static T ReinterpretAsSigned(U unsigned_val) { | |
134 // An unsigned value with only the highest order bit set (ex 0x80). | |
135 const U kUnsignedHighestBitMask = | |
136 static_cast<U>(1) << ((sizeof(U) * 8) - 1); | |
137 // A signed value with only the highest bit set. Since this is two's | |
138 // complement form, we can use the min value from std::numeric_limits. | |
139 const T kSignedHighestBitMask = std::numeric_limits<T>::min(); | |
140 | |
141 T val; | |
142 if ((unsigned_val & kUnsignedHighestBitMask) != 0) { | |
143 // Casting is only safe when unsigned value can be represented in the | |
144 // signed target type, so mask out highest bit and mask it back manually. | |
145 val = static_cast<T>(unsigned_val & ~kUnsignedHighestBitMask); | |
146 val |= kSignedHighestBitMask; | |
147 } else { | |
148 val = static_cast<T>(unsigned_val); | |
79 } | 149 } |
80 return val; | 150 return val; |
81 } | 151 } |
82 | 152 |
83 // If number of bytes is less than native data type (eg 24 bit, in int32_t), | 153 // If number of bytes is less than native data type (eg 24 bit, in int32_t), |
84 // and the most significant bit of the actual data is set, we must sign | 154 // and the most significant bit of the actual data is set, we must sign |
85 // extend the remaining byte(s) with ones so that the correct negative | 155 // extend the remaining byte(s) with ones so that the correct negative |
86 // number is retained. | 156 // number is retained. |
87 // Ex: 0x810A0B -> 0xFF810A0B, but 0x710A0B -> 0x00710A0B | 157 // Ex: 0x810A0B -> 0xFF810A0B, but 0x710A0B -> 0x00710A0B |
88 static T SignExtend(const T val) { | 158 static U SignExtend(const U val) { |
89 uint8_t msb = static_cast<uint8_t>(val >> ((B - 1) * 8)); | 159 const uint8_t kMsb = static_cast<uint8_t>(val >> ((B - 1) * 8)); |
90 if (msb & 0x80) { | 160 if ((kMsb & 0x80) != 0) { |
91 // Sign extension is -1 (all ones) shifted left B bytes. | 161 // Create a mask where all bits used by the B bytes are set to one, |
92 // The "B % sizeof(T)"-part is there to avoid compiler warning for | 162 // for instance 0x00FFFFFF for B = 3. Bit-wise invert that mask (to |
93 // shifting the whole size of the data type. | 163 // (0xFF000000 in the example above) and add it to the input value. |
94 T sign_extend = (sizeof(T) == B ? 0 : | 164 // The "B % sizeof(T)" is a workaround to undefined values warnings for |
95 (static_cast<T>(-1L) << ((B % sizeof(T)) * 8))); | 165 // B == sizeof(T), in which case this code won't be called anyway. |
96 | 166 const U kUsedBitsMask = (1 << ((B % sizeof(T)) * 8)) - 1; |
97 return val | sign_extend; | 167 return ~kUsedBitsMask | val; |
98 } | 168 } |
99 return val; | 169 return val; |
100 } | 170 } |
101 }; | 171 }; |
102 | 172 |
103 // Class for writing integers to a sequence of bytes | 173 // Class for writing integers to a sequence of bytes |
104 // T = type of integer, B = bytes to write | 174 // T = type of integer, B = bytes to write |
105 template<typename T, unsigned int B = sizeof(T)> | 175 template <typename T, |
106 class ByteWriter { | 176 unsigned int B = sizeof(T), |
177 bool is_signed = std::numeric_limits<T>::is_signed> | |
178 class ByteWriter; | |
179 | |
180 // Specialization of ByteWriter for unsigned types. | |
181 template <typename T, unsigned int B> | |
182 class ByteWriter<T, B, false> { | |
107 public: | 183 public: |
108 static void WriteBigEndian(uint8_t* data, T val) { | 184 static void WriteBigEndian(uint8_t* data, T val) { |
185 static_assert(B <= sizeof(T), kSizeErrorMsg); | |
109 for (unsigned int i = 0; i < B; ++i) { | 186 for (unsigned int i = 0; i < B; ++i) { |
110 data[i] = val >> ((B - 1 - i) * 8); | 187 data[i] = val >> ((B - 1 - i) * 8); |
111 } | 188 } |
112 } | 189 } |
113 | 190 |
114 static void WriteLittleEndian(uint8_t* data, T val) { | 191 static void WriteLittleEndian(uint8_t* data, T val) { |
192 static_assert(B <= sizeof(T), kSizeErrorMsg); | |
115 for (unsigned int i = 0; i < B; ++i) { | 193 for (unsigned int i = 0; i < B; ++i) { |
116 data[i] = val >> (i * 8); | 194 data[i] = val >> (i * 8); |
117 } | 195 } |
118 } | 196 } |
119 }; | 197 }; |
120 | 198 |
199 // Specialization of ByteWriter for signed types. | |
200 template <typename T, unsigned int B> | |
201 class ByteWriter<T, B, true> { | |
202 public: | |
203 typedef typename UnsignedOf<T>::Type U; | |
121 | 204 |
122 // -------- Below follows specializations for B in { 2, 4, 8 } -------- | 205 static void WriteBigEndian(uint8_t* data, T val) { |
206 ByteWriter<U, B, false>::WriteBigEndian(data, ReinterpretAsUnsigned(val)); | |
207 } | |
123 | 208 |
209 static void WriteLittleEndian(uint8_t* data, T val) { | |
210 ByteWriter<U, B, false>::WriteLittleEndian(data, | |
211 ReinterpretAsUnsigned(val)); | |
212 } | |
213 | |
214 private: | |
215 static U ReinterpretAsUnsigned(T val) { | |
216 // According to ISO C standard ISO/IEC 9899, section 6.3.1.3 (1, 2) a | |
217 // conversion from signed to unsigned keeps the value if the new type can | |
218 // represent it, and otherwise adds one more than the max value of T until | |
219 // the value is in range. For two's complement, this fortunately means | |
220 // that the bit-wise value will be intact. Thus, since we have asserted that | |
221 // two's complement form is actually used, a simple cast is sufficient. | |
222 return static_cast<U>(val); | |
223 } | |
224 }; | |
225 | |
226 // ----- Below follows specializations of UnsignedOf utility class ----- | |
227 | |
228 template <> | |
229 struct UnsignedOf<int8_t> { | |
230 typedef uint8_t Type; | |
231 }; | |
232 template <> | |
233 struct UnsignedOf<int16_t> { | |
234 typedef uint16_t Type; | |
235 }; | |
236 template <> | |
237 struct UnsignedOf<int32_t> { | |
238 typedef uint32_t Type; | |
239 }; | |
240 template <> | |
241 struct UnsignedOf<int64_t> { | |
242 typedef uint64_t Type; | |
243 }; | |
244 | |
245 // ----- Below follows specializations for unsigned, B in { 1, 2, 4, 8 } ----- | |
246 | |
247 // TODO(sprang): Check if these actually help or if generic cases will be | |
pbos-webrtc
2015/09/03 15:18:08
Do you want to add these before you know that it's
sprang_webrtc
2015/09/04 07:24:06
With this comment I meant all the specializations
| |
248 // unrolled to and optimized to similar performance. | |
249 | |
250 // Specializations for single bytes | |
251 template <typename T> | |
252 class ByteReader<T, 1, false> { | |
253 public: | |
254 static T ReadBigEndian(const uint8_t* data) { | |
255 static_assert(sizeof(T) == 1, kSizeErrorMsg); | |
256 return data[0]; | |
257 } | |
258 | |
259 static T ReadLittleEndian(const uint8_t* data) { | |
260 static_assert(sizeof(T) == 1, kSizeErrorMsg); | |
261 return data[0]; | |
262 } | |
263 }; | |
264 | |
265 template <typename T> | |
266 class ByteWriter<T, 1, false> { | |
267 public: | |
268 static void WriteBigEndian(uint8_t* data, T val) { | |
269 static_assert(sizeof(T) == 1, kSizeErrorMsg); | |
270 data[0] = val; | |
271 } | |
272 | |
273 static void WriteLittleEndian(uint8_t* data, T val) { | |
274 static_assert(sizeof(T) == 1, kSizeErrorMsg); | |
275 data[0] = val; | |
276 } | |
277 }; | |
124 | 278 |
125 // Specializations for two byte words | 279 // Specializations for two byte words |
126 template<typename T, bool is_signed> | 280 template <typename T> |
127 class ByteReader<T, 2, is_signed> { | 281 class ByteReader<T, 2, false> { |
128 public: | 282 public: |
129 static T ReadBigEndian(const uint8_t* data) { | 283 static T ReadBigEndian(const uint8_t* data) { |
284 static_assert(sizeof(T) >= 2, kSizeErrorMsg); | |
130 return (data[0] << 8) | data[1]; | 285 return (data[0] << 8) | data[1]; |
131 } | 286 } |
132 | 287 |
133 static T ReadLittleEndian(const uint8_t* data) { | 288 static T ReadLittleEndian(const uint8_t* data) { |
289 static_assert(sizeof(T) >= 2, kSizeErrorMsg); | |
134 return data[0] | (data[1] << 8); | 290 return data[0] | (data[1] << 8); |
135 } | 291 } |
136 }; | 292 }; |
137 | 293 |
138 template<typename T> | 294 template <typename T> |
139 class ByteWriter<T, 2> { | 295 class ByteWriter<T, 2, false> { |
140 public: | 296 public: |
141 static void WriteBigEndian(uint8_t* data, T val) { | 297 static void WriteBigEndian(uint8_t* data, T val) { |
298 static_assert(sizeof(T) >= 2, kSizeErrorMsg); | |
142 data[0] = val >> 8; | 299 data[0] = val >> 8; |
143 data[1] = val; | 300 data[1] = val; |
144 } | 301 } |
145 | 302 |
146 static void WriteLittleEndian(uint8_t* data, T val) { | 303 static void WriteLittleEndian(uint8_t* data, T val) { |
304 static_assert(sizeof(T) >= 2, kSizeErrorMsg); | |
147 data[0] = val; | 305 data[0] = val; |
148 data[1] = val >> 8; | 306 data[1] = val >> 8; |
149 } | 307 } |
150 }; | 308 }; |
151 | 309 |
152 // Specializations for four byte words. | 310 // Specializations for four byte words. |
153 template<typename T, bool is_signed> | 311 template <typename T> |
154 class ByteReader<T, 4, is_signed> { | 312 class ByteReader<T, 4, false> { |
155 public: | 313 public: |
156 static T ReadBigEndian(const uint8_t* data) { | 314 static T ReadBigEndian(const uint8_t* data) { |
315 static_assert(sizeof(T) >= 4, kSizeErrorMsg); | |
157 return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; | 316 return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; |
158 } | 317 } |
159 | 318 |
160 static T ReadLittleEndian(const uint8_t* data) { | 319 static T ReadLittleEndian(const uint8_t* data) { |
320 static_assert(sizeof(T) >= 4, kSizeErrorMsg); | |
161 return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | 321 return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); |
162 } | 322 } |
163 }; | 323 }; |
164 | 324 |
165 // Specializations for four byte words. | 325 // Specializations for four byte words. |
166 template<typename T> | 326 template <typename T> |
167 class ByteWriter<T, 4> { | 327 class ByteWriter<T, 4, false> { |
168 public: | 328 public: |
169 static void WriteBigEndian(uint8_t* data, T val) { | 329 static void WriteBigEndian(uint8_t* data, T val) { |
330 static_assert(sizeof(T) >= 4, kSizeErrorMsg); | |
170 data[0] = val >> 24; | 331 data[0] = val >> 24; |
171 data[1] = val >> 16; | 332 data[1] = val >> 16; |
172 data[2] = val >> 8; | 333 data[2] = val >> 8; |
173 data[3] = val; | 334 data[3] = val; |
174 } | 335 } |
175 | 336 |
176 static void WriteLittleEndian(uint8_t* data, T val) { | 337 static void WriteLittleEndian(uint8_t* data, T val) { |
338 static_assert(sizeof(T) >= 4, kSizeErrorMsg); | |
177 data[0] = val; | 339 data[0] = val; |
178 data[1] = val >> 8; | 340 data[1] = val >> 8; |
179 data[2] = val >> 16; | 341 data[2] = val >> 16; |
180 data[3] = val >> 24; | 342 data[3] = val >> 24; |
181 } | 343 } |
182 }; | 344 }; |
183 | 345 |
184 // Specializations for eight byte words. | 346 // Specializations for eight byte words. |
185 template<typename T, bool is_signed> | 347 template <typename T> |
186 class ByteReader<T, 8, is_signed> { | 348 class ByteReader<T, 8, false> { |
187 public: | 349 public: |
188 static T ReadBigEndian(const uint8_t* data) { | 350 static T ReadBigEndian(const uint8_t* data) { |
351 static_assert(sizeof(T) >= 8, kSizeErrorMsg); | |
189 return | 352 return |
190 (Get(data, 0) << 56) | (Get(data, 1) << 48) | | 353 (Get(data, 0) << 56) | (Get(data, 1) << 48) | |
191 (Get(data, 2) << 40) | (Get(data, 3) << 32) | | 354 (Get(data, 2) << 40) | (Get(data, 3) << 32) | |
192 (Get(data, 4) << 24) | (Get(data, 5) << 16) | | 355 (Get(data, 4) << 24) | (Get(data, 5) << 16) | |
193 (Get(data, 6) << 8) | Get(data, 7); | 356 (Get(data, 6) << 8) | Get(data, 7); |
194 } | 357 } |
195 | 358 |
196 static T ReadLittleEndian(const uint8_t* data) { | 359 static T ReadLittleEndian(const uint8_t* data) { |
360 static_assert(sizeof(T) >= 8, kSizeErrorMsg); | |
197 return | 361 return |
198 Get(data, 0) | (Get(data, 1) << 8) | | 362 Get(data, 0) | (Get(data, 1) << 8) | |
199 (Get(data, 2) << 16) | (Get(data, 3) << 24) | | 363 (Get(data, 2) << 16) | (Get(data, 3) << 24) | |
200 (Get(data, 4) << 32) | (Get(data, 5) << 40) | | 364 (Get(data, 4) << 32) | (Get(data, 5) << 40) | |
201 (Get(data, 6) << 48) | (Get(data, 7) << 56); | 365 (Get(data, 6) << 48) | (Get(data, 7) << 56); |
202 } | 366 } |
203 | 367 |
204 private: | 368 private: |
205 inline static T Get(const uint8_t* data, unsigned int index) { | 369 inline static T Get(const uint8_t* data, unsigned int index) { |
206 return static_cast<T>(data[index]); | 370 return static_cast<T>(data[index]); |
207 } | 371 } |
208 }; | 372 }; |
209 | 373 |
210 template<typename T> | 374 template <typename T> |
211 class ByteWriter<T, 8> { | 375 class ByteWriter<T, 8, false> { |
212 public: | 376 public: |
213 static void WriteBigEndian(uint8_t* data, T val) { | 377 static void WriteBigEndian(uint8_t* data, T val) { |
378 static_assert(sizeof(T) >= 8, kSizeErrorMsg); | |
214 data[0] = val >> 56; | 379 data[0] = val >> 56; |
215 data[1] = val >> 48; | 380 data[1] = val >> 48; |
216 data[2] = val >> 40; | 381 data[2] = val >> 40; |
217 data[3] = val >> 32; | 382 data[3] = val >> 32; |
218 data[4] = val >> 24; | 383 data[4] = val >> 24; |
219 data[5] = val >> 16; | 384 data[5] = val >> 16; |
220 data[6] = val >> 8; | 385 data[6] = val >> 8; |
221 data[7] = val; | 386 data[7] = val; |
222 } | 387 } |
223 | 388 |
224 static void WriteLittleEndian(uint8_t* data, T val) { | 389 static void WriteLittleEndian(uint8_t* data, T val) { |
390 static_assert(sizeof(T) >= 8, kSizeErrorMsg); | |
225 data[0] = val; | 391 data[0] = val; |
226 data[1] = val >> 8; | 392 data[1] = val >> 8; |
227 data[2] = val >> 16; | 393 data[2] = val >> 16; |
228 data[3] = val >> 24; | 394 data[3] = val >> 24; |
229 data[4] = val >> 32; | 395 data[4] = val >> 32; |
230 data[5] = val >> 40; | 396 data[5] = val >> 40; |
231 data[6] = val >> 48; | 397 data[6] = val >> 48; |
232 data[7] = val >> 56; | 398 data[7] = val >> 56; |
233 } | 399 } |
234 }; | 400 }; |
235 | 401 |
236 } // namespace webrtc | 402 } // namespace webrtc |
237 | 403 |
238 #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_ | 404 #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_ |
OLD | NEW |