fat 0.0.4 → 0.0.5
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.
- checksums.yaml +4 -4
- data/benchmarks/fat.rb +136 -0
- data/ext/fat/fat.c +30 -30
- data/fat.gemspec +1 -1
- data/test/fat_test.rb +8 -7
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fffbd3df88760a30ab94ec780231688a17944655
|
4
|
+
data.tar.gz: 9bdbe4cff365157a89f42cde46e5de3b94112abc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39307004150f2606963b21e8f8adae44d269b2cb7f01142ff333fd6740a098f881672259c738f5282523330d2cfab6de452f8c330923f2569c42591212409144
|
7
|
+
data.tar.gz: 11adbb07becc3a42b6c480aa7fc23d5598142932f66e12b20b98604e8307b65f8fdcf62ee590ed46868c26f4c9f57a72dd926abb23d7034f286384f46bba18f4
|
data/benchmarks/fat.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
require "benchmark/ips"
|
2
|
+
require_relative "../lib/fat"
|
3
|
+
|
4
|
+
class Hash
|
5
|
+
include Fat
|
6
|
+
|
7
|
+
def ruby_at(*args)
|
8
|
+
fields = args.length == 1 ? args[0].split(".") : args
|
9
|
+
value = self
|
10
|
+
|
11
|
+
fields.each do |field|
|
12
|
+
value = self[field]
|
13
|
+
return unless value
|
14
|
+
return value unless value.kind_of?(Hash)
|
15
|
+
end
|
16
|
+
|
17
|
+
value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
hash = {
|
22
|
+
"foo" => {
|
23
|
+
"bar" => {
|
24
|
+
"baz" => {
|
25
|
+
"key" => :value
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
puts "### String chain as a single argument."
|
32
|
+
Benchmark.ips do |bench|
|
33
|
+
bench.report("ruby") { hash.ruby_at("foo.bar.baz") }
|
34
|
+
bench.report("c") { hash.at("foo.bar.baz") }
|
35
|
+
bench.compare!
|
36
|
+
end
|
37
|
+
|
38
|
+
# ### String chain as a single argument.
|
39
|
+
# Calculating -------------------------------------
|
40
|
+
# ruby 47304 i/100ms
|
41
|
+
# c 55888 i/100ms
|
42
|
+
# -------------------------------------------------
|
43
|
+
# ruby 741487.1 (±10.6%) i/s - 3642408 in 5.002662s
|
44
|
+
# c 977630.9 (±11.3%) i/s - 4806368 in 5.001422s
|
45
|
+
# Comparison:
|
46
|
+
# c: 977630.9 i/s
|
47
|
+
# ruby: 741487.1 i/s - 1.32x slower
|
48
|
+
|
49
|
+
puts "### Each key as an argument."
|
50
|
+
Benchmark.ips do |bench|
|
51
|
+
bench.report("ruby") { hash.ruby_at("foo", "bar", "baz") }
|
52
|
+
bench.report("c") { hash.at("foo", "bar", "baz") }
|
53
|
+
bench.compare!
|
54
|
+
end
|
55
|
+
|
56
|
+
# ### Each key as an argument.
|
57
|
+
# Calculating -------------------------------------
|
58
|
+
# ruby 57145 i/100ms
|
59
|
+
# c 73161 i/100ms
|
60
|
+
# -------------------------------------------------
|
61
|
+
# ruby 1035908.2 (±9.7%) i/s - 5143050 in 5.036346s
|
62
|
+
# c 1513478.5 (±11.1%) i/s - 7462422 in 5.017305s
|
63
|
+
# Comparison:
|
64
|
+
# c: 1513478.5 i/s
|
65
|
+
# ruby: 1035908.2 i/s - 1.46x slower
|
66
|
+
|
67
|
+
puts "### No value found."
|
68
|
+
Benchmark.ips do |bench|
|
69
|
+
bench.report("ruby") { hash.ruby_at("foo.one.key") }
|
70
|
+
bench.report("c") { hash.at("foo.one.key") }
|
71
|
+
bench.compare!
|
72
|
+
end
|
73
|
+
|
74
|
+
# ### No value found.
|
75
|
+
# Calculating -------------------------------------
|
76
|
+
# ruby 46842 i/100ms
|
77
|
+
# c 62515 i/100ms
|
78
|
+
# -------------------------------------------------
|
79
|
+
# ruby 733070.0 (±10.0%) i/s - 3653676 in 5.052594s
|
80
|
+
# c 1103249.9 (±11.2%) i/s - 5438805 in 5.026985s
|
81
|
+
# Comparison:
|
82
|
+
# c: 1103249.9 i/s
|
83
|
+
# ruby: 733070.0 i/s - 1.50x slower
|
84
|
+
|
85
|
+
deep_hash = {
|
86
|
+
"foo" => {
|
87
|
+
"bar" => {
|
88
|
+
"baz" => {
|
89
|
+
"and" => {
|
90
|
+
"one" => {
|
91
|
+
"more" => {
|
92
|
+
"key" => :value
|
93
|
+
}
|
94
|
+
}
|
95
|
+
}
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
puts "### Deep hash - String chain argument."
|
102
|
+
Benchmark.ips do |bench|
|
103
|
+
bench.report("ruby") { deep_hash.ruby_at("foo.bar.baz.and.one.more.key") }
|
104
|
+
bench.report("c") { deep_hash.at("foo.bar.baz.and.one.more.key") }
|
105
|
+
bench.compare!
|
106
|
+
end
|
107
|
+
|
108
|
+
# ### Deep hash - String chain argument.
|
109
|
+
# Calculating -------------------------------------
|
110
|
+
# ruby 35209 i/100ms
|
111
|
+
# c 37201 i/100ms
|
112
|
+
# -------------------------------------------------
|
113
|
+
# ruby 490384.6 (±10.9%) i/s - 2429421 in 5.040102s
|
114
|
+
# c 530276.4 (±10.0%) i/s - 2641271 in 5.057748s
|
115
|
+
# Comparison:
|
116
|
+
# c: 530276.4 i/s
|
117
|
+
# ruby: 490384.6 i/s - 1.08x slower
|
118
|
+
|
119
|
+
puts "### Deep hash - Each key as an argument."
|
120
|
+
Benchmark.ips do |bench|
|
121
|
+
bench.report("ruby") { deep_hash.ruby_at("foo", "bar", "baz", "and", "one", "more", "key") }
|
122
|
+
bench.report("c") { deep_hash.at("foo", "bar", "baz", "and", "one", "more", "key") }
|
123
|
+
bench.compare!
|
124
|
+
end
|
125
|
+
|
126
|
+
# ### Deep hash - Each key as an argument.
|
127
|
+
# Calculating -------------------------------------
|
128
|
+
# ruby 44009 i/100ms
|
129
|
+
# c 46413 i/100ms
|
130
|
+
# -------------------------------------------------
|
131
|
+
# ruby 674854.4 (±10.2%) i/s - 3344684 in 5.040045s
|
132
|
+
# c 734889.3 (±8.5%) i/s - 3666627 in 5.039101s
|
133
|
+
# Comparison:
|
134
|
+
# c: 734889.3 i/s
|
135
|
+
# ruby: 674854.4 i/s - 1.09x slower
|
136
|
+
|
data/ext/fat/fat.c
CHANGED
@@ -13,8 +13,10 @@ static VALUE method_fetch_at(int argc, VALUE *argv, VALUE hash);
|
|
13
13
|
static VALUE fat(VALUE hash, VALUE fields, int raise_on_nil);
|
14
14
|
|
15
15
|
// Helpers
|
16
|
-
static void parse_fields(VALUE args, VALUE *fields);
|
17
|
-
static VALUE fields_upto_index(VALUE fields,
|
16
|
+
static inline void parse_fields(VALUE args, VALUE *fields);
|
17
|
+
static inline VALUE fields_upto_index(VALUE fields, long index);
|
18
|
+
static inline void parse_singleton_args(int argc, VALUE *argv, VALUE *hash, VALUE *fields);
|
19
|
+
static inline void parse_method_args(int argc, VALUE *argv, VALUE *fields);
|
18
20
|
|
19
21
|
void Init_fat(void) {
|
20
22
|
Fat = rb_define_module("Fat");
|
@@ -27,44 +29,34 @@ void Init_fat(void) {
|
|
27
29
|
|
28
30
|
static VALUE singleton_method_at(int argc, VALUE *argv, VALUE self) {
|
29
31
|
VALUE hash;
|
30
|
-
VALUE args;
|
31
|
-
|
32
|
-
rb_scan_args(argc, argv, "1*", &hash, &args);
|
33
|
-
|
34
32
|
VALUE fields;
|
35
|
-
|
33
|
+
|
34
|
+
parse_singleton_args(argc, argv, &hash, &fields);
|
36
35
|
|
37
36
|
return fat(hash, fields, 0);
|
38
37
|
}
|
39
38
|
|
40
39
|
static VALUE singleton_method_fetch_at(int argc, VALUE *argv, VALUE self) {
|
41
40
|
VALUE hash;
|
42
|
-
VALUE args;
|
43
|
-
|
44
|
-
rb_scan_args(argc, argv, "1*", &hash, &args);
|
45
|
-
|
46
41
|
VALUE fields;
|
47
|
-
|
42
|
+
|
43
|
+
parse_singleton_args(argc, argv, &hash, &fields);
|
48
44
|
|
49
45
|
return fat(hash, fields, 1);
|
50
46
|
}
|
51
47
|
|
52
48
|
static VALUE method_at(int argc, VALUE *argv, VALUE hash) {
|
53
|
-
VALUE args;
|
54
|
-
rb_scan_args(argc, argv, "*", &args);
|
55
|
-
|
56
49
|
VALUE fields;
|
57
|
-
|
50
|
+
|
51
|
+
parse_method_args(argc, argv, &fields);
|
58
52
|
|
59
53
|
return fat(hash, fields, 0);
|
60
54
|
}
|
61
55
|
|
62
56
|
static VALUE method_fetch_at(int argc, VALUE *argv, VALUE hash) {
|
63
|
-
VALUE args;
|
64
|
-
rb_scan_args(argc, argv, "*", &args);
|
65
|
-
|
66
57
|
VALUE fields;
|
67
|
-
|
58
|
+
|
59
|
+
parse_method_args(argc, argv, &fields);
|
68
60
|
|
69
61
|
return fat(hash, fields, 1);
|
70
62
|
}
|
@@ -72,12 +64,11 @@ static VALUE method_fetch_at(int argc, VALUE *argv, VALUE hash) {
|
|
72
64
|
static VALUE fat(VALUE hash, VALUE fields, int raise_on_nil) {
|
73
65
|
VALUE value = hash;
|
74
66
|
|
75
|
-
for (
|
76
|
-
|
77
|
-
value = rb_hash_aref(value, key);
|
67
|
+
for (long i = 0; i < RARRAY_LEN(fields); i++) {
|
68
|
+
value = rb_hash_aref(value, RARRAY_AREF(fields, i));
|
78
69
|
|
79
70
|
if (value == Qnil) {
|
80
|
-
if (raise_on_nil
|
71
|
+
if (raise_on_nil) {
|
81
72
|
rb_raise(rb_eKeyError, "No value found at %s", RSTRING_PTR(fields_upto_index(fields, i)));
|
82
73
|
} else {
|
83
74
|
return Qnil;
|
@@ -92,19 +83,28 @@ static VALUE fat(VALUE hash, VALUE fields, int raise_on_nil) {
|
|
92
83
|
return value;
|
93
84
|
}
|
94
85
|
|
95
|
-
static void parse_fields(VALUE args, VALUE *fields) {
|
86
|
+
static inline void parse_fields(VALUE args, VALUE *fields) {
|
96
87
|
if (RARRAY_LEN(args) == 1) {
|
97
|
-
|
98
|
-
|
99
|
-
StringValue(chain);
|
100
|
-
*fields = rb_str_split(chain, ".");
|
88
|
+
*fields = rb_str_split(RARRAY_PTR(args)[0], ".");
|
101
89
|
} else {
|
102
90
|
*fields = args;
|
103
91
|
}
|
104
92
|
}
|
105
93
|
|
106
|
-
static VALUE fields_upto_index(VALUE fields,
|
94
|
+
static inline VALUE fields_upto_index(VALUE fields, long index) {
|
107
95
|
VALUE range = rb_range_new(INT2FIX(0), INT2FIX(index), 0);
|
108
96
|
VALUE slice = rb_funcall(fields, rb_intern("slice"), 1, range);
|
109
97
|
return rb_ary_join(slice, rb_str_new2("."));
|
110
98
|
}
|
99
|
+
|
100
|
+
static inline void parse_singleton_args(int argc, VALUE *argv, VALUE *hash, VALUE *fields) {
|
101
|
+
VALUE args;
|
102
|
+
rb_scan_args(argc, argv, "1*", hash, &args);
|
103
|
+
parse_fields(args, fields);
|
104
|
+
}
|
105
|
+
|
106
|
+
static inline void parse_method_args(int argc, VALUE *argv, VALUE *fields) {
|
107
|
+
VALUE args;
|
108
|
+
rb_scan_args(argc, argv, "*", &args);
|
109
|
+
parse_fields(args, fields);
|
110
|
+
}
|
data/fat.gemspec
CHANGED
data/test/fat_test.rb
CHANGED
@@ -44,21 +44,22 @@ end
|
|
44
44
|
scope do
|
45
45
|
setup do
|
46
46
|
Hash.include(Fat)
|
47
|
-
end
|
48
|
-
|
49
|
-
test "include the module" do
|
50
|
-
assert Hash.new.respond_to?(:at)
|
51
|
-
end
|
52
47
|
|
53
|
-
|
54
|
-
hash = {
|
48
|
+
{
|
55
49
|
"foo" => {
|
56
50
|
"bar" => {
|
57
51
|
"baz" => :found
|
58
52
|
}
|
59
53
|
}
|
60
54
|
}
|
55
|
+
end
|
56
|
+
|
57
|
+
test "include the module" do |hash|
|
58
|
+
assert hash.respond_to?(:at)
|
59
|
+
assert hash.respond_to?(:fetch_at)
|
60
|
+
end
|
61
61
|
|
62
|
+
test "honor Fat interface" do |hash|
|
62
63
|
assert_equal :found, hash.at("foo", "bar", "baz")
|
63
64
|
assert_equal :found, hash.at("foo.bar.baz")
|
64
65
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lucas Tolchinsky
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-10-
|
11
|
+
date: 2014-10-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cutest
|
@@ -52,6 +52,7 @@ files:
|
|
52
52
|
- Makefile
|
53
53
|
- README.md
|
54
54
|
- Rakefile
|
55
|
+
- benchmarks/fat.rb
|
55
56
|
- ext/fat/extconf.rb
|
56
57
|
- ext/fat/fat.c
|
57
58
|
- fat.gemspec
|