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