codec.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /**
  2. * Copyright (C) 2015 Topology LP
  3. * All rights reserved.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy
  6. * of this software and associated documentation files (the "Software"), to
  7. * deal in the Software without restriction, including without limitation the
  8. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9. * sell copies of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in
  13. * all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  18. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21. * IN THE SOFTWARE.
  22. */
  23. #ifndef CPPCODEC_DETAIL_CODEC
  24. #define CPPCODEC_DETAIL_CODEC
  25. #include <assert.h>
  26. #include <stdint.h>
  27. #include <string>
  28. #include <vector>
  29. #include "../data/access.hpp"
  30. #include "../data/raw_result_buffer.hpp"
  31. namespace cppcodec {
  32. namespace detail {
  33. // SFINAE: Templates sometimes beat sensible overloads - make sure we don't call the wrong one.
  34. template <typename T>
  35. struct non_numeric : std::enable_if<!std::is_arithmetic<T>::value> { };
  36. /**
  37. * Public interface for all the codecs. For API documentation, see README.md.
  38. */
  39. template <typename CodecImpl>
  40. class codec
  41. {
  42. public:
  43. //
  44. // Encoding
  45. // Convenient version, returns an std::string.
  46. static std::string encode(const uint8_t* binary, size_t binary_size);
  47. static std::string encode(const char* binary, size_t binary_size);
  48. // static std::string encode(const T& binary); -> provided by template below
  49. // Convenient version with templated result type.
  50. template <typename Result> static Result encode(const uint8_t* binary, size_t binary_size);
  51. template <typename Result> static Result encode(const char* binary, size_t binary_size);
  52. template <typename Result = std::string, typename T = std::vector<uint8_t>>
  53. static Result encode(const T& binary);
  54. // Reused result container version. Resizes encoded_result before writing to it.
  55. template <typename Result>
  56. static void encode(Result& encoded_result, const uint8_t* binary, size_t binary_size);
  57. template <typename Result>
  58. static void encode(Result& encoded_result, const char* binary, size_t binary_size);
  59. template <typename Result, typename T, typename non_numeric<T>::type* = nullptr>
  60. static void encode(Result& encoded_result, const T& binary);
  61. // Raw pointer output, assumes pre-allocated memory with size > encoded_size(binary_size).
  62. static size_t encode(
  63. char* encoded_result, size_t encoded_buffer_size,
  64. const uint8_t* binary, size_t binary_size) noexcept;
  65. static size_t encode(
  66. char* encoded_result, size_t encoded_buffer_size,
  67. const char* binary, size_t binary_size) noexcept;
  68. template<typename T>
  69. static size_t encode(
  70. char* encoded_result, size_t encoded_buffer_size,
  71. const T& binary) noexcept;
  72. // Calculate the exact length of the encoded string based on binary size.
  73. static constexpr size_t encoded_size(size_t binary_size) noexcept;
  74. //
  75. // Decoding
  76. // Convenient version, returns an std::vector<uint8_t>.
  77. static std::vector<uint8_t> decode(const char* encoded, size_t encoded_size);
  78. // static std::vector<uint8_t> decode(const T& encoded); -> provided by template below
  79. // Convenient version with templated result type.
  80. template <typename Result> static Result decode(const char* encoded, size_t encoded_size);
  81. template <typename Result = std::vector<uint8_t>, typename T = std::string>
  82. static Result decode(const T& encoded);
  83. // Reused result container version. Resizes binary_result before writing to it.
  84. template <typename Result>
  85. static void decode(Result& binary_result, const char* encoded, size_t encoded_size);
  86. template <typename Result, typename T, typename non_numeric<T>::type* = nullptr>
  87. static void decode(Result& binary_result, const T& encoded);
  88. // Raw pointer output, assumes pre-allocated memory with size > decoded_max_size(encoded_size).
  89. static size_t decode(
  90. uint8_t* binary_result, size_t binary_buffer_size,
  91. const char* encoded, size_t encoded_size);
  92. static size_t decode(
  93. char* binary_result, size_t binary_buffer_size,
  94. const char* encoded, size_t encoded_size);
  95. template<typename T> static size_t decode(
  96. uint8_t* binary_result, size_t binary_buffer_size, const T& encoded);
  97. template<typename T> static size_t decode(
  98. char* binary_result, size_t binary_buffer_size, const T& encoded);
  99. // Calculate the maximum size of the decoded binary buffer based on the encoded string length.
  100. static constexpr size_t decoded_max_size(size_t encoded_size) noexcept;
  101. };
  102. //
  103. // Inline definitions of the above functions, using CRTP to call into CodecImpl
  104. //
  105. //
  106. // Encoding
  107. template <typename CodecImpl>
  108. inline std::string codec<CodecImpl>::encode(const uint8_t* binary, size_t binary_size)
  109. {
  110. return encode<std::string>(binary, binary_size);
  111. }
  112. template <typename CodecImpl>
  113. inline std::string codec<CodecImpl>::encode(const char* binary, size_t binary_size)
  114. {
  115. return encode<std::string>(reinterpret_cast<const uint8_t*>(binary), binary_size);
  116. }
  117. template <typename CodecImpl>
  118. template <typename Result>
  119. inline Result codec<CodecImpl>::encode(const uint8_t* binary, size_t binary_size)
  120. {
  121. Result encoded_result;
  122. encode(encoded_result, binary, binary_size);
  123. return encoded_result;
  124. }
  125. template <typename CodecImpl>
  126. template <typename Result>
  127. inline Result codec<CodecImpl>::encode(const char* binary, size_t binary_size)
  128. {
  129. return encode<Result>(reinterpret_cast<const uint8_t*>(binary), binary_size);
  130. }
  131. template <typename CodecImpl>
  132. template <typename Result, typename T>
  133. inline Result codec<CodecImpl>::encode(const T& binary)
  134. {
  135. return encode<Result>(data::uchar_data(binary), data::size(binary));
  136. }
  137. template <typename CodecImpl>
  138. template <typename Result>
  139. inline void codec<CodecImpl>::encode(
  140. Result& encoded_result, const uint8_t* binary, size_t binary_size)
  141. {
  142. // This overload is where we reserve buffer capacity and call into CodecImpl.
  143. size_t encoded_buffer_size = encoded_size(binary_size);
  144. auto state = data::create_state(encoded_result, data::specific_t());
  145. data::init(encoded_result, state, encoded_buffer_size);
  146. CodecImpl::encode(encoded_result, state, binary, binary_size);
  147. data::finish(encoded_result, state);
  148. assert(data::size(encoded_result) == encoded_buffer_size);
  149. }
  150. template <typename CodecImpl>
  151. template <typename Result>
  152. inline void codec<CodecImpl>::encode(
  153. Result& encoded_result, const char* binary, size_t binary_size)
  154. {
  155. encode(encoded_result, reinterpret_cast<const uint8_t*>(binary), binary_size);
  156. }
  157. template <typename CodecImpl>
  158. template <typename Result, typename T, typename non_numeric<T>::type*>
  159. inline void codec<CodecImpl>::encode(Result& encoded_result, const T& binary)
  160. {
  161. encode(encoded_result, data::uchar_data(binary), data::size(binary));
  162. }
  163. template <typename CodecImpl>
  164. inline size_t codec<CodecImpl>::encode(
  165. char* encoded_result, size_t encoded_buffer_size,
  166. const uint8_t* binary, size_t binary_size) noexcept
  167. {
  168. // This overload is where we wrap the result pointer & size.
  169. data::raw_result_buffer encoded(encoded_result, encoded_buffer_size);
  170. encode(encoded, binary, binary_size);
  171. size_t encoded_size = data::size(encoded);
  172. if (encoded_size < encoded_buffer_size) {
  173. encoded_result[encoded_size] = '\0';
  174. }
  175. return encoded_size;
  176. }
  177. template <typename CodecImpl>
  178. inline size_t codec<CodecImpl>::encode(
  179. char* encoded_result, size_t encoded_buffer_size,
  180. const char* binary, size_t binary_size) noexcept
  181. {
  182. // This overload is where we wrap the result pointer & size.
  183. return encode(encoded_result, encoded_buffer_size,
  184. reinterpret_cast<const uint8_t*>(binary), binary_size);
  185. }
  186. template <typename CodecImpl>
  187. template <typename T>
  188. inline size_t codec<CodecImpl>::encode(
  189. char* encoded_result, size_t encoded_buffer_size,
  190. const T& binary) noexcept
  191. {
  192. return encode(encoded_result, encoded_buffer_size, data::uchar_data(binary), data::size(binary));
  193. }
  194. template <typename CodecImpl>
  195. inline constexpr size_t codec<CodecImpl>::encoded_size(size_t binary_size) noexcept
  196. {
  197. return CodecImpl::encoded_size(binary_size);
  198. }
  199. //
  200. // Decoding
  201. template <typename CodecImpl>
  202. inline std::vector<uint8_t> codec<CodecImpl>::decode(const char* encoded, size_t encoded_size)
  203. {
  204. return decode<std::vector<uint8_t>>(encoded, encoded_size);
  205. }
  206. template <typename CodecImpl>
  207. template <typename Result>
  208. inline Result codec<CodecImpl>::decode(const char* encoded, size_t encoded_size)
  209. {
  210. Result result;
  211. decode(result, encoded, encoded_size);
  212. return result;
  213. }
  214. template <typename CodecImpl>
  215. template <typename Result, typename T>
  216. inline Result codec<CodecImpl>::decode(const T& encoded)
  217. {
  218. return decode<Result>(data::char_data(encoded), data::size(encoded));
  219. }
  220. template <typename CodecImpl>
  221. template <typename Result>
  222. inline void codec<CodecImpl>::decode(Result& binary_result, const char* encoded, size_t encoded_size)
  223. {
  224. // This overload is where we reserve buffer capacity and call into CodecImpl.
  225. size_t binary_buffer_size = decoded_max_size(encoded_size);
  226. auto state = data::create_state(binary_result, data::specific_t());
  227. data::init(binary_result, state, binary_buffer_size);
  228. CodecImpl::decode(binary_result, state, encoded, encoded_size);
  229. data::finish(binary_result, state);
  230. assert(data::size(binary_result) <= binary_buffer_size);
  231. }
  232. template <typename CodecImpl>
  233. template <typename Result, typename T, typename non_numeric<T>::type*>
  234. inline void codec<CodecImpl>::decode(Result& binary_result, const T& encoded)
  235. {
  236. decode(binary_result, data::char_data(encoded), data::size(encoded));
  237. }
  238. template <typename CodecImpl>
  239. inline size_t codec<CodecImpl>::decode(
  240. uint8_t* binary_result, size_t binary_buffer_size,
  241. const char* encoded, size_t encoded_size)
  242. {
  243. return decode(reinterpret_cast<char*>(binary_result), binary_buffer_size, encoded, encoded_size);
  244. }
  245. template <typename CodecImpl>
  246. inline size_t codec<CodecImpl>::decode(
  247. char* binary_result, size_t binary_buffer_size,
  248. const char* encoded, size_t encoded_size)
  249. {
  250. // This overload is where we wrap the result pointer & size.
  251. data::raw_result_buffer binary(binary_result, binary_buffer_size);
  252. decode(binary, encoded, encoded_size);
  253. return data::size(binary);
  254. }
  255. template <typename CodecImpl>
  256. template <typename T>
  257. inline size_t codec<CodecImpl>::decode(
  258. uint8_t* binary_result, size_t binary_buffer_size, const T& encoded)
  259. {
  260. return decode(reinterpret_cast<char*>(binary_result), binary_buffer_size, encoded);
  261. }
  262. template <typename CodecImpl>
  263. template <typename T>
  264. inline size_t codec<CodecImpl>::decode(char* binary_result, size_t binary_buffer_size, const T& encoded)
  265. {
  266. return decode(binary_result, binary_buffer_size, data::char_data(encoded), data::size(encoded));
  267. }
  268. template <typename CodecImpl>
  269. inline constexpr size_t codec<CodecImpl>::decoded_max_size(size_t encoded_size) noexcept
  270. {
  271. return CodecImpl::decoded_max_size(encoded_size);
  272. }
  273. } // namespace detail
  274. } // namespace cppcodec
  275. #endif