• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 6245438238

20 Sep 2023 07:34AM UTC coverage: 91.751% (+0.002%) from 91.749%
6245438238

Pull #3707

github

web-flow
Merge c71ad6879 into 1f26e75d7
Pull Request #3707: [std::span] {load,store}_{le,be}

79435 of 86577 relevant lines covered (91.75%)

8602965.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.05
/src/lib/utils/loadstor.h
1
/*
2
* Load/Store Operators
3
* (C) 1999-2007,2015,2017 Jack Lloyd
4
*     2007 Yves Jerschow
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#ifndef BOTAN_LOAD_STORE_H_
10
#define BOTAN_LOAD_STORE_H_
11

12
#include <botan/concepts.h>
13
#include <botan/mem_ops.h>
14
#include <botan/types.h>
15
#include <botan/internal/bswap.h>
16
#include <vector>
17

18
namespace Botan {
19

20
/**
21
* Byte extraction
22
* @param byte_num which byte to extract, 0 == highest byte
23
* @param input the value to extract from
24
* @return byte byte_num of input
25
*/
26
template <typename T>
27
inline constexpr uint8_t get_byte_var(size_t byte_num, T input) {
1,149,511✔
28
   return static_cast<uint8_t>(input >> (((~byte_num) & (sizeof(T) - 1)) << 3));
1,013,989✔
29
}
30

31
/**
32
* Byte extraction
33
* @param input the value to extract from
34
* @return byte byte number B of input
35
*/
36
template <size_t B, typename T>
37
inline constexpr uint8_t get_byte(T input)
2,147,483,647✔
38
   requires(B < sizeof(T))
39
{
40
   const size_t shift = ((~B) & (sizeof(T) - 1)) << 3;
2,147,483,647✔
41
   return static_cast<uint8_t>((input >> shift) & 0xFF);
2,147,483,647✔
42
}
43

44
/**
45
* Make a uint16_t from two bytes
46
* @param i0 the first byte
47
* @param i1 the second byte
48
* @return i0 || i1
49
*/
50
inline constexpr uint16_t make_uint16(uint8_t i0, uint8_t i1) {
1,151,909✔
51
   return static_cast<uint16_t>((static_cast<uint16_t>(i0) << 8) | i1);
1,164,136✔
52
}
53

54
/**
55
* Make a uint32_t from four bytes
56
* @param i0 the first byte
57
* @param i1 the second byte
58
* @param i2 the third byte
59
* @param i3 the fourth byte
60
* @return i0 || i1 || i2 || i3
61
*/
62
inline constexpr uint32_t make_uint32(uint8_t i0, uint8_t i1, uint8_t i2, uint8_t i3) {
40,746,290✔
63
   return ((static_cast<uint32_t>(i0) << 24) | (static_cast<uint32_t>(i1) << 16) | (static_cast<uint32_t>(i2) << 8) |
40,746,290✔
64
           (static_cast<uint32_t>(i3)));
40,746,290✔
65
}
66

67
/**
68
* Make a uint64_t from eight bytes
69
* @param i0 the first byte
70
* @param i1 the second byte
71
* @param i2 the third byte
72
* @param i3 the fourth byte
73
* @param i4 the fifth byte
74
* @param i5 the sixth byte
75
* @param i6 the seventh byte
76
* @param i7 the eighth byte
77
* @return i0 || i1 || i2 || i3 || i4 || i5 || i6 || i7
78
*/
79
inline constexpr uint64_t make_uint64(
80
   uint8_t i0, uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4, uint8_t i5, uint8_t i6, uint8_t i7) {
81
   return ((static_cast<uint64_t>(i0) << 56) | (static_cast<uint64_t>(i1) << 48) | (static_cast<uint64_t>(i2) << 40) |
82
           (static_cast<uint64_t>(i3) << 32) | (static_cast<uint64_t>(i4) << 24) | (static_cast<uint64_t>(i5) << 16) |
83
           (static_cast<uint64_t>(i6) << 8) | (static_cast<uint64_t>(i7)));
84
}
85

86
/**
87
* Load a big-endian unsigned integer
88
* @param in a fixed-length span with some bytes
89
* @return T loaded from in, as a big-endian value
90
*/
91
template <concepts::unsigned_integral T>
92
inline constexpr T load_be(std::span<const uint8_t, sizeof(T)> in) {
444,129,084✔
93
   if constexpr(sizeof(T) == 1) {
94
      return static_cast<T>(in[0]);
4,956,529✔
95
   } else {
96
#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
97
      return typecast_copy<T>(in);
98
#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
99
      return reverse_bytes(typecast_copy<T>(in));
440,739,724✔
100
#else
101
      return [&]<size_t... i>(std::index_sequence<i...>) {
102
         return ((static_cast<T>(in[i]) << ((sizeof(T) - i - 1) * 8)) | ...);
103
      }
104
      (std::make_index_sequence<sizeof(T)>());
105
#endif
106
   }
107
}
108

109
/**
110
* Load a little-endian unsigned integer
111
* @param in a fixed-length span with some bytes
112
* @return T loaded from in, as a little-endian value
113
*/
114
template <concepts::unsigned_integral T>
115
inline constexpr T load_le(std::span<const uint8_t, sizeof(T)> in) {
116
   if constexpr(sizeof(T) == 1) {
117
      return static_cast<T>(in[0]);
118
   } else {
119
#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
120
      return reverse_bytes(typecast_copy<T>(in));
121
#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
122
      return typecast_copy<T>(in);
123
#else
124
      return [&]<size_t... i>(std::index_sequence<i...>) {
125
         return ((static_cast<T>(in[i]) << (i * 8)) | ...);
126
      }
127
      (std::make_index_sequence<sizeof(T)>());
128
#endif
129
   }
130
}
131

132
/**
133
* Load a big-endian word
134
* @param in a pointer to some bytes
135
* @param off an offset into the array
136
* @return off'th T of in, as a big-endian value
137
*/
138
template <typename T>
139
inline constexpr T load_be(const uint8_t in[], size_t off) {
140
   in += off * sizeof(T);
141
   T out = 0;
142
   for(size_t i = 0; i != sizeof(T); ++i) {
143
      out = static_cast<T>((out << 8) | in[i]);
144
   }
145
   return out;
146
}
147

148
/**
149
* Load a little-endian word
150
* @param in a pointer to some bytes
151
* @param off an offset into the array
152
* @return off'th T of in, as a litte-endian value
153
*/
154
template <typename T>
155
inline constexpr T load_le(const uint8_t in[], size_t off) {
156
   in += off * sizeof(T);
157
   T out = 0;
158
   for(size_t i = 0; i != sizeof(T); ++i) {
159
      out = (out << 8) | in[sizeof(T) - 1 - i];
160
   }
161
   return out;
162
}
163

164
/**
165
* Load a big-endian unsigned integer
166
* @param in a pointer to some bytes
167
* @param off an offset into the array
168
* @return off'th unsigned integer of in, as a big-endian value
169
*/
170
template <concepts::unsigned_integral T>
171
inline constexpr T load_be(const uint8_t in[], size_t off) {
444,677,448✔
172
   return load_be<T>(std::span<const uint8_t, sizeof(T)>(in + off * sizeof(T), sizeof(T)));
444,677,020✔
173
}
174

175
/**
176
* Load a little-endian unsigned integer
177
* @param in a pointer to some bytes
178
* @param off an offset into the array
179
* @return off'th unsigned integer of in, as a little-endian value
180
*/
181
template <concepts::unsigned_integral T>
182
inline constexpr T load_le(const uint8_t in[], size_t off) {
1,648,443,907✔
183
   return load_le<T>(std::span<const uint8_t, sizeof(T)>(in + off * sizeof(T), sizeof(T)));
1,648,334,794✔
184
}
185

186
/**
187
* Load many big-endian unsigned integers
188
* @param in   a fixed-length span to some bytes
189
* @param outs a arbitrary-length parameter list of unsigned integers to be loaded
190
*/
191
template <concepts::unsigned_integral... Ts>
192
   requires all_same_v<Ts...>
193
inline constexpr void load_be(std::span<const uint8_t, (sizeof(Ts) + ...)> in, Ts&... outs) {
1,047,930✔
194
   auto load_one = [off = 0]<typename T>(auto i, T& o) mutable {
1,047,930✔
195
      o = load_be<T>(i.subspan(off).template first<sizeof(T)>());
1,047,930✔
196
      off += sizeof(T);
1,047,930✔
197
   };
198

199
   (load_one(in, outs), ...);
1,019,233✔
200
}
28,697✔
201

202
/**
203
* Load many little-endian unsigned integers
204
* @param in   a fixed-length span to some bytes
205
* @param outs a arbitrary-length parameter list of unsigned integers to be loaded
206
*/
207
template <concepts::unsigned_integral... Ts>
208
   requires all_same_v<Ts...>
209
inline constexpr void load_le(std::span<const uint8_t, (sizeof(Ts) + ...)> in, Ts&... outs) {
60,253✔
210
   auto load_one = [off = 0]<typename T>(auto i, T& o) mutable {
60,253✔
211
      o = load_le<T>(i.subspan(off).template first<sizeof(T)>());
60,253✔
212
      off += sizeof(T);
60,253✔
213
   };
214

215
   (load_one(in, outs), ...);
60,253✔
216
}
217

218
/**
219
* Load many big-endian unsigned integers
220
* @param in   a pointer to some bytes
221
* @param outs a arbitrary-length parameter list of unsigned integers to be loaded
222
*/
223
template <concepts::unsigned_integral... Ts>
224
   requires all_same_v<Ts...>
225
inline constexpr void load_be(const uint8_t in[], Ts&... outs) {
1,047,930✔
226
   constexpr auto bytes = (sizeof(outs) + ...);
1,047,930✔
227
   load_be(std::span<const uint8_t, bytes>(in, bytes), outs...);
1,047,930✔
228
}
229

230
/**
231
* Load many little-endian unsigned integers
232
* @param in   a pointer to some bytes
233
* @param outs a arbitrary-length parameter list of unsigned integers to be loaded
234
*/
235
template <concepts::unsigned_integral... Ts>
236
   requires all_same_v<Ts...>
237
inline constexpr void load_le(const uint8_t in[], Ts&... outs) {
60,253✔
238
   constexpr auto bytes = (sizeof(outs) + ...);
60,253✔
239
   load_le(std::span<const uint8_t, bytes>(in, bytes), outs...);
60,253✔
240
}
30,923✔
241

242
/**
243
* Load a variable number of little-endian words
244
* @param out the output array of words
245
* @param in the input array of bytes
246
* @param count how many words are in in
247
*/
248
template <typename T>
249
inline constexpr void load_le(T out[], const uint8_t in[], size_t count) {
98,340,701✔
250
   if(count > 0) {
377,487✔
251
#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
252
      typecast_copy(out, in, count);
98,372,281✔
253

254
#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
255
      typecast_copy(out, in, count);
256

257
      for(size_t i = 0; i != count; ++i)
258
         out[i] = reverse_bytes(out[i]);
259
#else
260
      for(size_t i = 0; i != count; ++i)
261
         out[i] = load_le<T>(in, i);
262
#endif
263
   }
264
}
240,728✔
265

266
/**
267
* Load a variable number of big-endian words
268
* @param out the output array of words
269
* @param in the input array of bytes
270
* @param count how many words are in in
271
*/
272
template <typename T>
273
inline constexpr void load_be(T out[], const uint8_t in[], size_t count) {
60,367✔
274
   if(count > 0) {
60,367✔
275
#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
276
      typecast_copy(out, in, count);
277

278
#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
279
      typecast_copy(out, in, count);
60,367✔
280

281
      for(size_t i = 0; i != count; ++i) {
424,013✔
282
         out[i] = reverse_bytes(out[i]);
363,646✔
283
      }
284
#else
285
      for(size_t i = 0; i != count; ++i)
286
         out[i] = load_be<T>(in, i);
287
#endif
288
   }
289
}
60,367✔
290

291
/**
292
* Store a big-endian unsigned integer
293
* @param in the input unsigned integer
294
* @param out the fixed-length span to write to
295
*/
296
template <concepts::unsigned_integral T>
297
inline constexpr void store_be(T in, std::span<uint8_t, sizeof(T)> out) {
960,840,298✔
298
   if constexpr(sizeof(T) == 1) {
299
      out[0] = static_cast<uint8_t>(in);
300
   } else {
301
#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
302
      typecast_copy(out, in);
303
#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
304
      typecast_copy(out, reverse_bytes(in));
960,821,737✔
305
#else
306
      [&]<size_t... i>(std::index_sequence<i...>) {
307
         ((out[i] = get_byte<i>(in)), ...);
308
      }
309
      (std::make_index_sequence<sizeof(T)>());
310
#endif
311
   }
312
}
313

314
/**
315
* Store a little-endian unsigned integer
316
* @param in the input unsigned integer
317
* @param out the fixed-length span to write to
318
*/
319
template <concepts::unsigned_integral T>
320
inline constexpr void store_le(T in, std::span<uint8_t, sizeof(T)> out) {
427,604,961✔
321
   if constexpr(sizeof(T) == 1) {
322
      out[0] = static_cast<uint8_t>(in);
323
   } else {
324
#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
325
      typecast_copy(out, reverse_bytes(in));
326
#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
327
      typecast_copy(out, in);
427,605,870✔
328
#else
329
      [&]<size_t... i>(std::index_sequence<i...>) {
330
         ((out[i] = get_byte<sizeof(T) - i - 1>(in)), ...);
331
      }
332
      (std::make_index_sequence<sizeof(T)>());
333
#endif
334
   }
335
}
336

337
/**
338
* Store a big-endian uint16_t
339
* @param in the input uint16_t
340
* @param out the byte array to write to
341
*/
342
inline constexpr void store_be(uint16_t in, uint8_t out[2]) {
141,010✔
343
#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
344
   typecast_copy(out, in);
345
#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
346
   typecast_copy(out, reverse_bytes(in));
139,730✔
347
#else
348
   out[0] = get_byte<0>(in);
349
   out[1] = get_byte<1>(in);
350
#endif
351
}
352

353
/**
354
* Store a little-endian uint16_t
355
* @param in the input uint16_t
356
* @param out the byte array to write to
357
*/
358
inline constexpr void store_le(uint16_t in, uint8_t out[2]) {
7✔
359
#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
360
   typecast_copy(out, reverse_bytes(in));
361
#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
362
   typecast_copy(out, in);
7✔
363
#else
364
   out[0] = get_byte<1>(in);
365
   out[1] = get_byte<0>(in);
366
#endif
367
}
368

369
/**
370
* Store a big-endian uint32_t
371
* @param in the input uint32_t
372
* @param out the byte array to write to
373
*/
374
inline constexpr void store_be(uint32_t in, uint8_t out[4]) {
891,083,450✔
375
#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
376
   typecast_copy(out, in);
377
#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
378
   typecast_copy(out, reverse_bytes(in));
891,080,878✔
379
#else
380
   out[0] = get_byte<0>(in);
381
   out[1] = get_byte<1>(in);
382
   out[2] = get_byte<2>(in);
383
   out[3] = get_byte<3>(in);
384
#endif
385
}
6,685✔
386

387
/**
388
* Store a little-endian uint32_t
389
* @param in the input uint32_t
390
* @param out the byte array to write to
391
*/
392
inline constexpr void store_le(uint32_t in, uint8_t out[4]) {
100,701,247✔
393
#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
394
   typecast_copy(out, reverse_bytes(in));
395
#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
396
   typecast_copy(out, in);
100,701,247✔
397
#else
398
   out[0] = get_byte<3>(in);
399
   out[1] = get_byte<2>(in);
400
   out[2] = get_byte<1>(in);
401
   out[3] = get_byte<0>(in);
402
#endif
403
}
404

405
/**
406
* Store a big-endian unsigned integer
407
* @param in the input unsigned integer
408
* @param out the byte array to write to
409
*/
410
template <concepts::unsigned_integral T>
411
inline constexpr void store_be(T in, uint8_t out[sizeof(T)]) {
955,648,262✔
412
   store_be(in, std::span<uint8_t, sizeof(T)>(out, sizeof(T)));
955,648,262✔
413
}
191,098,029✔
414

415
/**
416
* Store a little-endian unsigned integer
417
* @param in the input unsigned integer
418
* @param out the byte array to write to
419
*/
420
template <concepts::unsigned_integral T>
421
inline constexpr void store_le(T in, uint8_t out[sizeof(T)]) {
427,435,909✔
422
   store_le(in, std::span<uint8_t, sizeof(T)>(out, sizeof(T)));
427,435,909✔
423
}
2,723✔
424

425
/**
426
* Store many big-endian unsigned integers
427
* @param out a fixed-length span to some bytes
428
* @param ins a arbitrary-length parameter list of unsigned integers to be stored
429
*/
430
template <concepts::unsigned_integral... Ts>
431
   requires all_same_v<Ts...>
432
inline constexpr void store_be(std::span<uint8_t, (sizeof(Ts) + ...)> out, Ts... ins) {
5,173,476✔
433
   auto store_one = [off = 0]<typename T>(auto o, T i) mutable {
5,173,476✔
434
      store_be<T>(i, o.subspan(off).template first<sizeof(T)>());
5,173,476✔
435
      off += sizeof(T);
5,173,476✔
436
   };
437

438
   (store_one(out, ins), ...);
5,173,476✔
439
}
5,173,476✔
440

441
/**
442
* Store many little-endian unsigned integers
443
* @param out a fixed-length span to some bytes
444
* @param ins a arbitrary-length parameter list of unsigned integers to be stored
445
*/
446
template <concepts::unsigned_integral... Ts>
447
   requires all_same_v<Ts...>
448
inline constexpr void store_le(std::span<uint8_t, (sizeof(Ts) + ...)> out, Ts... ins) {
169,961✔
449
   auto store_one = [off = 0]<typename T>(auto o, T i) mutable {
169,961✔
450
      store_le<T>(i, o.subspan(off).template first<sizeof(T)>());
169,961✔
451
      off += sizeof(T);
169,961✔
452
   };
453

454
   (store_one(out, ins), ...);
169,961✔
455
}
169,961✔
456

457
/**
458
* Store many big-endian unsigned integers
459
* @param ins a pointer to some bytes to be written
460
* @param out a arbitrary-length parameter list of unsigned integers to be stored
461
*/
462
template <concepts::unsigned_integral... Ts>
463
   requires all_same_v<Ts...>
464
inline constexpr void store_be(uint8_t out[], Ts... ins) {
5,173,476✔
465
   constexpr auto bytes = (sizeof(ins) + ...);
5,173,476✔
466
   store_be(std::span<uint8_t, bytes>(out, bytes), ins...);
5,173,476✔
467
}
468

469
/**
470
* Store many little-endian unsigned integers
471
* @param ins a pointer to some bytes to be written
472
* @param out a arbitrary-length parameter list of unsigned integers to be stored
473
*/
474
template <concepts::unsigned_integral... Ts>
475
   requires all_same_v<Ts...>
476
inline constexpr void store_le(uint8_t out[], Ts... ins) {
169,961✔
477
   constexpr auto bytes = (sizeof(ins) + ...);
169,961✔
478
   store_le(std::span<uint8_t, bytes>(out, bytes), ins...);
169,961✔
479
}
30,923✔
480

481
template <typename T>
482
void copy_out_be(uint8_t out[], size_t out_bytes, const T in[]) {
191,145,865✔
483
   while(out_bytes >= sizeof(T)) {
1,710,588,533✔
484
      store_be(in[0], out);
1,519,442,668✔
485
      out += sizeof(T);
1,519,442,668✔
486
      out_bytes -= sizeof(T);
1,519,442,668✔
487
      in += 1;
1,519,442,668✔
488
   }
489

490
   for(size_t i = 0; i != out_bytes; ++i) {
191,145,865✔
491
      out[i] = get_byte_var(i % 8, in[0]);
×
492
   }
493
}
191,145,865✔
494

495
template <typename T, typename Alloc>
496
void copy_out_vec_be(uint8_t out[], size_t out_bytes, const std::vector<T, Alloc>& in) {
191,097,578✔
497
   copy_out_be(out, out_bytes, in.data());
191,097,578✔
498
}
499

500
template <typename T>
501
void copy_out_le(uint8_t out[], size_t out_bytes, const T in[]) {
563,589✔
502
   while(out_bytes >= sizeof(T)) {
3,051,809✔
503
      store_le(in[0], out);
2,488,220✔
504
      out += sizeof(T);
2,488,220✔
505
      out_bytes -= sizeof(T);
2,488,220✔
506
      in += 1;
2,488,220✔
507
   }
508

509
   for(size_t i = 0; i != out_bytes; ++i) {
583,477✔
510
      out[i] = get_byte_var(sizeof(T) - 1 - (i % 8), in[0]);
19,888✔
511
   }
512
}
563,589✔
513

514
template <typename T, typename Alloc>
515
void copy_out_vec_le(uint8_t out[], size_t out_bytes, const std::vector<T, Alloc>& in) {
233,014✔
516
   copy_out_le(out, out_bytes, in.data());
233,014✔
517
}
518

519
}  // namespace Botan
520

521
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc