Echo Writes Code

bytes.inl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#ifndef CRUCIBLE_PARSING_BYTES_INL
#define CRUCIBLE_PARSING_BYTES_INL

#include "crucible/parsing/bytes.hpp"

#include <climits>

namespace crucible::parsing::bytes {
  template<UnsignedIntegerType T, Endianness E>
  auto UnsignedInteger<T, E>::operator()(StateType const &initial_state) const -> ResultType {
    auto const remaining_bytes { initial_state.get_remaining_input() };

    if (remaining_bytes.size() < sizeof(T)) {
      return errors::make_reject(initial_state, errors::InsufficientInput { sizeof(T) });
    }

    T total { 0 };

    auto const shift_next_byte {
      [](std::byte const next_byte, std::size_t const byte_index) {
        std::size_t const bits_to_shift { byte_index * CHAR_BIT };
        auto const byte_value { std::to_integer<T>(next_byte) };
        return static_cast<T>(byte_value << bits_to_shift);
      }
    };

    for (std::size_t i { 0 }; i < sizeof(T); ++i) {
      if constexpr (E == Endianness::Le) {
        total |= shift_next_byte(remaining_bytes[i], i);
      } else {
        total |= shift_next_byte(remaining_bytes[i], sizeof(T) - (i + 1));
      }
    }

    auto const next_state { initial_state.advance(sizeof(T)) };
    return errors::make_accept(next_state, total);
  }
}

#endif // CRUCIBLE_PARSING_BYTES_INL