mmapscanner 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/ext/mmapscanner.c +98 -33
  2. data/spec/mmapscanner_spec.rb +74 -3
  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
- free(data);
31
+ xfree(data);
32
32
  }
33
33
 
34
- static VALUE create_mmap_object(int fd, size_t offset, size_t size)
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 = size;
44
- return Data_Wrap_Struct(cMmap, 0, mmap_free, data);
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
- VALUE src_data;
79
- mmapscanner_t *ms;
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
- src_data = ms->data;
140
+ src = ms->data;
141
+ src_size_defined = 1;
92
142
  } else if (TYPE(src) == T_FILE) {
93
- int fd;
94
- struct stat st;
95
- fd = RFILE(src)->fptr->fd;
96
- fstat(fd, &st);
97
- src_offset = 0;
98
- src_size = st.st_size;
99
- size = vsize == Qnil ? src_size - offset : NUM2SIZET(vsize);
100
- if (size > st.st_size - offset)
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
- src_offset = 0;
105
- src_size = RSTRING_LEN(src);
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, ms);
117
- ms->offset = src_offset + offset;
118
- ms->size = size;
119
- ms->pos = 0;
120
- ms->matched = 0;
121
- ms->matched_pos = 0;
122
- ms->data = src_data;
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
  }
@@ -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 '.new with position' do
188
- it 'raise error when invalid position' do
189
- expect{MmapScanner.new(@file, 4095)}.to raise_error(Errno::EINVAL)
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.1
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-03-23 00:00:00 +09:00
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.0
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