serialize.h revision 203bf2d31f9e4f55bcee1899e14bade235f1f1ee
1#if !defined(SERIALIZE_H)
2#define SERIALIZE_H
3
4#include <algorithm>
5#include <vector>
6
7#include <assert.h>
8#include <string.h>
9#include <stdint.h>
10#include <stddef.h>
11
12namespace serialization {
13
14namespace detail {
15  inline bool is_host_little_endian() {
16    unsigned long one = 0x1UL;
17    return *reinterpret_cast<unsigned char *>(&one);
18  }
19
20  inline void swap_byte_order(unsigned char (&array)[1]) {
21    // Nothing to do
22  }
23
24  inline void swap_byte_order(unsigned char (&array)[2]) {
25    std::swap(array[0], array[1]);
26  }
27
28  inline void swap_byte_order(unsigned char (&array)[4]) {
29    std::swap(array[0], array[3]);
30    std::swap(array[1], array[2]);
31  }
32
33  inline void swap_byte_order(unsigned char (&array)[8]) {
34    std::swap(array[0], array[7]);
35    std::swap(array[1], array[6]);
36    std::swap(array[2], array[5]);
37    std::swap(array[3], array[4]);
38  }
39
40  template <typename T>
41  struct type_traits {
42  private:
43    struct alignment_test {
44      char pending;
45      T element;
46    };
47
48  public:
49    enum { alignment = offsetof(alignment_test, element) };
50  };
51}
52
53
54template <bool is_archive_little_endian>
55class archive_reader {
56private:
57  unsigned char const *buf_begin;
58  unsigned char const *buf_end;
59  unsigned char const *cursor;
60  unsigned char const *cursor_base;
61
62  bool good;
63  bool packed;
64
65public:
66  archive_reader(unsigned char const *buf = NULL, size_t size = 0)
67  : buf_begin(buf), buf_end(buf + size),
68    cursor(buf), cursor_base(NULL), good(buf != NULL), packed(false) {
69  }
70
71  void set_packed(bool pac) {
72    packed = pac;
73  }
74
75  template <typename T> void operator<<=(T &b) {
76    assert(cursor_base == NULL);
77    cursor_base = cursor;
78  }
79
80  template <typename T> void operator>>=(T &b) {
81    assert(cursor_base != NULL);
82    assert(cursor_base + sizeof(T) >= cursor);
83    cursor = cursor_base + sizeof(T);
84    cursor_base = NULL;
85  }
86
87  void seek(off_t off, bool from_begin = false) {
88    if (from_begin) {
89      cursor = buf_begin + off;
90    } else {
91      cursor += off;
92    }
93  }
94
95  template <size_t size>
96  void operator&(char (&array)[size]) {
97    read_bytes(array, size);
98    seek(size);
99  }
100
101  template <size_t size>
102  void operator&(unsigned char (&array)[size]) {
103    read_bytes(array, size);
104    seek(size);
105  }
106
107#define SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER(T)                  \
108  void operator&(T &v) {                                                      \
109    using namespace detail;                                                   \
110                                                                              \
111    seek_to_next_address<T>();                                                \
112    read_bytes(&v, sizeof(T));                                                \
113    seek(sizeof(T));                                                          \
114                                                                              \
115    if (is_archive_little_endian != is_host_little_endian()) {                \
116      swap_byte_order(reinterpret_cast<unsigned char (&)[sizeof(T)]>(v));     \
117    }                                                                         \
118  }
119
120  SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER(bool)
121  SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER(int8_t)
122  SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER(int16_t)
123  SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER(int32_t)
124  SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER(int64_t)
125  SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER(uint8_t)
126  SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER(uint16_t)
127  SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER(uint32_t)
128  SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER(uint64_t)
129  SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER(float)
130  SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER(double)
131  SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER(void *)
132  SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER(void const *)
133
134#undef SERIALIZE_ARCHIVE_READER_READ_AND_SWAP_BYTE_ORDER
135
136  operator void *() const {
137    return good ? this : 0;
138  }
139
140  bool operator!() const {
141    return !good;
142  }
143
144private:
145  void read_bytes(void *array, size_t size) {
146    if (!good || cursor + size > buf_end) {
147      good = false;
148    } else {
149      memcpy(array, cursor, size);
150    }
151  }
152
153  template <typename T>
154  void seek_to_next_address() {
155    if (!packed) {
156      size_t align = detail::type_traits<T>::alignment;
157      size_t delta = reinterpret_cast<uintptr_t>(cursor) % align;
158
159      if (delta > 0) {
160        seek(align - delta);
161      }
162    }
163  }
164
165};
166
167typedef archive_reader<true>  archive_reader_from_little_endian;
168typedef archive_reader<false> archive_reader_from_big_endian;
169
170
171template <bool is_archive_little_endian>
172class archive_writer {
173private:
174  std::vector<unsigned char> buf;
175  size_t cursor;
176  size_t cursor_base;
177  bool packed;
178
179public:
180  archive_writer() : cursor(0), cursor_base((size_t)-1), packed(false) {
181  }
182
183  void setpacked(bool pac) {
184    packed = pac;
185  }
186
187  unsigned char const *begin() const {
188    return &*buf.begin();
189  }
190
191  unsigned char const *end() const {
192    return &*buf.end();
193  }
194
195  size_t size() const {
196    return buf.size();
197  }
198
199  template <typename T> void operator<<=(T const &src) {
200    assert(cursor_base == ((size_t)-1));
201    cursor_base = cursor;
202  }
203
204  template <typename T> void operator>>=(T const &src) {
205    assert(cursor_base != ((size_t)-1));
206    assert(cursor_base + sizeof(T) >= cursor);
207    cursor = cursor_base + sizeof(T);
208    cursor_base = (size_t)-1;
209  }
210
211  template <size_t size>
212  void operator&(char (&array)[size]) {
213    write_bytes(array, size);
214    seek(size);
215  }
216
217  template <size_t size>
218  void operator&(unsigned char (&array)[size]) {
219    write_bytes(array, size);
220    seek(size);
221  }
222
223#define SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER(T)                 \
224  void operator&(T const &v) {                                                \
225    using namespace detail;                                                   \
226                                                                              \
227    seek_to_next_address<T>();                                                \
228    write_bytes(&v, sizeof(T));                                               \
229                                                                              \
230    if (is_archive_little_endian != is_host_little_endian()) {                \
231      swap_byte_order(                                                        \
232        reinterpret_cast<unsigned char (&)[sizeof(T)]>(*get_cursor_ptr()));   \
233    }                                                                         \
234                                                                              \
235    seek(sizeof(T));                                                          \
236  }
237
238  SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER(bool)
239  SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER(int8_t)
240  SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER(int16_t)
241  SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER(int32_t)
242  SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER(int64_t)
243  SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER(uint8_t)
244  SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER(uint16_t)
245  SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER(uint32_t)
246  SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER(uint64_t)
247  SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER(float)
248  SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER(double)
249  SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER(void *)
250  SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER(void const *)
251
252#undef SERIALIZE_ARCHIVE_WRITER_WRITE_AND_SWAP_BYTE_ORDER
253
254  void seek(off_t off, bool from_begin = false) {
255    if (from_begin) {
256      cursor = off;
257    } else {
258      cursor += off;
259    }
260  }
261
262  // Note: Archive writer is always considered in "good" state, unless the
263  // buffer is not big enough, and an exception will be thrown.
264
265  operator void *() const {
266    return this;
267  }
268
269  bool operator!() const {
270    return false;
271  }
272
273private:
274  unsigned char *get_cursor_ptr() {
275    return &*buf.begin() + cursor;
276  }
277
278  void write_bytes(void const *array, size_t size) {
279    if (cursor + size > buf.size()) {
280      buf.resize(cursor + size);
281    }
282
283    memcpy(get_cursor_ptr(), array, size);
284  }
285
286  template <typename T>
287  void seek_to_next_address() {
288    if (!packed) {
289      size_t align = detail::type_traits<T>::alignment;
290      size_t delta = cursor % align;
291
292      if (delta > 0) {
293        memset(get_cursor_ptr(), '\0', align - delta);
294        seek(align - delta);
295      }
296    }
297  }
298
299};
300
301typedef archive_writer<true>  archive_writer_to_little_endian;
302typedef archive_writer<false> archive_writer_to_big_endian;
303
304}
305
306#endif
307