zstd-ruby 1.5.6.1 → 1.5.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40905f48d12335ff309bf984092915cf10b77425f3a913fa7ee721732fd200ec
4
- data.tar.gz: 50af86c41600c37b2395aef57f967e76bac3d296271b257d106b64456f6ab4cf
3
+ metadata.gz: 729474c9a3f3196fe69a06dfdd280c5879bc368b1884b8d508b75164aa7e1dcd
4
+ data.tar.gz: 1cdf1b0554dd89aa1f7b6450be8eb183773a0f3b895024715ae7b3243cec598b
5
5
  SHA512:
6
- metadata.gz: 1c01f7837f96849a1cd6bc3068b1b3b3d777e955849c26bc902529007184541a1b78838b33a2c27d4d50a11da4ca0e0f6b42c2c9318f9a1e23d81d4806d7f970
7
- data.tar.gz: 843369ab0c7dcc5010b6d027a73f364e5765dd63898683227a839ff7139fbba6ece018d3c77885b7f21a6aec4846a52f86abe90ee47bb18d675985df4111e873
6
+ metadata.gz: d69bc35190b5dbc8ce36f9e5acf6ef26a2c85a899ddd409f8eee4a83b005166b20d22e2659cae1b101fb1b97f6a7bf12cf4066e3da94b2a1991d41bf255cd1ce
7
+ data.tar.gz: 2ee85e56a8ae268da1e4b69bf35a016a5d9bc677f240435725e082b5c5279e60d7f8be32dbe57283e618b7cf59b3937b57aa859f6cbb0aafa64458a903747fa2
data/README.md CHANGED
@@ -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,6 +109,15 @@ result << stream.decompress(cstr[0, 10])
87
109
  result << stream.decompress(cstr[10..-1])
88
110
  ```
89
111
 
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
+
90
121
  ### Skippable frame
91
122
 
92
123
  ```ruby
@@ -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,109 @@ 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 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* compress_wrapper(void* args)
56
+ {
57
+ struct 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_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 compress_params params = { ctx, output, input, endOp };
69
+ rb_thread_call_without_gvl(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
+ static void set_decompress_params(ZSTD_DCtx* const dctx, VALUE kwargs)
78
+ {
79
+ ID kwargs_keys[1];
80
+ kwargs_keys[0] = rb_intern("dict");
81
+ VALUE kwargs_values[1];
82
+ rb_get_kwargs(kwargs, kwargs_keys, 0, 1, kwargs_values);
83
+
84
+ if (kwargs_values[0] != Qundef && kwargs_values[0] != Qnil) {
85
+ char* dict_buffer = RSTRING_PTR(kwargs_values[0]);
86
+ size_t dict_size = RSTRING_LEN(kwargs_values[0]);
87
+ size_t load_dict_ret = ZSTD_DCtx_loadDictionary(dctx, dict_buffer, dict_size);
88
+ if (ZSTD_isError(load_dict_ret)) {
89
+ ZSTD_freeDCtx(dctx);
90
+ rb_raise(rb_eRuntimeError, "%s", "ZSTD_CCtx_loadDictionary failed");
91
+ }
92
+ }
93
+ }
94
+
95
+ struct decompress_params {
96
+ ZSTD_DCtx* dctx;
97
+ ZSTD_outBuffer* output;
98
+ ZSTD_inBuffer* input;
99
+ size_t ret;
100
+ };
101
+
102
+ static void* decompress_wrapper(void* args)
103
+ {
104
+ struct decompress_params* params = args;
105
+ params->ret = ZSTD_decompressStream(params->dctx, params->output, params->input);
106
+ return NULL;
107
+ }
108
+
109
+ static size_t zstd_decompress(ZSTD_DCtx* const dctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input, bool gvl)
110
+ {
111
+ #ifdef HAVE_RUBY_THREAD_H
112
+ if (gvl) {
113
+ return ZSTD_decompressStream(dctx, output, input);
114
+ } else {
115
+ struct decompress_params params = { dctx, output, input };
116
+ rb_thread_call_without_gvl(decompress_wrapper, &params, NULL, NULL);
117
+ return params.ret;
118
+ }
119
+ #else
120
+ return ZSTD_decompressStream(dctx, output, input);
121
+ #endif
122
+ }
123
+
15
124
  #endif /* ZSTD_RUBY_H */
@@ -2,7 +2,7 @@ require "mkmf"
2
2
 
3
3
  have_func('rb_gc_mark_movable')
4
4
 
5
- $CFLAGS = '-I. -O3 -std=c99 -DZSTD_STATIC_LINKING_ONLY'
5
+ $CFLAGS = '-I. -O3 -std=c99 -DZSTD_STATIC_LINKING_ONLY -DZSTD_MULTITHREAD -pthread -DDEBUGLEVEL=0'
6
6
  $CPPFLAGS += " -fdeclspec" if CONFIG['CXX'] =~ /clang/
7
7
 
8
8
  Dir.chdir File.expand_path('..', __FILE__) do
data/ext/zstdruby/main.c CHANGED
@@ -1,4 +1,5 @@
1
- #include <common.h>
1
+ #include "common.h"
2
+
2
3
  VALUE rb_mZstd;
3
4
  void zstd_ruby_init(void);
4
5
  void zstd_ruby_skippable_frame_init(void);
@@ -1,4 +1,4 @@
1
- #include <common.h>
1
+ #include "common.h"
2
2
 
3
3
  extern VALUE rb_mZstd;
4
4
 
@@ -1,5 +1,4 @@
1
- #include <common.h>
2
- #include <streaming_compress.h>
1
+ #include "common.h"
3
2
 
4
3
  struct streaming_compress_t {
5
4
  ZSTD_CCtx* ctx;
@@ -71,9 +70,9 @@ rb_streaming_compress_allocate(VALUE klass)
71
70
  static VALUE
72
71
  rb_streaming_compress_initialize(int argc, VALUE *argv, VALUE obj)
73
72
  {
73
+ VALUE kwargs;
74
74
  VALUE compression_level_value;
75
- rb_scan_args(argc, argv, "01", &compression_level_value);
76
- int compression_level = convert_compression_level(compression_level_value);
75
+ rb_scan_args(argc, argv, "01:", &compression_level_value, &kwargs);
77
76
 
78
77
  struct streaming_compress_t* sc;
79
78
  TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
@@ -83,7 +82,8 @@ rb_streaming_compress_initialize(int argc, VALUE *argv, VALUE obj)
83
82
  if (ctx == NULL) {
84
83
  rb_raise(rb_eRuntimeError, "%s", "ZSTD_createCCtx error");
85
84
  }
86
- ZSTD_CCtx_setParameter(ctx, ZSTD_c_compressionLevel, compression_level);
85
+ set_compress_params(ctx, compression_level_value, kwargs);
86
+
87
87
  sc->ctx = ctx;
88
88
  sc->buf = rb_str_new(NULL, buffOutSize);
89
89
  sc->buf_size = buffOutSize;
@@ -106,7 +106,7 @@ no_compress(struct streaming_compress_t* sc, ZSTD_EndDirective endOp)
106
106
  do {
107
107
  ZSTD_outBuffer output = { (void*)output_data, sc->buf_size, 0 };
108
108
 
109
- size_t const ret = ZSTD_compressStream2(sc->ctx, &output, &input, endOp);
109
+ size_t const ret = zstd_compress(sc->ctx, &output, &input, endOp, false);
110
110
  if (ZSTD_isError(ret)) {
111
111
  rb_raise(rb_eRuntimeError, "flush error error code: %s", ZSTD_getErrorName(ret));
112
112
  }
@@ -125,11 +125,12 @@ rb_streaming_compress_compress(VALUE obj, VALUE src)
125
125
 
126
126
  struct streaming_compress_t* sc;
127
127
  TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
128
+
128
129
  const char* output_data = RSTRING_PTR(sc->buf);
129
130
  VALUE result = rb_str_new(0, 0);
130
131
  while (input.pos < input.size) {
131
132
  ZSTD_outBuffer output = { (void*)output_data, sc->buf_size, 0 };
132
- size_t const ret = ZSTD_compressStream2(sc->ctx, &output, &input, ZSTD_e_continue);
133
+ size_t const ret = zstd_compress(sc->ctx, &output, &input, ZSTD_e_continue, false);
133
134
  if (ZSTD_isError(ret)) {
134
135
  rb_raise(rb_eRuntimeError, "compress error error code: %s", ZSTD_getErrorName(ret));
135
136
  }
@@ -139,27 +140,54 @@ rb_streaming_compress_compress(VALUE obj, VALUE src)
139
140
  }
140
141
 
141
142
  static VALUE
142
- rb_streaming_compress_addstr(VALUE obj, VALUE src)
143
+ rb_streaming_compress_write(int argc, VALUE *argv, VALUE obj)
143
144
  {
144
- StringValue(src);
145
- const char* input_data = RSTRING_PTR(src);
146
- size_t input_size = RSTRING_LEN(src);
147
- ZSTD_inBuffer input = { input_data, input_size, 0 };
148
-
145
+ size_t total = 0;
146
+ VALUE result = rb_str_new(0, 0);
149
147
  struct streaming_compress_t* sc;
150
148
  TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
151
149
  const char* output_data = RSTRING_PTR(sc->buf);
152
150
 
153
- while (input.pos < input.size) {
154
- ZSTD_outBuffer output = { (void*)output_data, sc->buf_size, 0 };
155
- size_t const result = ZSTD_compressStream2(sc->ctx, &output, &input, ZSTD_e_continue);
156
- if (ZSTD_isError(result)) {
157
- rb_raise(rb_eRuntimeError, "compress error error code: %s", ZSTD_getErrorName(result));
151
+ while (argc-- > 0) {
152
+ VALUE str = *argv++;
153
+ StringValue(str);
154
+ const char* input_data = RSTRING_PTR(str);
155
+ size_t input_size = RSTRING_LEN(str);
156
+ ZSTD_inBuffer input = { input_data, input_size, 0 };
157
+
158
+ while (input.pos < input.size) {
159
+ ZSTD_outBuffer output = { (void*)output_data, sc->buf_size, 0 };
160
+ size_t const ret = zstd_compress(sc->ctx, &output, &input, ZSTD_e_continue, false);
161
+ if (ZSTD_isError(ret)) {
162
+ rb_raise(rb_eRuntimeError, "compress error error code: %s", ZSTD_getErrorName(ret));
163
+ }
164
+ total += RSTRING_LEN(str);
158
165
  }
159
166
  }
160
- return obj;
167
+ return SIZET2NUM(total);
161
168
  }
162
169
 
170
+ /*
171
+ * Document-method: <<
172
+ * Same as IO.
173
+ */
174
+ #define rb_streaming_compress_addstr rb_io_addstr
175
+ /*
176
+ * Document-method: printf
177
+ * Same as IO.
178
+ */
179
+ #define rb_streaming_compress_printf rb_io_printf
180
+ /*
181
+ * Document-method: print
182
+ * Same as IO.
183
+ */
184
+ #define rb_streaming_compress_print rb_io_print
185
+ /*
186
+ * Document-method: puts
187
+ * Same as IO.
188
+ */
189
+ #define rb_streaming_compress_puts rb_io_puts
190
+
163
191
  static VALUE
164
192
  rb_streaming_compress_flush(VALUE obj)
165
193
  {
@@ -186,7 +214,12 @@ zstd_ruby_streaming_compress_init(void)
186
214
  rb_define_alloc_func(cStreamingCompress, rb_streaming_compress_allocate);
187
215
  rb_define_method(cStreamingCompress, "initialize", rb_streaming_compress_initialize, -1);
188
216
  rb_define_method(cStreamingCompress, "compress", rb_streaming_compress_compress, 1);
217
+ rb_define_method(cStreamingCompress, "write", rb_streaming_compress_write, -1);
189
218
  rb_define_method(cStreamingCompress, "<<", rb_streaming_compress_addstr, 1);
219
+ rb_define_method(cStreamingCompress, "printf", rb_streaming_compress_printf, -1);
220
+ rb_define_method(cStreamingCompress, "print", rb_streaming_compress_print, -1);
221
+ rb_define_method(cStreamingCompress, "puts", rb_streaming_compress_puts, -1);
222
+
190
223
  rb_define_method(cStreamingCompress, "flush", rb_streaming_compress_flush, 0);
191
224
  rb_define_method(cStreamingCompress, "finish", rb_streaming_compress_finish, 0);
192
225
 
@@ -194,4 +227,3 @@ zstd_ruby_streaming_compress_init(void)
194
227
  rb_define_const(cStreamingCompress, "FLUSH", INT2FIX(ZSTD_e_flush));
195
228
  rb_define_const(cStreamingCompress, "END", INT2FIX(ZSTD_e_end));
196
229
  }
197
-
@@ -1,7 +1,7 @@
1
- #include <common.h>
1
+ #include "common.h"
2
2
 
3
3
  struct streaming_decompress_t {
4
- ZSTD_DCtx* ctx;
4
+ ZSTD_DCtx* dctx;
5
5
  VALUE buf;
6
6
  size_t buf_size;
7
7
  };
@@ -21,9 +21,9 @@ static void
21
21
  streaming_decompress_free(void *p)
22
22
  {
23
23
  struct streaming_decompress_t *sd = p;
24
- ZSTD_DCtx* ctx = sd->ctx;
25
- if (ctx != NULL) {
26
- ZSTD_freeDCtx(ctx);
24
+ ZSTD_DCtx* dctx = sd->dctx;
25
+ if (dctx != NULL) {
26
+ ZSTD_freeDCtx(dctx);
27
27
  }
28
28
  xfree(sd);
29
29
  }
@@ -61,24 +61,29 @@ rb_streaming_decompress_allocate(VALUE klass)
61
61
  {
62
62
  struct streaming_decompress_t* sd;
63
63
  VALUE obj = TypedData_Make_Struct(klass, struct streaming_decompress_t, &streaming_decompress_type, sd);
64
- sd->ctx = NULL;
64
+ sd->dctx = NULL;
65
65
  sd->buf = Qnil;
66
66
  sd->buf_size = 0;
67
67
  return obj;
68
68
  }
69
69
 
70
70
  static VALUE
71
- rb_streaming_decompress_initialize(VALUE obj)
71
+ rb_streaming_decompress_initialize(int argc, VALUE *argv, VALUE obj)
72
72
  {
73
+ VALUE kwargs;
74
+ rb_scan_args(argc, argv, "00:", &kwargs);
75
+
73
76
  struct streaming_decompress_t* sd;
74
77
  TypedData_Get_Struct(obj, struct streaming_decompress_t, &streaming_decompress_type, sd);
75
78
  size_t const buffOutSize = ZSTD_DStreamOutSize();
76
79
 
77
- ZSTD_DCtx* ctx = ZSTD_createDCtx();
78
- if (ctx == NULL) {
80
+ ZSTD_DCtx* dctx = ZSTD_createDCtx();
81
+ if (dctx == NULL) {
79
82
  rb_raise(rb_eRuntimeError, "%s", "ZSTD_createDCtx error");
80
83
  }
81
- sd->ctx = ctx;
84
+ set_decompress_params(dctx, kwargs);
85
+
86
+ sd->dctx = dctx;
82
87
  sd->buf = rb_str_new(NULL, buffOutSize);
83
88
  sd->buf_size = buffOutSize;
84
89
 
@@ -99,45 +104,21 @@ rb_streaming_decompress_decompress(VALUE obj, VALUE src)
99
104
  VALUE result = rb_str_new(0, 0);
100
105
  while (input.pos < input.size) {
101
106
  ZSTD_outBuffer output = { (void*)output_data, sd->buf_size, 0 };
102
- size_t const ret = ZSTD_decompressStream(sd->ctx, &output, &input);
107
+ size_t const ret = zstd_decompress(sd->dctx, &output, &input, false);
103
108
  if (ZSTD_isError(ret)) {
104
- rb_raise(rb_eRuntimeError, "compress error error code: %s", ZSTD_getErrorName(ret));
109
+ rb_raise(rb_eRuntimeError, "decompress error error code: %s", ZSTD_getErrorName(ret));
105
110
  }
106
111
  rb_str_cat(result, output.dst, output.pos);
107
112
  }
108
113
  return result;
109
114
  }
110
115
 
111
- static VALUE
112
- rb_streaming_decompress_addstr(VALUE obj, VALUE src)
113
- {
114
- StringValue(src);
115
- const char* input_data = RSTRING_PTR(src);
116
- size_t input_size = RSTRING_LEN(src);
117
- ZSTD_inBuffer input = { input_data, input_size, 0 };
118
-
119
- struct streaming_decompress_t* sd;
120
- TypedData_Get_Struct(obj, struct streaming_decompress_t, &streaming_decompress_type, sd);
121
- const char* output_data = RSTRING_PTR(sd->buf);
122
-
123
- while (input.pos < input.size) {
124
- ZSTD_outBuffer output = { (void*)output_data, sd->buf_size, 0 };
125
- size_t const result = ZSTD_decompressStream(sd->ctx, &output, &input);
126
- if (ZSTD_isError(result)) {
127
- rb_raise(rb_eRuntimeError, "compress error error code: %s", ZSTD_getErrorName(result));
128
- }
129
- }
130
- return obj;
131
- }
132
-
133
116
  extern VALUE rb_mZstd, cStreamingDecompress;
134
117
  void
135
118
  zstd_ruby_streaming_decompress_init(void)
136
119
  {
137
120
  VALUE cStreamingDecompress = rb_define_class_under(rb_mZstd, "StreamingDecompress", rb_cObject);
138
121
  rb_define_alloc_func(cStreamingDecompress, rb_streaming_decompress_allocate);
139
- rb_define_method(cStreamingDecompress, "initialize", rb_streaming_decompress_initialize, 0);
122
+ rb_define_method(cStreamingDecompress, "initialize", rb_streaming_decompress_initialize, -1);
140
123
  rb_define_method(cStreamingDecompress, "decompress", rb_streaming_decompress_decompress, 1);
141
- rb_define_method(cStreamingDecompress, "<<", rb_streaming_decompress_addstr, 1);
142
124
  }
143
-
@@ -12,28 +12,40 @@ static VALUE rb_compress(int argc, VALUE *argv, VALUE self)
12
12
  {
13
13
  VALUE input_value;
14
14
  VALUE compression_level_value;
15
- rb_scan_args(argc, argv, "11", &input_value, &compression_level_value);
16
- int compression_level = convert_compression_level(compression_level_value);
15
+ VALUE kwargs;
16
+ rb_scan_args(argc, argv, "11:", &input_value, &compression_level_value, &kwargs);
17
+
18
+ ZSTD_CCtx* const ctx = ZSTD_createCCtx();
19
+ if (ctx == NULL) {
20
+ rb_raise(rb_eRuntimeError, "%s", "ZSTD_createCCtx error");
21
+ }
22
+
23
+ set_compress_params(ctx, compression_level_value, kwargs);
17
24
 
18
25
  StringValue(input_value);
19
26
  char* input_data = RSTRING_PTR(input_value);
20
27
  size_t input_size = RSTRING_LEN(input_value);
28
+ ZSTD_inBuffer input = { input_data, input_size, 0 };
29
+ // ZSTD_compressBound causes SEGV under multi-thread
21
30
  size_t max_compressed_size = ZSTD_compressBound(input_size);
31
+ VALUE buf = rb_str_new(NULL, max_compressed_size);
32
+ char* output_data = RSTRING_PTR(buf);
33
+ ZSTD_outBuffer output = { (void*)output_data, max_compressed_size, 0 };
22
34
 
23
- VALUE output = rb_str_new(NULL, max_compressed_size);
24
- char* output_data = RSTRING_PTR(output);
25
- size_t compressed_size = ZSTD_compress((void*)output_data, max_compressed_size,
26
- (void*)input_data, input_size, compression_level);
27
- if (ZSTD_isError(compressed_size)) {
28
- rb_raise(rb_eRuntimeError, "%s: %s", "compress failed", ZSTD_getErrorName(compressed_size));
35
+ size_t const ret = zstd_compress(ctx, &output, &input, ZSTD_e_end, true);
36
+ if (ZSTD_isError(ret)) {
37
+ ZSTD_freeCCtx(ctx);
38
+ rb_raise(rb_eRuntimeError, "%s: %s", "compress failed", ZSTD_getErrorName(ret));
29
39
  }
30
-
31
- rb_str_resize(output, compressed_size);
32
- return output;
40
+ VALUE result = rb_str_new(0, 0);
41
+ rb_str_cat(result, output.dst, output.pos);
42
+ ZSTD_freeCCtx(ctx);
43
+ return result;
33
44
  }
34
45
 
35
46
  static VALUE rb_compress_using_dict(int argc, VALUE *argv, VALUE self)
36
47
  {
48
+ rb_warn("Zstd.compress_using_dict is deprecated; use Zstd.compress with `dict:` instead.");
37
49
  VALUE input_value;
38
50
  VALUE dict;
39
51
  VALUE compression_level_value;
@@ -76,61 +88,56 @@ static VALUE rb_compress_using_dict(int argc, VALUE *argv, VALUE self)
76
88
  }
77
89
 
78
90
 
79
- static VALUE decompress_buffered(const char* input_data, size_t input_size)
91
+ static VALUE decompress_buffered(ZSTD_DCtx* dctx, const char* input_data, size_t input_size)
80
92
  {
81
- const size_t outputBufferSize = 4096;
82
-
83
- ZSTD_DStream* const dstream = ZSTD_createDStream();
84
- if (dstream == NULL) {
85
- rb_raise(rb_eRuntimeError, "%s", "ZSTD_createDStream failed");
86
- }
87
-
88
- size_t initResult = ZSTD_initDStream(dstream);
89
- if (ZSTD_isError(initResult)) {
90
- ZSTD_freeDStream(dstream);
91
- rb_raise(rb_eRuntimeError, "%s: %s", "ZSTD_initDStream failed", ZSTD_getErrorName(initResult));
92
- }
93
-
94
93
  VALUE output_string = rb_str_new(NULL, 0);
95
94
  ZSTD_outBuffer output = { NULL, 0, 0 };
96
95
 
97
96
  ZSTD_inBuffer input = { input_data, input_size, 0 };
98
97
  while (input.pos < input.size) {
99
- output.size += outputBufferSize;
98
+ output.size += ZSTD_DStreamOutSize();
100
99
  rb_str_resize(output_string, output.size);
101
100
  output.dst = RSTRING_PTR(output_string);
102
101
 
103
- size_t readHint = ZSTD_decompressStream(dstream, &output, &input);
104
- if (ZSTD_isError(readHint)) {
105
- ZSTD_freeDStream(dstream);
106
- rb_raise(rb_eRuntimeError, "%s: %s", "ZSTD_decompressStream failed", ZSTD_getErrorName(readHint));
102
+ size_t ret = zstd_decompress(dctx, &output, &input, true);
103
+ if (ZSTD_isError(ret)) {
104
+ ZSTD_freeDCtx(dctx);
105
+ rb_raise(rb_eRuntimeError, "%s: %s", "ZSTD_decompressStream failed", ZSTD_getErrorName(ret));
107
106
  }
108
107
  }
109
-
110
- ZSTD_freeDStream(dstream);
111
108
  rb_str_resize(output_string, output.pos);
109
+ ZSTD_freeDCtx(dctx);
112
110
  return output_string;
113
111
  }
114
112
 
115
- static VALUE rb_decompress(VALUE self, VALUE input_value)
113
+ static VALUE rb_decompress(int argc, VALUE *argv, VALUE self)
116
114
  {
115
+ VALUE input_value;
116
+ VALUE kwargs;
117
+ rb_scan_args(argc, argv, "10:", &input_value, &kwargs);
117
118
  StringValue(input_value);
118
119
  char* input_data = RSTRING_PTR(input_value);
119
120
  size_t input_size = RSTRING_LEN(input_value);
121
+ ZSTD_DCtx* const dctx = ZSTD_createDCtx();
122
+ if (dctx == NULL) {
123
+ rb_raise(rb_eRuntimeError, "%s", "ZSTD_createDCtx failed");
124
+ }
125
+ set_decompress_params(dctx, kwargs);
120
126
 
121
127
  unsigned long long const uncompressed_size = ZSTD_getFrameContentSize(input_data, input_size);
122
128
  if (uncompressed_size == ZSTD_CONTENTSIZE_ERROR) {
123
129
  rb_raise(rb_eRuntimeError, "%s: %s", "not compressed by zstd", ZSTD_getErrorName(uncompressed_size));
124
130
  }
131
+ // ZSTD_decompressStream may be called multiple times when ZSTD_CONTENTSIZE_UNKNOWN, causing slowness.
132
+ // Therefore, we will not standardize on ZSTD_decompressStream
125
133
  if (uncompressed_size == ZSTD_CONTENTSIZE_UNKNOWN) {
126
- return decompress_buffered(input_data, input_size);
134
+ return decompress_buffered(dctx, input_data, input_size);
127
135
  }
128
136
 
129
137
  VALUE output = rb_str_new(NULL, uncompressed_size);
130
138
  char* output_data = RSTRING_PTR(output);
131
- size_t const decompress_size = ZSTD_decompress((void*)output_data, uncompressed_size,
132
- (void*)input_data, input_size);
133
139
 
140
+ size_t const decompress_size = ZSTD_decompressDCtx(dctx, output_data, uncompressed_size, input_data, input_size);
134
141
  if (ZSTD_isError(decompress_size)) {
135
142
  rb_raise(rb_eRuntimeError, "%s: %s", "decompress error", ZSTD_getErrorName(decompress_size));
136
143
  }
@@ -140,6 +147,7 @@ static VALUE rb_decompress(VALUE self, VALUE input_value)
140
147
 
141
148
  static VALUE rb_decompress_using_dict(int argc, VALUE *argv, VALUE self)
142
149
  {
150
+ rb_warn("Zstd.decompress_using_dict is deprecated; use Zstd.decompress with `dict:` instead.");
143
151
  VALUE input_value;
144
152
  VALUE dict;
145
153
  rb_scan_args(argc, argv, "20", &input_value, &dict);
@@ -147,15 +155,6 @@ static VALUE rb_decompress_using_dict(int argc, VALUE *argv, VALUE self)
147
155
  StringValue(input_value);
148
156
  char* input_data = RSTRING_PTR(input_value);
149
157
  size_t input_size = RSTRING_LEN(input_value);
150
- unsigned long long const uncompressed_size = ZSTD_getFrameContentSize(input_data, input_size);
151
- if (uncompressed_size == ZSTD_CONTENTSIZE_ERROR) {
152
- rb_raise(rb_eRuntimeError, "%s: %s", "not compressed by zstd", ZSTD_getErrorName(uncompressed_size));
153
- }
154
- if (uncompressed_size == ZSTD_CONTENTSIZE_UNKNOWN) {
155
- return decompress_buffered(input_data, input_size);
156
- }
157
- VALUE output = rb_str_new(NULL, uncompressed_size);
158
- char* output_data = RSTRING_PTR(output);
159
158
 
160
159
  char* dict_buffer = RSTRING_PTR(dict);
161
160
  size_t dict_size = RSTRING_LEN(dict);
@@ -163,12 +162,11 @@ static VALUE rb_decompress_using_dict(int argc, VALUE *argv, VALUE self)
163
162
  if (ddict == NULL) {
164
163
  rb_raise(rb_eRuntimeError, "%s", "ZSTD_createDDict failed");
165
164
  }
166
-
167
165
  unsigned const expected_dict_id = ZSTD_getDictID_fromDDict(ddict);
168
166
  unsigned const actual_dict_id = ZSTD_getDictID_fromFrame(input_data, input_size);
169
167
  if (expected_dict_id != actual_dict_id) {
170
168
  ZSTD_freeDDict(ddict);
171
- rb_raise(rb_eRuntimeError, "%s: %s", "DictID mismatch", ZSTD_getErrorName(uncompressed_size));
169
+ rb_raise(rb_eRuntimeError, "DictID mismatch");
172
170
  }
173
171
 
174
172
  ZSTD_DCtx* const ctx = ZSTD_createDCtx();
@@ -176,6 +174,19 @@ static VALUE rb_decompress_using_dict(int argc, VALUE *argv, VALUE self)
176
174
  ZSTD_freeDDict(ddict);
177
175
  rb_raise(rb_eRuntimeError, "%s", "ZSTD_createDCtx failed");
178
176
  }
177
+
178
+ unsigned long long const uncompressed_size = ZSTD_getFrameContentSize(input_data, input_size);
179
+ if (uncompressed_size == ZSTD_CONTENTSIZE_ERROR) {
180
+ ZSTD_freeDDict(ddict);
181
+ ZSTD_freeDCtx(ctx);
182
+ rb_raise(rb_eRuntimeError, "%s: %s", "not compressed by zstd", ZSTD_getErrorName(uncompressed_size));
183
+ }
184
+ if (uncompressed_size == ZSTD_CONTENTSIZE_UNKNOWN) {
185
+ return decompress_buffered(ctx, input_data, input_size);
186
+ }
187
+
188
+ VALUE output = rb_str_new(NULL, uncompressed_size);
189
+ char* output_data = RSTRING_PTR(output);
179
190
  size_t const decompress_size = ZSTD_decompress_usingDDict(ctx, output_data, uncompressed_size, input_data, input_size, ddict);
180
191
  if (ZSTD_isError(decompress_size)) {
181
192
  ZSTD_freeDDict(ddict);
@@ -193,6 +204,6 @@ zstd_ruby_init(void)
193
204
  rb_define_module_function(rb_mZstd, "zstd_version", zstdVersion, 0);
194
205
  rb_define_module_function(rb_mZstd, "compress", rb_compress, -1);
195
206
  rb_define_module_function(rb_mZstd, "compress_using_dict", rb_compress_using_dict, -1);
196
- rb_define_module_function(rb_mZstd, "decompress", rb_decompress, 1);
207
+ rb_define_module_function(rb_mZstd, "decompress", rb_decompress, -1);
197
208
  rb_define_module_function(rb_mZstd, "decompress_using_dict", rb_decompress_using_dict, -1);
198
209
  }
@@ -0,0 +1,22 @@
1
+ module Zstd
2
+ # @todo Exprimental
3
+ class StreamReader
4
+ def initialize(io)
5
+ @io = io
6
+ @stream = Zstd::StreamingDecompress.new
7
+ end
8
+
9
+ def read(length)
10
+ if @io.eof?
11
+ raise StandardError, "EOF"
12
+ end
13
+ data = @io.read(length)
14
+ @stream.decompress(data)
15
+ end
16
+
17
+ def close
18
+ @io.write(@stream.finish)
19
+ @io.close
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ module Zstd
2
+ # @todo Exprimental
3
+ class StreamWriter
4
+ def initialize(io, level: nil)
5
+ @io = io
6
+ @stream = Zstd::StreamingCompress.new(level)
7
+ end
8
+
9
+ def write(*data)
10
+ @stream.write(*data)
11
+ @io.write(@stream.flush)
12
+ end
13
+
14
+ def finish
15
+ @io.write(@stream.finish)
16
+ end
17
+
18
+ def close
19
+ @io.write(@stream.finish)
20
+ @io.close
21
+ end
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module Zstd
2
- VERSION = "1.5.6.1"
2
+ VERSION = "1.5.6.3"
3
3
  end
data/zstd-ruby.gemspec CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
  #end
25
25
 
26
26
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
- f.match(%r{^(test|spec|features|benchmarks|zstd|.github)/})
27
+ f.match(%r{^(test|spec|features|benchmarks|zstd|.github|examples)/})
28
28
  end
29
29
  spec.bindir = "exe"
30
30
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -35,4 +35,5 @@ Gem::Specification.new do |spec|
35
35
  spec.add_development_dependency "rake", "~> 13.0"
36
36
  spec.add_development_dependency "rake-compiler", '~> 1'
37
37
  spec.add_development_dependency "rspec", "~> 3.0"
38
+ spec.add_development_dependency "pry"
38
39
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zstd-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.6.1
4
+ version: 1.5.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - SpringMT
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-04-01 00:00:00.000000000 Z
11
+ date: 2024-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  description: Ruby binding for zstd(Zstandard - Fast real-time compression algorithm).
70
84
  See https://github.com/facebook/zstd
71
85
  email:
@@ -159,10 +173,11 @@ files:
159
173
  - ext/zstdruby/main.c
160
174
  - ext/zstdruby/skippable_frame.c
161
175
  - ext/zstdruby/streaming_compress.c
162
- - ext/zstdruby/streaming_compress.h
163
176
  - ext/zstdruby/streaming_decompress.c
164
177
  - ext/zstdruby/zstdruby.c
165
178
  - lib/zstd-ruby.rb
179
+ - lib/zstd-ruby/stream_reader.rb
180
+ - lib/zstd-ruby/stream_writer.rb
166
181
  - lib/zstd-ruby/version.rb
167
182
  - renovate.json
168
183
  - zstd-ruby.gemspec
@@ -1,5 +0,0 @@
1
- #if !defined(STREAMING_COMPRESS_H)
2
- #define STREAMING_COMPRESS_H
3
-
4
-
5
- #endif // STREAMING_COMPRESS_H