simple-mmap 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +55 -0
- data/ext/Makefile +157 -0
- data/ext/extconf.rb +5 -0
- data/ext/mapped_file.c +179 -0
- data/lib/simple_mmap.rb +24 -0
- data/lib/simple_mmap/file_window.rb +101 -0
- data/test/test_file_window.rb +75 -0
- data/test/test_mapped_file.rb +27 -0
- metadata +65 -0
data/README.txt
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
= simple_mmap
|
2
|
+
|
3
|
+
http://simple-mmap.rubyforge.org/
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
A simplistic interface for reading memory mapped files
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* mmap a file. Read data from it. Close it when you're done. More fun than the "ball in a cup" game.
|
12
|
+
* it ONLY supports reading mmap'ed files, not writing to the mmap'ed region
|
13
|
+
|
14
|
+
== SYNOPSIS:
|
15
|
+
|
16
|
+
>> fw = SimpleMmap::FileWindow.open("path/to/large/file")
|
17
|
+
>> fw[23467, 200] #=> data between byte 23467 and the next 200 bytes
|
18
|
+
# works with the same semantics as Array#[] (eg. fw[10..14] and fw[10...14])
|
19
|
+
>> fw.close # you MUST close the FileWindow after you're done (HAHA no blocks for you yet!)
|
20
|
+
|
21
|
+
|
22
|
+
== REQUIREMENTS:
|
23
|
+
|
24
|
+
* A mmap() capable platform.
|
25
|
+
|
26
|
+
== INSTALL:
|
27
|
+
|
28
|
+
$ gem install simple_mmap
|
29
|
+
# If you have ruby 1.9+ built with executables having a program-suffix:
|
30
|
+
$ env rake=rake1.9 gem install simple_mmap
|
31
|
+
|
32
|
+
== LICENSE:
|
33
|
+
|
34
|
+
(The MIT License)
|
35
|
+
|
36
|
+
Copyright (c) 2009 Johan Sørensen
|
37
|
+
|
38
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
39
|
+
a copy of this software and associated documentation files (the
|
40
|
+
'Software'), to deal in the Software without restriction, including
|
41
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
42
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
43
|
+
permit persons to whom the Software is furnished to do so, subject to
|
44
|
+
the following conditions:
|
45
|
+
|
46
|
+
The above copyright notice and this permission notice shall be
|
47
|
+
included in all copies or substantial portions of the Software.
|
48
|
+
|
49
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
50
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
51
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
52
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
53
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
54
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
55
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/ext/Makefile
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
|
2
|
+
SHELL = /bin/sh
|
3
|
+
|
4
|
+
#### Start of system configuration section. ####
|
5
|
+
|
6
|
+
srcdir = .
|
7
|
+
topdir = /Users/pieter/.rvm/rubies/ree-1.8.7-2010.01/lib/ruby/1.8/i686-darwin10.2.0
|
8
|
+
hdrdir = $(topdir)
|
9
|
+
VPATH = $(srcdir):$(topdir):$(hdrdir)
|
10
|
+
exec_prefix = $(prefix)
|
11
|
+
prefix = $(DESTDIR)/Users/pieter/.rvm/rubies/ree-1.8.7-2010.01
|
12
|
+
sharedstatedir = $(prefix)/com
|
13
|
+
mandir = $(datarootdir)/man
|
14
|
+
psdir = $(docdir)
|
15
|
+
oldincludedir = $(DESTDIR)/usr/include
|
16
|
+
localedir = $(datarootdir)/locale
|
17
|
+
bindir = $(exec_prefix)/bin
|
18
|
+
libexecdir = $(exec_prefix)/libexec
|
19
|
+
sitedir = $(libdir)/ruby/site_ruby
|
20
|
+
htmldir = $(docdir)
|
21
|
+
vendorarchdir = $(vendorlibdir)/$(sitearch)
|
22
|
+
includedir = $(prefix)/include
|
23
|
+
infodir = $(datarootdir)/info
|
24
|
+
vendorlibdir = $(vendordir)/$(ruby_version)
|
25
|
+
sysconfdir = $(prefix)/etc
|
26
|
+
libdir = $(exec_prefix)/lib
|
27
|
+
sbindir = $(exec_prefix)/sbin
|
28
|
+
rubylibdir = $(libdir)/ruby/$(ruby_version)
|
29
|
+
docdir = $(datarootdir)/doc/$(PACKAGE)
|
30
|
+
dvidir = $(docdir)
|
31
|
+
vendordir = $(libdir)/ruby/vendor_ruby
|
32
|
+
datarootdir = $(prefix)/share
|
33
|
+
pdfdir = $(docdir)
|
34
|
+
archdir = $(rubylibdir)/$(arch)
|
35
|
+
sitearchdir = $(sitelibdir)/$(sitearch)
|
36
|
+
datadir = $(datarootdir)
|
37
|
+
localstatedir = $(prefix)/var
|
38
|
+
sitelibdir = $(sitedir)/$(ruby_version)
|
39
|
+
|
40
|
+
CC = gcc
|
41
|
+
LIBRUBY = $(LIBRUBY_A)
|
42
|
+
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
43
|
+
LIBRUBYARG_SHARED =
|
44
|
+
LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
|
45
|
+
|
46
|
+
RUBY_EXTCONF_H =
|
47
|
+
CFLAGS = -fno-common -g -O2 -pipe -fno-common $(cflags)
|
48
|
+
INCFLAGS = -I. -I. -I/Users/pieter/.rvm/rubies/ree-1.8.7-2010.01/lib/ruby/1.8/i686-darwin10.2.0 -I.
|
49
|
+
DEFS =
|
50
|
+
CPPFLAGS = -DHAVE_MMAP -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE
|
51
|
+
CXXFLAGS = $(CFLAGS)
|
52
|
+
ldflags = -L.
|
53
|
+
dldflags =
|
54
|
+
archflag =
|
55
|
+
DLDFLAGS = $(ldflags) $(dldflags) $(archflag)
|
56
|
+
LDSHARED = cc -dynamic -bundle -undefined suppress -flat_namespace
|
57
|
+
AR = ar
|
58
|
+
EXEEXT =
|
59
|
+
|
60
|
+
RUBY_INSTALL_NAME = ruby
|
61
|
+
RUBY_SO_NAME = ruby
|
62
|
+
arch = i686-darwin10.2.0
|
63
|
+
sitearch = i686-darwin10.2.0
|
64
|
+
ruby_version = 1.8
|
65
|
+
ruby = /Users/pieter/.rvm/rubies/ree-1.8.7-2010.01/bin/ruby
|
66
|
+
RUBY = $(ruby)
|
67
|
+
RM = rm -f
|
68
|
+
MAKEDIRS = mkdir -p
|
69
|
+
INSTALL = /opt/local/bin/ginstall -c
|
70
|
+
INSTALL_PROG = $(INSTALL) -m 0755
|
71
|
+
INSTALL_DATA = $(INSTALL) -m 644
|
72
|
+
COPY = cp
|
73
|
+
|
74
|
+
#### End of system configuration section. ####
|
75
|
+
|
76
|
+
preload =
|
77
|
+
|
78
|
+
libpath = . $(libdir)
|
79
|
+
LIBPATH = -L. -L$(libdir)
|
80
|
+
DEFFILE =
|
81
|
+
|
82
|
+
CLEANFILES = mkmf.log
|
83
|
+
DISTCLEANFILES =
|
84
|
+
|
85
|
+
extout =
|
86
|
+
extout_prefix =
|
87
|
+
target_prefix =
|
88
|
+
LOCAL_LIBS =
|
89
|
+
LIBS = -ldl -lobjc
|
90
|
+
SRCS = mapped_file.c
|
91
|
+
OBJS = mapped_file.o
|
92
|
+
TARGET = mapped_file
|
93
|
+
DLLIB = $(TARGET).bundle
|
94
|
+
EXTSTATIC =
|
95
|
+
STATIC_LIB =
|
96
|
+
|
97
|
+
BINDIR = $(bindir)
|
98
|
+
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
99
|
+
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
100
|
+
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
101
|
+
|
102
|
+
TARGET_SO = $(DLLIB)
|
103
|
+
CLEANLIBS = $(TARGET).bundle $(TARGET).il? $(TARGET).tds $(TARGET).map
|
104
|
+
CLEANOBJS = *.o *.a *.s[ol] *.pdb *.exp *.bak
|
105
|
+
|
106
|
+
all: $(DLLIB)
|
107
|
+
static: $(STATIC_LIB)
|
108
|
+
|
109
|
+
clean:
|
110
|
+
@-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
|
111
|
+
|
112
|
+
distclean: clean
|
113
|
+
@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
|
114
|
+
@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
115
|
+
|
116
|
+
realclean: distclean
|
117
|
+
install: install-so install-rb
|
118
|
+
|
119
|
+
install-so: $(RUBYARCHDIR)
|
120
|
+
install-so: $(RUBYARCHDIR)/$(DLLIB)
|
121
|
+
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
|
122
|
+
$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
|
123
|
+
install-rb: pre-install-rb install-rb-default
|
124
|
+
install-rb-default: pre-install-rb-default
|
125
|
+
pre-install-rb: Makefile
|
126
|
+
pre-install-rb-default: Makefile
|
127
|
+
$(RUBYARCHDIR):
|
128
|
+
$(MAKEDIRS) $@
|
129
|
+
|
130
|
+
site-install: site-install-so site-install-rb
|
131
|
+
site-install-so: install-so
|
132
|
+
site-install-rb: install-rb
|
133
|
+
|
134
|
+
.SUFFIXES: .c .m .cc .cxx .cpp .C .o
|
135
|
+
|
136
|
+
.cc.o:
|
137
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
138
|
+
|
139
|
+
.cxx.o:
|
140
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
141
|
+
|
142
|
+
.cpp.o:
|
143
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
144
|
+
|
145
|
+
.C.o:
|
146
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
147
|
+
|
148
|
+
.c.o:
|
149
|
+
$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) -c $<
|
150
|
+
|
151
|
+
$(DLLIB): $(OBJS) Makefile
|
152
|
+
@-$(RM) $@
|
153
|
+
$(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
|
154
|
+
|
155
|
+
|
156
|
+
|
157
|
+
$(OBJS): ruby.h defines.h
|
data/ext/extconf.rb
ADDED
data/ext/mapped_file.c
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
/* Copyright (c) 2009 Johan Sørensen
|
2
|
+
*
|
3
|
+
* Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
* a copy of this software and associated documentation files (the
|
5
|
+
* 'Software'), to deal in the Software without restriction, including
|
6
|
+
* without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
* distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
* permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
* the following conditions:
|
10
|
+
*
|
11
|
+
* The above copyright notice and this permission notice shall be
|
12
|
+
* included in all copies or substantial portions of the Software.
|
13
|
+
*
|
14
|
+
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
17
|
+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
18
|
+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
19
|
+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
20
|
+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
*/
|
22
|
+
|
23
|
+
#include <stdio.h>
|
24
|
+
#include <sys/stat.h>
|
25
|
+
#include <sys/fcntl.h>
|
26
|
+
#include <sys/mman.h>
|
27
|
+
#include <errno.h>
|
28
|
+
#include <unistd.h>
|
29
|
+
#include "ruby.h"
|
30
|
+
|
31
|
+
// a memory mapped file
|
32
|
+
typedef struct {
|
33
|
+
int fd;
|
34
|
+
caddr_t map;
|
35
|
+
size_t len;
|
36
|
+
} simple_mmap_map;
|
37
|
+
|
38
|
+
static VALUE mod_simple_mmap;
|
39
|
+
static VALUE sm_mapped_file;
|
40
|
+
static VALUE sm_map_data;
|
41
|
+
|
42
|
+
/*
|
43
|
+
* Document-method: new
|
44
|
+
* call-seq: SimpleMMap::MappedFile.new(path)
|
45
|
+
*
|
46
|
+
* mmap() the file at +path+
|
47
|
+
*/
|
48
|
+
static VALUE sm_mapped_file_initialize(VALUE vself, VALUE filename)
|
49
|
+
{
|
50
|
+
int fd = -1;
|
51
|
+
size_t length;
|
52
|
+
struct stat st;
|
53
|
+
caddr_t base = (caddr_t) - 1;
|
54
|
+
VALUE vsm_map;
|
55
|
+
simple_mmap_map *sm_map;
|
56
|
+
|
57
|
+
fd = open(RSTRING_PTR(filename), O_RDONLY);
|
58
|
+
if (fd == -1) {
|
59
|
+
rb_raise(rb_eArgError, "Failed to open file %s", RSTRING_PTR(filename));
|
60
|
+
close(fd);
|
61
|
+
}
|
62
|
+
|
63
|
+
// Get the size of the file
|
64
|
+
if (fstat(fd, &st) == -1) {
|
65
|
+
rb_raise(rb_eArgError, "Failed to stat file %s", RSTRING_PTR(filename));
|
66
|
+
close(fd);
|
67
|
+
}
|
68
|
+
length = st.st_size;
|
69
|
+
|
70
|
+
// do the mmap
|
71
|
+
base = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, 0);
|
72
|
+
if (base == (caddr_t) -1) {
|
73
|
+
rb_raise(rb_eArgError, "Failed to mmap file %s", RSTRING_PTR(filename));
|
74
|
+
close(fd);
|
75
|
+
}
|
76
|
+
|
77
|
+
// set the mmap structure as an ivar
|
78
|
+
sm_map = ALLOC(simple_mmap_map);
|
79
|
+
vsm_map = Data_Wrap_Struct(sm_map_data, NULL, free, sm_map);
|
80
|
+
sm_map->fd = fd;
|
81
|
+
sm_map->map = base;
|
82
|
+
sm_map->len = length;
|
83
|
+
rb_ivar_set(vself, rb_intern("@mmap_data"), vsm_map);
|
84
|
+
|
85
|
+
return Qnil;
|
86
|
+
}
|
87
|
+
|
88
|
+
/*
|
89
|
+
* Document-method: close
|
90
|
+
* call-seq: obj.close
|
91
|
+
*
|
92
|
+
* munmap() the current mmapped file
|
93
|
+
*/
|
94
|
+
static VALUE sm_mapped_file_close(VALUE vself)
|
95
|
+
{
|
96
|
+
VALUE vsm_map;
|
97
|
+
simple_mmap_map *sm_map;
|
98
|
+
|
99
|
+
sm_map = ALLOC(simple_mmap_map);
|
100
|
+
vsm_map = rb_ivar_get(vself, rb_intern("@mmap_data"));
|
101
|
+
Data_Get_Struct(vsm_map, simple_mmap_map, sm_map);
|
102
|
+
|
103
|
+
if (sm_map->map != (caddr_t) -1)
|
104
|
+
munmap(sm_map->map, sm_map->len);
|
105
|
+
if (sm_map->fd != -1)
|
106
|
+
close(sm_map->fd);
|
107
|
+
|
108
|
+
return Qtrue;
|
109
|
+
}
|
110
|
+
|
111
|
+
/*
|
112
|
+
* Document-method: read_window_data
|
113
|
+
* call-seq: obj.read_window_data(offset, length)
|
114
|
+
*
|
115
|
+
* Read +length+ bytes starting at +offset+
|
116
|
+
*/
|
117
|
+
static VALUE sm_mapped_file_read_window_data(VALUE vself, VALUE voffset, VALUE vlength)
|
118
|
+
{
|
119
|
+
size_t offset = NUM2INT(voffset);
|
120
|
+
size_t length = NUM2INT(vlength);
|
121
|
+
char buff[length];
|
122
|
+
VALUE vsm_map;
|
123
|
+
simple_mmap_map *sm_map;
|
124
|
+
|
125
|
+
sm_map = ALLOC(simple_mmap_map);
|
126
|
+
vsm_map = rb_ivar_get(vself, rb_intern("@mmap_data"));
|
127
|
+
Data_Get_Struct(vsm_map, simple_mmap_map, sm_map);
|
128
|
+
|
129
|
+
if (offset > sm_map->len) {
|
130
|
+
return Qnil;
|
131
|
+
}
|
132
|
+
|
133
|
+
size_t curr;
|
134
|
+
curr = offset;
|
135
|
+
size_t i;
|
136
|
+
for(i = 0; i < length; ++i) {
|
137
|
+
//printf("i=%i offset=%i length=%i curr=%i map->len=%i\n", i, offset, length, curr, sm_map->len);
|
138
|
+
if ((curr + i) > sm_map->len)
|
139
|
+
break;
|
140
|
+
buff[i] = sm_map->map[curr++];
|
141
|
+
}
|
142
|
+
|
143
|
+
// If the range overflows, return part that overlaps
|
144
|
+
if ((offset + length) > sm_map->len)
|
145
|
+
return rb_str_new(buff, sm_map->len - offset);
|
146
|
+
|
147
|
+
return rb_str_new(buff, length);
|
148
|
+
}
|
149
|
+
|
150
|
+
/*
|
151
|
+
* Document-method: size
|
152
|
+
* call-seq: obj.size
|
153
|
+
*
|
154
|
+
* Return size of mapped file
|
155
|
+
*/
|
156
|
+
|
157
|
+
static VALUE sm_mapped_file_size(VALUE vself)
|
158
|
+
{
|
159
|
+
VALUE vsm_map;
|
160
|
+
simple_mmap_map *sm_map;
|
161
|
+
|
162
|
+
sm_map = ALLOC(simple_mmap_map);
|
163
|
+
vsm_map = rb_ivar_get(vself, rb_intern("@mmap_data"));
|
164
|
+
Data_Get_Struct(vsm_map, simple_mmap_map, sm_map);
|
165
|
+
return UINT2NUM(sm_map->len);
|
166
|
+
}
|
167
|
+
|
168
|
+
void Init_mapped_file()
|
169
|
+
{
|
170
|
+
mod_simple_mmap = rb_define_module("SimpleMmap");
|
171
|
+
|
172
|
+
sm_mapped_file = rb_define_class_under(mod_simple_mmap, "MappedFile", rb_cObject);
|
173
|
+
rb_define_private_method(sm_mapped_file, "initialize", sm_mapped_file_initialize, 1);
|
174
|
+
rb_define_method(sm_mapped_file, "close", sm_mapped_file_close, 0);
|
175
|
+
rb_define_method(sm_mapped_file, "read_window_data", sm_mapped_file_read_window_data, 2);
|
176
|
+
rb_define_method(sm_mapped_file, "size", sm_mapped_file_size, 0);
|
177
|
+
|
178
|
+
sm_map_data = rb_define_class_under(sm_mapped_file, "MmapData", rb_cObject);
|
179
|
+
}
|
data/lib/simple_mmap.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright (c) 2009 Johan Sørensen
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# 'Software'), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
17
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
18
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
19
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
20
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
$:.unshift File.dirname(__FILE__)
|
23
|
+
require "simple_mmap/mapped_file"
|
24
|
+
require "simple_mmap/file_window"
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# Copyright (c) 2009 Johan Sørensen
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# 'Software'), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
17
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
18
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
19
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
20
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
module SimpleMmap
|
23
|
+
# Represents a window into a mmap()'ed file, using a familiar index syntax
|
24
|
+
# for getting single bytes or Ranges of bytes within that FileWindow
|
25
|
+
class FileWindow
|
26
|
+
# Create a mmap'ed window for file at +path+
|
27
|
+
# You are responsible for closing it when you're done using #close
|
28
|
+
def initialize(path)
|
29
|
+
@path = path
|
30
|
+
@offset = 0
|
31
|
+
@mmap = SimpleMmap::MappedFile.new(@path)
|
32
|
+
end
|
33
|
+
attr_reader :path, :offset
|
34
|
+
|
35
|
+
# unmaps the mmap'ed file
|
36
|
+
def close
|
37
|
+
@mmap.close
|
38
|
+
@mmap = nil
|
39
|
+
end
|
40
|
+
alias_method :unmap, :close
|
41
|
+
|
42
|
+
# The current offset
|
43
|
+
def offset
|
44
|
+
@offset
|
45
|
+
end
|
46
|
+
alias_method :pos, :offset
|
47
|
+
|
48
|
+
# Set the current offset to +new_offset+
|
49
|
+
def offset=(new_offset)
|
50
|
+
@offset = new_offset
|
51
|
+
end
|
52
|
+
alias_method :pos=, :offset=
|
53
|
+
|
54
|
+
# Move the current offset to +to_pos+
|
55
|
+
def seek(to_pos)
|
56
|
+
self.pos = to_pos
|
57
|
+
end
|
58
|
+
|
59
|
+
# Read data from the mmap'ed file. Takes the same arguments as
|
60
|
+
# Array/String#[] (eg [2], [2,5], [2..5] or [2...5])
|
61
|
+
# The current offset will be tracked accordingly
|
62
|
+
def [](*index)
|
63
|
+
if index.length == 1
|
64
|
+
index = index.first
|
65
|
+
end
|
66
|
+
case index
|
67
|
+
when Array
|
68
|
+
offset, length = index
|
69
|
+
when Fixnum
|
70
|
+
offset = index
|
71
|
+
length = 0
|
72
|
+
when Range
|
73
|
+
offset = index.begin
|
74
|
+
length = index.end - index.begin
|
75
|
+
unless index.exclude_end?
|
76
|
+
length += 1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
@offset = offset + length
|
81
|
+
|
82
|
+
if length.zero?
|
83
|
+
@mmap.read_window_data(offset, 1)
|
84
|
+
else
|
85
|
+
@mmap.read_window_data(offset, length)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Read +length+ bytes starting from the current offset
|
90
|
+
def read(length)
|
91
|
+
data = @mmap.read_window_data(@offset, length)
|
92
|
+
@offset += length
|
93
|
+
data
|
94
|
+
end
|
95
|
+
|
96
|
+
# Return size of mapped file
|
97
|
+
def size
|
98
|
+
@mmap.size
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + "/../lib/simple_mmap"
|
4
|
+
|
5
|
+
class TestFileWindow < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@file = Tempfile.new("TestFileWindow.data")
|
8
|
+
File.open(@file.path, "w"){|f| f.write(('a'..'z').to_a.join) }
|
9
|
+
@fw = SimpleMmap::FileWindow.new(@file.path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
@fw.close
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_should_start_at_offset_0
|
17
|
+
assert_equal 0, @fw.offset
|
18
|
+
assert_equal 0, @fw.pos
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_should_be_able_to_set_the_offset
|
22
|
+
@fw.offset = 2
|
23
|
+
assert_equal 2, @fw.offset
|
24
|
+
assert_equal 2, @fw.pos
|
25
|
+
|
26
|
+
@fw.pos = 4
|
27
|
+
assert_equal 4, @fw.offset
|
28
|
+
assert_equal 4, @fw.pos
|
29
|
+
|
30
|
+
@fw.seek(6)
|
31
|
+
assert_equal 6, @fw.offset
|
32
|
+
assert_equal 6, @fw.pos
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_get_single_byte_at_current_offset_with_index
|
36
|
+
assert_equal "c", @fw[2]
|
37
|
+
assert_equal 2, @fw.offset
|
38
|
+
assert_equal "b", @fw[1]
|
39
|
+
assert_equal 1, @fw.offset
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_get_bytes_past_length
|
43
|
+
assert_equal "z", @fw[25, 10]
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_nil_on_negative_index
|
47
|
+
assert_equal nil, @fw[-1]
|
48
|
+
assert_equal nil, @fw[-1, 2]
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_get_from_x_to_y_with_index_comma_notation
|
52
|
+
assert_equal "cde", @fw[2, 3]
|
53
|
+
assert_equal 5, @fw.pos
|
54
|
+
assert_nil @fw[28, 2]
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_get_with_range_including
|
58
|
+
assert_equal "cde", @fw[2..4]
|
59
|
+
assert_equal 5, @fw.offset
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_get_with_range_excluding
|
63
|
+
assert_equal "cd", @fw[2...4]
|
64
|
+
assert_equal 4, @fw.offset
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_read
|
68
|
+
assert_equal "abc", @fw.read(3)
|
69
|
+
assert_equal 3, @fw.offset
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_size
|
73
|
+
assert_equal 26, @fw.size
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "tempfile"
|
3
|
+
|
4
|
+
require File.dirname(__FILE__) + "/../lib/simple_mmap"
|
5
|
+
|
6
|
+
class TestMappedFile < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@file = Tempfile.new("TestMappedFile.data")
|
9
|
+
File.open(@file.path, "w"){|f| f.puts(('a'..'z').to_a.join) }
|
10
|
+
@map = SimpleMmap::MappedFile.new(@file.path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
@map.close
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_read_window_data
|
18
|
+
assert_equal "abc", @map.read_window_data(0, 3)
|
19
|
+
assert_equal "bc", @map.read_window_data(1, 2)
|
20
|
+
assert_equal "klmno", @map.read_window_data(10, 5)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_read_window_beyond_buffer_size
|
24
|
+
assert_equal "z\n", @map.read_window_data(25, 5)
|
25
|
+
assert_nil @map.read_window_data(28, 5)
|
26
|
+
end
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simple-mmap
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Johan S\xC3\xB8rensen"
|
8
|
+
- Pieter Noordhuis
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2010-02-10 00:00:00 +01:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description:
|
18
|
+
email: pcnoordhuis@gmail.com
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions:
|
22
|
+
- ext/extconf.rb
|
23
|
+
extra_rdoc_files:
|
24
|
+
- README.txt
|
25
|
+
files:
|
26
|
+
- ext/Makefile
|
27
|
+
- ext/extconf.rb
|
28
|
+
- ext/mapped_file.c
|
29
|
+
- lib/simple_mmap.rb
|
30
|
+
- lib/simple_mmap/file_window.rb
|
31
|
+
- test/test_file_window.rb
|
32
|
+
- test/test_mapped_file.rb
|
33
|
+
- README.txt
|
34
|
+
has_rdoc: true
|
35
|
+
homepage: http://github.com/pietern/simple-mmap
|
36
|
+
licenses: []
|
37
|
+
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options:
|
40
|
+
- --charset=UTF-8
|
41
|
+
require_paths:
|
42
|
+
- ext
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
version:
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
requirements: []
|
57
|
+
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 1.3.5
|
60
|
+
signing_key:
|
61
|
+
specification_version: 3
|
62
|
+
summary: Read-only wrapper for mmap
|
63
|
+
test_files:
|
64
|
+
- test/test_file_window.rb
|
65
|
+
- test/test_mapped_file.rb
|