zstd.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // (C) Copyright Reimar Döffinger 2018.
  2. // Based on zstd.hpp by:
  3. // (C) Copyright Milan Svoboda 2008.
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
  6. // See http://www.boost.org/libs/iostreams for documentation.
  7. #ifndef BOOST_IOSTREAMS_ZSTD_HPP_INCLUDED
  8. #define BOOST_IOSTREAMS_ZSTD_HPP_INCLUDED
  9. #if defined(_MSC_VER)
  10. # pragma once
  11. #endif
  12. #include <cassert>
  13. #include <iosfwd> // streamsize.
  14. #include <memory> // allocator, bad_alloc.
  15. #include <new>
  16. #include <boost/config.hpp> // MSVC, STATIC_CONSTANT, DEDUCED_TYPENAME, DINKUM.
  17. #include <boost/detail/workaround.hpp>
  18. #include <boost/iostreams/constants.hpp> // buffer size.
  19. #include <boost/iostreams/detail/config/auto_link.hpp>
  20. #include <boost/iostreams/detail/config/dyn_link.hpp>
  21. #include <boost/iostreams/detail/config/wide_streams.hpp>
  22. #include <boost/iostreams/detail/ios.hpp> // failure, streamsize.
  23. #include <boost/iostreams/filter/symmetric.hpp>
  24. #include <boost/iostreams/pipeline.hpp>
  25. #include <boost/type_traits/is_same.hpp>
  26. // Must come last.
  27. #ifdef BOOST_MSVC
  28. # pragma warning(push)
  29. # pragma warning(disable:4251 4231 4660) // Dependencies not exported.
  30. #endif
  31. #include <boost/config/abi_prefix.hpp>
  32. namespace boost { namespace iostreams {
  33. namespace zstd {
  34. typedef void* (*alloc_func)(void*, size_t, size_t);
  35. typedef void (*free_func)(void*, void*);
  36. // Compression levels
  37. BOOST_IOSTREAMS_DECL extern const uint32_t best_speed;
  38. BOOST_IOSTREAMS_DECL extern const uint32_t best_compression;
  39. BOOST_IOSTREAMS_DECL extern const uint32_t default_compression;
  40. // Status codes
  41. BOOST_IOSTREAMS_DECL extern const int okay;
  42. BOOST_IOSTREAMS_DECL extern const int stream_end;
  43. // Flush codes
  44. BOOST_IOSTREAMS_DECL extern const int finish;
  45. BOOST_IOSTREAMS_DECL extern const int flush;
  46. BOOST_IOSTREAMS_DECL extern const int run;
  47. // Code for current OS
  48. // Null pointer constant.
  49. const int null = 0;
  50. // Default values
  51. } // End namespace zstd.
  52. //
  53. // Class name: zstd_params.
  54. // Description: Encapsulates the parameters passed to zstddec_init
  55. // to customize compression and decompression.
  56. //
  57. struct zstd_params {
  58. // Non-explicit constructor.
  59. zstd_params( uint32_t level = zstd::default_compression )
  60. : level(level)
  61. { }
  62. uint32_t level;
  63. };
  64. //
  65. // Class name: zstd_error.
  66. // Description: Subclass of std::ios::failure thrown to indicate
  67. // zstd errors other than out-of-memory conditions.
  68. //
  69. class BOOST_IOSTREAMS_DECL zstd_error : public BOOST_IOSTREAMS_FAILURE {
  70. public:
  71. explicit zstd_error(size_t error);
  72. int error() const { return error_; }
  73. static void check BOOST_PREVENT_MACRO_SUBSTITUTION(size_t error);
  74. private:
  75. size_t error_;
  76. };
  77. namespace detail {
  78. template<typename Alloc>
  79. struct zstd_allocator_traits {
  80. #ifndef BOOST_NO_STD_ALLOCATOR
  81. #if defined(BOOST_NO_CXX11_ALLOCATOR)
  82. typedef typename Alloc::template rebind<char>::other type;
  83. #else
  84. typedef typename std::allocator_traits<Alloc>::template rebind_alloc<char> type;
  85. #endif
  86. #else
  87. typedef std::allocator<char> type;
  88. #endif
  89. };
  90. template< typename Alloc,
  91. typename Base = // VC6 workaround (C2516)
  92. BOOST_DEDUCED_TYPENAME zstd_allocator_traits<Alloc>::type >
  93. struct zstd_allocator : private Base {
  94. private:
  95. #if defined(BOOST_NO_CXX11_ALLOCATOR) || defined(BOOST_NO_STD_ALLOCATOR)
  96. typedef typename Base::size_type size_type;
  97. #else
  98. typedef typename std::allocator_traits<Base>::size_type size_type;
  99. #endif
  100. public:
  101. BOOST_STATIC_CONSTANT(bool, custom =
  102. (!is_same<std::allocator<char>, Base>::value));
  103. typedef typename zstd_allocator_traits<Alloc>::type allocator_type;
  104. static void* allocate(void* self, size_t items, size_t size);
  105. static void deallocate(void* self, void* address);
  106. };
  107. class BOOST_IOSTREAMS_DECL zstd_base {
  108. public:
  109. typedef char char_type;
  110. protected:
  111. zstd_base();
  112. ~zstd_base();
  113. template<typename Alloc>
  114. void init( const zstd_params& p,
  115. bool compress,
  116. zstd_allocator<Alloc>& zalloc )
  117. {
  118. bool custom = zstd_allocator<Alloc>::custom;
  119. do_init( p, compress,
  120. custom ? zstd_allocator<Alloc>::allocate : 0,
  121. custom ? zstd_allocator<Alloc>::deallocate : 0,
  122. &zalloc );
  123. }
  124. void before( const char*& src_begin, const char* src_end,
  125. char*& dest_begin, char* dest_end );
  126. void after( const char*& src_begin, char*& dest_begin,
  127. bool compress );
  128. int deflate(int action);
  129. int inflate(int action);
  130. void reset(bool compress, bool realloc);
  131. private:
  132. void do_init( const zstd_params& p, bool compress,
  133. zstd::alloc_func,
  134. zstd::free_func,
  135. void* derived );
  136. void* cstream_; // Actual type: ZSTD_CStream *
  137. void* dstream_; // Actual type: ZSTD_DStream *
  138. void* in_; // Actual type: ZSTD_inBuffer *
  139. void* out_; // Actual type: ZSTD_outBuffer *
  140. int eof_;
  141. uint32_t level;
  142. };
  143. //
  144. // Template name: zstd_compressor_impl
  145. // Description: Model of C-Style Filter implementing compression by
  146. // delegating to the zstd function deflate.
  147. //
  148. template<typename Alloc = std::allocator<char> >
  149. class zstd_compressor_impl : public zstd_base, public zstd_allocator<Alloc> {
  150. public:
  151. zstd_compressor_impl(const zstd_params& = zstd::default_compression);
  152. ~zstd_compressor_impl();
  153. bool filter( const char*& src_begin, const char* src_end,
  154. char*& dest_begin, char* dest_end, bool flush );
  155. void close();
  156. };
  157. //
  158. // Template name: zstd_compressor_impl
  159. // Description: Model of C-Style Filte implementing decompression by
  160. // delegating to the zstd function inflate.
  161. //
  162. template<typename Alloc = std::allocator<char> >
  163. class zstd_decompressor_impl : public zstd_base, public zstd_allocator<Alloc> {
  164. public:
  165. zstd_decompressor_impl(const zstd_params&);
  166. zstd_decompressor_impl();
  167. ~zstd_decompressor_impl();
  168. bool filter( const char*& begin_in, const char* end_in,
  169. char*& begin_out, char* end_out, bool flush );
  170. void close();
  171. };
  172. } // End namespace detail.
  173. //
  174. // Template name: zstd_compressor
  175. // Description: Model of InputFilter and OutputFilter implementing
  176. // compression using zstd.
  177. //
  178. template<typename Alloc = std::allocator<char> >
  179. struct basic_zstd_compressor
  180. : symmetric_filter<detail::zstd_compressor_impl<Alloc>, Alloc>
  181. {
  182. private:
  183. typedef detail::zstd_compressor_impl<Alloc> impl_type;
  184. typedef symmetric_filter<impl_type, Alloc> base_type;
  185. public:
  186. typedef typename base_type::char_type char_type;
  187. typedef typename base_type::category category;
  188. basic_zstd_compressor( const zstd_params& = zstd::default_compression,
  189. std::streamsize buffer_size = default_device_buffer_size );
  190. };
  191. BOOST_IOSTREAMS_PIPABLE(basic_zstd_compressor, 1)
  192. typedef basic_zstd_compressor<> zstd_compressor;
  193. //
  194. // Template name: zstd_decompressor
  195. // Description: Model of InputFilter and OutputFilter implementing
  196. // decompression using zstd.
  197. //
  198. template<typename Alloc = std::allocator<char> >
  199. struct basic_zstd_decompressor
  200. : symmetric_filter<detail::zstd_decompressor_impl<Alloc>, Alloc>
  201. {
  202. private:
  203. typedef detail::zstd_decompressor_impl<Alloc> impl_type;
  204. typedef symmetric_filter<impl_type, Alloc> base_type;
  205. public:
  206. typedef typename base_type::char_type char_type;
  207. typedef typename base_type::category category;
  208. basic_zstd_decompressor( std::streamsize buffer_size = default_device_buffer_size );
  209. basic_zstd_decompressor( const zstd_params& p,
  210. std::streamsize buffer_size = default_device_buffer_size );
  211. };
  212. BOOST_IOSTREAMS_PIPABLE(basic_zstd_decompressor, 1)
  213. typedef basic_zstd_decompressor<> zstd_decompressor;
  214. //----------------------------------------------------------------------------//
  215. //------------------Implementation of zstd_allocator--------------------------//
  216. namespace detail {
  217. template<typename Alloc, typename Base>
  218. void* zstd_allocator<Alloc, Base>::allocate
  219. (void* self, size_t items, size_t size)
  220. {
  221. size_type len = items * size;
  222. char* ptr =
  223. static_cast<allocator_type*>(self)->allocate
  224. (len + sizeof(size_type)
  225. #if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
  226. , (char*)0
  227. #endif
  228. );
  229. *reinterpret_cast<size_type*>(ptr) = len;
  230. return ptr + sizeof(size_type);
  231. }
  232. template<typename Alloc, typename Base>
  233. void zstd_allocator<Alloc, Base>::deallocate(void* self, void* address)
  234. {
  235. char* ptr = reinterpret_cast<char*>(address) - sizeof(size_type);
  236. size_type len = *reinterpret_cast<size_type*>(ptr) + sizeof(size_type);
  237. static_cast<allocator_type*>(self)->deallocate(ptr, len);
  238. }
  239. //------------------Implementation of zstd_compressor_impl--------------------//
  240. template<typename Alloc>
  241. zstd_compressor_impl<Alloc>::zstd_compressor_impl(const zstd_params& p)
  242. { init(p, true, static_cast<zstd_allocator<Alloc>&>(*this)); }
  243. template<typename Alloc>
  244. zstd_compressor_impl<Alloc>::~zstd_compressor_impl()
  245. { reset(true, false); }
  246. template<typename Alloc>
  247. bool zstd_compressor_impl<Alloc>::filter
  248. ( const char*& src_begin, const char* src_end,
  249. char*& dest_begin, char* dest_end, bool flush )
  250. {
  251. before(src_begin, src_end, dest_begin, dest_end);
  252. int result = deflate(flush ? zstd::finish : zstd::run);
  253. after(src_begin, dest_begin, true);
  254. return result != zstd::stream_end;
  255. }
  256. template<typename Alloc>
  257. void zstd_compressor_impl<Alloc>::close() { reset(true, true); }
  258. //------------------Implementation of zstd_decompressor_impl------------------//
  259. template<typename Alloc>
  260. zstd_decompressor_impl<Alloc>::zstd_decompressor_impl(const zstd_params& p)
  261. { init(p, false, static_cast<zstd_allocator<Alloc>&>(*this)); }
  262. template<typename Alloc>
  263. zstd_decompressor_impl<Alloc>::~zstd_decompressor_impl()
  264. { reset(false, false); }
  265. template<typename Alloc>
  266. zstd_decompressor_impl<Alloc>::zstd_decompressor_impl()
  267. {
  268. zstd_params p;
  269. init(p, false, static_cast<zstd_allocator<Alloc>&>(*this));
  270. }
  271. template<typename Alloc>
  272. bool zstd_decompressor_impl<Alloc>::filter
  273. ( const char*& src_begin, const char* src_end,
  274. char*& dest_begin, char* dest_end, bool flush )
  275. {
  276. before(src_begin, src_end, dest_begin, dest_end);
  277. int result = inflate(flush ? zstd::finish : zstd::run);
  278. after(src_begin, dest_begin, false);
  279. return result != zstd::stream_end;
  280. }
  281. template<typename Alloc>
  282. void zstd_decompressor_impl<Alloc>::close() { reset(false, true); }
  283. } // End namespace detail.
  284. //------------------Implementation of zstd_compressor-----------------------//
  285. template<typename Alloc>
  286. basic_zstd_compressor<Alloc>::basic_zstd_compressor
  287. (const zstd_params& p, std::streamsize buffer_size)
  288. : base_type(buffer_size, p) { }
  289. //------------------Implementation of zstd_decompressor-----------------------//
  290. template<typename Alloc>
  291. basic_zstd_decompressor<Alloc>::basic_zstd_decompressor
  292. (std::streamsize buffer_size)
  293. : base_type(buffer_size) { }
  294. template<typename Alloc>
  295. basic_zstd_decompressor<Alloc>::basic_zstd_decompressor
  296. (const zstd_params& p, std::streamsize buffer_size)
  297. : base_type(buffer_size, p) { }
  298. //----------------------------------------------------------------------------//
  299. } } // End namespaces iostreams, boost.
  300. #include <boost/config/abi_suffix.hpp> // Pops abi_suffix.hpp pragmas.
  301. #ifdef BOOST_MSVC
  302. # pragma warning(pop)
  303. #endif
  304. #endif // #ifndef BOOST_IOSTREAMS_ZSTD_HPP_INCLUDED