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
         |