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