diff options
author | Jean Boussier <[email protected]> | 2024-03-25 13:03:14 +0100 |
---|---|---|
committer | Jean Boussier <[email protected]> | 2024-07-08 12:24:33 +0200 |
commit | 9594db0cf28d7bc10bfc46142239191a11f1dbbe (patch) | |
tree | b7818d1a33100604a0bf9a6a1ff0a08a196b816a /hash.c | |
parent | bfb8cad771aac8bc048fcd83e244bfe782d182e7 (diff) |
Implement Hash.new(capacity:)
[Feature #19236]
When building a large hash, pre-allocating it with enough
capacity can save many re-hashes and significantly improve
performance.
```
/opt/rubies/3.3.0/bin/ruby --disable=gems -rrubygems -I./benchmark/lib ./benchmark/benchmark-driver/exe/benchmark-driver \
--executables="compare-ruby::../miniruby-master -I.ext/common --disable-gem" \
--executables="built-ruby::./miniruby --disable-gem" \
--output=markdown --output-compare -v $(find ./benchmark -maxdepth 1 -name 'hash_new' -o -name '*hash_new*.yml' -o -name '*hash_new*.rb' | sort)
compare-ruby: ruby 3.4.0dev (2024-03-25T11:48:11Z master f53209f023) +YJIT dev [arm64-darwin23]
last_commit=[ruby/irb] Cache RDoc::RI::Driver.new (https://github.com/ruby/irb/pull/911)
built-ruby: ruby 3.4.0dev (2024-03-25T15:29:40Z hash-new-rb 77652b08a2) +YJIT dev [arm64-darwin23]
warming up...
| |compare-ruby|built-ruby|
|:-------------------|-----------:|---------:|
|new | 7.614M| 5.976M|
| | 1.27x| -|
|new_with_capa_1k | 13.931k| 15.698k|
| | -| 1.13x|
|new_with_capa_100k | 124.746| 148.283|
| | -| 1.19x|
```
Diffstat (limited to 'hash.c')
-rw-r--r-- | hash.c | 63 |
1 files changed, 19 insertions, 44 deletions
@@ -48,6 +48,7 @@ #include "ruby/thread_native.h" #include "ruby/ractor.h" #include "vm_sync.h" +#include "builtin.h" /* Flags of RHash * @@ -1762,58 +1763,31 @@ set_proc_default(VALUE hash, VALUE proc) RHASH_SET_IFNONE(hash, proc); } -/* - * call-seq: - * Hash.new(default_value = nil) -> new_hash - * Hash.new {|hash, key| ... } -> new_hash - * - * Returns a new empty +Hash+ object. - * - * The initial default value and initial default proc for the new hash - * depend on which form above was used. See {Default Values}[rdoc-ref:Hash@Default+Values]. - * - * If neither an argument nor a block given, - * initializes both the default value and the default proc to <tt>nil</tt>: - * h = Hash.new - * h.default # => nil - * h.default_proc # => nil - * - * If argument <tt>default_value</tt> given but no block given, - * initializes the default value to the given <tt>default_value</tt> - * and the default proc to <tt>nil</tt>: - * h = Hash.new(false) - * h.default # => false - * h.default_proc # => nil - * - * If a block given but no argument, stores the block as the default proc - * and sets the default value to <tt>nil</tt>: - * h = Hash.new {|hash, key| "Default value for #{key}" } - * h.default # => nil - * h.default_proc.class # => Proc - * h[:nosuch] # => "Default value for nosuch" - */ - static VALUE -rb_hash_initialize(int argc, VALUE *argv, VALUE hash) +rb_hash_init(rb_execution_context_t *ec, VALUE hash, VALUE capa_value, VALUE ifnone_unset, VALUE ifnone, VALUE block) { rb_hash_modify(hash); - if (rb_block_given_p()) { - rb_check_arity(argc, 0, 0); - SET_PROC_DEFAULT(hash, rb_block_proc()); + if (capa_value != INT2FIX(0)) { + long capa = NUM2LONG(capa_value); + if (capa > 0 && RHASH_SIZE(hash) == 0 && RHASH_AR_TABLE_P(hash)) { + hash_st_table_init(hash, &objhash, capa); + } } - else { - rb_check_arity(argc, 0, 1); - VALUE options, ifnone; - rb_scan_args(argc, argv, "01:", &ifnone, &options); - if (NIL_P(ifnone) && !NIL_P(options)) { - ifnone = options; - rb_warn_deprecated_to_remove("3.4", "Calling Hash.new with keyword arguments", "Hash.new({ key: value })"); + if (!NIL_P(block)) { + if (ifnone_unset != Qtrue) { + rb_check_arity(1, 0, 0); } - RHASH_SET_IFNONE(hash, ifnone); + else { + SET_PROC_DEFAULT(hash, block); + } + } + else { + RHASH_SET_IFNONE(hash, ifnone_unset == Qtrue ? Qnil : ifnone); } + hash_verify(hash); return hash; } @@ -7150,7 +7124,6 @@ Init_Hash(void) rb_define_alloc_func(rb_cHash, empty_hash_alloc); rb_define_singleton_method(rb_cHash, "[]", rb_hash_s_create, -1); rb_define_singleton_method(rb_cHash, "try_convert", rb_hash_s_try_convert, 1); - rb_define_method(rb_cHash, "initialize", rb_hash_initialize, -1); rb_define_method(rb_cHash, "initialize_copy", rb_hash_replace, 1); rb_define_method(rb_cHash, "rehash", rb_hash_rehash, 0); @@ -7477,3 +7450,5 @@ Init_Hash(void) HASH_ASSERT(sizeof(ar_hint_t) * RHASH_AR_TABLE_MAX_SIZE == sizeof(VALUE)); } + +#include "hash.rbinc" |