mmapscanner 0.3.1 → 0.3.2
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.
- data/ext/mmapscanner.c +98 -33
- data/spec/mmapscanner_spec.rb +74 -3
- metadata +3 -5
data/ext/mmapscanner.c
CHANGED
@@ -28,20 +28,68 @@ static void mmap_free(mmap_data_t *data)
|
|
28
28
|
{
|
29
29
|
if (data->ptr)
|
30
30
|
munmap(data->ptr, data->size);
|
31
|
-
|
31
|
+
xfree(data);
|
32
32
|
}
|
33
33
|
|
34
|
-
static VALUE
|
34
|
+
static VALUE mmap_allocate(VALUE klass)
|
35
35
|
{
|
36
36
|
mmap_data_t *data;
|
37
|
-
void *ptr;
|
38
|
-
if ((ptr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, offset)) == MAP_FAILED) {
|
39
|
-
rb_exc_raise(rb_funcall(rb_eSystemCallError, rb_intern("new"), 1, INT2FIX(errno)));
|
40
|
-
}
|
41
37
|
data = xmalloc(sizeof(mmap_data_t));
|
38
|
+
data->ptr = NULL;
|
39
|
+
data->size = 0;
|
40
|
+
return Data_Wrap_Struct(klass, 0, mmap_free, data);
|
41
|
+
}
|
42
|
+
|
43
|
+
static VALUE mmap_initialize(int argc, VALUE *argv, VALUE obj)
|
44
|
+
{
|
45
|
+
mmap_data_t *data;
|
46
|
+
Data_Get_Struct(obj, mmap_data_t, data);
|
47
|
+
if (data->ptr)
|
48
|
+
rb_raise(rb_eRuntimeError, "already mapped");
|
49
|
+
VALUE file, voffset, vlength;
|
50
|
+
off_t offset = 0;
|
51
|
+
size_t length = 0;
|
52
|
+
rb_scan_args(argc, argv, "12", &file, &voffset, &vlength);
|
53
|
+
if (TYPE(file) != T_FILE)
|
54
|
+
rb_raise(rb_eTypeError, "File object required");
|
55
|
+
if (voffset != Qnil && NUM2LL(voffset) < 0)
|
56
|
+
rb_raise(rb_eRangeError, "offset out of range: %lld", NUM2LL(voffset));
|
57
|
+
if (vlength != Qnil && NUM2LL(vlength) < 0)
|
58
|
+
rb_raise(rb_eRangeError, "length out of range: %lld", NUM2LL(vlength));
|
59
|
+
int fd = RFILE(file)->fptr->fd;
|
60
|
+
struct stat st;
|
61
|
+
if (fstat(fd, &st) < 0)
|
62
|
+
rb_sys_fail("fstat");
|
63
|
+
offset = voffset == Qnil ? 0 : NUM2SIZET(voffset);
|
64
|
+
length = vlength == Qnil ? st.st_size : NUM2SIZET(vlength);
|
65
|
+
if (offset + length > st.st_size)
|
66
|
+
length = st.st_size - offset;
|
67
|
+
void *ptr;
|
68
|
+
if ((ptr = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, offset)) == MAP_FAILED)
|
69
|
+
rb_sys_fail("mmap");
|
70
|
+
|
42
71
|
data->ptr = ptr;
|
43
|
-
data->size =
|
44
|
-
return
|
72
|
+
data->size = length;
|
73
|
+
return Qnil;
|
74
|
+
}
|
75
|
+
|
76
|
+
static VALUE mmap_size(VALUE obj)
|
77
|
+
{
|
78
|
+
mmap_data_t *data;
|
79
|
+
Data_Get_Struct(obj, mmap_data_t, data);
|
80
|
+
return SIZET2NUM(data->size);
|
81
|
+
}
|
82
|
+
|
83
|
+
static VALUE mmap_unmap(VALUE obj)
|
84
|
+
{
|
85
|
+
mmap_data_t *data;
|
86
|
+
Data_Get_Struct(obj, mmap_data_t, data);
|
87
|
+
if (data->ptr == NULL)
|
88
|
+
rb_raise(rb_eRuntimeError, "already unmapped");
|
89
|
+
if (munmap(data->ptr, data->size) < 0)
|
90
|
+
rb_sys_fail("munmap");
|
91
|
+
data->ptr = NULL;
|
92
|
+
return Qnil;
|
45
93
|
}
|
46
94
|
|
47
95
|
static void mmapscanner_free(mmapscanner_t *ms)
|
@@ -74,9 +122,9 @@ static VALUE initialize(int argc, VALUE *argv, VALUE obj)
|
|
74
122
|
{
|
75
123
|
VALUE src, voffset, vsize;
|
76
124
|
size_t offset, size;
|
77
|
-
size_t src_offset, src_size;
|
78
|
-
|
79
|
-
|
125
|
+
size_t src_offset = 0, src_size = 0;
|
126
|
+
mmapscanner_t *self;
|
127
|
+
int src_size_defined = 0;
|
80
128
|
|
81
129
|
rb_scan_args(argc, argv, "12", &src, &voffset, &vsize);
|
82
130
|
if (voffset != Qnil && NUM2LL(voffset) < 0)
|
@@ -85,27 +133,26 @@ static VALUE initialize(int argc, VALUE *argv, VALUE obj)
|
|
85
133
|
rb_raise(rb_eRangeError, "length out of range: %lld", NUM2LL(vsize));
|
86
134
|
offset = voffset == Qnil ? 0 : NUM2SIZET(voffset);
|
87
135
|
if (rb_obj_class(src) == cMmapScanner) {
|
136
|
+
mmapscanner_t *ms;
|
88
137
|
Data_Get_Struct(src, mmapscanner_t, ms);
|
89
138
|
src_offset = ms->offset;
|
90
139
|
src_size = ms->size;
|
91
|
-
|
140
|
+
src = ms->data;
|
141
|
+
src_size_defined = 1;
|
92
142
|
} else if (TYPE(src) == T_FILE) {
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
size = st.st_size - offset;
|
102
|
-
src_data = create_mmap_object(fd, offset, size);
|
143
|
+
src = rb_funcall(cMmap, rb_intern("new"), 1, src);
|
144
|
+
}
|
145
|
+
if (rb_obj_class(src) == cMmap) {
|
146
|
+
if (!src_size_defined) {
|
147
|
+
mmap_data_t *data;
|
148
|
+
Data_Get_Struct(src, mmap_data_t, data);
|
149
|
+
src_size = data->size;
|
150
|
+
}
|
103
151
|
} else if (TYPE(src) == T_STRING) {
|
104
|
-
|
105
|
-
|
106
|
-
src_data = src;
|
152
|
+
if (!src_size_defined)
|
153
|
+
src_size = RSTRING_LEN(src);
|
107
154
|
} else {
|
108
|
-
rb_raise(rb_eTypeError, "wrong argument type %s (expected File/String/MmapScanner)", rb_obj_classname(src));
|
155
|
+
rb_raise(rb_eTypeError, "wrong argument type %s (expected File/String/MmapScanner/MmapScanner::Mmap)", rb_obj_classname(src));
|
109
156
|
}
|
110
157
|
if (offset > src_size)
|
111
158
|
rb_raise(rb_eRangeError, "length out of range: %zu > %zu", offset, src_size);
|
@@ -113,13 +160,13 @@ static VALUE initialize(int argc, VALUE *argv, VALUE obj)
|
|
113
160
|
if (size > src_size - offset)
|
114
161
|
size = src_size - offset;
|
115
162
|
|
116
|
-
Data_Get_Struct(obj, mmapscanner_t,
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
163
|
+
Data_Get_Struct(obj, mmapscanner_t, self);
|
164
|
+
self->offset = src_offset + offset;
|
165
|
+
self->size = size;
|
166
|
+
self->pos = 0;
|
167
|
+
self->matched = 0;
|
168
|
+
self->matched_pos = 0;
|
169
|
+
self->data = src;
|
123
170
|
return Qnil;
|
124
171
|
}
|
125
172
|
|
@@ -130,6 +177,13 @@ static VALUE size(VALUE obj)
|
|
130
177
|
return SIZET2NUM(ms->size);
|
131
178
|
}
|
132
179
|
|
180
|
+
static VALUE data(VALUE obj)
|
181
|
+
{
|
182
|
+
mmapscanner_t *ms;
|
183
|
+
Data_Get_Struct(obj, mmapscanner_t, ms);
|
184
|
+
return ms->data;
|
185
|
+
}
|
186
|
+
|
133
187
|
static VALUE to_s(VALUE obj)
|
134
188
|
{
|
135
189
|
mmapscanner_t *ms;
|
@@ -138,6 +192,8 @@ static VALUE to_s(VALUE obj)
|
|
138
192
|
if (TYPE(ms->data) == T_STRING)
|
139
193
|
return rb_str_new(RSTRING_PTR(ms->data) + ms->offset, ms->size);
|
140
194
|
Data_Get_Struct(ms->data, mmap_data_t, mdata);
|
195
|
+
if (mdata->ptr == NULL)
|
196
|
+
rb_raise(rb_eRuntimeError, "already unmapped");
|
141
197
|
return rb_str_new(mdata->ptr + ms->offset, ms->size);
|
142
198
|
}
|
143
199
|
|
@@ -194,6 +250,8 @@ static VALUE scan_sub(VALUE obj, VALUE re, int forward, int headonly, int sizeon
|
|
194
250
|
ptr = RSTRING_PTR(ms->data);
|
195
251
|
else {
|
196
252
|
Data_Get_Struct(ms->data, mmap_data_t, mdata);
|
253
|
+
if (mdata->ptr == NULL)
|
254
|
+
rb_raise(rb_eRuntimeError, "already unmapped");
|
197
255
|
ptr = mdata->ptr;
|
198
256
|
}
|
199
257
|
ptr += ms->offset;
|
@@ -329,6 +387,8 @@ static VALUE matched_str(int argc, VALUE *argv, VALUE obj)
|
|
329
387
|
if (TYPE(ms->data) == T_STRING)
|
330
388
|
return rb_str_new(RSTRING_PTR(ms->data)+ms->offset+pos, len);
|
331
389
|
Data_Get_Struct(ms->data, mmap_data_t, mdata);
|
390
|
+
if (mdata->ptr == NULL)
|
391
|
+
rb_raise(rb_eRuntimeError, "already unmapped");
|
332
392
|
return rb_str_new(mdata->ptr+ms->offset+pos, len);
|
333
393
|
}
|
334
394
|
|
@@ -339,6 +399,7 @@ void Init_mmapscanner(void)
|
|
339
399
|
rb_define_method(cMmapScanner, "initialize", initialize, -1);
|
340
400
|
rb_define_method(cMmapScanner, "size", size, 0);
|
341
401
|
rb_define_method(cMmapScanner, "length", size, 0);
|
402
|
+
rb_define_method(cMmapScanner, "data", data, 0);
|
342
403
|
rb_define_method(cMmapScanner, "to_s", to_s, 0);
|
343
404
|
rb_define_method(cMmapScanner, "slice", slice, 2);
|
344
405
|
// rb_define_method(cMmapScanner, "[]", slice, 2);
|
@@ -357,4 +418,8 @@ void Init_mmapscanner(void)
|
|
357
418
|
rb_define_method(cMmapScanner, "matched_str", matched_str, -1);
|
358
419
|
|
359
420
|
cMmap = rb_define_class_under(cMmapScanner, "Mmap", rb_cObject);
|
421
|
+
rb_define_alloc_func(cMmap, mmap_allocate);
|
422
|
+
rb_define_method(cMmap, "initialize", mmap_initialize, -1);
|
423
|
+
rb_define_method(cMmap, "size", mmap_size, 0);
|
424
|
+
rb_define_method(cMmap, "unmap", mmap_unmap, 0);
|
360
425
|
}
|
data/spec/mmapscanner_spec.rb
CHANGED
@@ -3,6 +3,29 @@ require 'tempfile'
|
|
3
3
|
$LOAD_PATH.unshift "#{File.dirname __FILE__}/../ext"
|
4
4
|
require 'mmapscanner'
|
5
5
|
|
6
|
+
describe MmapScanner::Mmap do
|
7
|
+
before do
|
8
|
+
tmpf = Tempfile.new 'mmapscanner'
|
9
|
+
tmpf.write '0123456789'*1000
|
10
|
+
@file = File.open(tmpf.path)
|
11
|
+
end
|
12
|
+
subject{MmapScanner::Mmap.new(@file)}
|
13
|
+
it '#size returns file size' do
|
14
|
+
subject.size.should == 10000
|
15
|
+
end
|
16
|
+
it '.new with invalid offset raise error' do
|
17
|
+
expect{MmapScanner::Mmap.new(@file, 4095)}.to raise_error(Errno::EINVAL)
|
18
|
+
end
|
19
|
+
context 'unmapped object' do
|
20
|
+
before do
|
21
|
+
subject.unmap
|
22
|
+
end
|
23
|
+
it '#unmap raise error' do
|
24
|
+
expect{subject.unmap}.to raise_error(RuntimeError, 'already unmapped')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
6
29
|
describe MmapScanner do
|
7
30
|
shared_examples_for 'MmapScanner' do
|
8
31
|
it '#size returns size of file' do
|
@@ -184,9 +207,9 @@ describe MmapScanner do
|
|
184
207
|
let(:src){@file}
|
185
208
|
subject{MmapScanner.new(src)}
|
186
209
|
it_should_behave_like 'MmapScanner'
|
187
|
-
describe '
|
188
|
-
it '
|
189
|
-
|
210
|
+
describe '#data' do
|
211
|
+
it 'returns Mmap object' do
|
212
|
+
subject.data.should be_kind_of MmapScanner::Mmap
|
190
213
|
end
|
191
214
|
end
|
192
215
|
end
|
@@ -202,6 +225,49 @@ describe MmapScanner do
|
|
202
225
|
m.to_s.should be_empty
|
203
226
|
end
|
204
227
|
end
|
228
|
+
describe '#data' do
|
229
|
+
it 'returns source object' do
|
230
|
+
subject.data.should be_equal src
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
context 'with Mmap' do
|
236
|
+
before do
|
237
|
+
tmpf = Tempfile.new 'mmapscanner'
|
238
|
+
tmpf.write '0123456789'*1020
|
239
|
+
@file = File.open(tmpf.path)
|
240
|
+
end
|
241
|
+
let(:src){MmapScanner::Mmap.new(@file)}
|
242
|
+
subject{MmapScanner.new(src, 100, 10000)}
|
243
|
+
it_should_behave_like 'MmapScanner'
|
244
|
+
describe '.new with empty source' do
|
245
|
+
it 'returns empty MmapScanner' do
|
246
|
+
m = MmapScanner.new(src, 1020, 0)
|
247
|
+
m.size.should == 0
|
248
|
+
m.to_s.should be_empty
|
249
|
+
end
|
250
|
+
end
|
251
|
+
describe '#data' do
|
252
|
+
it 'returns source object' do
|
253
|
+
subject.data.should be_equal src
|
254
|
+
end
|
255
|
+
end
|
256
|
+
context 'unmapped object' do
|
257
|
+
before do
|
258
|
+
subject.scan(/.../)
|
259
|
+
src.unmap
|
260
|
+
end
|
261
|
+
it '#to_s raise RuntimeError' do
|
262
|
+
expect{subject.to_s}.to raise_error(RuntimeError, 'already unmapped')
|
263
|
+
end
|
264
|
+
it '#scan raise RuntimeError' do
|
265
|
+
expect{subject.scan(/./)}.to raise_error(RuntimeError, 'already unmapped')
|
266
|
+
end
|
267
|
+
it '#matched_str raise RuntimeError' do
|
268
|
+
expect{subject.matched_str}.to raise_error(RuntimeError, 'already unmapped')
|
269
|
+
end
|
270
|
+
end
|
205
271
|
end
|
206
272
|
|
207
273
|
context 'with MmapScanner' do
|
@@ -213,6 +279,11 @@ describe MmapScanner do
|
|
213
279
|
let(:src){MmapScanner.new(@file)}
|
214
280
|
subject{MmapScanner.new(src, 100, 10000)}
|
215
281
|
it_should_behave_like 'MmapScanner'
|
282
|
+
describe '#data' do
|
283
|
+
it 'returns data object' do
|
284
|
+
subject.data.should be_kind_of MmapScanner::Mmap
|
285
|
+
end
|
286
|
+
end
|
216
287
|
describe '.new with empty source' do
|
217
288
|
it 'returns empty MmapScanner' do
|
218
289
|
m = MmapScanner.new(src, 1020, 0)
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: mmapscanner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.3.
|
5
|
+
version: 0.3.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- TOMITA Masahiro
|
@@ -10,8 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
14
|
-
default_executable:
|
13
|
+
date: 2011-07-23 00:00:00 Z
|
15
14
|
dependencies: []
|
16
15
|
|
17
16
|
description:
|
@@ -27,7 +26,6 @@ files:
|
|
27
26
|
- ext/mmapscanner.c
|
28
27
|
- spec/mmapscanner_spec.rb
|
29
28
|
- ext/extconf.rb
|
30
|
-
has_rdoc: true
|
31
29
|
homepage: http://github.com/tmtm/mmapscanner
|
32
30
|
licenses:
|
33
31
|
- Ruby's
|
@@ -51,7 +49,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
51
49
|
requirements: []
|
52
50
|
|
53
51
|
rubyforge_project:
|
54
|
-
rubygems_version: 1.5
|
52
|
+
rubygems_version: 1.8.5
|
55
53
|
signing_key:
|
56
54
|
specification_version: 3
|
57
55
|
summary: MmapScanner like StringScanner but it use mmap(2)-ed data
|