zstd-ruby 1.5.6.1 → 1.5.6.3

Sign up to get free protection for your applications and to get access to all the features.
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