fat 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1fd45ba2047a3be07e832e7fb9a7ba405098b080
4
- data.tar.gz: b28efdaad73f42987a52f813b6ca6292e23cbfd7
3
+ metadata.gz: fffbd3df88760a30ab94ec780231688a17944655
4
+ data.tar.gz: 9bdbe4cff365157a89f42cde46e5de3b94112abc
5
5
  SHA512:
6
- metadata.gz: 45feaf74742e8023bf38e02b52667627f49a638ea6d9a6e41715c94665a02d1b5a88b9e36bea854445271d229fc5ee1564d1f6efc5112372a6aa1fe7a375b18e
7
- data.tar.gz: 234d08f9d9c752fce80a6e3dda850b3abcd2896b8ac83a33ad1ef09031a59b3b4df804eecdcc66bd2d36f76b8c95cc54758eb8c5fee7996fe46ab1fcfd8a2288
6
+ metadata.gz: 39307004150f2606963b21e8f8adae44d269b2cb7f01142ff333fd6740a098f881672259c738f5282523330d2cfab6de452f8c330923f2569c42591212409144
7
+ data.tar.gz: 11adbb07becc3a42b6c480aa7fc23d5598142932f66e12b20b98604e8307b65f8fdcf62ee590ed46868c26f4c9f57a72dd926abb23d7034f286384f46bba18f4
@@ -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
+
@@ -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, int index);
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
- parse_fields(args, &fields);
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
- parse_fields(args, &fields);
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
- parse_fields(args, &fields);
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
- parse_fields(args, &fields);
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 (int i = 0; i < RARRAY_LEN(fields); i++) {
76
- VALUE key = RARRAY_PTR(fields)[i];
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 == 1) {
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
- VALUE chain = RARRAY_PTR(args)[0];
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, int index) {
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
+ }
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "fat"
3
- s.version = "0.0.4"
3
+ s.version = "0.0.5"
4
4
  s.summary = "C extension to find values in nested hashes without pain"
5
5
  s.description = s.summary
6
6
  s.authors = ["Lucas Tolchinsky"]
@@ -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
- test "honor Fat interface" do
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
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-04 00:00:00.000000000 Z
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