ruby-lzws 1.2.0 → 1.4.1

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: 62d885a3a75f291ea4b808da4ef4e47a68574e74dae8fe39aad61d228a62643c
4
- data.tar.gz: 90e5fc29ea554392dcf93bb391a38361707c14306099b6654765e399d111ea9d
3
+ metadata.gz: 0cd332331b0c0eac3a21a008ec7796ffbee88d7b79039108f9e4857f5ed2a793
4
+ data.tar.gz: 42f29271be355fe9e48a877a640391d21e8820fd34ca96975b07d063dc3e1abb
5
5
  SHA512:
6
- metadata.gz: 66c07c08d7094be0e9f2d802c01796529e0c14bcde067752aa629d7e3337218e0d6a08e7cfe08725659097fb0e3be90e7565a872a3c79dc96813afa6b235e4ab
7
- data.tar.gz: a1d74a3408881c23f816818931685ec084bd2a0e9c114be212f8a059e37af8da882e9235f3780524e5e67557b3c9945f33b3ecab8535768e4737e972fc724d87
6
+ metadata.gz: 9545c057aee9de7e1528905d215c45fe15aa798d1f81dc03e418e1a9ae0b0669d17282d82997f33844563612f731b1ee87b744639b3d04b173d37b28bf492344
7
+ data.tar.gz: a8eec9b071600eb5ff98efb53aefbf0c48779aa3e468b3c538916bf3335171eefe0e1a73b3d6de8385823e439bd939c6c033cafd5a7c281111f1b4a51b012645
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Ruby bindings for lzws library
2
2
 
3
- | Travis | AppVeyor | Circle | Codecov |
4
- | :---: | :---: | :---: | :---: |
5
- | [![Travis test status](https://travis-ci.com/andrew-aladev/ruby-lzws.svg?branch=master)](https://travis-ci.com/andrew-aladev/ruby-lzws) | [![AppVeyor test status](https://ci.appveyor.com/api/projects/status/github/andrew-aladev/ruby-lzws?branch=master&svg=true)](https://ci.appveyor.com/project/andrew-aladev/ruby-lzws/branch/master) | [![Circle test status](https://circleci.com/gh/andrew-aladev/ruby-lzws/tree/master.svg?style=shield)](https://circleci.com/gh/andrew-aladev/ruby-lzws/tree/master) | [![Codecov](https://codecov.io/gh/andrew-aladev/ruby-lzws/branch/master/graph/badge.svg)](https://codecov.io/gh/andrew-aladev/ruby-lzws) |
3
+ | AppVeyor | Circle | Github actions | Codecov | Gem |
4
+ | :------: | :----: | :------------: | :-----: | :--: |
5
+ | [![AppVeyor test status](https://ci.appveyor.com/api/projects/status/github/andrew-aladev/ruby-lzws?branch=master&svg=true)](https://ci.appveyor.com/project/andrew-aladev/ruby-lzws/branch/master) | [![Circle test status](https://circleci.com/gh/andrew-aladev/ruby-lzws/tree/master.svg?style=shield)](https://circleci.com/gh/andrew-aladev/ruby-lzws/tree/master) | [![Github Actions test status](https://github.com/andrew-aladev/ruby-lzws/workflows/test/badge.svg?branch=master)](https://github.com/andrew-aladev/ruby-lzws/actions) | [![Codecov](https://codecov.io/gh/andrew-aladev/ruby-lzws/branch/master/graph/badge.svg)](https://codecov.io/gh/andrew-aladev/ruby-lzws) | [![Gem](https://img.shields.io/gem/v/ruby-lzws.svg)](https://rubygems.org/gems/ruby-lzws) |
6
6
 
7
7
  See [lzws library](https://github.com/andrew-aladev/lzws).
8
8
 
@@ -61,8 +61,8 @@ ensure
61
61
  end
62
62
  ```
63
63
 
64
- You can create and read `tar.Z` archives with `minitar` for example.
65
- LZWS is compatible with UNIX compress (with default options).
64
+ You can create and read `tar.Z` archives with [minitar](https://github.com/halostatue/minitar).
65
+ LZWS is compatible with [UNIX compress](https://en.wikipedia.org/wiki/Compress) (with default options).
66
66
 
67
67
  ```ruby
68
68
  require "lzws"
@@ -84,12 +84,37 @@ LZWS::Stream::Reader.open "file.tar.Z" do |reader|
84
84
  end
85
85
  ```
86
86
 
87
+ You can also use `Content-Encoding: compress` with [sinatra](http://sinatrarb.com):
88
+
89
+ ```ruby
90
+ require "lzws"
91
+ require "sinatra"
92
+
93
+ get "/" do
94
+ headers["Content-Encoding"] = "compress"
95
+ LZWS::String.compress "TOBEORNOTTOBEORTOBEORNOT"
96
+ end
97
+ ```
98
+
99
+ All functionality (including streaming) can be used inside multiple threads with [parallel](https://github.com/grosser/parallel).
100
+ This code will provide heavy load for your CPU.
101
+
102
+ ```ruby
103
+ require "lzws"
104
+ require "parallel"
105
+
106
+ Parallel.each large_datas do |large_data|
107
+ LZWS::String.compress large_data
108
+ end
109
+ ```
110
+
87
111
  ## Options
88
112
 
89
113
  | Option | Values | Default | Description |
90
114
  |-----------------------------|------------|----------|-------------|
91
115
  | `source_buffer_length` | 0, 2 - inf | 0 (auto) | internal buffer length for source data |
92
116
  | `destination_buffer_length` | 0, 2 - inf | 0 (auto) | internal buffer length for description data |
117
+ | `gvl` | true/false | false | enables global VM lock where possible |
93
118
  | `max_code_bit_length` | 9 - 16 | 16 | max code bit length |
94
119
  | `block_mode` | true/false | true | enables block mode |
95
120
  | `without_magic_header` | true/false | false | disables magic header |
@@ -101,6 +126,10 @@ There are internal buffers for compressed and decompressed data.
101
126
  For example you want to use 1 KB as `source_buffer_length` for compressor - please use 256 B as `destination_buffer_length`.
102
127
  You want to use 256 B as `source_buffer_length` for decompressor - please use 1 KB as `destination_buffer_length`.
103
128
 
129
+ `gvl` is disabled by default, this mode allows running multiple compressors/decompressors in different threads simultaneously.
130
+ Please consider enabling `gvl` if you don't want to launch processors in separate threads.
131
+ If `gvl` is enabled ruby won't waste time on acquiring/releasing VM lock.
132
+
104
133
  You can also read lzws docs for more info about options.
105
134
 
106
135
  | Option | Related constants |
@@ -111,6 +140,7 @@ Possible compressor options:
111
140
  ```
112
141
  :source_buffer_length
113
142
  :destination_buffer_length
143
+ :gvl
114
144
  :max_code_bit_length
115
145
  :block_mode
116
146
  :without_magic_header
@@ -123,6 +153,7 @@ Possible decompressor options:
123
153
  ```
124
154
  :source_buffer_length
125
155
  :destination_buffer_length
156
+ :gvl
126
157
  :without_magic_header
127
158
  :msb
128
159
  :unaligned_bit_groups
@@ -138,18 +169,6 @@ data = LZWS::String.compress "TOBEORNOTTOBEORTOBEORNOT", :msb => true
138
169
  puts LZWS::String.decompress(data, :msb => true)
139
170
  ```
140
171
 
141
- Default options are compatible with UNIX compress (`Content-Encoding: compress`):
142
-
143
- ```ruby
144
- require "lzws"
145
- require "sinatra"
146
-
147
- get "/" do
148
- headers["Content-Encoding"] = "compress"
149
- LZWS::String.compress "TOBEORNOTTOBEORTOBEORNOT"
150
- end
151
- ```
152
-
153
172
  Please read more about compatibility in lzws docs.
154
173
 
155
174
  ## String
@@ -176,7 +195,7 @@ File maintains both source and destination buffers, it accepts both `source_buff
176
195
 
177
196
  ## Stream::Writer
178
197
 
179
- Its behaviour is similar to builtin [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipWriter.html).
198
+ Its behaviour is similar to builtin [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipWriter.html).
180
199
 
181
200
  Writer maintains destination buffer only, so it accepts `destination_buffer_length` option only.
182
201
 
@@ -210,7 +229,7 @@ Set another encodings, `nil` is just for compatibility with `IO`.
210
229
  #tell
211
230
  ```
212
231
 
213
- See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
232
+ See [`IO`](https://ruby-doc.org/core/IO.html) docs.
214
233
 
215
234
  ```
216
235
  #write(*objects)
@@ -220,7 +239,7 @@ See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
220
239
  #closed?
221
240
  ```
222
241
 
223
- See [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipWriter.html) docs.
242
+ See [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipWriter.html) docs.
224
243
 
225
244
  ```
226
245
  #write_nonblock(object, *options)
@@ -234,6 +253,9 @@ Special asynchronous methods missing in `Zlib::GzipWriter`.
234
253
  So it is possible to have asynchronous variants for these synchronous methods.
235
254
  Behaviour is the same as `IO#write_nonblock` method.
236
255
 
256
+ All nonblock operations for file will raise `EBADF` error on Windows.
257
+ Setting file into nonblocking mode is [not available on Windows](https://github.com/ruby/ruby/blob/master/win32/win32.c#L4388).
258
+
237
259
  ```
238
260
  #<<(object)
239
261
  #print(*objects)
@@ -242,11 +264,11 @@ Behaviour is the same as `IO#write_nonblock` method.
242
264
  #puts(*objects)
243
265
  ```
244
266
 
245
- Typical helpers, see [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipWriter.html) docs.
267
+ Typical helpers, see [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipWriter.html) docs.
246
268
 
247
269
  ## Stream::Reader
248
270
 
249
- Its behaviour is similar to builtin [`Zlib::GzipReader`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipReader.html).
271
+ Its behaviour is similar to builtin [`Zlib::GzipReader`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipReader.html).
250
272
 
251
273
  Reader maintains both source and destination buffers, it accepts both `source_buffer_length` and `destination_buffer_length` options.
252
274
 
@@ -281,7 +303,7 @@ Set another encodings.
281
303
  #tell
282
304
  ```
283
305
 
284
- See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
306
+ See [`IO`](https://ruby-doc.org/core/IO.html) docs.
285
307
 
286
308
  ```
287
309
  #read(bytes_to_read = nil, out_buffer = nil)
@@ -291,14 +313,14 @@ See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
291
313
  #closed?
292
314
  ```
293
315
 
294
- See [`Zlib::GzipReader`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
316
+ See [`Zlib::GzipReader`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
295
317
 
296
318
  ```
297
319
  #readpartial(bytes_to_read = nil, out_buffer = nil)
298
320
  #read_nonblock(bytes_to_read, out_buffer = nil, *options)
299
321
  ```
300
322
 
301
- See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
323
+ See [`IO`](https://ruby-doc.org/core/IO.html) docs.
302
324
 
303
325
  ```
304
326
  #getbyte
@@ -321,14 +343,26 @@ See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
321
343
  #ungetline(line)
322
344
  ```
323
345
 
324
- Typical helpers, see [`Zlib::GzipReader`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
346
+ Typical helpers, see [`Zlib::GzipReader`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
347
+
348
+ ## Thread safety
349
+
350
+ `:gvl` option is disabled by default, you can use bindings effectively in multiple threads.
351
+ Please be careful: bindings are not thread safe.
352
+ You should lock all shared data between threads.
353
+
354
+ For example: you should not use same compressor/decompressor inside multiple threads.
355
+ Please verify that you are using each processor inside single thread at the same time.
356
+
357
+ ## Operating systems
358
+
359
+ GNU/Linux, FreeBSD, OSX, Windows (MinGW).
325
360
 
326
361
  ## CI
327
362
 
328
- See universal test script [scripts/ci_test.sh](scripts/ci_test.sh) for CI.
329
363
  Please visit [scripts/test-images](scripts/test-images).
330
- You can run this test script using many native and cross images.
364
+ See universal test script [scripts/ci_test.sh](scripts/ci_test.sh) for CI.
331
365
 
332
366
  ## License
333
367
 
334
- MIT license, see LICENSE and AUTHORS.
368
+ MIT license, see [LICENSE](LICENSE) and [AUTHORS](AUTHORS).
data/ext/extconf.rb CHANGED
@@ -3,23 +3,96 @@
3
3
 
4
4
  require "mkmf"
5
5
 
6
- def require_header(name, types = [])
6
+ have_func "rb_thread_call_without_gvl", "ruby/thread.h"
7
+
8
+ def require_header(name, constants: [], macroses: [], types: [], variables: [])
7
9
  abort "Can't find #{name} header" unless find_header name
8
10
 
11
+ constants.each do |constant|
12
+ abort "Can't find #{constant} constant in #{name} header" unless have_const constant, name
13
+ end
14
+
15
+ macroses.each do |macro|
16
+ abort "Can't find #{macro} macro in #{name} header" unless have_macro macro, name
17
+ end
18
+
9
19
  types.each do |type|
10
20
  abort "Can't find #{type} type in #{name} header" unless find_type type, nil, name
11
21
  end
22
+
23
+ variables.each do |variable|
24
+ abort "Can't find #{variable} variable in #{name} header" unless have_var variable, name
25
+ end
12
26
  end
13
27
 
14
- require_header "lzws/buffer.h"
15
- require_header "lzws/common.h", %w[lzws_result_t]
16
- require_header "lzws/compressor/common.h", %w[lzws_compressor_options_t]
28
+ require_header(
29
+ "lzws/buffer.h",
30
+ :macroses => %w[
31
+ LZWS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_COMPRESSOR
32
+ LZWS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_DECOMPRESSOR
33
+ LZWS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_COMPRESSOR
34
+ LZWS_DEFAULT_SOURCE_BUFFER_LENGTH_FOR_DECOMPRESSOR
35
+ ]
36
+ )
37
+ require_header(
38
+ "lzws/common.h",
39
+ :constants => %w[
40
+ LZWS_BIGGEST_MAX_CODE_BIT_LENGTH
41
+ LZWS_LOWEST_MAX_CODE_BIT_LENGTH
42
+ ],
43
+ :types => %w[
44
+ lzws_byte_fast_t
45
+ lzws_result_t
46
+ ]
47
+ )
48
+ require_header(
49
+ "lzws/compressor/common.h",
50
+ :constants => %w[
51
+ LZWS_COMPRESSOR_ALLOCATE_FAILED
52
+ LZWS_COMPRESSOR_INVALID_MAX_CODE_BIT_LENGTH
53
+ LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION
54
+ ],
55
+ :types => %w[lzws_compressor_options_t],
56
+ :variables => %w[LZWS_COMPRESSOR_DEFAULT_OPTIONS]
57
+ )
17
58
  require_header "lzws/compressor/main.h"
18
- require_header "lzws/compressor/state.h", %w[lzws_compressor_state_t]
19
- require_header "lzws/decompressor/common.h", %w[lzws_decompressor_options_t]
59
+ require_header(
60
+ "lzws/compressor/state.h",
61
+ :types => %w[lzws_compressor_state_t]
62
+ )
63
+ require_header(
64
+ "lzws/config.h",
65
+ :macroses => %w[LZWS_VERSION]
66
+ )
67
+ require_header(
68
+ "lzws/decompressor/common.h",
69
+ :constants => %w[
70
+ LZWS_DECOMPRESSOR_ALLOCATE_FAILED
71
+ LZWS_DECOMPRESSOR_CORRUPTED_SOURCE
72
+ LZWS_DECOMPRESSOR_INVALID_MAGIC_HEADER
73
+ LZWS_DECOMPRESSOR_INVALID_MAX_CODE_BIT_LENGTH
74
+ LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION
75
+ ],
76
+ :types => %w[lzws_decompressor_options_t],
77
+ :variables => %w[LZWS_DECOMPRESSOR_DEFAULT_OPTIONS]
78
+ )
20
79
  require_header "lzws/decompressor/main.h"
21
- require_header "lzws/decompressor/state.h", %w[lzws_decompressor_state_t]
22
- require_header "lzws/file.h"
80
+ require_header(
81
+ "lzws/decompressor/state.h",
82
+ :types => %w[lzws_decompressor_state_t]
83
+ )
84
+ require_header(
85
+ "lzws/file.h",
86
+ :constants => %w[
87
+ LZWS_FILE_ALLOCATE_FAILED
88
+ LZWS_FILE_DECOMPRESSOR_CORRUPTED_SOURCE
89
+ LZWS_FILE_NOT_ENOUGH_DESTINATION_BUFFER
90
+ LZWS_FILE_NOT_ENOUGH_SOURCE_BUFFER
91
+ LZWS_FILE_READ_FAILED
92
+ LZWS_FILE_VALIDATE_FAILED
93
+ LZWS_FILE_WRITE_FAILED
94
+ ]
95
+ )
23
96
 
24
97
  def require_library(name, functions)
25
98
  functions.each do |function|
@@ -30,22 +103,19 @@ end
30
103
  require_library(
31
104
  "lzws",
32
105
  %w[
106
+ lzws_compress
107
+ lzws_compress_file
108
+ lzws_compressor_finish
109
+ lzws_compressor_free_state
110
+ lzws_compressor_get_initial_state
33
111
  lzws_create_source_buffer_for_compressor
34
- lzws_create_destination_buffer_for_compressor
35
112
  lzws_create_source_buffer_for_decompressor
113
+ lzws_create_destination_buffer_for_compressor
36
114
  lzws_create_destination_buffer_for_decompressor
37
-
38
- lzws_compressor_get_initial_state
39
- lzws_compressor_free_state
40
- lzws_compress
41
- lzws_compressor_finish
42
-
43
- lzws_decompressor_get_initial_state
44
- lzws_decompressor_free_state
45
115
  lzws_decompress
46
-
47
- lzws_compress_file
48
116
  lzws_decompress_file
117
+ lzws_decompressor_free_state
118
+ lzws_decompressor_get_initial_state
49
119
  ]
50
120
  )
51
121
 
@@ -73,7 +143,7 @@ $libs = $libs.split(%r{\s})
73
143
  .uniq
74
144
  .join " "
75
145
 
76
- if ENV["CI"] || ENV["COVERAGE"]
146
+ if ENV["CI"]
77
147
  $CFLAGS << " --coverage"
78
148
  $LDFLAGS << " --coverage"
79
149
  end
@@ -5,17 +5,15 @@
5
5
 
6
6
  #include <lzws/buffer.h>
7
7
 
8
- #include "ruby.h"
9
-
10
8
  VALUE lzws_ext_create_string_buffer(VALUE length)
11
9
  {
12
10
  return rb_str_new(NULL, NUM2SIZET(length));
13
11
  }
14
12
 
15
- VALUE lzws_ext_resize_string_buffer(VALUE args)
13
+ VALUE lzws_ext_resize_string_buffer(VALUE buffer_args)
16
14
  {
17
- VALUE buffer = rb_ary_entry(args, 0);
18
- VALUE length = rb_ary_entry(args, 1);
15
+ VALUE buffer = rb_ary_entry(buffer_args, 0);
16
+ VALUE length = rb_ary_entry(buffer_args, 1);
19
17
 
20
18
  return rb_str_resize(buffer, NUM2SIZET(length));
21
19
  }
@@ -11,12 +11,12 @@ VALUE lzws_ext_create_string_buffer(VALUE length);
11
11
  #define LZWS_EXT_CREATE_STRING_BUFFER(buffer, length, exception) \
12
12
  VALUE buffer = rb_protect(lzws_ext_create_string_buffer, SIZET2NUM(length), &exception);
13
13
 
14
- VALUE lzws_ext_resize_string_buffer(VALUE args);
14
+ VALUE lzws_ext_resize_string_buffer(VALUE buffer_args);
15
15
 
16
- #define LZWS_EXT_RESIZE_STRING_BUFFER(buffer, length, exception) \
17
- VALUE args = rb_ary_new_from_args(2, buffer, SIZET2NUM(length)); \
18
- buffer = rb_protect(lzws_ext_resize_string_buffer, args, &exception); \
19
- RB_GC_GUARD(args);
16
+ #define LZWS_EXT_RESIZE_STRING_BUFFER(buffer, length, exception) \
17
+ VALUE buffer_args = rb_ary_new_from_args(2, buffer, SIZET2NUM(length)); \
18
+ buffer = rb_protect(lzws_ext_resize_string_buffer, buffer_args, &exception); \
19
+ RB_GC_GUARD(buffer_args);
20
20
 
21
21
  void lzws_ext_buffer_exports(VALUE root_module);
22
22
 
data/ext/lzws_ext/error.c CHANGED
@@ -3,9 +3,7 @@
3
3
 
4
4
  #include "lzws_ext/error.h"
5
5
 
6
- #include "ruby.h"
7
-
8
- static inline NORETURN(void raise(const char* name, const char* description))
6
+ static inline NORETURN(void raise_error(const char* name, const char* description))
9
7
  {
10
8
  VALUE module = rb_define_module(LZWS_EXT_MODULE_NAME);
11
9
  VALUE error = rb_const_get(module, rb_intern(name));
@@ -16,28 +14,28 @@ void lzws_ext_raise_error(lzws_ext_result_t ext_result)
16
14
  {
17
15
  switch (ext_result) {
18
16
  case LZWS_EXT_ERROR_ALLOCATE_FAILED:
19
- raise("AllocateError", "allocate error");
17
+ raise_error("AllocateError", "allocate error");
20
18
  case LZWS_EXT_ERROR_VALIDATE_FAILED:
21
- raise("ValidateError", "validate error");
19
+ raise_error("ValidateError", "validate error");
22
20
 
23
21
  case LZWS_EXT_ERROR_USED_AFTER_CLOSE:
24
- raise("UsedAfterCloseError", "used after closed");
22
+ raise_error("UsedAfterCloseError", "used after closed");
25
23
  case LZWS_EXT_ERROR_NOT_ENOUGH_SOURCE_BUFFER:
26
- raise("NotEnoughSourceBufferError", "not enough source buffer");
24
+ raise_error("NotEnoughSourceBufferError", "not enough source buffer");
27
25
  case LZWS_EXT_ERROR_NOT_ENOUGH_DESTINATION_BUFFER:
28
- raise("NotEnoughDestinationBufferError", "not enough destination buffer");
26
+ raise_error("NotEnoughDestinationBufferError", "not enough destination buffer");
29
27
  case LZWS_EXT_ERROR_DECOMPRESSOR_CORRUPTED_SOURCE:
30
- raise("DecompressorCorruptedSourceError", "decompressor received corrupted source");
28
+ raise_error("DecompressorCorruptedSourceError", "decompressor received corrupted source");
31
29
 
32
30
  case LZWS_EXT_ERROR_ACCESS_IO:
33
- raise("AccessIOError", "failed to access IO");
31
+ raise_error("AccessIOError", "failed to access IO");
34
32
  case LZWS_EXT_ERROR_READ_IO:
35
- raise("ReadIOError", "failed to read IO");
33
+ raise_error("ReadIOError", "failed to read IO");
36
34
  case LZWS_EXT_ERROR_WRITE_IO:
37
- raise("WriteIOError", "failed to write IO");
35
+ raise_error("WriteIOError", "failed to write IO");
38
36
 
39
37
  default:
40
38
  // LZWS_EXT_ERROR_UNEXPECTED
41
- raise("UnexpectedError", "unexpected error");
39
+ raise_error("UnexpectedError", "unexpected error");
42
40
  }
43
41
  }
@@ -0,0 +1,24 @@
1
+ // Ruby bindings for lzws library.
2
+ // Copyright (c) 2019 AUTHORS, MIT License.
3
+
4
+ #if !defined(LZWS_EXT_GVL_H)
5
+ #define LZWS_EXT_GVL_H
6
+
7
+ #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
8
+
9
+ #include "ruby/thread.h"
10
+
11
+ #define LZWS_EXT_GVL_WRAP(gvl, function, data) \
12
+ if (gvl) { \
13
+ function((void*) data); \
14
+ } else { \
15
+ rb_thread_call_without_gvl(function, (void*) data, RUBY_UBF_IO, NULL); \
16
+ }
17
+
18
+ #else
19
+
20
+ #define LZWS_EXT_GVL_WRAP(_gvl, function, data) function((void*) data);
21
+
22
+ #endif
23
+
24
+ #endif // LZWS_EXT_GVL_H
data/ext/lzws_ext/io.c CHANGED
@@ -6,11 +6,13 @@
6
6
  #include <lzws/file.h>
7
7
 
8
8
  #include "lzws_ext/error.h"
9
+ #include "lzws_ext/gvl.h"
9
10
  #include "lzws_ext/macro.h"
10
11
  #include "lzws_ext/option.h"
11
- #include "ruby.h"
12
12
  #include "ruby/io.h"
13
13
 
14
+ // -- utils --
15
+
14
16
  #define GET_FILE(target) \
15
17
  Check_Type(target, T_FILE); \
16
18
  \
@@ -47,20 +49,52 @@ static inline lzws_ext_result_t get_file_error(lzws_result_t result)
47
49
  }
48
50
  }
49
51
 
52
+ // -- compress --
53
+
54
+ typedef struct
55
+ {
56
+ FILE* source_file;
57
+ size_t source_buffer_length;
58
+ FILE* destination_file;
59
+ size_t destination_buffer_length;
60
+ lzws_compressor_options_t* compressor_options_ptr;
61
+ lzws_result_t result;
62
+ } compress_args_t;
63
+
64
+ static inline void* compress_wrapper(void* data)
65
+ {
66
+ compress_args_t* args = data;
67
+
68
+ args->result = lzws_compress_file(
69
+ args->source_file,
70
+ args->source_buffer_length,
71
+ args->destination_file,
72
+ args->destination_buffer_length,
73
+ args->compressor_options_ptr);
74
+
75
+ return NULL;
76
+ }
77
+
50
78
  VALUE lzws_ext_compress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE destination, VALUE options)
51
79
  {
52
80
  GET_FILE(source);
53
81
  GET_FILE(destination);
54
82
  Check_Type(options, T_HASH);
83
+ LZWS_EXT_GET_SIZE_OPTION(options, source_buffer_length);
84
+ LZWS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
85
+ LZWS_EXT_GET_BOOL_OPTION(options, gvl);
55
86
  LZWS_EXT_GET_COMPRESSOR_OPTIONS(options);
56
- LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, source_buffer_length);
57
- LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
58
87
 
59
- lzws_result_t result = lzws_compress_file(
60
- source_file, source_buffer_length, destination_file, destination_buffer_length, &compressor_options);
88
+ compress_args_t args = {
89
+ .source_file = source_file,
90
+ .source_buffer_length = source_buffer_length,
91
+ .destination_file = destination_file,
92
+ .destination_buffer_length = destination_buffer_length,
93
+ .compressor_options_ptr = &compressor_options};
61
94
 
62
- if (result != 0) {
63
- lzws_ext_raise_error(get_file_error(result));
95
+ LZWS_EXT_GVL_WRAP(gvl, compress_wrapper, &args);
96
+ if (args.result != 0) {
97
+ lzws_ext_raise_error(get_file_error(args.result));
64
98
  }
65
99
 
66
100
  // Ruby itself won't flush stdio file before closing fd, flush is required.
@@ -69,20 +103,52 @@ VALUE lzws_ext_compress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE dest
69
103
  return Qnil;
70
104
  }
71
105
 
106
+ // -- decompress --
107
+
108
+ typedef struct
109
+ {
110
+ FILE* source_file;
111
+ size_t source_buffer_length;
112
+ FILE* destination_file;
113
+ size_t destination_buffer_length;
114
+ lzws_decompressor_options_t* decompressor_options_ptr;
115
+ lzws_result_t result;
116
+ } decompress_args_t;
117
+
118
+ static inline void* decompress_wrapper(void* data)
119
+ {
120
+ decompress_args_t* args = data;
121
+
122
+ args->result = lzws_decompress_file(
123
+ args->source_file,
124
+ args->source_buffer_length,
125
+ args->destination_file,
126
+ args->destination_buffer_length,
127
+ args->decompressor_options_ptr);
128
+
129
+ return NULL;
130
+ }
131
+
72
132
  VALUE lzws_ext_decompress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE destination, VALUE options)
73
133
  {
74
134
  GET_FILE(source);
75
135
  GET_FILE(destination);
76
136
  Check_Type(options, T_HASH);
137
+ LZWS_EXT_GET_SIZE_OPTION(options, source_buffer_length);
138
+ LZWS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
139
+ LZWS_EXT_GET_BOOL_OPTION(options, gvl);
77
140
  LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options);
78
- LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, source_buffer_length);
79
- LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
80
141
 
81
- lzws_result_t result = lzws_decompress_file(
82
- source_file, source_buffer_length, destination_file, destination_buffer_length, &decompressor_options);
142
+ decompress_args_t args = {
143
+ .source_file = source_file,
144
+ .source_buffer_length = source_buffer_length,
145
+ .destination_file = destination_file,
146
+ .destination_buffer_length = destination_buffer_length,
147
+ .decompressor_options_ptr = &decompressor_options};
83
148
 
84
- if (result != 0) {
85
- lzws_ext_raise_error(get_file_error(result));
149
+ LZWS_EXT_GVL_WRAP(gvl, decompress_wrapper, &args);
150
+ if (args.result != 0) {
151
+ lzws_ext_raise_error(get_file_error(args.result));
86
152
  }
87
153
 
88
154
  // Ruby itself won't flush stdio file before closing fd, flush is required.
@@ -91,6 +157,8 @@ VALUE lzws_ext_decompress_io(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE de
91
157
  return Qnil;
92
158
  }
93
159
 
160
+ // -- exports --
161
+
94
162
  void lzws_ext_io_exports(VALUE root_module)
95
163
  {
96
164
  rb_define_module_function(root_module, "_native_compress_io", RUBY_METHOD_FUNC(lzws_ext_compress_io), 3);
data/ext/lzws_ext/main.c CHANGED
@@ -1,13 +1,14 @@
1
1
  // Ruby bindings for lzws library.
2
2
  // Copyright (c) 2019 AUTHORS, MIT License.
3
3
 
4
+ #include <lzws/config.h>
5
+
4
6
  #include "lzws_ext/buffer.h"
5
7
  #include "lzws_ext/io.h"
6
8
  #include "lzws_ext/option.h"
7
9
  #include "lzws_ext/stream/compressor.h"
8
10
  #include "lzws_ext/stream/decompressor.h"
9
11
  #include "lzws_ext/string.h"
10
- #include "ruby.h"
11
12
 
12
13
  void Init_lzws_ext()
13
14
  {
@@ -19,4 +20,7 @@ void Init_lzws_ext()
19
20
  lzws_ext_compressor_exports(root_module);
20
21
  lzws_ext_decompressor_exports(root_module);
21
22
  lzws_ext_string_exports(root_module);
23
+
24
+ VALUE version = rb_str_new2(LZWS_VERSION);
25
+ rb_define_const(root_module, "LIBRARY_VERSION", rb_obj_freeze(version));
22
26
  }