Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/core/StarDataStream.hpp
blob: d5f9bcb563aca7ed76152bb83ff6563d8517822d (plain)
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
#pragma once

#include "StarString.hpp"
#include "StarNetCompatibility.hpp"

namespace Star {

STAR_EXCEPTION(DataStreamException, IOException);
extern unsigned const CurrentStreamVersion;

// Writes complex types to bytes in a portable big-endian fashion.
class DataStream {
public:
  DataStream();
  virtual ~DataStream() = default;

  // DataStream defaults to big-endian order for all primitive types
  ByteOrder byteOrder() const;
  void setByteOrder(ByteOrder byteOrder);

  // DataStream can optionally write strings as null terminated rather than
  // length prefixed
  bool nullTerminatedStrings() const;
  void setNullTerminatedStrings(bool nullTerminatedStrings);

  // streamCompatibilityVersion defaults to CurrentStreamVersion, but can be
  // changed for compatibility with older versions of DataStream serialization.
  unsigned streamCompatibilityVersion() const;
  void setStreamCompatibilityVersion(unsigned streamCompatibilityVersion);
  void setStreamCompatibilityVersion(NetCompatibilityRules const& rules);
  // Do direct reads and writes
  virtual void readData(char* data, size_t len) = 0;
  virtual void writeData(char const* data, size_t len) = 0;

  // These do not read / write sizes, they simply read / write directly.
  ByteArray readBytes(size_t len);
  void writeBytes(ByteArray const& ba);

  DataStream& operator<<(bool d);
  DataStream& operator<<(char c);
  DataStream& operator<<(int8_t d);
  DataStream& operator<<(uint8_t d);
  DataStream& operator<<(int16_t d);
  DataStream& operator<<(uint16_t d);
  DataStream& operator<<(int32_t d);
  DataStream& operator<<(uint32_t d);
  DataStream& operator<<(int64_t d);
  DataStream& operator<<(uint64_t d);
  DataStream& operator<<(float d);
  DataStream& operator<<(double d);

  DataStream& operator>>(bool& d);
  DataStream& operator>>(char& c);
  DataStream& operator>>(int8_t& d);
  DataStream& operator>>(uint8_t& d);
  DataStream& operator>>(int16_t& d);
  DataStream& operator>>(uint16_t& d);
  DataStream& operator>>(int32_t& d);
  DataStream& operator>>(uint32_t& d);
  DataStream& operator>>(int64_t& d);
  DataStream& operator>>(uint64_t& d);
  DataStream& operator>>(float& d);
  DataStream& operator>>(double& d);

  // Writes and reads a VLQ encoded integer.  Can write / read anywhere from 1
  // to 10 bytes of data, with integers of smaller (absolute) value taking up
  // fewer bytes.  size_t version can be used to portably write a size_t type,
  // and portably and efficiently handles the case of NPos.

  size_t writeVlqU(uint64_t i);
  size_t writeVlqI(int64_t i);
  size_t writeVlqS(size_t i);

  size_t readVlqU(uint64_t& i);
  size_t readVlqI(int64_t& i);
  size_t readVlqS(size_t& i);

  uint64_t readVlqU();
  int64_t readVlqI();
  size_t readVlqS();

  // The following functions write / read data with length and then content
  // following, but note that the length is encoded as an unsigned VLQ integer.
  // String objects are encoded in utf8, and can optionally be written as null
  // terminated rather than length then content.

  DataStream& operator<<(const char* s);
  DataStream& operator<<(std::string const& d);
  DataStream& operator<<(ByteArray const& d);
  DataStream& operator<<(String const& s);

  DataStream& operator>>(std::string& d);
  DataStream& operator>>(ByteArray& d);
  DataStream& operator>>(String& s);

  // All enum types are automatically serializable

  template <typename EnumType, typename = typename std::enable_if<std::is_enum<EnumType>::value>::type>
  DataStream& operator<<(EnumType const& e);

  template <typename EnumType, typename = typename std::enable_if<std::is_enum<EnumType>::value>::type>
  DataStream& operator>>(EnumType& e);

  // Convenience method to avoid temporary.
  template <typename T>
  T read();

  // Convenient argument style reading / writing

  template <typename Data>
  void read(Data& data);

  template <typename Data>
  void write(Data const& data);

  // Argument style reading / writing with casting.

  template <typename ReadType, typename Data>
  void cread(Data& data);

  template <typename WriteType, typename Data>
  void cwrite(Data const& data);

  // Argument style reading / writing of variable length integers.  Arguments
  // are explicitly casted, so things like enums are allowed.

  template <typename IntegralType>
  void vuread(IntegralType& data);

  template <typename IntegralType>
  void viread(IntegralType& data);

  template <typename IntegralType>
  void vsread(IntegralType& data);

  template <typename IntegralType>
  void vuwrite(IntegralType const& data);

  template <typename IntegralType>
  void viwrite(IntegralType const& data);

  template <typename IntegralType>
  void vswrite(IntegralType const& data);

  // Store a fixed point number as a variable length integer

  template <typename FloatType>
  void vfread(FloatType& data, FloatType base);

  template <typename FloatType>
  void vfwrite(FloatType const& data, FloatType base);

  // Read a shared / unique ptr, and store whether the pointer is initialized.

  template <typename PointerType, typename ReadFunction>
  void pread(PointerType& pointer, ReadFunction readFunction);

  template <typename PointerType, typename WriteFunction>
  void pwrite(PointerType const& pointer, WriteFunction writeFunction);

  template <typename PointerType>
  void pread(PointerType& pointer);

  template <typename PointerType>
  void pwrite(PointerType const& pointer);

  // WriteFunction should be void (DataStream& ds, Element const& e)
  template <typename Container, typename WriteFunction>
  void writeContainer(Container const& container, WriteFunction function);

  // ReadFunction should be void (DataStream& ds, Element& e)
  template <typename Container, typename ReadFunction>
  void readContainer(Container& container, ReadFunction function);

  template <typename Container, typename WriteFunction>
  void writeMapContainer(Container& map, WriteFunction function);

  // Specialization of readContainer for map types (whose elements are a pair
  // with the key type marked const)
  template <typename Container, typename ReadFunction>
  void readMapContainer(Container& map, ReadFunction function);

  template <typename Container>
  void writeContainer(Container const& container);

  template <typename Container>
  void readContainer(Container& container);

  template <typename Container>
  void writeMapContainer(Container const& container);

  template <typename Container>
  void readMapContainer(Container& container);

private:
  void writeStringData(char const* data, size_t len);

  ByteOrder m_byteOrder;
  bool m_nullTerminatedStrings;
  unsigned m_streamCompatibilityVersion;
};

template <typename EnumType, typename>
DataStream& DataStream::operator<<(EnumType const& e) {
  *this << (typename std::underlying_type<EnumType>::type)e;
  return *this;
}

template <typename EnumType, typename>
DataStream& DataStream::operator>>(EnumType& e) {
  typename std::underlying_type<EnumType>::type i;
  *this >> i;
  e = (EnumType)i;
  return *this;
}

template <typename T>
T DataStream::read() {
  T t;
  *this >> t;
  return t;
}

template <typename Data>
void DataStream::read(Data& data) {
  *this >> data;
}

template <typename Data>
void DataStream::write(Data const& data) {
  *this << data;
}

template <typename ReadType, typename Data>
void DataStream::cread(Data& data) {
  ReadType v;
  *this >> v;
  data = (Data)v;
}

template <typename WriteType, typename Data>
void DataStream::cwrite(Data const& data) {
  WriteType v = (WriteType)data;
  *this << v;
}

template <typename IntegralType>
void DataStream::vuread(IntegralType& data) {
  uint64_t i = readVlqU();
  data = (IntegralType)i;
}

template <typename IntegralType>
void DataStream::viread(IntegralType& data) {
  int64_t i = readVlqI();
  data = (IntegralType)i;
}

template <typename IntegralType>
void DataStream::vsread(IntegralType& data) {
  size_t s = readVlqS();
  data = (IntegralType)s;
}

template <typename IntegralType>
void DataStream::vuwrite(IntegralType const& data) {
  writeVlqU((uint64_t)data);
}

template <typename IntegralType>
void DataStream::viwrite(IntegralType const& data) {
  writeVlqI((int64_t)data);
}

template <typename IntegralType>
void DataStream::vswrite(IntegralType const& data) {
  writeVlqS((size_t)data);
}

template <typename FloatType>
void DataStream::vfread(FloatType& data, FloatType base) {
  int64_t i = readVlqI();
  data = (FloatType)i * base;
}

template <typename FloatType>
void DataStream::vfwrite(FloatType const& data, FloatType base) {
  writeVlqI((int64_t)round(data / base));
}

template <typename PointerType, typename ReadFunction>
void DataStream::pread(PointerType& pointer, ReadFunction readFunction) {
  bool initialized = read<bool>();
  if (initialized) {
    auto element = make_unique<typename std::decay<typename PointerType::element_type>::type>();
    readFunction(*this, *element);
    pointer.reset(element.release());
  } else {
    pointer.reset();
  }
}

template <typename PointerType, typename WriteFunction>
void DataStream::pwrite(PointerType const& pointer, WriteFunction writeFunction) {
  if (pointer) {
    write(true);
    writeFunction(*this, *pointer);
  } else {
    write(false);
  }
}

template <typename PointerType>
void DataStream::pread(PointerType& pointer) {
  return pread(pointer, [](DataStream& ds, typename std::decay<typename PointerType::element_type>::type& value) {
      ds.read(value);
    });
}

template <typename PointerType>
void DataStream::pwrite(PointerType const& pointer) {
  return pwrite(pointer, [](DataStream& ds, typename std::decay<typename PointerType::element_type>::type const& value) {
      ds.write(value);
    });
}

template <typename Container, typename WriteFunction>
void DataStream::writeContainer(Container const& container, WriteFunction function) {
  writeVlqU(container.size());
  for (auto const& elem : container)
    function(*this, elem);
}

template <typename Container, typename ReadFunction>
void DataStream::readContainer(Container& container, ReadFunction function) {
  container.clear();
  size_t size = readVlqU();
  for (size_t i = 0; i < size; ++i) {
    typename Container::value_type elem;
    function(*this, elem);
    container.insert(container.end(), elem);
  }
}

template <typename Container, typename WriteFunction>
void DataStream::writeMapContainer(Container& map, WriteFunction function) {
  writeVlqU(map.size());
  for (auto const& elem : map)
    function(*this, elem.first, elem.second);
}

template <typename Container, typename ReadFunction>
void DataStream::readMapContainer(Container& map, ReadFunction function) {
  map.clear();
  size_t size = readVlqU();
  for (size_t i = 0; i < size; ++i) {
    typename Container::key_type key;
    typename Container::mapped_type mapped;
    function(*this, key, mapped);
    map.insert(make_pair(std::move(key), std::move(mapped)));
  }
}

template <typename Container>
void DataStream::writeContainer(Container const& container) {
  writeContainer(container, [](DataStream& ds, typename Container::value_type const& element) { ds << element; });
}

template <typename Container>
void DataStream::readContainer(Container& container) {
  readContainer(container, [](DataStream& ds, typename Container::value_type& element) { ds >> element; });
}

template <typename Container>
void DataStream::writeMapContainer(Container const& container) {
  writeMapContainer(container, [](DataStream& ds, typename Container::key_type const& key, typename Container::mapped_type const& mapped) {
      ds << key;
      ds << mapped;
    });
}

template <typename Container>
void DataStream::readMapContainer(Container& container) {
  readMapContainer(container, [](DataStream& ds, typename Container::key_type& key, typename Container::mapped_type& mapped) {
      ds >> key;
      ds >> mapped;
    });
}

}