simple-mmap 1.1.0
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/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
|