ruby-zstds 1.0.3 → 1.1.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 +4 -4
- data/README.md +133 -170
- data/ext/extconf.rb +13 -1
- data/ext/zstds_ext/buffer.c +4 -3
- data/ext/zstds_ext/buffer.h +5 -5
- data/ext/zstds_ext/dictionary.c +104 -42
- data/ext/zstds_ext/dictionary.h +1 -1
- data/ext/zstds_ext/error.c +12 -12
- data/ext/zstds_ext/error.h +2 -1
- data/ext/zstds_ext/gvl.h +24 -0
- data/ext/zstds_ext/io.c +229 -137
- data/ext/zstds_ext/option.c +44 -43
- data/ext/zstds_ext/option.h +62 -51
- data/ext/zstds_ext/stream/compressor.c +103 -50
- data/ext/zstds_ext/stream/compressor.h +4 -1
- data/ext/zstds_ext/stream/decompressor.c +46 -22
- data/ext/zstds_ext/stream/decompressor.h +4 -1
- data/ext/zstds_ext/string.c +93 -62
- data/lib/zstds/dictionary.rb +2 -0
- data/lib/zstds/file.rb +6 -2
- data/lib/zstds/option.rb +18 -7
- data/lib/zstds/stream/abstract.rb +6 -9
- data/lib/zstds/stream/raw/abstract.rb +6 -2
- data/lib/zstds/stream/raw/compressor.rb +3 -7
- data/lib/zstds/stream/raw/decompressor.rb +1 -5
- data/lib/zstds/stream/reader.rb +72 -52
- data/lib/zstds/stream/reader_helpers.rb +1 -1
- data/lib/zstds/stream/writer.rb +9 -4
- data/lib/zstds/stream/writer_helpers.rb +3 -2
- data/lib/zstds/validation.rb +4 -2
- data/lib/zstds/version.rb +1 -1
- metadata +62 -19
data/lib/zstds/file.rb
CHANGED
@@ -19,9 +19,11 @@ module ZSTDS
|
|
19
19
|
|
20
20
|
options[:pledged_size] = ::File.size source
|
21
21
|
|
22
|
-
open_files
|
22
|
+
open_files source, destination do |source_io, destination_io|
|
23
23
|
ZSTDS._native_compress_io source_io, destination_io, options
|
24
24
|
end
|
25
|
+
|
26
|
+
nil
|
25
27
|
end
|
26
28
|
|
27
29
|
def self.decompress(source, destination, options = {})
|
@@ -30,9 +32,11 @@ module ZSTDS
|
|
30
32
|
|
31
33
|
options = Option.get_decompressor_options options, BUFFER_LENGTH_NAMES
|
32
34
|
|
33
|
-
open_files
|
35
|
+
open_files source, destination do |source_io, destination_io|
|
34
36
|
ZSTDS._native_decompress_io source_io, destination_io, options
|
35
37
|
end
|
38
|
+
|
39
|
+
nil
|
36
40
|
end
|
37
41
|
|
38
42
|
private_class_method def self.open_files(source, destination, &_block)
|
data/lib/zstds/option.rb
CHANGED
@@ -12,6 +12,7 @@ module ZSTDS
|
|
12
12
|
DEFAULT_BUFFER_LENGTH = 0
|
13
13
|
|
14
14
|
COMPRESSOR_DEFAULTS = {
|
15
|
+
:gvl => false,
|
15
16
|
:compression_level => nil,
|
16
17
|
:window_log => nil,
|
17
18
|
:hash_log => nil,
|
@@ -36,6 +37,7 @@ module ZSTDS
|
|
36
37
|
.freeze
|
37
38
|
|
38
39
|
DECOMPRESSOR_DEFAULTS = {
|
40
|
+
:gvl => false,
|
39
41
|
:window_log_max => nil,
|
40
42
|
:dictionary => nil
|
41
43
|
}
|
@@ -44,11 +46,16 @@ module ZSTDS
|
|
44
46
|
def self.get_compressor_options(options, buffer_length_names)
|
45
47
|
Validation.validate_hash options
|
46
48
|
|
47
|
-
buffer_length_defaults = buffer_length_names.each_with_object({})
|
48
|
-
|
49
|
+
buffer_length_defaults = buffer_length_names.each_with_object({}) do |name, defaults|
|
50
|
+
defaults[name] = DEFAULT_BUFFER_LENGTH
|
51
|
+
end
|
52
|
+
|
53
|
+
options = COMPRESSOR_DEFAULTS.merge(buffer_length_defaults).merge options
|
49
54
|
|
50
55
|
buffer_length_names.each { |name| Validation.validate_not_negative_integer options[name] }
|
51
56
|
|
57
|
+
Validation.validate_bool options[:gvl]
|
58
|
+
|
52
59
|
compression_level = options[:compression_level]
|
53
60
|
unless compression_level.nil?
|
54
61
|
Validation.validate_integer compression_level
|
@@ -166,9 +173,8 @@ module ZSTDS
|
|
166
173
|
end
|
167
174
|
|
168
175
|
dictionary = options[:dictionary]
|
169
|
-
|
170
|
-
|
171
|
-
end
|
176
|
+
raise ValidateError, "invalid dictionary" unless
|
177
|
+
dictionary.nil? || dictionary.is_a?(Dictionary)
|
172
178
|
|
173
179
|
options
|
174
180
|
end
|
@@ -176,11 +182,16 @@ module ZSTDS
|
|
176
182
|
def self.get_decompressor_options(options, buffer_length_names)
|
177
183
|
Validation.validate_hash options
|
178
184
|
|
179
|
-
buffer_length_defaults = buffer_length_names.each_with_object({})
|
180
|
-
|
185
|
+
buffer_length_defaults = buffer_length_names.each_with_object({}) do |name, defaults|
|
186
|
+
defaults[name] = DEFAULT_BUFFER_LENGTH
|
187
|
+
end
|
188
|
+
|
189
|
+
options = DECOMPRESSOR_DEFAULTS.merge(buffer_length_defaults).merge options
|
181
190
|
|
182
191
|
buffer_length_names.each { |name| Validation.validate_not_negative_integer options[name] }
|
183
192
|
|
193
|
+
Validation.validate_bool options[:gvl]
|
194
|
+
|
184
195
|
window_log_max = options[:window_log_max]
|
185
196
|
unless window_log_max.nil?
|
186
197
|
Validation.validate_not_negative_integer window_log_max
|
@@ -12,17 +12,13 @@ module ZSTDS
|
|
12
12
|
# Native stream is not seekable by design.
|
13
13
|
# Related methods like "seek" and "pos=" can't be implemented.
|
14
14
|
|
15
|
-
# It is not possible to maintain correspondance between bytes
|
15
|
+
# It is not possible to maintain correspondance between bytes
|
16
|
+
# consumed from source and bytes written to destination by design.
|
16
17
|
# We will consume all source bytes and maintain buffer with remaining destination data.
|
17
18
|
|
18
19
|
include Delegates
|
19
20
|
|
20
|
-
attr_reader :io
|
21
|
-
attr_reader :stat
|
22
|
-
attr_reader :external_encoding
|
23
|
-
attr_reader :internal_encoding
|
24
|
-
attr_reader :transcode_options
|
25
|
-
attr_reader :pos
|
21
|
+
attr_reader :io, :stat, :external_encoding, :internal_encoding, :transcode_options, :pos
|
26
22
|
|
27
23
|
alias tell pos
|
28
24
|
|
@@ -94,8 +90,9 @@ module ZSTDS
|
|
94
90
|
end
|
95
91
|
|
96
92
|
internal_encoding = args[1]
|
97
|
-
|
98
|
-
|
93
|
+
unless internal_encoding.nil? || internal_encoding.is_a?(::Encoding)
|
94
|
+
Validation.validate_string internal_encoding
|
95
|
+
end
|
99
96
|
|
100
97
|
transcode_options = args[2]
|
101
98
|
Validation.validate_hash transcode_options unless transcode_options.nil?
|
@@ -19,11 +19,13 @@ module ZSTDS
|
|
19
19
|
|
20
20
|
def flush(&writer)
|
21
21
|
write_result(&writer)
|
22
|
+
|
23
|
+
nil
|
22
24
|
end
|
23
25
|
|
24
|
-
protected def
|
26
|
+
protected def more_destination(&writer)
|
25
27
|
result_bytesize = write_result(&writer)
|
26
|
-
raise NotEnoughDestinationError, "not enough destination" if result_bytesize
|
28
|
+
raise NotEnoughDestinationError, "not enough destination" if result_bytesize.zero?
|
27
29
|
end
|
28
30
|
|
29
31
|
protected def write_result(&_writer)
|
@@ -44,6 +46,8 @@ module ZSTDS
|
|
44
46
|
|
45
47
|
@native_stream.close
|
46
48
|
@is_closed = true
|
49
|
+
|
50
|
+
nil
|
47
51
|
end
|
48
52
|
|
49
53
|
def closed?
|
@@ -39,7 +39,7 @@ module ZSTDS
|
|
39
39
|
|
40
40
|
if need_more_destination
|
41
41
|
source = source.byteslice bytes_written, source.bytesize - bytes_written
|
42
|
-
|
42
|
+
more_destination(&writer)
|
43
43
|
next
|
44
44
|
end
|
45
45
|
|
@@ -65,7 +65,7 @@ module ZSTDS
|
|
65
65
|
need_more_destination = @native_stream.flush
|
66
66
|
|
67
67
|
if need_more_destination
|
68
|
-
|
68
|
+
more_destination(&writer)
|
69
69
|
next
|
70
70
|
end
|
71
71
|
|
@@ -73,8 +73,6 @@ module ZSTDS
|
|
73
73
|
end
|
74
74
|
|
75
75
|
super
|
76
|
-
|
77
|
-
nil
|
78
76
|
end
|
79
77
|
|
80
78
|
def close(&writer)
|
@@ -86,7 +84,7 @@ module ZSTDS
|
|
86
84
|
need_more_destination = @native_stream.finish
|
87
85
|
|
88
86
|
if need_more_destination
|
89
|
-
|
87
|
+
more_destination(&writer)
|
90
88
|
next
|
91
89
|
end
|
92
90
|
|
@@ -94,8 +92,6 @@ module ZSTDS
|
|
94
92
|
end
|
95
93
|
|
96
94
|
super
|
97
|
-
|
98
|
-
nil
|
99
95
|
end
|
100
96
|
end
|
101
97
|
end
|
@@ -34,7 +34,7 @@ module ZSTDS
|
|
34
34
|
|
35
35
|
if need_more_destination
|
36
36
|
source = source.byteslice bytes_read, source.bytesize - bytes_read
|
37
|
-
|
37
|
+
more_destination(&writer)
|
38
38
|
next
|
39
39
|
end
|
40
40
|
|
@@ -51,8 +51,6 @@ module ZSTDS
|
|
51
51
|
Validation.validate_proc writer
|
52
52
|
|
53
53
|
super
|
54
|
-
|
55
|
-
nil
|
56
54
|
end
|
57
55
|
|
58
56
|
def close(&writer)
|
@@ -61,8 +59,6 @@ module ZSTDS
|
|
61
59
|
Validation.validate_proc writer
|
62
60
|
|
63
61
|
super
|
64
|
-
|
65
|
-
nil
|
66
62
|
end
|
67
63
|
end
|
68
64
|
end
|
data/lib/zstds/stream/reader.rb
CHANGED
@@ -20,79 +20,61 @@ module ZSTDS
|
|
20
20
|
|
21
21
|
initialize_source_buffer_length
|
22
22
|
reset_io_remainder
|
23
|
+
reset_need_to_flush
|
23
24
|
|
24
25
|
@lineno = 0
|
25
26
|
end
|
26
27
|
|
28
|
+
protected def create_raw_stream
|
29
|
+
Raw::Decompressor.new @options
|
30
|
+
end
|
31
|
+
|
27
32
|
protected def initialize_source_buffer_length
|
28
33
|
source_buffer_length = @options[:source_buffer_length]
|
29
34
|
Validation.validate_not_negative_integer source_buffer_length unless source_buffer_length.nil?
|
30
35
|
|
31
|
-
source_buffer_length
|
32
|
-
|
36
|
+
if source_buffer_length.nil? || source_buffer_length.zero?
|
37
|
+
source_buffer_length = Buffer::DEFAULT_SOURCE_BUFFER_LENGTH_FOR_DECOMPRESSOR
|
38
|
+
end
|
33
39
|
|
34
40
|
@source_buffer_length = source_buffer_length
|
35
41
|
end
|
36
42
|
|
37
|
-
protected def create_raw_stream
|
38
|
-
Raw::Decompressor.new @options
|
39
|
-
end
|
40
|
-
|
41
43
|
protected def reset_io_remainder
|
42
44
|
@io_remainder = ::String.new :encoding => ::Encoding::BINARY
|
43
45
|
end
|
44
46
|
|
47
|
+
protected def reset_need_to_flush
|
48
|
+
@need_to_flush = false
|
49
|
+
end
|
50
|
+
|
45
51
|
# -- synchronous --
|
46
52
|
|
47
53
|
def read(bytes_to_read = nil, out_buffer = nil)
|
48
54
|
Validation.validate_not_negative_integer bytes_to_read unless bytes_to_read.nil?
|
49
55
|
Validation.validate_string out_buffer unless out_buffer.nil?
|
50
56
|
|
51
|
-
return ::String.new :encoding => ::Encoding::BINARY if bytes_to_read == 0
|
52
|
-
|
53
57
|
unless bytes_to_read.nil?
|
58
|
+
return ::String.new :encoding => ::Encoding::BINARY if bytes_to_read.zero?
|
54
59
|
return nil if eof?
|
55
60
|
|
56
|
-
|
61
|
+
append_io_data @io.read(@source_buffer_length) while @buffer.bytesize < bytes_to_read && !@io.eof?
|
62
|
+
flush_io_data if @buffer.bytesize < bytes_to_read
|
57
63
|
|
58
64
|
return read_bytes_from_buffer bytes_to_read, out_buffer
|
59
65
|
end
|
60
66
|
|
61
|
-
|
62
|
-
|
63
|
-
result = @buffer
|
64
|
-
reset_buffer
|
65
|
-
@pos += result.bytesize
|
66
|
-
|
67
|
-
result.force_encoding @external_encoding unless @external_encoding.nil?
|
68
|
-
result = transcode_to_internal result
|
69
|
-
result = out_buffer.replace result unless out_buffer.nil?
|
70
|
-
|
71
|
-
result
|
72
|
-
end
|
73
|
-
|
74
|
-
protected def read_more_to_buffer
|
75
|
-
io_data = @io.read @source_buffer_length
|
76
|
-
append_io_data_to_buffer io_data
|
77
|
-
end
|
78
|
-
|
79
|
-
def readpartial(bytes_to_read = nil, out_buffer = nil)
|
80
|
-
raise ::EOFError if eof?
|
81
|
-
|
82
|
-
readpartial_to_buffer until @buffer.bytesize >= bytes_to_read || @io.eof?
|
83
|
-
|
84
|
-
read_bytes_from_buffer bytes_to_read, out_buffer
|
85
|
-
end
|
67
|
+
append_io_data @io.read(@source_buffer_length) until @io.eof?
|
68
|
+
flush_io_data
|
86
69
|
|
87
|
-
|
88
|
-
io_data = @io.readpartial @source_buffer_length
|
89
|
-
append_io_data_to_buffer io_data
|
70
|
+
read_buffer out_buffer
|
90
71
|
end
|
91
72
|
|
92
73
|
def rewind
|
93
74
|
raw_wrapper :close
|
94
75
|
|
95
76
|
reset_io_remainder
|
77
|
+
reset_need_to_flush
|
96
78
|
|
97
79
|
super
|
98
80
|
end
|
@@ -103,25 +85,61 @@ module ZSTDS
|
|
103
85
|
super
|
104
86
|
end
|
105
87
|
|
88
|
+
def eof?
|
89
|
+
empty? && @io.eof?
|
90
|
+
end
|
91
|
+
|
106
92
|
# -- asynchronous --
|
107
93
|
|
94
|
+
def readpartial(bytes_to_read, out_buffer = nil)
|
95
|
+
read_more_nonblock(bytes_to_read, out_buffer) { @io.readpartial @source_buffer_length }
|
96
|
+
end
|
97
|
+
|
108
98
|
def read_nonblock(bytes_to_read, out_buffer = nil, *options)
|
109
|
-
|
99
|
+
read_more_nonblock(bytes_to_read, out_buffer) { @io.read_nonblock(@source_buffer_length, *options) }
|
100
|
+
end
|
101
|
+
|
102
|
+
protected def read_more_nonblock(bytes_to_read, out_buffer, &_block)
|
103
|
+
Validation.validate_not_negative_integer bytes_to_read
|
104
|
+
Validation.validate_string out_buffer unless out_buffer.nil?
|
105
|
+
|
106
|
+
return ::String.new :encoding => ::Encoding::BINARY if bytes_to_read.zero?
|
107
|
+
|
108
|
+
io_provided_eof_error = false
|
110
109
|
|
111
|
-
|
110
|
+
if @buffer.bytesize < bytes_to_read
|
111
|
+
begin
|
112
|
+
append_io_data yield
|
113
|
+
rescue ::EOFError
|
114
|
+
io_provided_eof_error = true
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
flush_io_data if @buffer.bytesize < bytes_to_read
|
119
|
+
raise ::EOFError if empty? && io_provided_eof_error
|
112
120
|
|
113
121
|
read_bytes_from_buffer bytes_to_read, out_buffer
|
114
122
|
end
|
115
123
|
|
116
|
-
|
117
|
-
|
118
|
-
|
124
|
+
# -- common --
|
125
|
+
|
126
|
+
protected def append_io_data(io_data)
|
127
|
+
io_portion = @io_remainder + io_data
|
128
|
+
bytes_read = raw_wrapper :read, io_portion
|
129
|
+
@io_remainder = io_portion.byteslice bytes_read, io_portion.bytesize - bytes_read
|
130
|
+
|
131
|
+
# Even empty io data may require flush.
|
132
|
+
@need_to_flush = true
|
119
133
|
end
|
120
134
|
|
121
|
-
|
135
|
+
protected def flush_io_data
|
136
|
+
raw_wrapper :flush
|
122
137
|
|
123
|
-
|
124
|
-
|
138
|
+
@need_to_flush = false
|
139
|
+
end
|
140
|
+
|
141
|
+
protected def empty?
|
142
|
+
!@need_to_flush && @buffer.bytesize.zero?
|
125
143
|
end
|
126
144
|
|
127
145
|
protected def read_bytes_from_buffer(bytes_to_read, out_buffer)
|
@@ -136,14 +154,16 @@ module ZSTDS
|
|
136
154
|
result
|
137
155
|
end
|
138
156
|
|
139
|
-
protected def
|
140
|
-
|
141
|
-
|
142
|
-
@
|
157
|
+
protected def read_buffer(out_buffer)
|
158
|
+
result = @buffer
|
159
|
+
reset_buffer
|
160
|
+
@pos += result.bytesize
|
143
161
|
|
144
|
-
|
145
|
-
|
146
|
-
|
162
|
+
result.force_encoding @external_encoding unless @external_encoding.nil?
|
163
|
+
result = transcode_to_internal result
|
164
|
+
|
165
|
+
result = out_buffer.replace result unless out_buffer.nil?
|
166
|
+
result
|
147
167
|
end
|
148
168
|
|
149
169
|
protected def transcode_to_internal(data)
|
data/lib/zstds/stream/writer.rb
CHANGED
@@ -64,7 +64,7 @@ module ZSTDS
|
|
64
64
|
end
|
65
65
|
|
66
66
|
protected def write_remaining_buffer
|
67
|
-
return nil if @buffer.bytesize
|
67
|
+
return nil if @buffer.bytesize.zero?
|
68
68
|
|
69
69
|
@io.write @buffer
|
70
70
|
|
@@ -77,6 +77,11 @@ module ZSTDS
|
|
77
77
|
|
78
78
|
# -- asynchronous --
|
79
79
|
|
80
|
+
# IO write nonblock can raise wait writable error.
|
81
|
+
# After resolving this error user may provide same content again.
|
82
|
+
# It is not possible to revert accepted content after error.
|
83
|
+
# So we have to accept content after processing IO write nonblock.
|
84
|
+
# It means that first write nonblock won't call IO write nonblock.
|
80
85
|
def write_nonblock(object, *options)
|
81
86
|
return 0 unless write_remaining_buffer_nonblock(*options)
|
82
87
|
|
@@ -120,14 +125,14 @@ module ZSTDS
|
|
120
125
|
end
|
121
126
|
|
122
127
|
protected def write_remaining_buffer_nonblock(*options)
|
123
|
-
return true if @buffer.bytesize
|
128
|
+
return true if @buffer.bytesize.zero?
|
124
129
|
|
125
130
|
bytes_written = @io.write_nonblock @buffer, *options
|
126
|
-
return false if bytes_written
|
131
|
+
return false if bytes_written.zero?
|
127
132
|
|
128
133
|
@buffer = @buffer.byteslice bytes_written, @buffer.bytesize - bytes_written
|
129
134
|
|
130
|
-
@buffer.bytesize
|
135
|
+
@buffer.bytesize.zero?
|
131
136
|
end
|
132
137
|
|
133
138
|
protected def raw_nonblock_wrapper(method_name, *args)
|