Echo Writes Code

bits.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
41
42
43
44
45
46
47
48
49
50
51
52
#ifndef CRUCIBLE_PARSING_BITS_INL
#define CRUCIBLE_PARSING_BITS_INL

#include "crucible/parsing/bits.hpp"

#include <climits>

namespace crucible::parsing::bits {
  template<FixedWidthUnsignedIntegerType T>
  auto LittleEndianUnsignedInteger<T>::operator()(StateType const &state) const -> ResultType {
    auto const remaining_bytes { state.get_remaining_bytes_in_input() };

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

    T total { 0 };

    for (std::size_t i { 0 }; i < sizeof(T); ++i) {
      std::size_t const bits_to_shift { i * CHAR_BIT };
      auto const byte_value { std::to_integer<T>(remaining_bytes[i]) };
      T const shifted_value { static_cast<T>(byte_value << bits_to_shift) };
      total |= shifted_value;
    }

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

  template<FixedWidthUnsignedIntegerType T>
  auto BigEndianUnsignedInteger<T>::operator()(StateType const &state) const -> ResultType {
    auto const remaining_bytes { state.get_remaining_bytes_in_input() };

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

    T total { 0 };

    for (std::size_t i { 0 }; i < sizeof(T); ++i) {
      std::size_t const bits_to_shift { (sizeof(T) - (i + 1)) * CHAR_BIT };
      auto const byte_value { std::to_integer<T>(remaining_bytes[i]) };
      T const shifted_value { static_cast<T>(byte_value << bits_to_shift) };
      total |= shifted_value;
    }

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

#endif // CRUCIBLE_PARSING_BITS_INL