ruby-brs 1.1.2 → 1.2.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 +103 -82
- data/ext/brs_ext/buffer.c +21 -7
- data/ext/brs_ext/buffer.h +7 -7
- data/ext/brs_ext/error.c +11 -11
- data/ext/brs_ext/error.h +2 -1
- data/ext/brs_ext/gvl.h +24 -0
- data/ext/brs_ext/io.c +240 -122
- data/ext/brs_ext/option.c +37 -27
- data/ext/brs_ext/option.h +37 -29
- data/ext/brs_ext/stream/compressor.c +118 -52
- data/ext/brs_ext/stream/compressor.h +4 -1
- data/ext/brs_ext/stream/decompressor.c +54 -22
- data/ext/brs_ext/stream/decompressor.h +4 -1
- data/ext/brs_ext/string.c +118 -64
- data/ext/extconf.rb +10 -1
- data/lib/brs/file.rb +6 -2
- data/lib/brs/option.rb +16 -4
- data/lib/brs/stream/abstract.rb +6 -9
- data/lib/brs/stream/raw/abstract.rb +6 -2
- data/lib/brs/stream/raw/compressor.rb +3 -7
- data/lib/brs/stream/raw/decompressor.rb +1 -5
- data/lib/brs/stream/reader.rb +72 -52
- data/lib/brs/stream/reader_helpers.rb +1 -1
- data/lib/brs/stream/writer.rb +9 -4
- data/lib/brs/stream/writer_helpers.rb +3 -2
- data/lib/brs/validation.rb +4 -2
- data/lib/brs/version.rb +1 -1
- metadata +62 -19
data/ext/extconf.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
|
4
4
|
require "mkmf"
|
5
5
|
|
6
|
+
have_func "rb_thread_call_without_gvl", "ruby/thread.h"
|
7
|
+
|
6
8
|
def require_header(name, types = [])
|
7
9
|
abort "Can't find #{name} header" unless find_header name
|
8
10
|
|
@@ -61,7 +63,14 @@ $srcs = %w[
|
|
61
63
|
.map { |name| "src/#{extension_name}/#{name}.c" }
|
62
64
|
.freeze
|
63
65
|
|
64
|
-
|
66
|
+
# Removing library duplicates.
|
67
|
+
$libs = $libs.split(%r{\s})
|
68
|
+
.reject(&:empty?)
|
69
|
+
.sort
|
70
|
+
.uniq
|
71
|
+
.join " "
|
72
|
+
|
73
|
+
if ENV["CI"]
|
65
74
|
$CFLAGS << " --coverage"
|
66
75
|
$LDFLAGS << " --coverage"
|
67
76
|
end
|
data/lib/brs/file.rb
CHANGED
@@ -19,9 +19,11 @@ module BRS
|
|
19
19
|
|
20
20
|
options[:size_hint] = ::File.size source
|
21
21
|
|
22
|
-
open_files
|
22
|
+
open_files source, destination do |source_io, destination_io|
|
23
23
|
BRS._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 BRS
|
|
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
|
BRS._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/brs/option.rb
CHANGED
@@ -11,6 +11,7 @@ module BRS
|
|
11
11
|
DEFAULT_BUFFER_LENGTH = 0
|
12
12
|
|
13
13
|
COMPRESSOR_DEFAULTS = {
|
14
|
+
:gvl => false,
|
14
15
|
:mode => nil,
|
15
16
|
:quality => nil,
|
16
17
|
:lgwin => nil,
|
@@ -21,6 +22,7 @@ module BRS
|
|
21
22
|
.freeze
|
22
23
|
|
23
24
|
DECOMPRESSOR_DEFAULTS = {
|
25
|
+
:gvl => false,
|
24
26
|
:disable_ring_buffer_reallocation => nil,
|
25
27
|
:large_window => nil
|
26
28
|
}
|
@@ -29,11 +31,16 @@ module BRS
|
|
29
31
|
def self.get_compressor_options(options, buffer_length_names)
|
30
32
|
Validation.validate_hash options
|
31
33
|
|
32
|
-
buffer_length_defaults = buffer_length_names.each_with_object({})
|
33
|
-
|
34
|
+
buffer_length_defaults = buffer_length_names.each_with_object({}) do |name, defaults|
|
35
|
+
defaults[name] = DEFAULT_BUFFER_LENGTH
|
36
|
+
end
|
37
|
+
|
38
|
+
options = COMPRESSOR_DEFAULTS.merge(buffer_length_defaults).merge options
|
34
39
|
|
35
40
|
buffer_length_names.each { |name| Validation.validate_not_negative_integer options[name] }
|
36
41
|
|
42
|
+
Validation.validate_bool options[:gvl]
|
43
|
+
|
37
44
|
mode = options[:mode]
|
38
45
|
unless mode.nil?
|
39
46
|
Validation.validate_symbol mode
|
@@ -70,11 +77,16 @@ module BRS
|
|
70
77
|
def self.get_decompressor_options(options, buffer_length_names)
|
71
78
|
Validation.validate_hash options
|
72
79
|
|
73
|
-
buffer_length_defaults = buffer_length_names.each_with_object({})
|
74
|
-
|
80
|
+
buffer_length_defaults = buffer_length_names.each_with_object({}) do |name, defaults|
|
81
|
+
defaults[name] = DEFAULT_BUFFER_LENGTH
|
82
|
+
end
|
83
|
+
|
84
|
+
options = DECOMPRESSOR_DEFAULTS.merge(buffer_length_defaults).merge options
|
75
85
|
|
76
86
|
buffer_length_names.each { |name| Validation.validate_not_negative_integer options[name] }
|
77
87
|
|
88
|
+
Validation.validate_bool options[:gvl]
|
89
|
+
|
78
90
|
disable_ring_buffer_reallocation = options[:disable_ring_buffer_reallocation]
|
79
91
|
Validation.validate_bool disable_ring_buffer_reallocation unless disable_ring_buffer_reallocation.nil?
|
80
92
|
|
data/lib/brs/stream/abstract.rb
CHANGED
@@ -12,17 +12,13 @@ module BRS
|
|
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 BRS
|
|
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 BRS
|
|
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 BRS
|
|
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 BRS
|
|
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 BRS
|
|
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 BRS
|
|
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 BRS
|
|
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 BRS
|
|
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 BRS
|
|
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 BRS
|
|
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 BRS
|
|
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/brs/stream/reader.rb
CHANGED
@@ -20,79 +20,61 @@ module BRS
|
|
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 BRS
|
|
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 BRS
|
|
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/brs/stream/writer.rb
CHANGED
@@ -64,7 +64,7 @@ module BRS
|
|
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 BRS
|
|
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 BRS
|
|
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)
|