na_str 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,132 @@
1
+
2
+ SHELL = /bin/sh
3
+
4
+ #### Start of system configuration section. ####
5
+
6
+ srcdir = .
7
+ topdir = $(rubylibdir)/$(arch)
8
+ hdrdir = $(rubylibdir)/$(arch)
9
+ VPATH = $(srcdir)
10
+ prefix = $(DESTDIR)/dmsp/reference/ruby-1.8.1/
11
+ exec_prefix = $(prefix)
12
+ sitedir = $(prefix)/lib/ruby/site_ruby
13
+ rubylibdir = $(libdir)/ruby/$(ruby_version)
14
+ builddir = $(ac_builddir)
15
+ archdir = $(rubylibdir)/$(arch)
16
+ sbindir = $(exec_prefix)/sbin
17
+ compile_dir = $(DESTDIR)/dmsp/moby-1-1/reference/build/ruby-1.8.1
18
+ datadir = $(prefix)/share
19
+ includedir = $(prefix)/include
20
+ infodir = $(prefix)/info
21
+ top_builddir = $(ac_top_builddir)
22
+ sysconfdir = $(prefix)/etc
23
+ mandir = $(prefix)/man
24
+ libdir = $(exec_prefix)/lib
25
+ sharedstatedir = $(prefix)/com
26
+ oldincludedir = $(DESTDIR)/usr/include
27
+ sitearchdir = $(sitelibdir)/$(sitearch)
28
+ bindir = $(exec_prefix)/bin
29
+ localstatedir = $(prefix)/var
30
+ sitelibdir = $(sitedir)/$(ruby_version)
31
+ libexecdir = $(exec_prefix)/libexec
32
+
33
+ CC = gcc
34
+ LIBRUBY = $(LIBRUBY_A)
35
+ LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
36
+ LIBRUBYARG_SHARED =
37
+ LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
38
+
39
+ CFLAGS = -fPIC -g -O2 -I /dmsp/reference/ruby-1.8.1//lib/ruby/site_ruby/1.8/i686-linux
40
+ CPPFLAGS = -I. -I$(topdir) -I$(hdrdir) -I$(srcdir)
41
+ CXXFLAGS = $(CFLAGS)
42
+ DLDFLAGS = /dmsp/reference/ruby-1.8.1//lib/ruby/site_ruby/1.8/i686-linux/narray.so
43
+ LDSHARED = gcc -shared
44
+ AR = ar
45
+ EXEEXT =
46
+
47
+ RUBY_INSTALL_NAME = ruby
48
+ RUBY_SO_NAME = $(RUBY_INSTALL_NAME)
49
+ arch = i686-linux
50
+ sitearch = i686-linux
51
+ ruby_version = 1.8
52
+ RUBY = ruby
53
+ RM = $(RUBY) -run -e rm -- -f
54
+ MAKEDIRS = $(RUBY) -run -e mkdir -- -p
55
+ INSTALL_PROG = $(RUBY) -run -e install -- -vpm 0755
56
+ INSTALL_DATA = $(RUBY) -run -e install -- -vpm 0644
57
+
58
+ #### End of system configuration section. ####
59
+
60
+
61
+ LIBPATH = -L"$(libdir)"
62
+ DEFFILE =
63
+
64
+ CLEANFILES =
65
+ DISTCLEANFILES =
66
+
67
+ target_prefix =
68
+ LOCAL_LIBS =
69
+ LIBS = -ldl -lcrypt -lm -lc
70
+ OBJS = na_str.o
71
+ TARGET = na_str
72
+ DLLIB = $(TARGET).so
73
+ STATIC_LIB = $(TARGET).a
74
+
75
+ RUBYCOMMONDIR = $(sitedir)$(target_prefix)
76
+ RUBYLIBDIR = $(sitelibdir)$(target_prefix)
77
+ RUBYARCHDIR = $(sitearchdir)$(target_prefix)
78
+
79
+ CLEANLIBS = "$(TARGET).{lib,exp,il?,tds,map}" $(DLLIB)
80
+ CLEANOBJS = "*.{o,a,s[ol],pdb,bak}"
81
+
82
+ all: $(DLLIB)
83
+ static: $(STATIC_LIB)
84
+
85
+ clean:
86
+ @$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
87
+
88
+ distclean: clean
89
+ @$(RM) Makefile extconf.h conftest.* mkmf.log
90
+ @$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
91
+
92
+ realclean: distclean
93
+ install: $(RUBYARCHDIR)
94
+ install: $(RUBYARCHDIR)/$(DLLIB)
95
+ $(RUBYARCHDIR)/$(DLLIB): $(DLLIB) $(RUBYARCHDIR)
96
+ @$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
97
+ install: $(RUBYLIBDIR)
98
+ install: $(RUBYLIBDIR)/nmap.rb
99
+ $(RUBYLIBDIR)/nmap.rb: $(srcdir)/lib/nmap.rb $(RUBYLIBDIR)
100
+ @$(INSTALL_DATA) $(srcdir)/lib/nmap.rb $(RUBYLIBDIR)
101
+ $(RUBYARCHDIR):
102
+ @$(MAKEDIRS) $(RUBYARCHDIR)
103
+ $(RUBYLIBDIR):
104
+ @$(MAKEDIRS) $(RUBYLIBDIR)
105
+
106
+ site-install: install
107
+
108
+ .SUFFIXES: .c .cc .m .cxx .cpp .C .o
109
+
110
+ .cc.o:
111
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
112
+
113
+ .cpp.o:
114
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
115
+
116
+ .cxx.o:
117
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
118
+
119
+ .C.o:
120
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
121
+
122
+ .c.o:
123
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
124
+
125
+ $(DLLIB): $(OBJS)
126
+ @-$(RM) $@
127
+ $(LDSHARED) $(DLDFLAGS) $(LIBPATH) -o $(DLLIB) $(OBJS) $(LOCAL_LIBS) $(LIBS)
128
+
129
+ $(STATIC_LIB): $(OBJS)
130
+ $(AR) cru $@ $(OBJS)
131
+ @-ranlib $(DLLIB) 2> /dev/null || true
132
+
data/README ADDED
@@ -0,0 +1,103 @@
1
+ NAME
2
+
3
+ na_str (c extension)
4
+
5
+ nmap (reference ruby class which combines narray and mmap)
6
+
7
+
8
+ URIS
9
+
10
+ http://codeforpeople.com/lib/ruby/na_str/
11
+
12
+
13
+ SYNOPSIS
14
+
15
+ na_str is designed to allow data sharing between narray object and other ruby
16
+ objects. the shared data is that returned by the objects to_s or to_str method
17
+ and rb_string_new4. using this technique memory mapped (using guy's mmap
18
+ extensions) data can be altered with no explicit io on the users part and
19
+ partial changed to numerical grids can occur very quickly and persistently.
20
+
21
+ the nmap.rb reference impl is a concrete example of this usage and is
22
+ included in the distribution
23
+
24
+
25
+ EXAMPLE USAGE
26
+
27
+ jib:~/eg/ruby/na_str > cat a.rb
28
+ #
29
+ # the nmap extension is installed along with na_str
30
+ #
31
+ require 'nmap'
32
+ #
33
+ # the NMap ctor interface is similar to NArray's, but a backing file must also
34
+ # be specified
35
+ #
36
+ path, x, y = 'int.data', 3, 4
37
+ nmap = NMap.int path, x, y
38
+ #
39
+ # copy the last row to the first
40
+ #
41
+ nmap.na[true, 0] = nmap.na[true, 3]
42
+ #
43
+ # set the last row to be the current time. if you run this a few times you'll
44
+ # notice that changes to the narray are automatically written to the to
45
+ # backing file via the magic of mmap
46
+ #
47
+ nmap.na[true, 3] = Time.now.to_i
48
+ #
49
+ # show the narray
50
+ #
51
+ p nmap.na
52
+
53
+
54
+ jib:~/eg/ruby/na_str > ruby a.rb
55
+ NArray(ref).int(3,4):
56
+ [ [ 0, 0, 0 ],
57
+ [ 0, 0, 0 ],
58
+ [ 0, 0, 0 ],
59
+ [ 1151439012, 1151439012, 1151439012 ] ]
60
+
61
+ jib:~/eg/ruby/na_str > ruby a.rb
62
+ NArray(ref).int(3,4):
63
+ [ [ 1151439012, 1151439012, 1151439012 ],
64
+ [ 0, 0, 0 ],
65
+ [ 0, 0, 0 ],
66
+ [ 1151439014, 1151439014, 1151439014 ] ]
67
+
68
+
69
+ SPEED
70
+
71
+ jib:~/eg/ruby/na_str > cat a.rb
72
+ #
73
+ # reference impl installed with na_str
74
+ #
75
+ require 'nmap'
76
+ #
77
+ # setup a narray grid containing 1 gb of ints
78
+ #
79
+ gb = 2 ** 30
80
+ mb = 2 ** 20
81
+ sizeof_int = [42].pack('i').size
82
+ gig_of_ints = gb / sizeof_int
83
+ nmap = NMap.int '1GB', gig_of_ints
84
+ #
85
+ # set about 1 million of the ints to 42
86
+ #
87
+ nmap.na[0 .. mb] = 42
88
+ #
89
+ # show that the data was written
90
+ #
91
+ p nmap.na[mb - 1]
92
+
93
+
94
+ jib:~/eg/ruby/na_str > time ruby a.rb
95
+ 42
96
+
97
+ real 0m0.078s
98
+ user 0m0.020s
99
+ sys 0m0.020s
100
+
101
+
102
+ jib:~/eg/ruby/na_str > ls -ltar 1GB
103
+ -rw-rw-r-- 1 ahoward ahoward 1073741824 Jun 27 14:28 1GB
Binary file
@@ -0,0 +1,9 @@
1
+ require "mkmf"
2
+ require "rbconfig"
3
+
4
+ sitearchdir = Config::CONFIG["sitearchdir"]
5
+
6
+ $CFLAGS += " -I #{ sitearchdir } "
7
+ $LDFLAGS += " #{ sitearchdir }/narray.so " # force a link so narray.so symbols will be resolved
8
+
9
+ create_makefile "na_str"
@@ -0,0 +1,30 @@
1
+
2
+ lib, version = File::basename(File::dirname(File::expand_path(__FILE__))).split %r/-/, 2
3
+
4
+ require 'rubygems'
5
+
6
+ Gem::Specification::new do |spec|
7
+ $VERBOSE = nil
8
+ spec.name = lib
9
+ spec.version = version
10
+ spec.platform = Gem::Platform::RUBY
11
+ spec.summary = lib
12
+
13
+ spec.files = Dir::glob "**/**"
14
+ spec.executables = Dir::glob("bin/*").map{|exe| File::basename exe}
15
+
16
+ spec.require_path = "lib"
17
+ spec.autorequire = lib
18
+
19
+ spec.has_rdoc = File::exist? "doc"
20
+ spec.test_suite_file = "test/#{ lib }.rb" if File::directory? "test"
21
+
22
+ spec.extensions << "extconf.rb" if File::exists? "extconf.rb"
23
+
24
+ spec.author = "Ara T. Howard"
25
+ spec.email = "ara.t.howard@noaa.gov"
26
+ spec.homepage = "http://codeforpeople.com/lib/ruby/#{ lib }/"
27
+
28
+ spec.requirements << "http://moulon.inra.fr/ruby/mmap.html"
29
+ spec.requirements << "http://narray.rubyforge.org/"
30
+ end
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rbconfig'
3
+ require 'find'
4
+ require 'ftools'
5
+ require 'tempfile'
6
+ include Config
7
+
8
+ LIBDIR = "lib"
9
+ LIBDIR_MODE = 0644
10
+
11
+ BINDIR = "bin"
12
+ BINDIR_MODE = 0755
13
+
14
+
15
+ $srcdir = CONFIG["srcdir"]
16
+ $version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
17
+ $libdir = File.join(CONFIG["libdir"], "ruby", $version)
18
+ $archdir = File.join($libdir, CONFIG["arch"])
19
+ $site_libdir = $:.find {|x| x =~ /site_ruby$/}
20
+ $bindir = CONFIG["bindir"] || CONFIG['BINDIR']
21
+ $ruby_install_name = CONFIG['ruby_install_name'] || CONFIG['RUBY_INSTALL_NAME'] || 'ruby'
22
+ $ruby_ext = CONFIG['EXEEXT'] || ''
23
+ $ruby = File.join($bindir, ($ruby_install_name + $ruby_ext))
24
+
25
+ if !$site_libdir
26
+ $site_libdir = File.join($libdir, "site_ruby")
27
+ elsif $site_libdir !~ %r/#{Regexp.quote($version)}/
28
+ $site_libdir = File.join($site_libdir, $version)
29
+ end
30
+
31
+ def install_rb(srcdir=nil, destdir=nil, mode=nil, bin=nil)
32
+ #{{{
33
+ path = []
34
+ dir = []
35
+ Find.find(srcdir) do |f|
36
+ next unless FileTest.file?(f)
37
+ next if (f = f[srcdir.length+1..-1]) == nil
38
+ next if (/CVS$/ =~ File.dirname(f))
39
+ next if f =~ %r/\.lnk/
40
+ path.push f
41
+ dir |= [File.dirname(f)]
42
+ end
43
+ for f in dir
44
+ next if f == "."
45
+ next if f == "CVS"
46
+ File::makedirs(File.join(destdir, f))
47
+ end
48
+ for f in path
49
+ next if (/\~$/ =~ f)
50
+ next if (/^\./ =~ File.basename(f))
51
+ unless bin
52
+ File::install(File.join(srcdir, f), File.join(destdir, f), mode, true)
53
+ else
54
+ from = File.join(srcdir, f)
55
+ to = File.join(destdir, f)
56
+ shebangify(from) do |sf|
57
+ $deferr.print from, " -> ", File::catname(from, to), "\n"
58
+ $deferr.printf "chmod %04o %s\n", mode, to
59
+ File::install(sf, to, mode, false)
60
+ end
61
+ end
62
+ end
63
+ #}}}
64
+ end
65
+ def shebangify f
66
+ #{{{
67
+ open(f) do |fd|
68
+ buf = fd.read 42
69
+ if buf =~ %r/^\s*#\s*!.*ruby/o
70
+ ftmp = Tempfile::new("#{ $$ }_#{ File::basename(f) }")
71
+ begin
72
+ fd.rewind
73
+ ftmp.puts "#!#{ $ruby }"
74
+ while((buf = fd.read(8192)))
75
+ ftmp.write buf
76
+ end
77
+ ftmp.close
78
+ yield ftmp.path
79
+ ensure
80
+ ftmp.close!
81
+ end
82
+ else
83
+ yield f
84
+ end
85
+ end
86
+ #}}}
87
+ end
88
+ def ARGV.switch
89
+ #{{{
90
+ return nil if self.empty?
91
+ arg = self.shift
92
+ return nil if arg == '--'
93
+ if arg =~ /^-(.)(.*)/
94
+ return arg if $1 == '-'
95
+ raise 'unknown switch "-"' if $2.index('-')
96
+ self.unshift "-#{$2}" if $2.size > 0
97
+ "-#{$1}"
98
+ else
99
+ self.unshift arg
100
+ nil
101
+ end
102
+ #}}}
103
+ end
104
+ def ARGV.req_arg
105
+ #{{{
106
+ self.shift || raise('missing argument')
107
+ #}}}
108
+ end
109
+ def linkify d, linked = []
110
+ #--{{{
111
+ if test ?d, d
112
+ versioned = Dir[ File::join(d, "*-[0-9].[0-9].[0-9].rb") ]
113
+ versioned.each do |v|
114
+ src, dst = v, v.gsub(%r/\-[\d\.]+\.rb$/, '.rb')
115
+ lnk = nil
116
+ begin
117
+ if test ?l, dst
118
+ lnk = "#{ dst }.lnk"
119
+ puts "#{ dst } -> #{ lnk }"
120
+ File::rename dst, lnk
121
+ end
122
+ unless test ?e, dst
123
+ puts "#{ src } -> #{ dst }"
124
+ File::copy src, dst
125
+ linked << dst
126
+ end
127
+ ensure
128
+ if lnk
129
+ at_exit do
130
+ puts "#{ lnk } -> #{ dst }"
131
+ File::rename lnk, dst
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ linked
138
+ #--}}}
139
+ end
140
+
141
+
142
+ #
143
+ # main program
144
+ #
145
+
146
+ libdir = $site_libdir
147
+ bindir = $bindir
148
+ no_linkify = false
149
+ linked = nil
150
+ help = false
151
+
152
+ usage = <<-usage
153
+ #{ File::basename $0 }
154
+ -d, --destdir <destdir>
155
+ -l, --libdir <libdir>
156
+ -b, --bindir <bindir>
157
+ -r, --ruby <ruby>
158
+ -n, --no_linkify
159
+ -s, --sudo
160
+ -h, --help
161
+ usage
162
+
163
+ begin
164
+ while switch = ARGV.switch
165
+ case switch
166
+ when '-d', '--destdir'
167
+ libdir = ARGV.req_arg
168
+ when '-l', '--libdir'
169
+ libdir = ARGV.req_arg
170
+ when '-b', '--bindir'
171
+ bindir = ARGV.req_arg
172
+ when '-r', '--ruby'
173
+ $ruby = ARGV.req_arg
174
+ when '-n', '--no_linkify'
175
+ no_linkify = true
176
+ when '-s', '--sudo'
177
+ sudo = 'sudo'
178
+ when '-h', '--help'
179
+ help = true
180
+ else
181
+ raise "unknown switch #{switch.dump}"
182
+ end
183
+ end
184
+ rescue
185
+ STDERR.puts $!.to_s
186
+ STDERR.puts usage
187
+ exit 1
188
+ end
189
+
190
+ if help
191
+ STDOUT.puts usage
192
+ exit
193
+ end
194
+
195
+ system "#{ sudo } #{ $ruby } pre-install.rb" if test(?s, 'pre-install.rb')
196
+
197
+ unless no_linkify
198
+ linked = linkify('lib') + linkify('bin')
199
+ end
200
+
201
+ system "#{ $ruby } extconf.rb && make && #{ sudo } make install" if test(?s, 'extconf.rb')
202
+
203
+ install_rb(LIBDIR, libdir, LIBDIR_MODE)
204
+ install_rb(BINDIR, bindir, BINDIR_MODE, bin=true)
205
+
206
+ if linked
207
+ linked.each{|path| File::rm_f path}
208
+ end
209
+
210
+ system "#{ sudo } #{ $ruby } post-install.rb" if test(?s, 'post-install.rb')
@@ -0,0 +1,198 @@
1
+ #
2
+ # built-in
3
+ #
4
+ require "yaml"
5
+ #
6
+ # rubyforge.org/raa.ruby-lang.org
7
+ #
8
+ require "mmap"
9
+ require "narray"
10
+ #
11
+ # homegrown
12
+ #
13
+ require "na_str"
14
+ #
15
+ # here we creates a little convenience class for working with memory mapped
16
+ # numerical grids
17
+ #
18
+ class NMap
19
+ module Util
20
+ def string_of obj
21
+ obj.to_str
22
+ rescue
23
+ raise ArgumentError, "cannot convert <#{ obj.inspect }> to string"
24
+ end
25
+
26
+ def int_of obj
27
+ Integer obj
28
+ rescue
29
+ raise ArgumentError, "cannot convert <#{ obj.inspect }> to int"
30
+ end
31
+
32
+ def int_list_of obj
33
+ [*obj].flatten.map{|elem| int_of elem}
34
+ rescue
35
+ raise ArgumentError, "cannot convert <#{ obj.inspect }> to int list"
36
+ end
37
+ end
38
+
39
+ class Header < ::Hash
40
+ include Util
41
+
42
+ def initialize path, *argv
43
+ @path = string_of path
44
+
45
+ self.na_type = argv.shift
46
+ self.shape = argv
47
+
48
+ self.na_type = int_of na_type if na_type
49
+ self.shape = int_list_of shape if shape
50
+
51
+ init! if na_type and shape
52
+
53
+ load!
54
+ end
55
+
56
+ def init!
57
+ open(@path, "w"){|f| ::YAML::dump(({}.update self), f)}
58
+ end
59
+
60
+ def load!
61
+ self.update(open(@path){|f| ::YAML::load f})
62
+ end
63
+
64
+ def na_type
65
+ self["na_type"]
66
+ end
67
+
68
+ def na_type= val
69
+ self["na_type"] = val
70
+ end
71
+
72
+ def shape
73
+ self["shape"]
74
+ end
75
+
76
+ def shape= val
77
+ self["shape"] = val
78
+ end
79
+
80
+ def self.init(*a, &b) new(*a, &b) end
81
+ end
82
+
83
+ include Util
84
+
85
+ attr "path"
86
+ attr "na_type"
87
+ attr "shape"
88
+ attr "lockfile"
89
+ attr "header"
90
+ attr "na"
91
+ attr "closed"
92
+
93
+ def initialize path, *argv
94
+ @path = string_of path
95
+
96
+ @na_type = argv.shift
97
+ @shape = argv
98
+
99
+ @na_type = int_of @na_type if @na_type
100
+ @shape = int_list_of @shape if @shape
101
+
102
+ @lockfile = @path + '.lock'
103
+
104
+ locked do
105
+ init! unless test ?s, @path
106
+ load_header!
107
+ load!
108
+ end
109
+
110
+ @closed = false
111
+
112
+ if block_given?
113
+ begin
114
+ yield self
115
+ ensure
116
+ close
117
+ end
118
+ end
119
+ end
120
+
121
+ def init!
122
+ raise ArgumentError, "no na_type" unless @na_type
123
+ raise ArgumentError, "no shape" unless @shape
124
+ sizeof_type = NArray::new(@na_type, 1).to_s.size
125
+ size = @shape.inject(1){|product, dim| product *= dim}
126
+ pos = sizeof_type * size
127
+ File.unlink @path rescue nil
128
+ open(@path, File::CREAT|File::EXCL|File::RDWR){|f| f.truncate pos}
129
+ Header::init @path + '.nmap', @na_type, @shape
130
+ end
131
+
132
+ def load_header!
133
+ @header = Header::new @path + '.nmap'
134
+ @na_type = @header.na_type
135
+ @shape = @header.shape
136
+ end
137
+
138
+ def load!
139
+ @mmap = ::Mmap::new @path, "rw", Mmap::MAP_SHARED
140
+ @na = ::NArray::str @mmap, @na_type, *@shape
141
+ end
142
+
143
+ def locked
144
+ f = open @lockfile, 'a+'
145
+ f.flock File::LOCK_EX
146
+ yield
147
+ ensure
148
+ if f
149
+ f.flock File::LOCK_UN rescue nil
150
+ f.close rescue nil
151
+ end
152
+ end
153
+
154
+ def sync
155
+ @mmap.msync
156
+ end
157
+
158
+ def close
159
+ return if @closed
160
+ sync
161
+ @mmap.munmap
162
+ @mmap = nil
163
+ @na = nil
164
+ @closed = true
165
+ end
166
+
167
+ class << self
168
+ def init(*a, &b) new(*a, &b) end
169
+ ctors = ::NArray.constants.select{|c| ::NArray.respond_to? c.downcase}
170
+ ctors.each do |m|
171
+ module_eval <<-code
172
+ def #{ m.downcase }(path, *argv)
173
+ new path, NArray::#{ m }, *argv
174
+ end
175
+ code
176
+ end
177
+ end
178
+ end
179
+
180
+ #
181
+ # sample usage - be sure to run more than once!!
182
+ #
183
+ if $0 == __FILE__
184
+ require 'tmpdir'
185
+ require 'yaml'
186
+
187
+ ipath = File.join Dir.tmpdir, 'i.na'
188
+
189
+ t, f = true, false
190
+
191
+ nmap = NMap.int ipath, 3,4
192
+ na = nmap.na
193
+ p na
194
+ na[t,0] = 42
195
+ na[0,t] = Time.now.to_i
196
+ p na
197
+
198
+ end
File without changes
@@ -0,0 +1,67 @@
1
+ #include <ruby.h>
2
+ #include <version.h>
3
+ #include "narray.h"
4
+ #include "narray_config.h"
5
+
6
+ static VALUE
7
+ str_new4 (VALUE str)
8
+ {
9
+ StringValue (str);
10
+ if (FL_TEST (str, ELTS_SHARED))
11
+ {
12
+ rb_str_buf_cat2 (str, ""); /* unanchor literal string */
13
+ }
14
+ return rb_str_new4 (str);
15
+ }
16
+
17
+ static VALUE
18
+ na_s_str (int argc, VALUE * argv, VALUE klass)
19
+ {
20
+ struct NARRAY *ary;
21
+ VALUE v;
22
+ VALUE str;
23
+ int i, type, len = 1, str_len, *shape, rank = argc - 2;
24
+
25
+ if (argc < 1)
26
+ rb_raise (rb_eArgError, "String Argument required");
27
+
28
+ if (argc < 2)
29
+ rb_raise (rb_eArgError, "Type and Size Arguments required");
30
+
31
+ type = na_get_typecode (argv[1]);
32
+ str = str_new4 (argv[0]);
33
+ str_len = RSTRING (str)->len;
34
+
35
+ if (argc == 2)
36
+ {
37
+ rank = 1;
38
+ shape = ALLOCA_N (int, rank);
39
+ if (str_len % na_sizeof[type] != 0)
40
+ rb_raise (rb_eArgError, "string size mismatch");
41
+ shape[0] = str_len / na_sizeof[type];
42
+ }
43
+ else
44
+ {
45
+ shape = ALLOCA_N (int, rank);
46
+ for (i = 0; i < rank; i++)
47
+ len *= shape[i] = NUM2INT (argv[i + 2]);
48
+ len *= na_sizeof[type];
49
+ if (len != str_len)
50
+ rb_raise (rb_eArgError, "size mismatch");
51
+ }
52
+
53
+ v = na_make_object (type, rank, shape, cNArray);
54
+ GetNArray (v, ary);
55
+ ary->ptr = RSTRING (str)->ptr;
56
+ ary->ref = str;
57
+
58
+ return v;
59
+ }
60
+
61
+ void
62
+ Init_na_str ()
63
+ {
64
+ rb_require ("narray");
65
+ rb_define_singleton_method (cNArray, "str", na_s_str, -1);
66
+ rb_define_singleton_method (cNArray, "from_string", na_s_str, -1);
67
+ }
data/nmap.rb ADDED
@@ -0,0 +1,198 @@
1
+ #
2
+ # built-in
3
+ #
4
+ require "yaml"
5
+ #
6
+ # rubyforge.org/raa.ruby-lang.org
7
+ #
8
+ require "mmap"
9
+ require "narray"
10
+ #
11
+ # homegrown
12
+ #
13
+ require "na_str"
14
+ #
15
+ # here we creates a little convenience class for working with memory mapped
16
+ # numerical grids
17
+ #
18
+ class NMap
19
+ module Util
20
+ def string_of obj
21
+ obj.to_str
22
+ rescue
23
+ raise ArgumentError, "cannot convert <#{ obj.inspect }> to string"
24
+ end
25
+
26
+ def int_of obj
27
+ Integer obj
28
+ rescue
29
+ raise ArgumentError, "cannot convert <#{ obj.inspect }> to int"
30
+ end
31
+
32
+ def int_list_of obj
33
+ [*obj].flatten.map{|elem| int_of elem}
34
+ rescue
35
+ raise ArgumentError, "cannot convert <#{ obj.inspect }> to int list"
36
+ end
37
+ end
38
+
39
+ class Header < ::Hash
40
+ include Util
41
+
42
+ def initialize path, *argv
43
+ @path = string_of path
44
+
45
+ self.na_type = argv.shift
46
+ self.shape = argv
47
+
48
+ self.na_type = int_of na_type if na_type
49
+ self.shape = int_list_of shape if shape
50
+
51
+ init! if na_type and shape
52
+
53
+ load!
54
+ end
55
+
56
+ def init!
57
+ open(@path, "w"){|f| ::YAML::dump(({}.update self), f)}
58
+ end
59
+
60
+ def load!
61
+ self.update(open(@path){|f| ::YAML::load f})
62
+ end
63
+
64
+ def na_type
65
+ self["na_type"]
66
+ end
67
+
68
+ def na_type= val
69
+ self["na_type"] = val
70
+ end
71
+
72
+ def shape
73
+ self["shape"]
74
+ end
75
+
76
+ def shape= val
77
+ self["shape"] = val
78
+ end
79
+
80
+ def self.init(*a, &b) new(*a, &b) end
81
+ end
82
+
83
+ include Util
84
+
85
+ attr "path"
86
+ attr "na_type"
87
+ attr "shape"
88
+ attr "lockfile"
89
+ attr "header"
90
+ attr "na"
91
+ attr "closed"
92
+
93
+ def initialize path, *argv
94
+ @path = string_of path
95
+
96
+ @na_type = argv.shift
97
+ @shape = argv
98
+
99
+ @na_type = int_of @na_type if @na_type
100
+ @shape = int_list_of @shape if @shape
101
+
102
+ @lockfile = @path + '.lock'
103
+
104
+ locked do
105
+ init! unless test ?s, @path
106
+ load_header!
107
+ load!
108
+ end
109
+
110
+ @closed = false
111
+
112
+ if block_given?
113
+ begin
114
+ yield self
115
+ ensure
116
+ close
117
+ end
118
+ end
119
+ end
120
+
121
+ def init!
122
+ raise ArgumentError, "no na_type" unless @na_type
123
+ raise ArgumentError, "no shape" unless @shape
124
+ sizeof_type = NArray::new(@na_type, 1).to_s.size
125
+ size = @shape.inject(1){|product, dim| product *= dim}
126
+ pos = sizeof_type * size
127
+ File.unlink @path rescue nil
128
+ open(@path, File::CREAT|File::EXCL|File::RDWR){|f| f.truncate pos}
129
+ Header::init @path + '.yml', @na_type, @shape
130
+ end
131
+
132
+ def load_header!
133
+ @header = Header::new @path + '.yml'
134
+ @na_type = @header.na_type
135
+ @shape = @header.shape
136
+ end
137
+
138
+ def load!
139
+ @mmap = ::Mmap::new @path, "rw", Mmap::MAP_SHARED
140
+ @na = ::NArray::str @mmap, @na_type, *@shape
141
+ end
142
+
143
+ def locked
144
+ f = open @lockfile, 'a+'
145
+ f.flock File::LOCK_EX
146
+ yield
147
+ ensure
148
+ if f
149
+ f.flock File::LOCK_UN rescue nil
150
+ f.close rescue nil
151
+ end
152
+ end
153
+
154
+ def sync
155
+ @mmap.msync
156
+ end
157
+
158
+ def close
159
+ return if @closed
160
+ sync
161
+ @mmap.munmap
162
+ @mmap = nil
163
+ @na = nil
164
+ @closed = true
165
+ end
166
+
167
+ class << self
168
+ def init(*a, &b) new(*a, &b) end
169
+ ctors = ::NArray.constants.select{|c| ::NArray.respond_to? c.downcase}
170
+ ctors.each do |m|
171
+ module_eval <<-code
172
+ def #{ m.downcase }(path, *argv)
173
+ new path, NArray::#{ m }, *argv
174
+ end
175
+ code
176
+ end
177
+ end
178
+ end
179
+
180
+ #
181
+ # sample usage - be sure to run more than once!!
182
+ #
183
+ if $0 == __FILE__
184
+ require 'tmpdir'
185
+ require 'yaml'
186
+
187
+ ipath = File.join Dir.tmpdir, 'i.na'
188
+
189
+ t, f = true, false
190
+
191
+ nmap = NMap.int ipath, 3,4
192
+ na = nmap.na
193
+ p na
194
+ na[t,0] = 42
195
+ na[0,t] = Time.now.to_i
196
+ p na
197
+
198
+ end
@@ -0,0 +1,18 @@
1
+ %w( ./lib ../lib . ..).each{|d| $:.unshift d}
2
+ require 'na_str'
3
+
4
+ #
5
+ # na_str allows you to share memory with any object that responds to to_s or
6
+ # to_str. the object whose memory is shared is frozen and cannot be modified
7
+ # and a reference to the object is kept so it is not gc'd. the object's
8
+ # memory can be modified using this 'view' of the data.
9
+ #
10
+
11
+ buf = [0,0,0,0].pack 'i*'
12
+
13
+ na = NArray::str buf, NArray::INT, 4
14
+ na[0] = 42
15
+ na[-1] = 42
16
+
17
+ p buf.unpack('i*')
18
+ p buf
@@ -0,0 +1,47 @@
1
+ %w( ./lib ../lib . ..).each{|d| $:.unshift d}
2
+ require "na_str"
3
+ require "mmap"
4
+ require "yaml"
5
+
6
+ #
7
+ # setup
8
+ #
9
+ sizeof_int = [42].pack("i").size
10
+
11
+ #
12
+ # setup an empty data file big enough to hold four ints if one doesn"t already
13
+ # exist
14
+ #
15
+ data = __FILE__ + ".data"
16
+ open(data, File::CREAT|File::EXCL|File::RDWR){|f| f.write(0.chr * 4 * sizeof_int)} rescue nil
17
+
18
+ #
19
+ # show the orginal data - run the script more than once to see that the data
20
+ # persists between invocations
21
+ #
22
+ y "before" => IO::read(data).unpack("i*")
23
+
24
+ #
25
+ # mmap data in
26
+ #
27
+ m = Mmap::new data, "rw", Mmap::MAP_SHARED
28
+
29
+ #
30
+ # overlay an narray over the memory map and manipulate it. note that any
31
+ # changes to the narray changes the memory map, which in turn changes the
32
+ # file!
33
+ #
34
+ na = NArray::str m, NArray::INT, 4
35
+ na[0] = 42
36
+ na[-1] = Time.now.to_i.abs
37
+
38
+ #
39
+ # sync, and unmap the data
40
+ #
41
+ m.msync
42
+ m.munmap
43
+
44
+ #
45
+ # show that the underlying data has been transparently changed!
46
+ #
47
+ y "after" => IO::read(data).unpack("i*")
Binary file
@@ -0,0 +1,18 @@
1
+ %w( ./lib ../lib . ..).each{|d| $:.unshift d}
2
+ #
3
+ # be sure to run this a few times in a row - wait a second or two between runs
4
+ # - notice that the data will automagically persist between calls!
5
+ #
6
+ require 'tmpdir'
7
+ require 'nmap'
8
+
9
+ ipath = File.join Dir.tmpdir, 'i.na'
10
+
11
+ nmap = NMap.int ipath, 3,4
12
+ na = nmap.na
13
+ p na
14
+
15
+ na[0,true] = Time.now.to_i
16
+ na[2,true] = 1
17
+ na[1,1..2] = 42
18
+ p na
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: na_str
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.0
7
+ date: 2007-02-28 00:00:00.000000 -07:00
8
+ summary: na_str
9
+ require_paths:
10
+ - lib
11
+ email: ara.t.howard@noaa.gov
12
+ homepage: http://codeforpeople.com/lib/ruby/na_str/
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: na_str
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: false
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ -
22
+ - ">"
23
+ - !ruby/object:Gem::Version
24
+ version: 0.0.0
25
+ version:
26
+ platform: ruby
27
+ signing_key:
28
+ cert_chain:
29
+ authors:
30
+ - Ara T. Howard
31
+ files:
32
+ - depends
33
+ - extconf.rb
34
+ - install.rb
35
+ - lib
36
+ - Makefile
37
+ - na_str.c
38
+ - nmap.rb
39
+ - README
40
+ - samples
41
+ - gemspec.rb
42
+ - na_str-0.1.0.gem
43
+ - depends/mmap.tar.gz
44
+ - depends/narray-0.5.7p2.tar.gz
45
+ - lib/nmap.rb
46
+ - samples/b.rb.data
47
+ - samples/b.rb
48
+ - samples/a.rb
49
+ - samples/c.rb
50
+ test_files: []
51
+ rdoc_options: []
52
+ extra_rdoc_files: []
53
+ executables: []
54
+ extensions:
55
+ - extconf.rb
56
+ requirements:
57
+ - http://moulon.inra.fr/ruby/mmap.html
58
+ - http://narray.rubyforge.org/
59
+ dependencies: []