rehash 0.1
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 +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
|
+
|