aboutsummaryrefslogtreecommitdiffstats
path: root/enum.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-07-18 02:10:37 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-07-18 02:10:37 +0000
commit0d0fc55122f7e64cf4d491c4a5f4bb941f29ec65 (patch)
treebc8d40e52e738bf4224a53b8f652edda1d38ba70 /enum.c
parentc317e978f79c920924f70eea8f66e69b40369fa5 (diff)
downloadruby-0d0fc55122f7e64cf4d491c4a5f4bb941f29ec65.tar.gz
enum.c: optimize any? object allocations for Array and Hash
* enum.c (enum_any): optimize object allocations for Array and Hash when `each` is not redefined, always false if empty and the case without a block. [fix GH-617] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@46859 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'enum.c')
-rw-r--r--enum.c35
1 files changed, 34 insertions, 1 deletions
diff --git a/enum.c b/enum.c
index 44a73d3543..1703003c7d 100644
--- a/enum.c
+++ b/enum.c
@@ -14,6 +14,7 @@
#include "node.h"
#include "id.h"
#include "internal.h"
+#include "vm_core.h"
VALUE rb_f_send(int argc, VALUE *argv, VALUE recv);
@@ -1023,6 +1024,11 @@ name##_iter_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memo)) \
static VALUE \
enum_##name##_func(VALUE result, NODE *memo)
+#define ARY_OPTIMIZABLE_EACH(obj) \
+ (RBASIC_CLASS(obj) == rb_cArray && BASIC_OP_UNREDEFINED_P(BOP_EACH, ARRAY_REDEFINED_OP_FLAG))
+#define HASH_OPTIMIZABLE_EACH(obj) \
+ (RBASIC_CLASS(obj) == rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_EACH, HASH_REDEFINED_OP_FLAG))
+
DEFINE_ENUMFUNCS(all)
{
if (!RTEST(result)) {
@@ -1086,7 +1092,34 @@ DEFINE_ENUMFUNCS(any)
static VALUE
enum_any(VALUE obj)
{
- NODE *memo = NEW_MEMO(Qfalse, 0, 0);
+ NODE *memo;
+
+ if (!SPECIAL_CONST_P(obj)) {
+ switch (BUILTIN_TYPE(obj)) {
+ case T_ARRAY:
+ if (ARY_OPTIMIZABLE_EACH(obj)) {
+ long i, len = RARRAY_LEN(obj);
+ if (!len) return Qfalse;
+ if (!rb_block_given_p()) {
+ const VALUE *ptr = RARRAY_CONST_PTR(obj);
+ for (i = 0; i < len; ++i) if (RTEST(ptr[i])) return Qtrue;
+ return Qfalse;
+ }
+ }
+ break;
+ case T_HASH:
+ if (HASH_OPTIMIZABLE_EACH(obj)) {
+ if (RHASH_EMPTY_P(obj)) return Qfalse;
+ if (!rb_block_given_p()) {
+ /* yields pairs, never false */
+ return Qtrue;
+ }
+ }
+ break;
+ }
+ }
+
+ memo = NEW_MEMO(Qfalse, 0, 0);
rb_block_call(obj, id_each, 0, 0, ENUMFUNC(any), (VALUE)memo);
return memo->u1.value;
}