Numbers.hpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. ///
  2. /// \file Archive/Numbers.hpp
  3. ///
  4. /// Numeric support for serialization.
  5. ///
  6. /// Integers are serialized into a portable byte ordering
  7. /// to work across big and little platform endianness.
  8. /// In addition, all long types get serialized as 8 bytes
  9. /// because the size of long may vary from 4 to 8 bytes.
  10. ///
  11. /// Floats are cast to an integer type of identical size
  12. /// and serialized as an integer; also for platform endianness.
  13. /// The implementation assumes the IEEE-754 format for floats,
  14. /// but could easily be expanded for soft packing of IEEE-754.
  15. ///
  16. /// \copyright
  17. /// Copyright (c) 2016-2017 Josh Blum
  18. /// SPDX-License-Identifier: BSL-1.0
  19. ///
  20. #pragma once
  21. #include <Pothos/Config.hpp>
  22. #include <Pothos/Archive/Invoke.hpp>
  23. #include <Pothos/Archive/BinaryObject.hpp>
  24. #include <type_traits>
  25. #include <limits> //is_iec559
  26. namespace Pothos {
  27. namespace serialization {
  28. //------------ boolean support --------------//
  29. template<typename Archive>
  30. void save(Archive &ar, const bool &t, const unsigned int)
  31. {
  32. unsigned char value(t?1:0);
  33. ar << value;
  34. }
  35. template<typename Archive>
  36. void load(Archive &ar, bool &t, const unsigned int)
  37. {
  38. unsigned char value;
  39. ar >> value;
  40. t = (value == 0)?false:true;
  41. }
  42. //------------ 8 bit integer support (all char types) --------------//
  43. template<typename Archive, typename T>
  44. typename std::enable_if<
  45. std::is_same<T, unsigned char>::value or
  46. std::is_same<T, signed char>::value or
  47. std::is_same<T, char>::value
  48. >::type save(Archive &ar, const T &t, const unsigned int)
  49. {
  50. BinaryObject bo(&t, 1);
  51. ar << bo;
  52. }
  53. template<typename Archive, typename T>
  54. typename std::enable_if<
  55. std::is_same<T, unsigned char>::value or
  56. std::is_same<T, signed char>::value or
  57. std::is_same<T, char>::value
  58. >::type load(Archive &ar, T &t, const unsigned int)
  59. {
  60. BinaryObject bo(&t, 1);
  61. ar >> bo;
  62. }
  63. //------------ 16 bit integer support (short types) --------------//
  64. template<typename Archive, typename T>
  65. typename std::enable_if<
  66. std::is_same<T, unsigned short>::value or
  67. std::is_same<T, signed short>::value
  68. >::type save(Archive &ar, const T &t, const unsigned int)
  69. {
  70. unsigned char buff[2];
  71. const auto v = static_cast<unsigned short>(t);
  72. buff[0] = static_cast<unsigned char>(v >> 0);
  73. buff[1] = static_cast<unsigned char>(v >> 8);
  74. BinaryObject bo(buff, sizeof(buff));
  75. ar << bo;
  76. }
  77. template<typename Archive, typename T>
  78. typename std::enable_if<
  79. std::is_same<T, unsigned short>::value or
  80. std::is_same<T, signed short>::value
  81. >::type load(Archive &ar, T &t, const unsigned int)
  82. {
  83. unsigned char buff[2];
  84. BinaryObject bo(buff, sizeof(buff));
  85. ar >> bo;
  86. t = static_cast<T>(
  87. (static_cast<unsigned short>(buff[0]) << 0) |
  88. (static_cast<unsigned short>(buff[1]) << 8));
  89. }
  90. //------------ 32-64 bit signed integer types --------------//
  91. // use signed LEB128 encoding for variable length encoding
  92. // https://en.wikipedia.org/wiki/LEB128
  93. template<typename Archive, typename T>
  94. typename std::enable_if<
  95. std::is_same<T, signed int>::value or
  96. std::is_same<T, signed long>::value or
  97. std::is_same<T, signed long long>::value
  98. >::type save(Archive &ar, const T &t, const unsigned int)
  99. {
  100. T value(t);
  101. unsigned char byte;
  102. do
  103. {
  104. byte = static_cast<unsigned char>(value) & 0x7f;
  105. value >>= 7; //must be arithmetic shift
  106. const auto signbit = byte & 0x40;
  107. if ((value != 0 or signbit != 0) and
  108. (value != -1 or signbit == 0)) byte |= 0x80;
  109. ar << byte;
  110. } while ((byte & 0x80) != 0);
  111. }
  112. template<typename Archive, typename T>
  113. typename std::enable_if<
  114. std::is_same<T, signed int>::value or
  115. std::is_same<T, signed long>::value or
  116. std::is_same<T, signed long long>::value
  117. >::type load(Archive &ar, T &t, const unsigned int)
  118. {
  119. t = T(0);
  120. unsigned shift(0);
  121. unsigned char byte;
  122. do
  123. {
  124. ar >> byte;
  125. t |= T(byte & 0x7f) << shift;
  126. shift += 7;
  127. } while ((byte & 0x80) != 0);
  128. //sign extend the remaining bits when negative
  129. const auto signbit = byte & 0x40;
  130. if (signbit != 0 and shift < (sizeof(T)*8)) t |= -(1 << shift);
  131. }
  132. //------------ 32-64 bit unsigned integer types --------------//
  133. // use unsigned LEB128 encoding for variable length encoding
  134. // https://en.wikipedia.org/wiki/LEB128
  135. template<typename Archive, typename T>
  136. typename std::enable_if<
  137. std::is_same<T, unsigned int>::value or
  138. std::is_same<T, unsigned long>::value or
  139. std::is_same<T, unsigned long long>::value
  140. >::type save(Archive &ar, const T &t, const unsigned int)
  141. {
  142. T value(t);
  143. unsigned char byte;
  144. do
  145. {
  146. byte = static_cast<unsigned char>(value) & 0x7f;
  147. value >>= 7;
  148. if (value != 0) byte |= 0x80;
  149. ar << byte;
  150. } while ((byte & 0x80) != 0);
  151. }
  152. template<typename Archive, typename T>
  153. typename std::enable_if<
  154. std::is_same<T, unsigned int>::value or
  155. std::is_same<T, unsigned long>::value or
  156. std::is_same<T, unsigned long long>::value
  157. >::type load(Archive &ar, T &t, const unsigned int)
  158. {
  159. t = T(0);
  160. unsigned shift(0);
  161. unsigned char byte;
  162. do
  163. {
  164. ar >> byte;
  165. t |= T(byte & 0x7f) << shift;
  166. shift += 7;
  167. } while ((byte & 0x80) != 0);
  168. }
  169. //------------ 32-bit float support --------------//
  170. static_assert(std::numeric_limits<float>::is_iec559, "System is IEEE-754");
  171. template<typename Archive>
  172. typename std::enable_if<std::numeric_limits<float>::is_iec559>::type
  173. save(Archive &ar, const float &t, const unsigned int)
  174. {
  175. const void *bin(&t);
  176. ar << *static_cast<const unsigned int *>(bin);
  177. }
  178. template<typename Archive>
  179. typename std::enable_if<std::numeric_limits<float>::is_iec559>::type
  180. load(Archive &ar, float &t, const unsigned int)
  181. {
  182. unsigned int num;
  183. ar >> num;
  184. const void *bin(&num);
  185. t = *reinterpret_cast<const float *>(bin);
  186. }
  187. //------------ 64-bit float support --------------//
  188. static_assert(std::numeric_limits<double>::is_iec559, "System is IEEE-754");
  189. template<typename Archive>
  190. typename std::enable_if<std::numeric_limits<double>::is_iec559>::type
  191. save(Archive &ar, const double &t, const unsigned int)
  192. {
  193. const void *bin(&t);
  194. ar << *static_cast<const unsigned long long *>(bin);
  195. }
  196. template<typename Archive>
  197. typename std::enable_if<std::numeric_limits<double>::is_iec559>::type
  198. load(Archive &ar, double &t, const unsigned int)
  199. {
  200. unsigned long long num;
  201. ar >> num;
  202. const void *bin(&num);
  203. t = *reinterpret_cast<const double *>(bin);
  204. }
  205. //------------ serialize for integers and floats --------------//
  206. template <typename Archive, typename T>
  207. typename std::enable_if<std::is_arithmetic<T>::value>::type
  208. serialize(Archive &ar, T &t, const unsigned int ver)
  209. {
  210. Pothos::serialization::invokeSplit(ar, t, ver);
  211. }
  212. }}