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 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