zstd-ruby 1.5.5.0 → 1.5.6.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/README.md +81 -11
  4. data/ext/zstdruby/common.h +172 -1
  5. data/ext/zstdruby/extconf.rb +3 -1
  6. data/ext/zstdruby/libzstd/common/allocations.h +1 -1
  7. data/ext/zstdruby/libzstd/common/bitstream.h +49 -29
  8. data/ext/zstdruby/libzstd/common/compiler.h +114 -22
  9. data/ext/zstdruby/libzstd/common/cpu.h +36 -0
  10. data/ext/zstdruby/libzstd/common/debug.c +6 -0
  11. data/ext/zstdruby/libzstd/common/debug.h +20 -11
  12. data/ext/zstdruby/libzstd/common/error_private.h +45 -36
  13. data/ext/zstdruby/libzstd/common/fse.h +3 -2
  14. data/ext/zstdruby/libzstd/common/fse_decompress.c +19 -17
  15. data/ext/zstdruby/libzstd/common/huf.h +14 -1
  16. data/ext/zstdruby/libzstd/common/mem.h +0 -9
  17. data/ext/zstdruby/libzstd/common/pool.c +1 -1
  18. data/ext/zstdruby/libzstd/common/pool.h +1 -1
  19. data/ext/zstdruby/libzstd/common/portability_macros.h +2 -0
  20. data/ext/zstdruby/libzstd/common/threading.c +8 -2
  21. data/ext/zstdruby/libzstd/common/xxhash.c +5 -11
  22. data/ext/zstdruby/libzstd/common/xxhash.h +2341 -1007
  23. data/ext/zstdruby/libzstd/common/zstd_internal.h +5 -5
  24. data/ext/zstdruby/libzstd/compress/fse_compress.c +8 -7
  25. data/ext/zstdruby/libzstd/compress/huf_compress.c +54 -25
  26. data/ext/zstdruby/libzstd/compress/zstd_compress.c +282 -161
  27. data/ext/zstdruby/libzstd/compress/zstd_compress_internal.h +29 -27
  28. data/ext/zstdruby/libzstd/compress/zstd_compress_superblock.c +224 -113
  29. data/ext/zstdruby/libzstd/compress/zstd_cwksp.h +19 -13
  30. data/ext/zstdruby/libzstd/compress/zstd_double_fast.c +17 -5
  31. data/ext/zstdruby/libzstd/compress/zstd_double_fast.h +11 -0
  32. data/ext/zstdruby/libzstd/compress/zstd_fast.c +14 -6
  33. data/ext/zstdruby/libzstd/compress/zstd_lazy.c +129 -87
  34. data/ext/zstdruby/libzstd/compress/zstd_lazy.h +103 -28
  35. data/ext/zstdruby/libzstd/compress/zstd_ldm.c +8 -2
  36. data/ext/zstdruby/libzstd/compress/zstd_opt.c +216 -112
  37. data/ext/zstdruby/libzstd/compress/zstd_opt.h +31 -7
  38. data/ext/zstdruby/libzstd/compress/zstdmt_compress.c +94 -79
  39. data/ext/zstdruby/libzstd/decompress/huf_decompress.c +188 -126
  40. data/ext/zstdruby/libzstd/decompress/huf_decompress_amd64.S +38 -19
  41. data/ext/zstdruby/libzstd/decompress/zstd_decompress.c +84 -32
  42. data/ext/zstdruby/libzstd/decompress/zstd_decompress_block.c +231 -208
  43. data/ext/zstdruby/libzstd/decompress/zstd_decompress_block.h +1 -1
  44. data/ext/zstdruby/libzstd/decompress/zstd_decompress_internal.h +2 -0
  45. data/ext/zstdruby/libzstd/dictBuilder/cover.c +16 -12
  46. data/ext/zstdruby/libzstd/dictBuilder/cover.h +2 -8
  47. data/ext/zstdruby/libzstd/dictBuilder/fastcover.c +2 -2
  48. data/ext/zstdruby/libzstd/dictBuilder/zdict.c +12 -6
  49. data/ext/zstdruby/libzstd/zstd.h +129 -60
  50. data/ext/zstdruby/main.c +2 -1
  51. data/ext/zstdruby/skippable_frame.c +1 -1
  52. data/ext/zstdruby/streaming_compress.c +75 -23
  53. data/ext/zstdruby/streaming_decompress.c +41 -40
  54. data/ext/zstdruby/zstdruby.c +60 -52
  55. data/lib/zstd-ruby/stream_reader.rb +22 -0
  56. data/lib/zstd-ruby/stream_writer.rb +23 -0
  57. data/lib/zstd-ruby/version.rb +1 -1
  58. data/lib/zstd-ruby.rb +2 -0
  59. data/renovate.json +6 -0
  60. data/zstd-ruby.gemspec +2 -1
  61. metadata +20 -4
  62. data/ext/zstdruby/streaming_compress.h +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 76dbffc6a0a13fccd92ea93abd90e33c4a26ab2ac2972877b7928a515e37033e
4
- data.tar.gz: 21e3eba574ac94d9f34ac0d33732435ed3fd2373e9db921702a74d2a2c9d606a
3
+ metadata.gz: 1fe1a5bcfa102673b36ea9a48096636faa76535095211998cddfe316775a3d78
4
+ data.tar.gz: e2a96d0d1d2bdda0bc3d34080df219aeaa8c5274a2dac7a838730fce54ebe4f6
5
5
  SHA512:
6
- metadata.gz: 4f8c40ad6eaa9b014467fc57651f857713767f7930b2e7e2060c50ff58d05262416d0e9cb1427f440298af577eeef5247daec1866a55003ca6d9b2e2ea6212de
7
- data.tar.gz: 5836f8061f7588081df400bf0705fcc74003029ec9ef9225e43f5ba5a0b19ec747af71cf0e34f150212a5efd90b9e1ea5ebe49a7231297e3f2ab8080bbf8247d
6
+ metadata.gz: 6bdffd7e5b2d824fdf5ebad116ef4b965c4d4d2a77898df5a51623020db6fddf0e4562aa4d80de7f8978fa5f557ce85e56d19042667c379b3ac97c3a274a9d11
7
+ data.tar.gz: 639a3d64cf8a8fa36a10cf180560a4102516d4da21e3100c1cdd724732fb583449c828ac4eeef6f9bad89c2f22467f7adf80b083116121ccff8d356c58246966
data/.gitignore CHANGED
@@ -19,3 +19,5 @@ vendor/
19
19
  .rspec_status
20
20
 
21
21
  .ruby-version
22
+
23
+ .vscode
data/README.md CHANGED
@@ -10,7 +10,7 @@ See https://github.com/facebook/zstd
10
10
  Fork from https://github.com/jarredholman/ruby-zstd.
11
11
 
12
12
  ## Zstd version
13
- v1.5.5 (https://github.com/facebook/zstd/tree/v1.5.5)
13
+ [v1.5.6](https://github.com/facebook/zstd/tree/v1.5.6)
14
14
 
15
15
  ## Installation
16
16
 
@@ -34,20 +34,22 @@ Or install it yourself as:
34
34
  require 'zstd-ruby'
35
35
  ```
36
36
 
37
- ### Simple Compression
37
+ ### Compression
38
+
39
+ #### Simple Compression
38
40
 
39
41
  ```ruby
40
42
  compressed_data = Zstd.compress(data)
41
- compressed_data = Zstd.compress(data, complession_level) # default compression_level is 0
43
+ compressed_data = Zstd.compress(data, level: complession_level) # default compression_level is 3
42
44
  ```
43
45
 
44
- ### Compression using Dictionary
46
+ #### Compression with Dictionary
45
47
  ```ruby
46
48
  # dictionary is supposed to have been created using `zstd --train`
47
- compressed_using_dict = Zstd.compress_using_dict("", IO.read('dictionary_file'))
49
+ compressed_using_dict = Zstd.compress("", dict: File.read('dictionary_file'))
48
50
  ```
49
51
 
50
- ### Streaming Compression
52
+ #### Streaming Compression
51
53
  ```ruby
52
54
  stream = Zstd::StreamingCompress.new
53
55
  stream << "abc" << "def"
@@ -66,19 +68,39 @@ res << stream.compress("def")
66
68
  res << stream.finish
67
69
  ```
68
70
 
69
- ### Simple Decompression
71
+ #### Streaming Compression with Dictionary
72
+ ```ruby
73
+ stream = Zstd::StreamingCompress.new(dict: File.read('dictionary_file'))
74
+ stream << "abc" << "def"
75
+ res = stream.flush
76
+ stream << "ghi"
77
+ res << stream.finish
78
+ ```
79
+
80
+ #### Streaming Compression with level and Dictionary
81
+ ```ruby
82
+ stream = Zstd::StreamingCompress.new(level: 5, dict: File.read('dictionary_file'))
83
+ stream << "abc" << "def"
84
+ res = stream.flush
85
+ stream << "ghi"
86
+ res << stream.finish
87
+ ```
88
+
89
+ ### Decompression
90
+
91
+ #### Simple Decompression
70
92
 
71
93
  ```ruby
72
94
  data = Zstd.decompress(compressed_data)
73
95
  ```
74
96
 
75
- ### Decomporession using Dictionary
97
+ #### Decompression with Dictionary
76
98
  ```ruby
77
99
  # dictionary is supposed to have been created using `zstd --train`
78
- Zstd.decompress_using_dict(compressed_using_dict, IO.read('dictionary_file'))
100
+ Zstd.decompress(compressed_using_dict, dict: File.read('dictionary_file'))
79
101
  ```
80
102
 
81
- ### Streaming Decompression
103
+ #### Streaming Decompression
82
104
  ```ruby
83
105
  cstr = "" # Compressed data
84
106
  stream = Zstd::StreamingDecompress.new
@@ -87,7 +109,16 @@ result << stream.decompress(cstr[0, 10])
87
109
  result << stream.decompress(cstr[10..-1])
88
110
  ```
89
111
 
90
- ### Skippable flame
112
+ #### Streaming Decompression with dictionary
113
+ ```ruby
114
+ cstr = "" # Compressed data
115
+ stream = Zstd::StreamingDecompress.new(dict: File.read('dictionary_file'))
116
+ result = ''
117
+ result << stream.decompress(cstr[0, 10])
118
+ result << stream.decompress(cstr[10..-1])
119
+ ```
120
+
121
+ ### Skippable frame
91
122
 
92
123
  ```ruby
93
124
  compressed_data_with_skippable_frame = Zstd.write_skippable_frame(compressed_data, "sample data")
@@ -96,6 +127,45 @@ Zstd.read_skippable_frame(compressed_data_with_skippable_frame)
96
127
  # => "sample data"
97
128
  ```
98
129
 
130
+ ### Stream Writer and Reader Wrapper
131
+ **EXPERIMENTAL**
132
+
133
+ * These features are experimental and may be subject to API changes in future releases.
134
+ * There may be performance and compatibility issues, so extensive testing is required before production use.
135
+ * If you have any questions, encounter bugs, or have suggestions, please report them via [GitHub issues](https://github.com/SpringMT/zstd-ruby/issues).
136
+
137
+ #### Zstd::StreamWriter
138
+
139
+ ```ruby
140
+ require 'stringio'
141
+ require 'zstd-ruby'
142
+
143
+ io = StringIO.new
144
+ stream = Zstd::StreamWriter.new(io)
145
+ stream.write("abc")
146
+ stream.finish
147
+
148
+ io.rewind
149
+ # Retrieve the compressed data
150
+ compressed_data = io.read
151
+ ```
152
+
153
+ #### Zstd::StreamReader
154
+
155
+ ```ruby
156
+ require 'stringio'
157
+ require 'zstd-ruby' # Add the appropriate require statement if necessary
158
+
159
+ io = StringIO.new(compressed_data)
160
+ reader = Zstd::StreamReader.new(io)
161
+
162
+ # Read and output the decompressed data
163
+ puts reader.read(10) # 'abc'
164
+ puts reader.read(10) # 'def'
165
+ puts reader.read(10) # '' (end of data)
166
+ ```
167
+
168
+
99
169
  ## JRuby
100
170
  This gem does not support JRuby.
101
171
 
@@ -1,7 +1,11 @@
1
1
  #ifndef ZSTD_RUBY_H
2
2
  #define ZSTD_RUBY_H 1
3
3
 
4
- #include "ruby.h"
4
+ #include <ruby.h>
5
+ #ifdef HAVE_RUBY_THREAD_H
6
+ #include <ruby/thread.h>
7
+ #endif
8
+ #include <stdbool.h>
5
9
  #include "./libzstd/zstd.h"
6
10
 
7
11
  static int convert_compression_level(VALUE compression_level_value)
@@ -12,4 +16,171 @@ static int convert_compression_level(VALUE compression_level_value)
12
16
  return NUM2INT(compression_level_value);
13
17
  }
14
18
 
19
+ static void set_compress_params(ZSTD_CCtx* const ctx, VALUE level_from_args, VALUE kwargs)
20
+ {
21
+ ID kwargs_keys[2];
22
+ kwargs_keys[0] = rb_intern("level");
23
+ kwargs_keys[1] = rb_intern("dict");
24
+ VALUE kwargs_values[2];
25
+ rb_get_kwargs(kwargs, kwargs_keys, 0, 2, kwargs_values);
26
+
27
+ int compression_level = ZSTD_CLEVEL_DEFAULT;
28
+ if (kwargs_values[0] != Qundef && kwargs_values[0] != Qnil) {
29
+ compression_level = convert_compression_level(kwargs_values[0]);
30
+ } else if (!NIL_P(level_from_args)) {
31
+ rb_warn("`level` in args is deprecated; use keyword args `level:` instead.");
32
+ compression_level = convert_compression_level(level_from_args);
33
+ }
34
+ ZSTD_CCtx_setParameter(ctx, ZSTD_c_compressionLevel, compression_level);
35
+
36
+ if (kwargs_values[1] != Qundef && kwargs_values[1] != Qnil) {
37
+ char* dict_buffer = RSTRING_PTR(kwargs_values[1]);
38
+ size_t dict_size = RSTRING_LEN(kwargs_values[1]);
39
+ size_t load_dict_ret = ZSTD_CCtx_loadDictionary(ctx, dict_buffer, dict_size);
40
+ if (ZSTD_isError(load_dict_ret)) {
41
+ ZSTD_freeCCtx(ctx);
42
+ rb_raise(rb_eRuntimeError, "%s", "ZSTD_CCtx_loadDictionary failed");
43
+ }
44
+ }
45
+ }
46
+
47
+ struct stream_compress_params {
48
+ ZSTD_CCtx* ctx;
49
+ ZSTD_outBuffer* output;
50
+ ZSTD_inBuffer* input;
51
+ ZSTD_EndDirective endOp;
52
+ size_t ret;
53
+ };
54
+
55
+ static void* stream_compress_wrapper(void* args)
56
+ {
57
+ struct stream_compress_params* params = args;
58
+ params->ret = ZSTD_compressStream2(params->ctx, params->output, params->input, params->endOp);
59
+ return NULL;
60
+ }
61
+
62
+ static size_t zstd_stream_compress(ZSTD_CCtx* const ctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input, ZSTD_EndDirective endOp, bool gvl)
63
+ {
64
+ #ifdef HAVE_RUBY_THREAD_H
65
+ if (gvl) {
66
+ return ZSTD_compressStream2(ctx, output, input, endOp);
67
+ } else {
68
+ struct stream_compress_params params = { ctx, output, input, endOp };
69
+ rb_thread_call_without_gvl(stream_compress_wrapper, &params, NULL, NULL);
70
+ return params.ret;
71
+ }
72
+ #else
73
+ return ZSTD_compressStream2(ctx, output, input, endOp);
74
+ #endif
75
+ }
76
+
77
+ struct compress_params {
78
+ ZSTD_CCtx* ctx;
79
+ char* output_data;
80
+ size_t output_size;
81
+ char* input_data;
82
+ size_t input_size;
83
+ size_t ret;
84
+ };
85
+
86
+ static void* compress_wrapper(void* args)
87
+ {
88
+ struct compress_params* params = args;
89
+ params->ret = ZSTD_compress2(params->ctx ,params->output_data, params->output_size, params->input_data, params->input_size);
90
+ return NULL;
91
+ }
92
+
93
+ static size_t zstd_compress(ZSTD_CCtx* const ctx, char* output_data, size_t output_size, char* input_data, size_t input_size, bool gvl)
94
+ {
95
+ #ifdef HAVE_RUBY_THREAD_H
96
+ if (gvl) {
97
+ return ZSTD_compress2(ctx , output_data, output_size, input_data, input_size);
98
+ } else {
99
+ struct compress_params params = { ctx, output_data, output_size, input_data, input_size };
100
+ rb_thread_call_without_gvl(compress_wrapper, &params, NULL, NULL);
101
+ return params.ret;
102
+ }
103
+ #else
104
+ return ZSTD_compress2(ctx , output_data, output_size, input_data, input_size);
105
+ #endif
106
+ }
107
+
108
+ static void set_decompress_params(ZSTD_DCtx* const dctx, VALUE kwargs)
109
+ {
110
+ ID kwargs_keys[1];
111
+ kwargs_keys[0] = rb_intern("dict");
112
+ VALUE kwargs_values[1];
113
+ rb_get_kwargs(kwargs, kwargs_keys, 0, 1, kwargs_values);
114
+
115
+ if (kwargs_values[0] != Qundef && kwargs_values[0] != Qnil) {
116
+ char* dict_buffer = RSTRING_PTR(kwargs_values[0]);
117
+ size_t dict_size = RSTRING_LEN(kwargs_values[0]);
118
+ size_t load_dict_ret = ZSTD_DCtx_loadDictionary(dctx, dict_buffer, dict_size);
119
+ if (ZSTD_isError(load_dict_ret)) {
120
+ ZSTD_freeDCtx(dctx);
121
+ rb_raise(rb_eRuntimeError, "%s", "ZSTD_CCtx_loadDictionary failed");
122
+ }
123
+ }
124
+ }
125
+
126
+ struct stream_decompress_params {
127
+ ZSTD_DCtx* dctx;
128
+ ZSTD_outBuffer* output;
129
+ ZSTD_inBuffer* input;
130
+ size_t ret;
131
+ };
132
+
133
+ static void* stream_decompress_wrapper(void* args)
134
+ {
135
+ struct stream_decompress_params* params = args;
136
+ params->ret = ZSTD_decompressStream(params->dctx, params->output, params->input);
137
+ return NULL;
138
+ }
139
+
140
+ static size_t zstd_stream_decompress(ZSTD_DCtx* const dctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input, bool gvl)
141
+ {
142
+ #ifdef HAVE_RUBY_THREAD_H
143
+ if (gvl) {
144
+ return ZSTD_decompressStream(dctx, output, input);
145
+ } else {
146
+ struct stream_decompress_params params = { dctx, output, input };
147
+ rb_thread_call_without_gvl(stream_decompress_wrapper, &params, NULL, NULL);
148
+ return params.ret;
149
+ }
150
+ #else
151
+ return ZSTD_decompressStream(dctx, output, input);
152
+ #endif
153
+ }
154
+
155
+ struct decompress_params {
156
+ ZSTD_DCtx* dctx;
157
+ char* output_data;
158
+ size_t output_size;
159
+ char* input_data;
160
+ size_t input_size;
161
+ size_t ret;
162
+ };
163
+
164
+ static void* decompress_wrapper(void* args)
165
+ {
166
+ struct decompress_params* params = args;
167
+ params->ret = ZSTD_decompressDCtx(params->dctx, params->output_data, params->output_size, params->input_data, params->input_size);
168
+ return NULL;
169
+ }
170
+
171
+ static size_t zstd_decompress(ZSTD_DCtx* const dctx, char* output_data, size_t output_size, char* input_data, size_t input_size, bool gvl)
172
+ {
173
+ #ifdef HAVE_RUBY_THREAD_H
174
+ if (gvl) {
175
+ return ZSTD_decompressDCtx(dctx, output_data, output_size, input_data, input_size);
176
+ } else {
177
+ struct decompress_params params = { dctx, output_data, output_size, input_data, input_size };
178
+ rb_thread_call_without_gvl(decompress_wrapper, &params, NULL, NULL);
179
+ return params.ret;
180
+ }
181
+ #else
182
+ return ZSTD_decompressDCtx(dctx, output_data, output_size, input_data, input_size);
183
+ #endif
184
+ }
185
+
15
186
  #endif /* ZSTD_RUBY_H */
@@ -1,6 +1,8 @@
1
1
  require "mkmf"
2
2
 
3
- $CFLAGS = '-I. -O3 -std=c99 -DZSTD_STATIC_LINKING_ONLY'
3
+ have_func('rb_gc_mark_movable')
4
+
5
+ $CFLAGS = '-I. -O3 -std=c99 -DZSTD_STATIC_LINKING_ONLY -DZSTD_MULTITHREAD -pthread -DDEBUGLEVEL=0'
4
6
  $CPPFLAGS += " -fdeclspec" if CONFIG['CXX'] =~ /clang/
5
7
 
6
8
  Dir.chdir File.expand_path('..', __FILE__) do
@@ -14,7 +14,7 @@
14
14
  #define ZSTD_DEPS_NEED_MALLOC
15
15
  #include "zstd_deps.h" /* ZSTD_malloc, ZSTD_calloc, ZSTD_free, ZSTD_memset */
16
16
 
17
- #include "mem.h" /* MEM_STATIC */
17
+ #include "compiler.h" /* MEM_STATIC */
18
18
  #define ZSTD_STATIC_LINKING_ONLY
19
19
  #include "../zstd.h" /* ZSTD_customMem */
20
20
 
@@ -90,19 +90,20 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
90
90
  /*-********************************************
91
91
  * bitStream decoding API (read backward)
92
92
  **********************************************/
93
+ typedef size_t BitContainerType;
93
94
  typedef struct {
94
- size_t bitContainer;
95
+ BitContainerType bitContainer;
95
96
  unsigned bitsConsumed;
96
97
  const char* ptr;
97
98
  const char* start;
98
99
  const char* limitPtr;
99
100
  } BIT_DStream_t;
100
101
 
101
- typedef enum { BIT_DStream_unfinished = 0,
102
- BIT_DStream_endOfBuffer = 1,
103
- BIT_DStream_completed = 2,
104
- BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */
105
- /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
102
+ typedef enum { BIT_DStream_unfinished = 0, /* fully refilled */
103
+ BIT_DStream_endOfBuffer = 1, /* still some bits left in bitstream */
104
+ BIT_DStream_completed = 2, /* bitstream entirely consumed, bit-exact */
105
+ BIT_DStream_overflow = 3 /* user requested more bits than present in bitstream */
106
+ } BIT_DStream_status; /* result of BIT_reloadDStream() */
106
107
 
107
108
  MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
108
109
  MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
@@ -112,7 +113,7 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
112
113
 
113
114
  /* Start by invoking BIT_initDStream().
114
115
  * A chunk of the bitStream is then stored into a local register.
115
- * Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
116
+ * Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (BitContainerType).
116
117
  * You can then retrieve bitFields stored into the local register, **in reverse order**.
117
118
  * Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
118
119
  * A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
@@ -162,7 +163,7 @@ MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC,
162
163
  return 0;
163
164
  }
164
165
 
165
- MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
166
+ FORCE_INLINE_TEMPLATE size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
166
167
  {
167
168
  #if defined(STATIC_BMI2) && STATIC_BMI2 == 1 && !defined(ZSTD_NO_INTRINSICS)
168
169
  return _bzhi_u64(bitContainer, nbBits);
@@ -267,22 +268,22 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si
267
268
  bitD->bitContainer = *(const BYTE*)(bitD->start);
268
269
  switch(srcSize)
269
270
  {
270
- case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
271
+ case 7: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
271
272
  ZSTD_FALLTHROUGH;
272
273
 
273
- case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
274
+ case 6: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
274
275
  ZSTD_FALLTHROUGH;
275
276
 
276
- case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
277
+ case 5: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
277
278
  ZSTD_FALLTHROUGH;
278
279
 
279
- case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;
280
+ case 4: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[3]) << 24;
280
281
  ZSTD_FALLTHROUGH;
281
282
 
282
- case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;
283
+ case 3: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[2]) << 16;
283
284
  ZSTD_FALLTHROUGH;
284
285
 
285
- case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8;
286
+ case 2: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[1]) << 8;
286
287
  ZSTD_FALLTHROUGH;
287
288
 
288
289
  default: break;
@@ -297,12 +298,12 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si
297
298
  return srcSize;
298
299
  }
299
300
 
300
- MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
301
+ FORCE_INLINE_TEMPLATE size_t BIT_getUpperBits(BitContainerType bitContainer, U32 const start)
301
302
  {
302
303
  return bitContainer >> start;
303
304
  }
304
305
 
305
- MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
306
+ FORCE_INLINE_TEMPLATE size_t BIT_getMiddleBits(BitContainerType bitContainer, U32 const start, U32 const nbBits)
306
307
  {
307
308
  U32 const regMask = sizeof(bitContainer)*8 - 1;
308
309
  /* if start > regMask, bitstream is corrupted, and result is undefined */
@@ -325,7 +326,7 @@ MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 c
325
326
  * On 32-bits, maxNbBits==24.
326
327
  * On 64-bits, maxNbBits==56.
327
328
  * @return : value extracted */
328
- MEM_STATIC FORCE_INLINE_ATTR size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
329
+ FORCE_INLINE_TEMPLATE size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
329
330
  {
330
331
  /* arbitrate between double-shift and shift+mask */
331
332
  #if 1
@@ -348,7 +349,7 @@ MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
348
349
  return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask);
349
350
  }
350
351
 
351
- MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
352
+ FORCE_INLINE_TEMPLATE void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
352
353
  {
353
354
  bitD->bitsConsumed += nbBits;
354
355
  }
@@ -357,7 +358,7 @@ MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
357
358
  * Read (consume) next n bits from local register and update.
358
359
  * Pay attention to not read more than nbBits contained into local register.
359
360
  * @return : extracted value. */
360
- MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
361
+ FORCE_INLINE_TEMPLATE size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
361
362
  {
362
363
  size_t const value = BIT_lookBits(bitD, nbBits);
363
364
  BIT_skipBits(bitD, nbBits);
@@ -374,6 +375,21 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits)
374
375
  return value;
375
376
  }
376
377
 
378
+ /*! BIT_reloadDStream_internal() :
379
+ * Simple variant of BIT_reloadDStream(), with two conditions:
380
+ * 1. bitstream is valid : bitsConsumed <= sizeof(bitD->bitContainer)*8
381
+ * 2. look window is valid after shifted down : bitD->ptr >= bitD->start
382
+ */
383
+ MEM_STATIC BIT_DStream_status BIT_reloadDStream_internal(BIT_DStream_t* bitD)
384
+ {
385
+ assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8);
386
+ bitD->ptr -= bitD->bitsConsumed >> 3;
387
+ assert(bitD->ptr >= bitD->start);
388
+ bitD->bitsConsumed &= 7;
389
+ bitD->bitContainer = MEM_readLEST(bitD->ptr);
390
+ return BIT_DStream_unfinished;
391
+ }
392
+
377
393
  /*! BIT_reloadDStreamFast() :
378
394
  * Similar to BIT_reloadDStream(), but with two differences:
379
395
  * 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold!
@@ -384,31 +400,35 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD)
384
400
  {
385
401
  if (UNLIKELY(bitD->ptr < bitD->limitPtr))
386
402
  return BIT_DStream_overflow;
387
- assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8);
388
- bitD->ptr -= bitD->bitsConsumed >> 3;
389
- bitD->bitsConsumed &= 7;
390
- bitD->bitContainer = MEM_readLEST(bitD->ptr);
391
- return BIT_DStream_unfinished;
403
+ return BIT_reloadDStream_internal(bitD);
392
404
  }
393
405
 
394
406
  /*! BIT_reloadDStream() :
395
407
  * Refill `bitD` from buffer previously set in BIT_initDStream() .
396
- * This function is safe, it guarantees it will not read beyond src buffer.
408
+ * This function is safe, it guarantees it will not never beyond src buffer.
397
409
  * @return : status of `BIT_DStream_t` internal register.
398
410
  * when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
399
- MEM_STATIC FORCE_INLINE_ATTR BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
411
+ FORCE_INLINE_TEMPLATE BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
400
412
  {
401
- if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */
413
+ /* note : once in overflow mode, a bitstream remains in this mode until it's reset */
414
+ if (UNLIKELY(bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8))) {
415
+ static const BitContainerType zeroFilled = 0;
416
+ bitD->ptr = (const char*)&zeroFilled; /* aliasing is allowed for char */
417
+ /* overflow detected, erroneous scenario or end of stream: no update */
402
418
  return BIT_DStream_overflow;
419
+ }
420
+
421
+ assert(bitD->ptr >= bitD->start);
403
422
 
404
423
  if (bitD->ptr >= bitD->limitPtr) {
405
- return BIT_reloadDStreamFast(bitD);
424
+ return BIT_reloadDStream_internal(bitD);
406
425
  }
407
426
  if (bitD->ptr == bitD->start) {
427
+ /* reached end of bitStream => no update */
408
428
  if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
409
429
  return BIT_DStream_completed;
410
430
  }
411
- /* start < ptr < limitPtr */
431
+ /* start < ptr < limitPtr => cautious update */
412
432
  { U32 nbBytes = bitD->bitsConsumed >> 3;
413
433
  BIT_DStream_status result = BIT_DStream_unfinished;
414
434
  if (bitD->ptr - nbBytes < bitD->start) {