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.
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