rehash 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +20 -0
- data/Rakefile +71 -0
- data/ext/rehash/Makefile +187 -0
- data/ext/rehash/extconf.rb +6 -0
- data/ext/rehash/mkmf.log +22 -0
- data/ext/rehash/rehash.bundle +0 -0
- data/ext/rehash/rehash.c +63 -0
- data/ext/rehash/rehash.h +17 -0
- data/ext/rehash/rehash.o +0 -0
- data/ext/rehash/rehash_18.h +78 -0
- data/ext/rehash/rehash_19.h +21 -0
- data/rehash.gemspec +14 -0
- data/test/test.rb +3 -0
- data/test/test_rehash.rb +44 -0
- metadata +79 -0
data/README
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Simple by key / value rehashing for Ruby MRI
|
2
|
+
(c) 2010 Lourens Naudé (methodmissing) and James Tucker (raggi)
|
3
|
+
|
4
|
+
http://github.com/methodmissing/rehash
|
5
|
+
|
6
|
+
This library works with Ruby 1.8 and 1.9 and exposes the following API :
|
7
|
+
|
8
|
+
hash = { 'a' => 1, 'b' => 2 }
|
9
|
+
hash.rekey!(:upcase)
|
10
|
+
hash == { 'A' => 1, 'B' => 2 }
|
11
|
+
|
12
|
+
hash = { 1 => 'a, 2 => 'b' }
|
13
|
+
hash.revalue!(:upcase)
|
14
|
+
hash == { 1 => 'A', 2 => 'B' }
|
15
|
+
|
16
|
+
To run the test suite:
|
17
|
+
|
18
|
+
rake
|
19
|
+
|
20
|
+
Work in progress, thanks for watching!
|
data/Rakefile
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/clean'
|
4
|
+
$:.unshift(File.expand_path('lib'))
|
5
|
+
REHASH_ROOT = 'ext/rehash'
|
6
|
+
|
7
|
+
desc 'Default: test'
|
8
|
+
task :default => :test
|
9
|
+
|
10
|
+
desc 'Run rehash tests.'
|
11
|
+
Rake::TestTask.new(:test) do |t|
|
12
|
+
t.libs = [REHASH_ROOT]
|
13
|
+
t.pattern = 'test/test_*.rb'
|
14
|
+
t.ruby_opts << '-rtest'
|
15
|
+
t.libs << 'test'
|
16
|
+
t.warning = true
|
17
|
+
t.verbose = true
|
18
|
+
end
|
19
|
+
task :test => :build
|
20
|
+
|
21
|
+
namespace :build do
|
22
|
+
file "#{REHASH_ROOT}/rehash.c"
|
23
|
+
file "#{REHASH_ROOT}/extconf.rb"
|
24
|
+
file "#{REHASH_ROOT}/Makefile" => %W(#{REHASH_ROOT}/rehash.c #{REHASH_ROOT}/extconf.rb) do
|
25
|
+
Dir.chdir(REHASH_ROOT) do
|
26
|
+
ruby 'extconf.rb'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "generate makefile"
|
31
|
+
task :makefile => %W(#{REHASH_ROOT}/Makefile #{REHASH_ROOT}/rehash.c)
|
32
|
+
|
33
|
+
dlext = Config::CONFIG['DLEXT']
|
34
|
+
file "#{REHASH_ROOT}/rehash.#{dlext}" => %W(#{REHASH_ROOT}/Makefile #{REHASH_ROOT}/rehash.c) do
|
35
|
+
Dir.chdir(REHASH_ROOT) do
|
36
|
+
sh 'make' # TODO - is there a config for which make somewhere?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "compile rehash extension"
|
41
|
+
task :compile => "#{REHASH_ROOT}/rehash.#{dlext}"
|
42
|
+
|
43
|
+
task :clean do
|
44
|
+
Dir.chdir(REHASH_ROOT) do
|
45
|
+
sh 'make clean'
|
46
|
+
end if File.exists?("#{REHASH_ROOT}/Makefile")
|
47
|
+
end
|
48
|
+
|
49
|
+
CLEAN.include("#{REHASH_ROOT}/Makefile")
|
50
|
+
CLEAN.include("#{REHASH_ROOT}/rehash.#{dlext}")
|
51
|
+
end
|
52
|
+
|
53
|
+
task :clean => %w(build:clean)
|
54
|
+
|
55
|
+
desc "compile"
|
56
|
+
task :build => %w(build:compile)
|
57
|
+
|
58
|
+
task :install do |t|
|
59
|
+
Dir.chdir(REHASH_ROOT) do
|
60
|
+
sh 'sudo make install'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "clean build install"
|
65
|
+
task :setup => %w(clean build install)
|
66
|
+
|
67
|
+
desc 'Run benchmarks'
|
68
|
+
task :bench do
|
69
|
+
ruby "bench/rehash.rb"
|
70
|
+
end
|
71
|
+
task :bench => :build
|
data/ext/rehash/Makefile
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
|
2
|
+
SHELL = /bin/sh
|
3
|
+
|
4
|
+
#### Start of system configuration section. ####
|
5
|
+
|
6
|
+
srcdir = .
|
7
|
+
topdir = /Users/lourens/.rvm/rubies/ruby-1.9.2-head/include/ruby-1.9.1
|
8
|
+
hdrdir = /Users/lourens/.rvm/rubies/ruby-1.9.2-head/include/ruby-1.9.1
|
9
|
+
arch_hdrdir = /Users/lourens/.rvm/rubies/ruby-1.9.2-head/include/ruby-1.9.1/$(arch)
|
10
|
+
VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
|
11
|
+
prefix = $(DESTDIR)/Users/lourens/.rvm/rubies/ruby-1.9.2-head
|
12
|
+
rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
|
13
|
+
exec_prefix = $(prefix)
|
14
|
+
vendorhdrdir = $(rubyhdrdir)/vendor_ruby
|
15
|
+
sitehdrdir = $(rubyhdrdir)/site_ruby
|
16
|
+
rubyhdrdir = $(includedir)/$(RUBY_BASE_NAME)-$(ruby_version)
|
17
|
+
vendordir = $(rubylibprefix)/vendor_ruby
|
18
|
+
sitedir = $(rubylibprefix)/site_ruby
|
19
|
+
ridir = $(datarootdir)/$(RI_BASE_NAME)
|
20
|
+
mandir = $(datarootdir)/man
|
21
|
+
localedir = $(datarootdir)/locale
|
22
|
+
libdir = $(exec_prefix)/lib
|
23
|
+
psdir = $(docdir)
|
24
|
+
pdfdir = $(docdir)
|
25
|
+
dvidir = $(docdir)
|
26
|
+
htmldir = $(docdir)
|
27
|
+
infodir = $(datarootdir)/info
|
28
|
+
docdir = $(datarootdir)/doc/$(PACKAGE)
|
29
|
+
oldincludedir = $(DESTDIR)/usr/include
|
30
|
+
includedir = $(prefix)/include
|
31
|
+
localstatedir = $(prefix)/var
|
32
|
+
sharedstatedir = $(prefix)/com
|
33
|
+
sysconfdir = $(prefix)/etc
|
34
|
+
datadir = $(datarootdir)
|
35
|
+
datarootdir = $(prefix)/share
|
36
|
+
libexecdir = $(exec_prefix)/libexec
|
37
|
+
sbindir = $(exec_prefix)/sbin
|
38
|
+
bindir = $(exec_prefix)/bin
|
39
|
+
rubylibdir = $(rubylibprefix)/$(ruby_version)
|
40
|
+
archdir = $(rubylibdir)/$(arch)
|
41
|
+
sitelibdir = $(sitedir)/$(ruby_version)
|
42
|
+
sitearchdir = $(sitelibdir)/$(sitearch)
|
43
|
+
vendorlibdir = $(vendordir)/$(ruby_version)
|
44
|
+
vendorarchdir = $(vendorlibdir)/$(sitearch)
|
45
|
+
|
46
|
+
CC = gcc
|
47
|
+
CXX = g++
|
48
|
+
LIBRUBY = $(LIBRUBY_SO)
|
49
|
+
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
50
|
+
LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
|
51
|
+
LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
|
52
|
+
OUTFLAG = -o
|
53
|
+
COUTFLAG = -o
|
54
|
+
|
55
|
+
RUBY_EXTCONF_H =
|
56
|
+
cflags = $(optflags) $(debugflags) $(warnflags)
|
57
|
+
optflags = -O3
|
58
|
+
debugflags = -ggdb
|
59
|
+
warnflags = -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long
|
60
|
+
CFLAGS = -fno-common $(cflags) -fno-common -pipe
|
61
|
+
INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
|
62
|
+
DEFS =
|
63
|
+
CPPFLAGS = -DHAVE_RB_THREAD_BLOCKING_REGION -pedantic -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE $(DEFS) $(cppflags)
|
64
|
+
CXXFLAGS = $(CFLAGS) $(cxxflags)
|
65
|
+
ldflags = -L. -L/usr/local/lib
|
66
|
+
dldflags = -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress -Wl,-flat_namespace
|
67
|
+
ARCH_FLAG =
|
68
|
+
DLDFLAGS = $(ldflags) $(dldflags)
|
69
|
+
LDSHARED = $(CC) -dynamic -bundle
|
70
|
+
LDSHAREDXX = $(CXX) -dynamic -bundle
|
71
|
+
AR = ar
|
72
|
+
EXEEXT =
|
73
|
+
|
74
|
+
RUBY_BASE_NAME = ruby
|
75
|
+
RUBY_INSTALL_NAME = ruby
|
76
|
+
RUBY_SO_NAME = ruby.1.9.1
|
77
|
+
arch = x86_64-darwin10.4.0
|
78
|
+
sitearch = $(arch)
|
79
|
+
ruby_version = 1.9.1
|
80
|
+
ruby = /Users/lourens/.rvm/rubies/ruby-1.9.2-head/bin/ruby
|
81
|
+
RUBY = $(ruby)
|
82
|
+
RM = rm -f
|
83
|
+
RM_RF = $(RUBY) -run -e rm -- -rf
|
84
|
+
RMDIRS = $(RUBY) -run -e rmdir -- -p
|
85
|
+
MAKEDIRS = mkdir -p
|
86
|
+
INSTALL = /usr/bin/install -c
|
87
|
+
INSTALL_PROG = $(INSTALL) -m 0755
|
88
|
+
INSTALL_DATA = $(INSTALL) -m 644
|
89
|
+
COPY = cp
|
90
|
+
|
91
|
+
#### End of system configuration section. ####
|
92
|
+
|
93
|
+
preload =
|
94
|
+
|
95
|
+
libpath = . $(libdir)
|
96
|
+
LIBPATH = -L. -L$(libdir)
|
97
|
+
DEFFILE =
|
98
|
+
|
99
|
+
CLEANFILES = mkmf.log
|
100
|
+
DISTCLEANFILES =
|
101
|
+
DISTCLEANDIRS =
|
102
|
+
|
103
|
+
extout =
|
104
|
+
extout_prefix =
|
105
|
+
target_prefix =
|
106
|
+
LOCAL_LIBS =
|
107
|
+
LIBS = $(LIBRUBYARG_SHARED) -lpthread -ldl -lobjc
|
108
|
+
SRCS = rehash.c
|
109
|
+
OBJS = rehash.o
|
110
|
+
TARGET = rehash
|
111
|
+
DLLIB = $(TARGET).bundle
|
112
|
+
EXTSTATIC =
|
113
|
+
STATIC_LIB =
|
114
|
+
|
115
|
+
BINDIR = $(bindir)
|
116
|
+
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
117
|
+
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
118
|
+
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
119
|
+
HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
|
120
|
+
ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
|
121
|
+
|
122
|
+
TARGET_SO = $(DLLIB)
|
123
|
+
CLEANLIBS = $(TARGET).bundle
|
124
|
+
CLEANOBJS = *.o *.bak
|
125
|
+
|
126
|
+
all: $(DLLIB)
|
127
|
+
static: $(STATIC_LIB)
|
128
|
+
.PHONY: all install static install-so install-rb
|
129
|
+
.PHONY: clean clean-so clean-rb
|
130
|
+
|
131
|
+
clean-rb-default::
|
132
|
+
clean-rb::
|
133
|
+
clean-so::
|
134
|
+
clean: clean-so clean-rb-default clean-rb
|
135
|
+
@-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
|
136
|
+
|
137
|
+
distclean-rb-default::
|
138
|
+
distclean-rb::
|
139
|
+
distclean-so::
|
140
|
+
distclean: clean distclean-so distclean-rb-default distclean-rb
|
141
|
+
@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
|
142
|
+
@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
143
|
+
@-$(RMDIRS) $(DISTCLEANDIRS)
|
144
|
+
|
145
|
+
realclean: distclean
|
146
|
+
install: install-so install-rb
|
147
|
+
|
148
|
+
install-so: $(RUBYARCHDIR)
|
149
|
+
install-so: $(RUBYARCHDIR)/$(DLLIB)
|
150
|
+
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
|
151
|
+
@-$(MAKEDIRS) $(@D)
|
152
|
+
$(INSTALL_PROG) $(DLLIB) $(@D)
|
153
|
+
install-rb: pre-install-rb install-rb-default
|
154
|
+
install-rb-default: pre-install-rb-default
|
155
|
+
pre-install-rb: Makefile
|
156
|
+
pre-install-rb-default: Makefile
|
157
|
+
$(RUBYARCHDIR):
|
158
|
+
$(MAKEDIRS) $@
|
159
|
+
|
160
|
+
site-install: site-install-so site-install-rb
|
161
|
+
site-install-so: install-so
|
162
|
+
site-install-rb: install-rb
|
163
|
+
|
164
|
+
.SUFFIXES: .c .m .cc .cxx .cpp .C .o
|
165
|
+
|
166
|
+
.cc.o:
|
167
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
168
|
+
|
169
|
+
.cxx.o:
|
170
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
171
|
+
|
172
|
+
.cpp.o:
|
173
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
174
|
+
|
175
|
+
.C.o:
|
176
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
177
|
+
|
178
|
+
.c.o:
|
179
|
+
$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
|
180
|
+
|
181
|
+
$(DLLIB): $(OBJS) Makefile
|
182
|
+
@-$(RM) $(@)
|
183
|
+
$(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
$(OBJS): $(hdrdir)/ruby.h $(hdrdir)/ruby/defines.h $(arch_hdrdir)/ruby/config.h
|
data/ext/rehash/mkmf.log
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
have_func: checking for rb_thread_blocking_region()... -------------------- yes
|
2
|
+
|
3
|
+
"gcc -o conftest -I/Users/lourens/.rvm/rubies/ruby-1.9.2-head/include/ruby-1.9.1/x86_64-darwin10.4.0 -I/Users/lourens/.rvm/rubies/ruby-1.9.2-head/include/ruby-1.9.1/ruby/backward -I/Users/lourens/.rvm/rubies/ruby-1.9.2-head/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long -fno-common -pipe conftest.c -L. -L/Users/lourens/.rvm/rubies/ruby-1.9.2-head/lib -L. -L/usr/local/lib -lruby.1.9.1-static -lpthread -ldl -lobjc "
|
4
|
+
checked program was:
|
5
|
+
/* begin */
|
6
|
+
1: #include "ruby.h"
|
7
|
+
2:
|
8
|
+
3: int main() {return 0;}
|
9
|
+
/* end */
|
10
|
+
|
11
|
+
"gcc -o conftest -I/Users/lourens/.rvm/rubies/ruby-1.9.2-head/include/ruby-1.9.1/x86_64-darwin10.4.0 -I/Users/lourens/.rvm/rubies/ruby-1.9.2-head/include/ruby-1.9.1/ruby/backward -I/Users/lourens/.rvm/rubies/ruby-1.9.2-head/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long -fno-common -pipe conftest.c -L. -L/Users/lourens/.rvm/rubies/ruby-1.9.2-head/lib -L. -L/usr/local/lib -lruby.1.9.1-static -lpthread -ldl -lobjc "
|
12
|
+
checked program was:
|
13
|
+
/* begin */
|
14
|
+
1: #include "ruby.h"
|
15
|
+
2:
|
16
|
+
3: /*top*/
|
17
|
+
4: int main() {return 0;}
|
18
|
+
5: int t() { void ((*volatile p)()); p = (void ((*)()))rb_thread_blocking_region; return 0; }
|
19
|
+
/* end */
|
20
|
+
|
21
|
+
--------------------
|
22
|
+
|
Binary file
|
data/ext/rehash/rehash.c
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#ifdef HAVE_RB_THREAD_BLOCKING_REGION
|
3
|
+
#define RUBY19
|
4
|
+
#include <rehash_19.h>
|
5
|
+
#else
|
6
|
+
#define RUBY18
|
7
|
+
#include <rehash_18.h>
|
8
|
+
#endif
|
9
|
+
|
10
|
+
#include <rehash.h>
|
11
|
+
|
12
|
+
static inline int
|
13
|
+
rb_hash_rekey_i(VALUE key, VALUE value, rehash_arg* arg)
|
14
|
+
{
|
15
|
+
HASH_REHASH_METHOD(arg->tbl, rb_funcall(key, arg->method, 0, 0), value)
|
16
|
+
}
|
17
|
+
|
18
|
+
static VALUE
|
19
|
+
rb_hash_rekey_bang(VALUE hash, VALUE method)
|
20
|
+
{
|
21
|
+
rehash_arg arg;
|
22
|
+
HASH_REHASH_WITH(hash, method, rb_hash_rekey_i)
|
23
|
+
}
|
24
|
+
|
25
|
+
static inline int
|
26
|
+
rb_hash_revalue_i(VALUE key, VALUE value, rehash_arg* arg)
|
27
|
+
{
|
28
|
+
HASH_REHASH_METHOD(arg->tbl, key, rb_funcall(value, arg->method, 0, 0))
|
29
|
+
}
|
30
|
+
|
31
|
+
static VALUE
|
32
|
+
rb_hash_revalue_bang(VALUE hash, VALUE method)
|
33
|
+
{
|
34
|
+
rehash_arg arg;
|
35
|
+
HASH_REHASH_WITH(hash, method, rb_hash_revalue_i)
|
36
|
+
}
|
37
|
+
|
38
|
+
static VALUE
|
39
|
+
rb_hash_rekey(VALUE hash, VALUE method)
|
40
|
+
{
|
41
|
+
rehash_arg arg;
|
42
|
+
VALUE dup;
|
43
|
+
dup = rb_obj_dup(hash);
|
44
|
+
HASH_REHASH_WITH(dup, method, rb_hash_rekey_i)
|
45
|
+
}
|
46
|
+
|
47
|
+
static VALUE
|
48
|
+
rb_hash_revalue(VALUE hash, VALUE method)
|
49
|
+
{
|
50
|
+
rehash_arg arg;
|
51
|
+
VALUE dup;
|
52
|
+
dup = rb_obj_dup(hash);
|
53
|
+
HASH_REHASH_WITH(dup, method, rb_hash_revalue_i)
|
54
|
+
}
|
55
|
+
|
56
|
+
void
|
57
|
+
Init_rehash()
|
58
|
+
{
|
59
|
+
rb_define_method(rb_cHash, "rekey!", rb_hash_rekey_bang, 1);
|
60
|
+
rb_define_method(rb_cHash, "revalue!", rb_hash_revalue_bang, 1);
|
61
|
+
rb_define_method(rb_cHash, "rekey", rb_hash_rekey, 1);
|
62
|
+
rb_define_method(rb_cHash, "revalue", rb_hash_revalue, 1);
|
63
|
+
}
|
data/ext/rehash/rehash.h
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
typedef struct {
|
2
|
+
st_table *tbl;
|
3
|
+
ID method;
|
4
|
+
} rehash_arg;
|
5
|
+
|
6
|
+
#define HASH_REHASH_METHOD(tbl, k, v) \
|
7
|
+
if ((k) != Qundef) st_insert(tbl, (k), (v)); \
|
8
|
+
return ST_CONTINUE;
|
9
|
+
|
10
|
+
#define HASH_REHASH_WITH(hash, method, func) \
|
11
|
+
HASH_MOD_CHECK((hash)) \
|
12
|
+
arg.method = rb_to_id(method); \
|
13
|
+
arg.tbl = st_init_table_with_size(HASH_TYPE((hash)), HASH_SIZE((hash))); \
|
14
|
+
rb_hash_foreach((hash), func, (VALUE)&arg); \
|
15
|
+
st_free_table(HASH_TBL((hash))); \
|
16
|
+
HASH_TBL((hash)) = arg.tbl; \
|
17
|
+
return (hash);
|
data/ext/rehash/rehash.o
ADDED
Binary file
|
@@ -0,0 +1,78 @@
|
|
1
|
+
#include "st.h"
|
2
|
+
#define HASH_TBL(hash) RHASH(hash)->tbl
|
3
|
+
#define HASH_SIZE(hash) RHASH(hash)->tbl->num_entries
|
4
|
+
#define HASH_TYPE(hash) &objhash
|
5
|
+
#define HASH_MOD_CHECK(hash) rb_hash_modify(hash);
|
6
|
+
|
7
|
+
/* leeched from core hash.c - would be nice to have these not be static and exposed via intern.h */
|
8
|
+
|
9
|
+
static void
|
10
|
+
rb_hash_modify(hash)
|
11
|
+
VALUE hash;
|
12
|
+
{
|
13
|
+
if (!RHASH(hash)->tbl) rb_raise(rb_eTypeError, "uninitialized Hash");
|
14
|
+
if (OBJ_FROZEN(hash)) rb_error_frozen("hash");
|
15
|
+
if (!OBJ_TAINTED(hash) && rb_safe_level() >= 4)
|
16
|
+
rb_raise(rb_eSecurityError, "Insecure: can't modify hash");
|
17
|
+
}
|
18
|
+
|
19
|
+
static VALUE
|
20
|
+
eql(args)
|
21
|
+
VALUE *args;
|
22
|
+
{
|
23
|
+
return (VALUE)rb_eql(args[0], args[1]);
|
24
|
+
}
|
25
|
+
|
26
|
+
static int
|
27
|
+
rb_any_cmp(a, b)
|
28
|
+
VALUE a, b;
|
29
|
+
{
|
30
|
+
VALUE args[2];
|
31
|
+
|
32
|
+
if (a == b) return 0;
|
33
|
+
if (FIXNUM_P(a) && FIXNUM_P(b)) {
|
34
|
+
return a != b;
|
35
|
+
}
|
36
|
+
if (TYPE(a) == T_STRING && RBASIC(a)->klass == rb_cString &&
|
37
|
+
TYPE(b) == T_STRING && RBASIC(b)->klass == rb_cString) {
|
38
|
+
return rb_str_cmp(a, b);
|
39
|
+
}
|
40
|
+
if (a == Qundef || b == Qundef) return -1;
|
41
|
+
if (SYMBOL_P(a) && SYMBOL_P(b)) {
|
42
|
+
return a != b;
|
43
|
+
}
|
44
|
+
|
45
|
+
args[0] = a;
|
46
|
+
args[1] = b;
|
47
|
+
return !rb_with_disable_interrupt(eql, (VALUE)args);
|
48
|
+
}
|
49
|
+
|
50
|
+
static int
|
51
|
+
rb_any_hash(a)
|
52
|
+
VALUE a;
|
53
|
+
{
|
54
|
+
VALUE hval;
|
55
|
+
int hnum;
|
56
|
+
|
57
|
+
switch (TYPE(a)) {
|
58
|
+
case T_FIXNUM:
|
59
|
+
case T_SYMBOL:
|
60
|
+
hnum = (int)a;
|
61
|
+
break;
|
62
|
+
|
63
|
+
case T_STRING:
|
64
|
+
hnum = rb_str_hash(a);
|
65
|
+
break;
|
66
|
+
|
67
|
+
default:
|
68
|
+
hval = rb_hash(a);
|
69
|
+
hnum = (int)FIX2LONG(hval);
|
70
|
+
}
|
71
|
+
hnum <<= 1;
|
72
|
+
return RSHIFT(hnum, 1);
|
73
|
+
}
|
74
|
+
|
75
|
+
static struct st_hash_type objhash = {
|
76
|
+
rb_any_cmp,
|
77
|
+
rb_any_hash,
|
78
|
+
};
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#include "ruby/st.h"
|
2
|
+
#define HASH_TBL(hash) RHASH(hash)->ntbl
|
3
|
+
#define HASH_SIZE(hash) RHASH(hash)->ntbl->num_entries
|
4
|
+
#define HASH_TYPE(hash) RHASH(hash)->ntbl->type
|
5
|
+
#define HASH_MOD_CHECK(hash) \
|
6
|
+
if (RHASH(hash)->iter_lev > 0) { \
|
7
|
+
rb_raise(rb_eRuntimeError, "rehash during iteration"); \
|
8
|
+
} \
|
9
|
+
rb_hash_modify_check(hash); \
|
10
|
+
if (!RHASH(hash)->ntbl) \
|
11
|
+
return hash;
|
12
|
+
|
13
|
+
/* leeched from core hash.c - would be nice to have these not be static and exposed via intern.h */
|
14
|
+
|
15
|
+
static void
|
16
|
+
rb_hash_modify_check(VALUE hash)
|
17
|
+
{
|
18
|
+
if (OBJ_FROZEN(hash)) rb_error_frozen("hash");
|
19
|
+
if (!OBJ_UNTRUSTED(hash) && rb_safe_level() >= 4)
|
20
|
+
rb_raise(rb_eSecurityError, "Insecure: can't modify hash");
|
21
|
+
}
|
data/rehash.gemspec
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'rehash'
|
3
|
+
s.version = '0.1'
|
4
|
+
s.date = '2010-09-10'
|
5
|
+
s.authors = ['Lourens Naudé', 'James Tucker']
|
6
|
+
s.email = ['lourens@methodmissing.com', 'jftucker@gmail.com']
|
7
|
+
s.description = 'This gem provides basic rehashing abilities.'
|
8
|
+
s.homepage = 'http://github.com/methodmissing/rehash'
|
9
|
+
s.summary = 'This gem provides basic rehashing abilities.'
|
10
|
+
s.extensions = 'ext/rehash/extconf.rb'
|
11
|
+
s.files = Dir.glob("{ext,test}/**/*") + %w[README Rakefile rehash.gemspec]
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.extra_rdoc_files = Dir['ext/rehash/*.c']
|
14
|
+
end
|
data/test/test.rb
ADDED
data/test/test_rehash.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
class TestRehash < Test::Unit::TestCase
|
2
|
+
def test_rekey
|
3
|
+
hash = { 'a' => 1, 'b' => 2 }
|
4
|
+
rekeyed = hash.rekey(:upcase)
|
5
|
+
assert_not_equal hash.object_id, rekeyed.object_id
|
6
|
+
assert_rekeyed rekeyed, %w(A B)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_rekey_bang
|
10
|
+
hash = { 'a' => 1, 'b' => 2 }
|
11
|
+
hash.rekey!(:upcase)
|
12
|
+
assert_rekeyed hash, %w(A B)
|
13
|
+
hash.rekey!(:to_sym)
|
14
|
+
assert_rekeyed hash, [:A, :B]
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_revalue
|
18
|
+
hash = { 1 => 'a', 2 => 'b' }
|
19
|
+
revalued = hash.revalue(:upcase)
|
20
|
+
assert_not_equal hash.object_id, revalued.object_id
|
21
|
+
assert_revalued revalued, %w(A B)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_revalue_bang
|
25
|
+
hash = { 1 => 'a', 2 => 'b' }
|
26
|
+
hash.revalue!(:upcase)
|
27
|
+
assert_revalued hash, %w(A B)
|
28
|
+
hash.revalue!(:to_sym)
|
29
|
+
assert_revalued hash, [:A, :B]
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def assert_revalued(hash, expected)
|
34
|
+
assert_rehased(hash, :value?, expected)
|
35
|
+
end
|
36
|
+
|
37
|
+
def assert_rekeyed(hash, expected)
|
38
|
+
assert_rehased(hash, :key?, expected)
|
39
|
+
end
|
40
|
+
|
41
|
+
def assert_rehased(hash, meth, expected)
|
42
|
+
assert expected.all?{|k| hash.__send__(meth, k) }
|
43
|
+
end
|
44
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rehash
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
version: "0.1"
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- "Lourens Naud\xC3\xA9"
|
12
|
+
- James Tucker
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-09-10 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: This gem provides basic rehashing abilities.
|
22
|
+
email:
|
23
|
+
- lourens@methodmissing.com
|
24
|
+
- jftucker@gmail.com
|
25
|
+
executables: []
|
26
|
+
|
27
|
+
extensions:
|
28
|
+
- ext/rehash/extconf.rb
|
29
|
+
extra_rdoc_files:
|
30
|
+
- ext/rehash/rehash.c
|
31
|
+
files:
|
32
|
+
- ext/rehash/extconf.rb
|
33
|
+
- ext/rehash/Makefile
|
34
|
+
- ext/rehash/mkmf.log
|
35
|
+
- ext/rehash/rehash.bundle
|
36
|
+
- ext/rehash/rehash.c
|
37
|
+
- ext/rehash/rehash.h
|
38
|
+
- ext/rehash/rehash.o
|
39
|
+
- ext/rehash/rehash_18.h
|
40
|
+
- ext/rehash/rehash_19.h
|
41
|
+
- test/test.rb
|
42
|
+
- test/test_rehash.rb
|
43
|
+
- README
|
44
|
+
- Rakefile
|
45
|
+
- rehash.gemspec
|
46
|
+
has_rdoc: true
|
47
|
+
homepage: http://github.com/methodmissing/rehash
|
48
|
+
licenses: []
|
49
|
+
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
version: "0"
|
71
|
+
requirements: []
|
72
|
+
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 1.3.7
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: This gem provides basic rehashing abilities.
|
78
|
+
test_files: []
|
79
|
+
|