serializer.hpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #pragma once
  2. //serializer: a class designed to save and restore the state of classes.
  3. //
  4. //benefits:
  5. //- data() will be portable in size (it is not necessary to specify type sizes.)
  6. //- data() will be portable in endianness (always stored internally as little-endian.)
  7. //- one serialize function can both save and restore class states.
  8. //
  9. //caveats:
  10. //- only plain-old-data can be stored. complex classes must provide serialize(serializer&);
  11. //- floating-point usage is not portable across different implementations
  12. #include <nall/array.hpp>
  13. #include <nall/range.hpp>
  14. #include <nall/stdint.hpp>
  15. #include <nall/traits.hpp>
  16. #include <nall/utility.hpp>
  17. namespace nall {
  18. struct serializer;
  19. template<typename T>
  20. struct has_serialize {
  21. template<typename C> static auto test(decltype(std::declval<C>().serialize(std::declval<serializer&>()))*) -> char;
  22. template<typename C> static auto test(...) -> long;
  23. static const bool value = sizeof(test<T>(0)) == sizeof(char);
  24. };
  25. struct serializer {
  26. enum Mode : uint { Load, Save, Size };
  27. explicit operator bool() const {
  28. return _size;
  29. }
  30. auto setMode(Mode mode) -> void {
  31. _mode = mode;
  32. _size = 0;
  33. }
  34. auto mode() const -> Mode {
  35. return _mode;
  36. }
  37. auto data() const -> const uint8_t* {
  38. return _data;
  39. }
  40. auto size() const -> uint {
  41. return _size;
  42. }
  43. auto capacity() const -> uint {
  44. return _capacity;
  45. }
  46. template<typename T> auto real(T& value) -> serializer& {
  47. enum : uint { size = sizeof(T) };
  48. //this is rather dangerous, and not cross-platform safe;
  49. //but there is no standardized way to export FP-values
  50. auto p = (uint8_t*)&value;
  51. if(_mode == Save) {
  52. for(uint n : range(size)) _data[_size++] = p[n];
  53. } else if(_mode == Load) {
  54. for(uint n : range(size)) p[n] = _data[_size++];
  55. } else {
  56. _size += size;
  57. }
  58. return *this;
  59. }
  60. template<typename T> auto boolean(T& value) -> serializer& {
  61. if(_mode == Save) {
  62. _data[_size++] = (bool)value;
  63. } else if(_mode == Load) {
  64. value = (bool)_data[_size++];
  65. } else if(_mode == Size) {
  66. _size += 1;
  67. }
  68. return *this;
  69. }
  70. template<typename T> auto integer(T& value) -> serializer& {
  71. enum : uint { size = std::is_same<bool, T>::value ? 1 : sizeof(T) };
  72. if(_mode == Save) {
  73. T copy = value;
  74. for(uint n : range(size)) _data[_size++] = copy, copy >>= 8;
  75. } else if(_mode == Load) {
  76. value = 0;
  77. for(uint n : range(size)) value |= (T)_data[_size++] << (n << 3);
  78. } else if(_mode == Size) {
  79. _size += size;
  80. }
  81. return *this;
  82. }
  83. template<typename T, int N> auto array(T (&array)[N]) -> serializer& {
  84. for(uint n : range(N)) operator()(array[n]);
  85. return *this;
  86. }
  87. template<typename T> auto array(T array, uint size) -> serializer& {
  88. for(uint n : range(size)) operator()(array[n]);
  89. return *this;
  90. }
  91. template<typename T, uint Size> auto array(nall::array<T[Size]>& array) -> serializer& {
  92. for(auto& value : array) operator()(value);
  93. return *this;
  94. }
  95. //optimized specializations
  96. auto array(uint8_t* data, uint size) -> serializer& {
  97. if(_mode == Save) {
  98. memory::copy(_data + _size, data, size);
  99. } else if(_mode == Load) {
  100. memory::copy(data, _data + _size, size);
  101. } else {
  102. }
  103. _size += size;
  104. return *this;
  105. }
  106. template<int N> auto array(uint8_t (&data)[N]) -> serializer& {
  107. return array(data, N);
  108. }
  109. //nall/serializer saves data in little-endian ordering
  110. #if defined(ENDIAN_LSB)
  111. auto array(uint16_t* data, uint size) -> serializer& { return array((uint8_t*)data, size * sizeof(uint16_t)); }
  112. auto array(uint32_t* data, uint size) -> serializer& { return array((uint8_t*)data, size * sizeof(uint32_t)); }
  113. auto array(uint64_t* data, uint size) -> serializer& { return array((uint8_t*)data, size * sizeof(uint64_t)); }
  114. template<int N> auto array(uint16_t (&data)[N]) -> serializer& { return array(data, N); }
  115. template<int N> auto array(uint32_t (&data)[N]) -> serializer& { return array(data, N); }
  116. template<int N> auto array(uint64_t (&data)[N]) -> serializer& { return array(data, N); }
  117. #endif
  118. template<typename T> auto operator()(T& value, typename std::enable_if<has_serialize<T>::value>::type* = 0) -> serializer& { value.serialize(*this); return *this; }
  119. template<typename T> auto operator()(T& value, typename std::enable_if<std::is_integral<T>::value>::type* = 0) -> serializer& { return integer(value); }
  120. template<typename T> auto operator()(T& value, typename std::enable_if<std::is_floating_point<T>::value>::type* = 0) -> serializer& { return real(value); }
  121. template<typename T> auto operator()(T& value, typename std::enable_if<std::is_array<T>::value>::type* = 0) -> serializer& { return array(value); }
  122. template<typename T> auto operator()(T& value, uint size, typename std::enable_if<std::is_pointer<T>::value>::type* = 0) -> serializer& { return array(value, size); }
  123. auto operator=(const serializer& s) -> serializer& {
  124. if(_data) delete[] _data;
  125. _mode = s._mode;
  126. _data = new uint8_t[s._capacity];
  127. _size = s._size;
  128. _capacity = s._capacity;
  129. memcpy(_data, s._data, s._capacity);
  130. return *this;
  131. }
  132. auto operator=(serializer&& s) -> serializer& {
  133. if(_data) delete[] _data;
  134. _mode = s._mode;
  135. _data = s._data;
  136. _size = s._size;
  137. _capacity = s._capacity;
  138. s._data = nullptr;
  139. return *this;
  140. }
  141. serializer() = default;
  142. serializer(const serializer& s) { operator=(s); }
  143. serializer(serializer&& s) { operator=(move(s)); }
  144. serializer(uint capacity) {
  145. _mode = Save;
  146. _data = new uint8_t[capacity]();
  147. _size = 0;
  148. _capacity = capacity;
  149. }
  150. serializer(const uint8_t* data, uint capacity) {
  151. _mode = Load;
  152. _data = new uint8_t[capacity];
  153. _size = 0;
  154. _capacity = capacity;
  155. memcpy(_data, data, capacity);
  156. }
  157. ~serializer() {
  158. if(_data) delete[] _data;
  159. }
  160. private:
  161. Mode _mode = Size;
  162. uint8_t* _data = nullptr;
  163. uint _size = 0;
  164. uint _capacity = 0;
  165. };
  166. }