OpenTTD Source: src/misc/endian_buffer.hpp Source File

OpenTTD Source 13.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>>
28 class EndianBufferWriter {
30 Titer buffer;
31
32 public:
33 EndianBufferWriter(Titer buffer) : buffer(buffer) {}
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
120 class EndianBufferReader {
122 span<const byte> buffer;
124 size_t read_pos = 0;
125
126 public:
127 EndianBufferReader(span<const byte> buffer) : buffer(buffer) {}
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