OpenTTD Source  13.2.1
endian_buffer.hpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #ifndef ENDIAN_BUFFER_HPP
11 #define ENDIAN_BUFFER_HPP
12 
13 #include <iterator>
14 #include <string_view>
15 #include "../core/span_type.hpp"
16 #include "../core/bitmath_func.hpp"
17 #include "../core/overflowsafe_type.hpp"
18 
19 struct StrongTypedefBase;
20 
27 template <typename Tcont = typename std::vector<byte>, typename Titer = typename std::back_insert_iterator<Tcont>>
30  Titer buffer;
31 
32 public:
34  EndianBufferWriter(typename Titer::container_type &container) : buffer(std::back_inserter(container)) {}
35 
36  EndianBufferWriter &operator <<(const std::string &data) { return *this << std::string_view{ data }; }
37  EndianBufferWriter &operator <<(const char *data) { return *this << std::string_view{ data }; }
38  EndianBufferWriter &operator <<(std::string_view data) { this->Write(data); return *this; }
39  EndianBufferWriter &operator <<(bool data) { return *this << static_cast<byte>(data ? 1 : 0); }
40 
41  template <typename T>
42  EndianBufferWriter &operator <<(const OverflowSafeInt<T> &data) { return *this << static_cast<T>(data); };
43 
44  template <typename... Targs>
45  EndianBufferWriter &operator <<(const std::tuple<Targs...> &data)
46  {
47  this->WriteTuple(data, std::index_sequence_for<Targs...>{});
48  return *this;
49  }
50 
51  template <class T, std::enable_if_t<std::disjunction_v<std::negation<std::is_class<T>>, std::is_base_of<StrongTypedefBase, T>>, int> = 0>
52  EndianBufferWriter &operator <<(const T data)
53  {
54  if constexpr (std::is_enum_v<T>) {
55  this->Write(static_cast<std::underlying_type_t<const T>>(data));
56  } else if constexpr (std::is_base_of_v<StrongTypedefBase, T>) {
57  this->Write(data.value);
58  } else {
59  this->Write(data);
60  }
61  return *this;
62  }
63 
64  template <typename Tvalue, typename Tbuf = std::vector<byte>>
65  static Tbuf FromValue(const Tvalue &data)
66  {
67  Tbuf buffer;
68  EndianBufferWriter writer{ buffer };
69  writer << data;
70  return buffer;
71  }
72 
73 private:
75  template<class Ttuple, size_t... Tindices>
76  void WriteTuple(const Ttuple &values, std::index_sequence<Tindices...>) {
77  ((*this << std::get<Tindices>(values)), ...);
78  }
79 
81  void Write(std::string_view value)
82  {
83  for (auto c : value) {
84  this->buffer++ = c;
85  }
86  this->buffer++ = '\0';
87  }
88 
90  template <class T>
91  void Write(T value)
92  {
93  static_assert(sizeof(T) <= 8, "Value can't be larger than 8 bytes");
94 
95  if constexpr (sizeof(T) > 1) {
96  this->buffer++ = GB(value, 0, 8);
97  this->buffer++ = GB(value, 8, 8);
98  if constexpr (sizeof(T) > 2) {
99  this->buffer++ = GB(value, 16, 8);
100  this->buffer++ = GB(value, 24, 8);
101  }
102  if constexpr (sizeof(T) > 4) {
103  this->buffer++ = GB(value, 32, 8);
104  this->buffer++ = GB(value, 40, 8);
105  this->buffer++ = GB(value, 48, 8);
106  this->buffer++ = GB(value, 56, 8);
107  }
108  } else {
109  this->buffer++ = value;
110  }
111  }
112 };
113 
124  size_t read_pos = 0;
125 
126 public:
128 
129  void rewind() { this->read_pos = 0; }
130 
131  EndianBufferReader &operator >>(std::string &data) { data = this->ReadStr(); return *this; }
132  EndianBufferReader &operator >>(bool &data) { data = this->Read<byte>() != 0; return *this; }
133 
134  template <typename T>
135  EndianBufferReader &operator >>(OverflowSafeInt<T> &data) { data = this->Read<T>(); return *this; };
136 
137  template <typename... Targs>
138  EndianBufferReader &operator >>(std::tuple<Targs...> &data)
139  {
140  this->ReadTuple(data, std::index_sequence_for<Targs...>{});
141  return *this;
142  }
143 
144  template <class T, std::enable_if_t<std::disjunction_v<std::negation<std::is_class<T>>, std::is_base_of<StrongTypedefBase, T>>, int> = 0>
145  EndianBufferReader &operator >>(T &data)
146  {
147  if constexpr (std::is_enum_v<T>) {
148  data = static_cast<T>(this->Read<std::underlying_type_t<T>>());
149  } else if constexpr (std::is_base_of_v<StrongTypedefBase, T>) {
150  data.value = this->Read<decltype(data.value)>();
151  } else {
152  data = this->Read<T>();
153  }
154  return *this;
155  }
156 
157  template <typename Tvalue>
158  static Tvalue ToValue(span<const byte> buffer)
159  {
160  Tvalue result{};
161  EndianBufferReader reader{ buffer };
162  reader >> result;
163  return result;
164  }
165 
166 private:
168  template<class Ttuple, size_t... Tindices>
169  void ReadTuple(Ttuple &values, std::index_sequence<Tindices...>) {
170  ((*this >> std::get<Tindices>(values)), ...);
171  }
172 
174  std::string ReadStr()
175  {
176  std::string str;
177  while (this->read_pos < this->buffer.size()) {
178  char ch = this->Read<char>();
179  if (ch == '\0') break;
180  str.push_back(ch);
181  }
182  return str;
183  }
184 
186  template <class T>
187  T Read()
188  {
189  static_assert(!std::is_const_v<T>, "Can't read into const variables");
190  static_assert(sizeof(T) <= 8, "Value can't be larger than 8 bytes");
191 
192  if (read_pos + sizeof(T) > this->buffer.size()) return {};
193 
194  T value = static_cast<T>(this->buffer[this->read_pos++]);
195  if constexpr (sizeof(T) > 1) {
196  value += static_cast<T>(this->buffer[this->read_pos++]) << 8;
197  }
198  if constexpr (sizeof(T) > 2) {
199  value += static_cast<T>(this->buffer[this->read_pos++]) << 16;
200  value += static_cast<T>(this->buffer[this->read_pos++]) << 24;
201  }
202  if constexpr (sizeof(T) > 4) {
203  value += static_cast<T>(this->buffer[this->read_pos++]) << 32;
204  value += static_cast<T>(this->buffer[this->read_pos++]) << 40;
205  value += static_cast<T>(this->buffer[this->read_pos++]) << 48;
206  value += static_cast<T>(this->buffer[this->read_pos++]) << 56;
207  }
208 
209  return value;
210  }
211 };
212 
213 #endif /* ENDIAN_BUFFER_HPP */
GB
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
Definition: bitmath_func.hpp:32
EndianBufferWriter::buffer
Titer buffer
Output iterator for the destination buffer.
Definition: endian_buffer.hpp:30
EndianBufferReader::read_pos
size_t read_pos
Current read position.
Definition: endian_buffer.hpp:124
span< const byte >
EndianBufferReader
Endian-aware buffer adapter that always reads values in little endian order.
Definition: endian_buffer.hpp:120
EndianBufferReader::ReadTuple
void ReadTuple(Ttuple &values, std::index_sequence< Tindices... >)
Helper function to read a tuple from the buffer.
Definition: endian_buffer.hpp:169
EndianBufferReader::buffer
span< const byte > buffer
Reference to storage buffer.
Definition: endian_buffer.hpp:122
StrongTypedefBase
Non-templated base for StrongTypedef for use with type trait queries.
Definition: strong_typedef_type.hpp:14
EndianBufferWriter::Write
void Write(T value)
Fundamental write function.
Definition: endian_buffer.hpp:91
EndianBufferWriter::WriteTuple
void WriteTuple(const Ttuple &values, std::index_sequence< Tindices... >)
Helper function to write a tuple to the buffer.
Definition: endian_buffer.hpp:76
OverflowSafeInt
Overflow safe template for integers, i.e.
Definition: overflowsafe_type.hpp:30
EndianBufferWriter
Endian-aware buffer adapter that always writes values in little endian order.
Definition: endian_buffer.hpp:28
EndianBufferWriter::Write
void Write(std::string_view value)
Write overload for string values.
Definition: endian_buffer.hpp:81
EndianBufferReader::ReadStr
std::string ReadStr()
Read overload for string data.
Definition: endian_buffer.hpp:174
EndianBufferReader::Read
T Read()
Fundamental read function.
Definition: endian_buffer.hpp:187