2000-05-01 13:42:38 +04:00
|
|
|
/**********************************************************************
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
array.c -
|
|
|
|
|
|
|
|
$Author$
|
|
|
|
created at: Fri Aug 6 09:46:12 JST 1993
|
|
|
|
|
* encoding.c: provide basic features for M17N.
* parse.y: encoding aware parsing.
* parse.y (pragma_encoding): encoding specification pragma.
* parse.y (rb_intern3): encoding specified symbols.
* string.c (rb_str_length): length based on characters.
for older behavior, bytesize method added.
* string.c (rb_str_index_m): index based on characters. rindex as
well.
* string.c (succ_char): encoding aware succeeding string.
* string.c (rb_str_reverse): reverse based on characters.
* string.c (rb_str_inspect): encoding aware string description.
* string.c (rb_str_upcase_bang): encoding aware case conversion.
downcase, capitalize, swapcase as well.
* string.c (rb_str_tr_bang): tr based on characters. delete,
squeeze, tr_s, count as well.
* string.c (rb_str_split_m): split based on characters.
* string.c (rb_str_each_line): encoding aware each_line.
* string.c (rb_str_each_char): added. iteration based on
characters.
* string.c (rb_str_strip_bang): encoding aware whitespace
stripping. lstrip, rstrip as well.
* string.c (rb_str_justify): encoding aware justifying (ljust,
rjust, center).
* string.c (str_encoding): get encoding attribute from a string.
* re.c (rb_reg_initialize): encoding aware regular expression
* sprintf.c (rb_str_format): formatting (i.e. length count) based
on characters.
* io.c (rb_io_getc): getc to return one-character string.
for older behavior, getbyte method added.
* ext/stringio/stringio.c (strio_getc): ditto.
* io.c (rb_io_ungetc): allow pushing arbitrary string at the
current reading point.
* ext/stringio/stringio.c (strio_ungetc): ditto.
* ext/strscan/strscan.c: encoding support.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13261 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-08-25 07:29:39 +04:00
|
|
|
Copyright (C) 1993-2007 Yukihiro Matsumoto
|
2000-05-01 13:42:38 +04:00
|
|
|
Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
|
2000-05-09 08:53:16 +04:00
|
|
|
Copyright (C) 2000 Information-technology Promotion Agency, Japan
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2000-05-01 13:42:38 +04:00
|
|
|
**********************************************************************/
|
2019-12-04 11:16:30 +03:00
|
|
|
|
|
|
|
#include "debug_counter.h"
|
|
|
|
#include "id.h"
|
|
|
|
#include "internal.h"
|
|
|
|
#include "internal/array.h"
|
|
|
|
#include "internal/compar.h"
|
|
|
|
#include "internal/enum.h"
|
|
|
|
#include "internal/gc.h"
|
|
|
|
#include "internal/hash.h"
|
|
|
|
#include "internal/numeric.h"
|
|
|
|
#include "internal/object.h"
|
|
|
|
#include "internal/proc.h"
|
|
|
|
#include "internal/rational.h"
|
|
|
|
#include "internal/vm.h"
|
|
|
|
#include "probes.h"
|
2018-01-09 09:24:11 +03:00
|
|
|
#include "ruby/encoding.h"
|
2007-06-10 07:06:15 +04:00
|
|
|
#include "ruby/st.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "ruby/util.h"
|
2018-10-31 00:53:56 +03:00
|
|
|
#include "transient_heap.h"
|
2020-01-26 12:27:40 +03:00
|
|
|
#include "builtin.h"
|
2008-10-17 14:42:11 +04:00
|
|
|
|
2018-10-31 00:53:56 +03:00
|
|
|
#if !ARRAY_DEBUG
|
2020-04-17 23:40:57 +03:00
|
|
|
# undef NDEBUG
|
2008-10-17 14:42:11 +04:00
|
|
|
# define NDEBUG
|
|
|
|
#endif
|
2016-01-22 11:33:55 +03:00
|
|
|
#include "ruby_assert.h"
|
1998-01-16 15:13:05 +03:00
|
|
|
|
* sprintf.c (rb_str_format): allow %c to print one character
string (e.g. ?x).
* lib/tempfile.rb (Tempfile::make_tmpname): put dot between
basename and pid. [ruby-talk:196272]
* parse.y (do_block): remove -> style block.
* parse.y (parser_yylex): remove tLAMBDA_ARG.
* eval.c (rb_call0): binding for the return event hook should have
consistent scope. [ruby-core:07928]
* eval.c (proc_invoke): return behavior should depend whether it
is surrounded by a lambda or a mere block.
* eval.c (formal_assign): handles post splat arguments.
* eval.c (rb_call0): ditto.
* st.c (strhash): use FNV-1a hash.
* parse.y (parser_yylex): removed experimental ';;' terminator.
* eval.c (rb_node_arity): should be aware of post splat arguments.
* eval.c (rb_proc_arity): ditto.
* parse.y (f_args): syntax rule enhanced to support arguments
after the splat.
* parse.y (block_param): ditto for block parameters.
* parse.y (f_post_arg): mandatory formal arguments after the splat
argument.
* parse.y (new_args_gen): generate nodes for mandatory formal
arguments after the splat argument.
* eval.c (rb_eval): dispatch mandatory formal arguments after the
splat argument.
* parse.y (args): allow more than one splat in the argument list.
* parse.y (method_call): allow aref [] to accept all kind of
method argument, including assocs, splat, and block argument.
* eval.c (SETUP_ARGS0): prepare block argument as well.
* lib/mathn.rb (Integer): remove Integer#gcd2. [ruby-core:07931]
* eval.c (error_line): print receivers true/false/nil specially.
* eval.c (rb_proc_yield): handles parameters in yield semantics.
* eval.c (nil_yield): gives LocalJumpError to denote no block
error.
* io.c (rb_io_getc): now takes one-character string.
* string.c (rb_str_hash): use FNV-1a hash from Fowler/Noll/Vo
hashing algorithm.
* string.c (rb_str_aref): str[0] now returns 1 character string,
instead of a fixnum. [Ruby2]
* parse.y (parser_yylex): ?c now returns 1 character string,
instead of a fixnum. [Ruby2]
* string.c (rb_str_aset): no longer support fixnum insertion.
* eval.c (umethod_bind): should not update original class.
[ruby-dev:28636]
* eval.c (ev_const_get): should support constant access from
within instance_eval(). [ruby-dev:28327]
* time.c (time_timeval): should round for usec floating
number. [ruby-core:07896]
* time.c (time_add): ditto.
* dir.c (sys_warning): should not call a vararg function
rb_sys_warning() indirectly. [ruby-core:07886]
* numeric.c (flo_divmod): the first element of Float#divmod should
be an integer. [ruby-dev:28589]
* test/ruby/test_float.rb: add tests for divmod, div, modulo and remainder.
* re.c (rb_reg_initialize): should not allow modifying literal
regexps. frozen check moved from rb_reg_initialize_m as well.
* re.c (rb_reg_initialize): should not modify untainted objects in
safe levels higher than 3.
* re.c (rb_memcmp): type change from char* to const void*.
* dir.c (dir_close): should not close untainted dir stream.
* dir.c (GetDIR): add tainted/frozen check for each dir operation.
* lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_symbol_arg):
typo fixed. a patch from Florian Gross <florg at florg.net>.
* eval.c (EXEC_EVENT_HOOK): trace_func may remove itself from
event_hooks. no guarantee for arbitrary hook deletion.
[ruby-dev:28632]
* util.c (ruby_strtod): differ addition to minimize error.
[ruby-dev:28619]
* util.c (ruby_strtod): should not raise ERANGE when the input
string does not have any digits. [ruby-dev:28629]
* eval.c (proc_invoke): should restore old ruby_frame->block.
thanks to ts <decoux at moulon.inra.fr>. [ruby-core:07833]
also fix [ruby-dev:28614] as well.
* signal.c (trap): sig should be less then NSIG. Coverity found
this bug. a patch from Kevin Tew <tewk at tewk.com>.
[ruby-core:07823]
* math.c (math_log2): add new method inspired by
[ruby-talk:191237].
* math.c (math_log): add optional base argument to Math::log().
[ruby-talk:191308]
* ext/syck/emitter.c (syck_scan_scalar): avoid accessing
uninitialized array element. a patch from Pat Eyler
<rubypate at gmail.com>. [ruby-core:07809]
* array.c (rb_ary_fill): initialize local variables first. a
patch from Pat Eyler <rubypate at gmail.com>. [ruby-core:07810]
* ext/syck/yaml2byte.c (syck_yaml2byte_handler): need to free
type_tag. a patch from Pat Eyler <rubypate at gmail.com>.
[ruby-core:07808]
* ext/socket/socket.c (make_hostent_internal): accept ai_family
check from Sam Roberts <sroberts at uniserve.com>.
[ruby-core:07691]
* util.c (ruby_strtod): should not cut off 18 digits for no
reason. [ruby-core:07796]
* array.c (rb_ary_fill): internalize local variable "beg" to
pacify Coverity. [ruby-core:07770]
* pack.c (pack_unpack): now supports CRLF newlines. a patch from
<tommy at tmtm.org>. [ruby-dev:28601]
* applied code clean-up patch from Stefan Huehner
<stefan at huehner.org>. [ruby-core:07764]
* lib/jcode.rb (String::tr_s): should have translated non
squeezing character sequence (i.e. a character) as well. thanks
to Hiroshi Ichikawa <gimite at gimite.ddo.jp> [ruby-list:42090]
* ext/socket/socket.c: document update patch from Sam Roberts
<sroberts at uniserve.com>. [ruby-core:07701]
* lib/mathn.rb (Integer): need not to remove gcd2. a patch from
NARUSE, Yui <naruse at airemix.com>. [ruby-dev:28570]
* parse.y (arg): too much NEW_LIST()
* eval.c (SETUP_ARGS0): remove unnecessary access to nd_alen.
* eval.c (rb_eval): use ARGSCAT for NODE_OP_ASGN1.
[ruby-dev:28585]
* parse.y (arg): use NODE_ARGSCAT for placeholder.
* lib/getoptlong.rb (GetoptLong::get): RDoc update patch from
mathew <meta at pobox.com>. [ruby-core:07738]
* variable.c (rb_const_set): raise error when no target klass is
supplied. [ruby-dev:28582]
* prec.c (prec_prec_f): documentation patch from
<gerardo.santana at gmail.com>. [ruby-core:07689]
* bignum.c (rb_big_pow): second operand may be too big even if
it's a Fixnum. [ruby-talk:187984]
* README.EXT: update symbol description. [ruby-talk:188104]
* COPYING: explicitly note GPLv2. [ruby-talk:187922]
* parse.y: remove some obsolete syntax rules (unparenthesized
method calls in argument list).
* eval.c (rb_call0): insecure calling should be checked for non
NODE_SCOPE method invocations too.
* eval.c (rb_alias): should preserve the current safe level as
well as method definition.
* process.c (rb_f_sleep): remove RDoc description about SIGALRM
which is not valid on the current implementation. [ruby-dev:28464]
Thu Mar 23 21:40:47 2006 K.Kosako <sndgk393 AT ybb.ne.jp>
* eval.c (method_missing): should support argument splat in
super. a bug in combination of super, splat and
method_missing. [ruby-talk:185438]
* configure.in: Solaris SunPro compiler -rapth patch from
<kuwa at labs.fujitsu.com>. [ruby-dev:28443]
* configure.in: remove enable_rpath=no for Solaris.
[ruby-dev:28440]
* ext/win32ole/win32ole.c (ole_val2olevariantdata): change behavior
of converting OLE Variant object with VT_ARRAY|VT_UI1 and Ruby
String object.
* ruby.1: a clarification patch from David Lutterkort
<dlutter at redhat.com>. [ruby-core:7508]
* lib/rdoc/ri/ri_paths.rb (RI::Paths): adding paths from rubygems
directories. a patch from Eric Hodel <drbrain at segment7.net>.
[ruby-core:07423]
* eval.c (rb_clear_cache_by_class): clearing wrong cache.
* ext/extmk.rb: use :remove_destination to install extension libraries
to avoid SEGV. [ruby-dev:28417]
* eval.c (rb_thread_fd_writable): should not re-schedule output
from KILLED thread (must be error printing).
* array.c (rb_ary_flatten_bang): allow specifying recursion
level. [ruby-talk:182170]
* array.c (rb_ary_flatten): ditto.
* gc.c (add_heap): a heap_slots may overflow. a patch from Stefan
Weil <weil at mail.berlios.de>.
* eval.c (rb_call): use separate cache for fcall/vcall
invocation.
* eval.c (rb_eval): NODE_FCALL, NODE_VCALL can call local
functions.
* eval.c (rb_mod_local): a new method to specify newly added
visibility "local".
* eval.c (search_method): search for local methods which are
visible only from the current class.
* class.c (rb_class_local_methods): a method to list local methods.
* object.c (Init_Object): add BasicObject class as a top level
BlankSlate class.
* ruby.h (SYM2ID): should not cast to signed long.
[ruby-core:07414]
* class.c (rb_include_module): allow module duplication.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10235 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2006-06-10 01:20:17 +04:00
|
|
|
VALUE rb_cArray;
|
2004-04-07 06:51:05 +04:00
|
|
|
|
2017-06-30 01:40:36 +03:00
|
|
|
/* for OPTIMIZED_CMP: */
|
|
|
|
#define id_cmp idCmp
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
#define ARY_DEFAULT_SIZE 16
|
* array.c, bignum.c, dln.c, error.c, gc.c, io.c, marshal.c,
numeric.c, pack.c, strftime.c, string.c, thread.c, transcode.c,
transcode_data.h, util.c, variable.c, vm_dump.c,
include/ruby/encoding.h, missing/crypt.c, missing/vsnprintf.c:
suppress VC type warnings. [ruby-core:22726]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22914 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-03-12 12:16:15 +03:00
|
|
|
#define ARY_MAX_SIZE (LONG_MAX / (int)sizeof(VALUE))
|
2017-09-29 10:43:22 +03:00
|
|
|
#define SMALL_ARRAY_LEN 16
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2019-07-19 17:50:30 +03:00
|
|
|
static int
|
|
|
|
should_be_T_ARRAY(VALUE ary)
|
2019-07-19 17:41:24 +03:00
|
|
|
{
|
2019-07-19 17:50:30 +03:00
|
|
|
return RB_TYPE_P(ary, T_ARRAY);
|
2019-07-19 17:41:24 +03:00
|
|
|
}
|
|
|
|
|
2019-07-20 03:08:34 +03:00
|
|
|
static int
|
|
|
|
should_not_be_shared_and_embedded(VALUE ary)
|
|
|
|
{
|
|
|
|
return !FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG);
|
|
|
|
}
|
|
|
|
|
Use FL_TEST_RAW() to check flags.
FL_TEST() uses FL_ABLE() which test data types. However,
in array.c we don't need to check it (all of them should be
T_ARRAY), so I changed from FL_TEST() to FL_TEST_RAW() which
does not check FL_ABLE(). Instead of FL_ABLE(), add assertion
to check given object is a T_ARRAY object.
For example, rb_ary_free() becomes slim:
with FL_TEST():
0000000000006a30 <rb_ary_free>:
6a30: 40 f6 c7 07 test $0x7,%dil
6a34: 48 8b 07 mov (%rdi),%rax
6a37: 75 09 jne 6a42 <rb_ary_free+0x12>
6a39: 48 f7 c7 f7 ff ff ff test $0xfffffffffffffff7,%rdi
6a40: 75 1e jne 6a60 <rb_ary_free+0x30>
6a42: a9 00 00 00 02 test $0x2000000,%eax
6a47: 74 07 je 6a50 <rb_ary_free+0x20>
6a49: f3 c3 repz retq
6a4b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a50: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a54: e9 00 00 00 00 jmpq 6a59 <rb_ary_free+0x29>
6a59: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
6a60: 89 c2 mov %eax,%edx
6a62: 83 e2 1f and $0x1f,%edx
6a65: 83 fa 1b cmp $0x1b,%edx
6a68: 74 d8 je 6a42 <rb_ary_free+0x12>
6a6a: f6 c4 60 test $0x60,%ah
6a6d: 74 d3 je 6a42 <rb_ary_free+0x12>
6a6f: eb d8 jmp 6a49 <rb_ary_free+0x19>```
with FL_TEST_RAW():
0000000000006a30 <rb_ary_free>:
6a30: 48 f7 07 00 60 00 02 testq $0x2006000,(%rdi)
6a37: 74 07 je 6a40 <rb_ary_free+0x10>
6a39: f3 c3 repz retq
6a3b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a40: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a44: e9 00 00 00 00 jmpq 6a49 <rb_ary_free+0x19>
2019-07-19 08:37:59 +03:00
|
|
|
#define ARY_SHARED_P(ary) \
|
2019-07-19 17:50:30 +03:00
|
|
|
(assert(should_be_T_ARRAY((VALUE)(ary))), \
|
2019-07-20 03:08:34 +03:00
|
|
|
assert(should_not_be_shared_and_embedded((VALUE)ary)), \
|
Use FL_TEST_RAW() to check flags.
FL_TEST() uses FL_ABLE() which test data types. However,
in array.c we don't need to check it (all of them should be
T_ARRAY), so I changed from FL_TEST() to FL_TEST_RAW() which
does not check FL_ABLE(). Instead of FL_ABLE(), add assertion
to check given object is a T_ARRAY object.
For example, rb_ary_free() becomes slim:
with FL_TEST():
0000000000006a30 <rb_ary_free>:
6a30: 40 f6 c7 07 test $0x7,%dil
6a34: 48 8b 07 mov (%rdi),%rax
6a37: 75 09 jne 6a42 <rb_ary_free+0x12>
6a39: 48 f7 c7 f7 ff ff ff test $0xfffffffffffffff7,%rdi
6a40: 75 1e jne 6a60 <rb_ary_free+0x30>
6a42: a9 00 00 00 02 test $0x2000000,%eax
6a47: 74 07 je 6a50 <rb_ary_free+0x20>
6a49: f3 c3 repz retq
6a4b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a50: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a54: e9 00 00 00 00 jmpq 6a59 <rb_ary_free+0x29>
6a59: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
6a60: 89 c2 mov %eax,%edx
6a62: 83 e2 1f and $0x1f,%edx
6a65: 83 fa 1b cmp $0x1b,%edx
6a68: 74 d8 je 6a42 <rb_ary_free+0x12>
6a6a: f6 c4 60 test $0x60,%ah
6a6d: 74 d3 je 6a42 <rb_ary_free+0x12>
6a6f: eb d8 jmp 6a49 <rb_ary_free+0x19>```
with FL_TEST_RAW():
0000000000006a30 <rb_ary_free>:
6a30: 48 f7 07 00 60 00 02 testq $0x2006000,(%rdi)
6a37: 74 07 je 6a40 <rb_ary_free+0x10>
6a39: f3 c3 repz retq
6a3b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a40: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a44: e9 00 00 00 00 jmpq 6a49 <rb_ary_free+0x19>
2019-07-19 08:37:59 +03:00
|
|
|
FL_TEST_RAW((ary),ELTS_SHARED)!=0)
|
|
|
|
|
|
|
|
#define ARY_EMBED_P(ary) \
|
2019-07-19 17:50:30 +03:00
|
|
|
(assert(should_be_T_ARRAY((VALUE)(ary))), \
|
2019-07-20 03:08:34 +03:00
|
|
|
assert(should_not_be_shared_and_embedded((VALUE)ary)), \
|
Use FL_TEST_RAW() to check flags.
FL_TEST() uses FL_ABLE() which test data types. However,
in array.c we don't need to check it (all of them should be
T_ARRAY), so I changed from FL_TEST() to FL_TEST_RAW() which
does not check FL_ABLE(). Instead of FL_ABLE(), add assertion
to check given object is a T_ARRAY object.
For example, rb_ary_free() becomes slim:
with FL_TEST():
0000000000006a30 <rb_ary_free>:
6a30: 40 f6 c7 07 test $0x7,%dil
6a34: 48 8b 07 mov (%rdi),%rax
6a37: 75 09 jne 6a42 <rb_ary_free+0x12>
6a39: 48 f7 c7 f7 ff ff ff test $0xfffffffffffffff7,%rdi
6a40: 75 1e jne 6a60 <rb_ary_free+0x30>
6a42: a9 00 00 00 02 test $0x2000000,%eax
6a47: 74 07 je 6a50 <rb_ary_free+0x20>
6a49: f3 c3 repz retq
6a4b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a50: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a54: e9 00 00 00 00 jmpq 6a59 <rb_ary_free+0x29>
6a59: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
6a60: 89 c2 mov %eax,%edx
6a62: 83 e2 1f and $0x1f,%edx
6a65: 83 fa 1b cmp $0x1b,%edx
6a68: 74 d8 je 6a42 <rb_ary_free+0x12>
6a6a: f6 c4 60 test $0x60,%ah
6a6d: 74 d3 je 6a42 <rb_ary_free+0x12>
6a6f: eb d8 jmp 6a49 <rb_ary_free+0x19>```
with FL_TEST_RAW():
0000000000006a30 <rb_ary_free>:
6a30: 48 f7 07 00 60 00 02 testq $0x2006000,(%rdi)
6a37: 74 07 je 6a40 <rb_ary_free+0x10>
6a39: f3 c3 repz retq
6a3b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a40: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a44: e9 00 00 00 00 jmpq 6a49 <rb_ary_free+0x19>
2019-07-19 08:37:59 +03:00
|
|
|
FL_TEST_RAW((ary), RARRAY_EMBED_FLAG) != 0)
|
2006-09-02 18:42:08 +04:00
|
|
|
|
2008-10-09 09:47:04 +04:00
|
|
|
#define ARY_HEAP_PTR(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.ptr)
|
|
|
|
#define ARY_HEAP_LEN(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.len)
|
Use FL_TEST_RAW() to check flags.
FL_TEST() uses FL_ABLE() which test data types. However,
in array.c we don't need to check it (all of them should be
T_ARRAY), so I changed from FL_TEST() to FL_TEST_RAW() which
does not check FL_ABLE(). Instead of FL_ABLE(), add assertion
to check given object is a T_ARRAY object.
For example, rb_ary_free() becomes slim:
with FL_TEST():
0000000000006a30 <rb_ary_free>:
6a30: 40 f6 c7 07 test $0x7,%dil
6a34: 48 8b 07 mov (%rdi),%rax
6a37: 75 09 jne 6a42 <rb_ary_free+0x12>
6a39: 48 f7 c7 f7 ff ff ff test $0xfffffffffffffff7,%rdi
6a40: 75 1e jne 6a60 <rb_ary_free+0x30>
6a42: a9 00 00 00 02 test $0x2000000,%eax
6a47: 74 07 je 6a50 <rb_ary_free+0x20>
6a49: f3 c3 repz retq
6a4b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a50: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a54: e9 00 00 00 00 jmpq 6a59 <rb_ary_free+0x29>
6a59: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
6a60: 89 c2 mov %eax,%edx
6a62: 83 e2 1f and $0x1f,%edx
6a65: 83 fa 1b cmp $0x1b,%edx
6a68: 74 d8 je 6a42 <rb_ary_free+0x12>
6a6a: f6 c4 60 test $0x60,%ah
6a6d: 74 d3 je 6a42 <rb_ary_free+0x12>
6a6f: eb d8 jmp 6a49 <rb_ary_free+0x19>```
with FL_TEST_RAW():
0000000000006a30 <rb_ary_free>:
6a30: 48 f7 07 00 60 00 02 testq $0x2006000,(%rdi)
6a37: 74 07 je 6a40 <rb_ary_free+0x10>
6a39: f3 c3 repz retq
6a3b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a40: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a44: e9 00 00 00 00 jmpq 6a49 <rb_ary_free+0x19>
2019-07-19 08:37:59 +03:00
|
|
|
#define ARY_HEAP_CAPA(a) (assert(!ARY_EMBED_P(a)), assert(!ARY_SHARED_ROOT_P(a)), \
|
|
|
|
RARRAY(a)->as.heap.aux.capa)
|
2018-10-31 00:53:56 +03:00
|
|
|
|
2008-10-09 09:47:04 +04:00
|
|
|
#define ARY_EMBED_PTR(a) (assert(ARY_EMBED_P(a)), RARRAY(a)->as.ary)
|
|
|
|
#define ARY_EMBED_LEN(a) \
|
|
|
|
(assert(ARY_EMBED_P(a)), \
|
|
|
|
(long)((RBASIC(a)->flags >> RARRAY_EMBED_LEN_SHIFT) & \
|
|
|
|
(RARRAY_EMBED_LEN_MASK >> RARRAY_EMBED_LEN_SHIFT)))
|
2019-06-23 22:28:22 +03:00
|
|
|
#define ARY_HEAP_SIZE(a) (assert(!ARY_EMBED_P(a)), assert(ARY_OWNS_HEAP_P(a)), ARY_CAPA(a) * sizeof(VALUE))
|
2008-10-09 09:47:04 +04:00
|
|
|
|
2019-07-19 17:50:30 +03:00
|
|
|
#define ARY_OWNS_HEAP_P(a) (assert(should_be_T_ARRAY((VALUE)(a))), \
|
Use FL_TEST_RAW() to check flags.
FL_TEST() uses FL_ABLE() which test data types. However,
in array.c we don't need to check it (all of them should be
T_ARRAY), so I changed from FL_TEST() to FL_TEST_RAW() which
does not check FL_ABLE(). Instead of FL_ABLE(), add assertion
to check given object is a T_ARRAY object.
For example, rb_ary_free() becomes slim:
with FL_TEST():
0000000000006a30 <rb_ary_free>:
6a30: 40 f6 c7 07 test $0x7,%dil
6a34: 48 8b 07 mov (%rdi),%rax
6a37: 75 09 jne 6a42 <rb_ary_free+0x12>
6a39: 48 f7 c7 f7 ff ff ff test $0xfffffffffffffff7,%rdi
6a40: 75 1e jne 6a60 <rb_ary_free+0x30>
6a42: a9 00 00 00 02 test $0x2000000,%eax
6a47: 74 07 je 6a50 <rb_ary_free+0x20>
6a49: f3 c3 repz retq
6a4b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a50: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a54: e9 00 00 00 00 jmpq 6a59 <rb_ary_free+0x29>
6a59: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
6a60: 89 c2 mov %eax,%edx
6a62: 83 e2 1f and $0x1f,%edx
6a65: 83 fa 1b cmp $0x1b,%edx
6a68: 74 d8 je 6a42 <rb_ary_free+0x12>
6a6a: f6 c4 60 test $0x60,%ah
6a6d: 74 d3 je 6a42 <rb_ary_free+0x12>
6a6f: eb d8 jmp 6a49 <rb_ary_free+0x19>```
with FL_TEST_RAW():
0000000000006a30 <rb_ary_free>:
6a30: 48 f7 07 00 60 00 02 testq $0x2006000,(%rdi)
6a37: 74 07 je 6a40 <rb_ary_free+0x10>
6a39: f3 c3 repz retq
6a3b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a40: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a44: e9 00 00 00 00 jmpq 6a49 <rb_ary_free+0x19>
2019-07-19 08:37:59 +03:00
|
|
|
!FL_TEST_RAW((a), ELTS_SHARED|RARRAY_EMBED_FLAG))
|
|
|
|
|
2008-10-09 09:47:04 +04:00
|
|
|
#define FL_SET_EMBED(a) do { \
|
|
|
|
assert(!ARY_SHARED_P(a)); \
|
2010-12-01 15:44:03 +03:00
|
|
|
FL_SET((a), RARRAY_EMBED_FLAG); \
|
2018-11-01 11:53:44 +03:00
|
|
|
RARY_TRANSIENT_UNSET(a); \
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(a); \
|
2008-10-09 09:47:04 +04:00
|
|
|
} while (0)
|
Use FL_TEST_RAW() to check flags.
FL_TEST() uses FL_ABLE() which test data types. However,
in array.c we don't need to check it (all of them should be
T_ARRAY), so I changed from FL_TEST() to FL_TEST_RAW() which
does not check FL_ABLE(). Instead of FL_ABLE(), add assertion
to check given object is a T_ARRAY object.
For example, rb_ary_free() becomes slim:
with FL_TEST():
0000000000006a30 <rb_ary_free>:
6a30: 40 f6 c7 07 test $0x7,%dil
6a34: 48 8b 07 mov (%rdi),%rax
6a37: 75 09 jne 6a42 <rb_ary_free+0x12>
6a39: 48 f7 c7 f7 ff ff ff test $0xfffffffffffffff7,%rdi
6a40: 75 1e jne 6a60 <rb_ary_free+0x30>
6a42: a9 00 00 00 02 test $0x2000000,%eax
6a47: 74 07 je 6a50 <rb_ary_free+0x20>
6a49: f3 c3 repz retq
6a4b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a50: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a54: e9 00 00 00 00 jmpq 6a59 <rb_ary_free+0x29>
6a59: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
6a60: 89 c2 mov %eax,%edx
6a62: 83 e2 1f and $0x1f,%edx
6a65: 83 fa 1b cmp $0x1b,%edx
6a68: 74 d8 je 6a42 <rb_ary_free+0x12>
6a6a: f6 c4 60 test $0x60,%ah
6a6d: 74 d3 je 6a42 <rb_ary_free+0x12>
6a6f: eb d8 jmp 6a49 <rb_ary_free+0x19>```
with FL_TEST_RAW():
0000000000006a30 <rb_ary_free>:
6a30: 48 f7 07 00 60 00 02 testq $0x2006000,(%rdi)
6a37: 74 07 je 6a40 <rb_ary_free+0x10>
6a39: f3 c3 repz retq
6a3b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a40: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a44: e9 00 00 00 00 jmpq 6a49 <rb_ary_free+0x19>
2019-07-19 08:37:59 +03:00
|
|
|
|
2010-12-01 15:44:03 +03:00
|
|
|
#define FL_UNSET_EMBED(ary) FL_UNSET((ary), RARRAY_EMBED_FLAG|RARRAY_EMBED_LEN_MASK)
|
2008-10-09 09:47:04 +04:00
|
|
|
#define FL_SET_SHARED(ary) do { \
|
|
|
|
assert(!ARY_EMBED_P(ary)); \
|
2010-12-01 15:44:03 +03:00
|
|
|
FL_SET((ary), ELTS_SHARED); \
|
2008-10-09 09:47:04 +04:00
|
|
|
} while (0)
|
2010-12-01 15:44:03 +03:00
|
|
|
#define FL_UNSET_SHARED(ary) FL_UNSET((ary), ELTS_SHARED)
|
2008-10-09 09:47:04 +04:00
|
|
|
|
|
|
|
#define ARY_SET_PTR(ary, p) do { \
|
|
|
|
assert(!ARY_EMBED_P(ary)); \
|
|
|
|
assert(!OBJ_FROZEN(ary)); \
|
|
|
|
RARRAY(ary)->as.heap.ptr = (p); \
|
|
|
|
} while (0)
|
|
|
|
#define ARY_SET_EMBED_LEN(ary, n) do { \
|
2010-12-01 15:44:03 +03:00
|
|
|
long tmp_n = (n); \
|
2008-10-09 09:47:04 +04:00
|
|
|
assert(ARY_EMBED_P(ary)); \
|
|
|
|
assert(!OBJ_FROZEN(ary)); \
|
|
|
|
RBASIC(ary)->flags &= ~RARRAY_EMBED_LEN_MASK; \
|
|
|
|
RBASIC(ary)->flags |= (tmp_n) << RARRAY_EMBED_LEN_SHIFT; \
|
|
|
|
} while (0)
|
|
|
|
#define ARY_SET_HEAP_LEN(ary, n) do { \
|
|
|
|
assert(!ARY_EMBED_P(ary)); \
|
2010-12-01 15:44:03 +03:00
|
|
|
RARRAY(ary)->as.heap.len = (n); \
|
2008-10-09 09:47:04 +04:00
|
|
|
} while (0)
|
2006-09-02 18:42:08 +04:00
|
|
|
#define ARY_SET_LEN(ary, n) do { \
|
2008-10-09 09:47:04 +04:00
|
|
|
if (ARY_EMBED_P(ary)) { \
|
2010-12-01 15:44:03 +03:00
|
|
|
ARY_SET_EMBED_LEN((ary), (n)); \
|
2008-10-09 09:47:04 +04:00
|
|
|
} \
|
|
|
|
else { \
|
2010-12-01 15:44:03 +03:00
|
|
|
ARY_SET_HEAP_LEN((ary), (n)); \
|
2008-10-09 09:47:04 +04:00
|
|
|
} \
|
2010-12-01 15:44:03 +03:00
|
|
|
assert(RARRAY_LEN(ary) == (n)); \
|
2009-02-22 17:23:33 +03:00
|
|
|
} while (0)
|
2008-10-09 09:47:04 +04:00
|
|
|
#define ARY_INCREASE_PTR(ary, n) do { \
|
|
|
|
assert(!ARY_EMBED_P(ary)); \
|
|
|
|
assert(!OBJ_FROZEN(ary)); \
|
2010-12-01 15:44:03 +03:00
|
|
|
RARRAY(ary)->as.heap.ptr += (n); \
|
2008-10-09 09:47:04 +04:00
|
|
|
} while (0)
|
|
|
|
#define ARY_INCREASE_LEN(ary, n) do { \
|
|
|
|
assert(!OBJ_FROZEN(ary)); \
|
|
|
|
if (ARY_EMBED_P(ary)) { \
|
2010-12-01 15:44:03 +03:00
|
|
|
ARY_SET_EMBED_LEN((ary), RARRAY_LEN(ary)+(n)); \
|
2008-10-09 09:47:04 +04:00
|
|
|
} \
|
|
|
|
else { \
|
2010-12-01 15:44:03 +03:00
|
|
|
RARRAY(ary)->as.heap.len += (n); \
|
2008-10-09 09:47:04 +04:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2008-10-17 17:09:33 +04:00
|
|
|
#define ARY_CAPA(ary) (ARY_EMBED_P(ary) ? RARRAY_EMBED_LEN_MAX : \
|
2018-10-31 00:54:13 +03:00
|
|
|
ARY_SHARED_ROOT_P(ary) ? RARRAY_LEN(ary) : ARY_HEAP_CAPA(ary))
|
2008-10-09 09:47:04 +04:00
|
|
|
#define ARY_SET_CAPA(ary, n) do { \
|
|
|
|
assert(!ARY_EMBED_P(ary)); \
|
|
|
|
assert(!ARY_SHARED_P(ary)); \
|
|
|
|
assert(!OBJ_FROZEN(ary)); \
|
|
|
|
RARRAY(ary)->as.heap.aux.capa = (n); \
|
|
|
|
} while (0)
|
2006-09-02 18:42:08 +04:00
|
|
|
|
2019-07-19 07:02:38 +03:00
|
|
|
#define ARY_SHARED_ROOT(ary) (assert(ARY_SHARED_P(ary)), RARRAY(ary)->as.heap.aux.shared_root)
|
2008-10-09 09:47:04 +04:00
|
|
|
#define ARY_SET_SHARED(ary, value) do { \
|
* gc.c: support RGENGC. [ruby-trunk - Feature #8339]
See this ticet about RGENGC.
* gc.c: Add several flags:
* RGENGC_DEBUG: if >0, then prints debug information.
* RGENGC_CHECK_MODE: if >0, add assertions.
* RGENGC_PROFILE: if >0, add profiling features.
check GC.stat and GC::Profiler.
* include/ruby/ruby.h: disable RGENGC by default (USE_RGENGC == 0).
* array.c: add write barriers for T_ARRAY and generate sunny objects.
* include/ruby/ruby.h (RARRAY_PTR_USE): added. Use this macro if
you want to access raw pointers. If you modify the contents which
pointer pointed, then you need to care write barrier.
* bignum.c, marshal.c, random.c: generate T_BIGNUM sunny objects.
* complex.c, include/ruby/ruby.h: add write barriers for T_COMPLEX
and generate sunny objects.
* rational.c (nurat_s_new_internal), include/ruby/ruby.h: add write
barriers for T_RATIONAL and generate sunny objects.
* internal.h: add write barriers for RBasic::klass.
* numeric.c (rb_float_new_in_heap): generate sunny T_FLOAT objects.
* object.c (rb_class_allocate_instance), range.c:
generate sunny T_OBJECT objects.
* string.c: add write barriers for T_STRING and generate sunny objects.
* variable.c: add write barriers for ivars.
* vm_insnhelper.c (vm_setivar): ditto.
* include/ruby/ruby.h, debug.c: use two flags
FL_WB_PROTECTED and FL_OLDGEN.
* node.h (NODE_FL_CREF_PUSHED_BY_EVAL, NODE_FL_CREF_OMOD_SHARED):
move flag bits.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40703 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 22:07:47 +04:00
|
|
|
const VALUE _ary_ = (ary); \
|
|
|
|
const VALUE _value_ = (value); \
|
|
|
|
assert(!ARY_EMBED_P(_ary_)); \
|
|
|
|
assert(ARY_SHARED_P(_ary_)); \
|
|
|
|
assert(ARY_SHARED_ROOT_P(_value_)); \
|
2019-07-19 07:02:38 +03:00
|
|
|
RB_OBJ_WRITE(_ary_, &RARRAY(_ary_)->as.heap.aux.shared_root, _value_); \
|
2006-09-02 18:42:08 +04:00
|
|
|
} while (0)
|
2008-10-17 17:09:33 +04:00
|
|
|
#define RARRAY_SHARED_ROOT_FLAG FL_USER5
|
2019-07-19 17:50:30 +03:00
|
|
|
#define ARY_SHARED_ROOT_P(ary) (assert(should_be_T_ARRAY((VALUE)(ary))), \
|
Use FL_TEST_RAW() to check flags.
FL_TEST() uses FL_ABLE() which test data types. However,
in array.c we don't need to check it (all of them should be
T_ARRAY), so I changed from FL_TEST() to FL_TEST_RAW() which
does not check FL_ABLE(). Instead of FL_ABLE(), add assertion
to check given object is a T_ARRAY object.
For example, rb_ary_free() becomes slim:
with FL_TEST():
0000000000006a30 <rb_ary_free>:
6a30: 40 f6 c7 07 test $0x7,%dil
6a34: 48 8b 07 mov (%rdi),%rax
6a37: 75 09 jne 6a42 <rb_ary_free+0x12>
6a39: 48 f7 c7 f7 ff ff ff test $0xfffffffffffffff7,%rdi
6a40: 75 1e jne 6a60 <rb_ary_free+0x30>
6a42: a9 00 00 00 02 test $0x2000000,%eax
6a47: 74 07 je 6a50 <rb_ary_free+0x20>
6a49: f3 c3 repz retq
6a4b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a50: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a54: e9 00 00 00 00 jmpq 6a59 <rb_ary_free+0x29>
6a59: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
6a60: 89 c2 mov %eax,%edx
6a62: 83 e2 1f and $0x1f,%edx
6a65: 83 fa 1b cmp $0x1b,%edx
6a68: 74 d8 je 6a42 <rb_ary_free+0x12>
6a6a: f6 c4 60 test $0x60,%ah
6a6d: 74 d3 je 6a42 <rb_ary_free+0x12>
6a6f: eb d8 jmp 6a49 <rb_ary_free+0x19>```
with FL_TEST_RAW():
0000000000006a30 <rb_ary_free>:
6a30: 48 f7 07 00 60 00 02 testq $0x2006000,(%rdi)
6a37: 74 07 je 6a40 <rb_ary_free+0x10>
6a39: f3 c3 repz retq
6a3b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a40: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a44: e9 00 00 00 00 jmpq 6a49 <rb_ary_free+0x19>
2019-07-19 08:37:59 +03:00
|
|
|
FL_TEST_RAW((ary), RARRAY_SHARED_ROOT_FLAG))
|
2019-07-19 07:02:38 +03:00
|
|
|
#define ARY_SHARED_ROOT_REFCNT(ary) \
|
2008-10-17 17:09:33 +04:00
|
|
|
(assert(ARY_SHARED_ROOT_P(ary)), RARRAY(ary)->as.heap.aux.capa)
|
2019-07-19 07:02:38 +03:00
|
|
|
#define ARY_SHARED_ROOT_OCCUPIED(ary) (ARY_SHARED_ROOT_REFCNT(ary) == 1)
|
|
|
|
#define ARY_SET_SHARED_ROOT_REFCNT(ary, value) do { \
|
2008-10-17 17:09:33 +04:00
|
|
|
assert(ARY_SHARED_ROOT_P(ary)); \
|
|
|
|
RARRAY(ary)->as.heap.aux.capa = (value); \
|
|
|
|
} while (0)
|
|
|
|
#define FL_SET_SHARED_ROOT(ary) do { \
|
|
|
|
assert(!ARY_EMBED_P(ary)); \
|
2018-10-31 00:53:56 +03:00
|
|
|
assert(!RARRAY_TRANSIENT_P(ary)); \
|
2010-12-01 15:44:03 +03:00
|
|
|
FL_SET((ary), RARRAY_SHARED_ROOT_FLAG); \
|
2008-10-17 17:09:33 +04:00
|
|
|
} while (0)
|
2006-09-02 18:42:08 +04:00
|
|
|
|
2019-05-21 08:58:39 +03:00
|
|
|
static inline void
|
|
|
|
ARY_SET(VALUE a, long i, VALUE v)
|
|
|
|
{
|
|
|
|
assert(!ARY_SHARED_P(a));
|
|
|
|
assert(!OBJ_FROZEN(a));
|
|
|
|
|
|
|
|
RARRAY_ASET(a, i, v);
|
|
|
|
}
|
|
|
|
#undef RARRAY_ASET
|
2014-04-11 13:55:10 +04:00
|
|
|
|
2018-10-31 00:53:56 +03:00
|
|
|
|
|
|
|
#if ARRAY_DEBUG
|
|
|
|
#define ary_verify(ary) ary_verify_(ary, __FILE__, __LINE__)
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
ary_verify_(VALUE ary, const char *file, int line)
|
|
|
|
{
|
|
|
|
assert(RB_TYPE_P(ary, T_ARRAY));
|
|
|
|
|
|
|
|
if (FL_TEST(ary, ELTS_SHARED)) {
|
2019-07-19 07:02:38 +03:00
|
|
|
VALUE root = RARRAY(ary)->as.heap.aux.shared_root;
|
2018-10-31 00:53:56 +03:00
|
|
|
const VALUE *ptr = ARY_HEAP_PTR(ary);
|
|
|
|
const VALUE *root_ptr = RARRAY_CONST_PTR_TRANSIENT(root);
|
|
|
|
long len = ARY_HEAP_LEN(ary), root_len = RARRAY_LEN(root);
|
|
|
|
assert(FL_TEST(root, RARRAY_SHARED_ROOT_FLAG));
|
|
|
|
assert(root_ptr <= ptr && ptr + len <= root_ptr + root_len);
|
|
|
|
ary_verify(root);
|
|
|
|
}
|
|
|
|
else if (ARY_EMBED_P(ary)) {
|
|
|
|
assert(!RARRAY_TRANSIENT_P(ary));
|
|
|
|
assert(!ARY_SHARED_P(ary));
|
|
|
|
assert(RARRAY_LEN(ary) <= RARRAY_EMBED_LEN_MAX);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
#if 1
|
|
|
|
const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
|
|
|
|
long i, len = RARRAY_LEN(ary);
|
|
|
|
volatile VALUE v;
|
|
|
|
if (len > 1) len = 1; /* check only HEAD */
|
|
|
|
for (i=0; i<len; i++) {
|
|
|
|
v = ptr[i]; /* access check */
|
|
|
|
}
|
|
|
|
v = v;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-02-25 06:42:00 +03:00
|
|
|
#if USE_TRANSIENT_HEAP
|
2018-10-31 00:53:56 +03:00
|
|
|
if (RARRAY_TRANSIENT_P(ary)) {
|
|
|
|
assert(rb_transient_heap_managed_ptr_p(RARRAY_CONST_PTR_TRANSIENT(ary)));
|
|
|
|
}
|
2020-02-25 06:42:00 +03:00
|
|
|
#endif
|
2018-10-31 00:53:56 +03:00
|
|
|
|
|
|
|
rb_transient_heap_verify();
|
|
|
|
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-01-09 16:58:49 +03:00
|
|
|
rb_ary_verify(VALUE ary)
|
|
|
|
{
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define ary_verify(ary) ((void)0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
VALUE *
|
|
|
|
rb_ary_ptr_use_start(VALUE ary)
|
|
|
|
{
|
|
|
|
#if ARRAY_DEBUG
|
|
|
|
FL_SET_RAW(ary, RARRAY_PTR_IN_USE_FLAG);
|
|
|
|
#endif
|
|
|
|
return (VALUE *)RARRAY_CONST_PTR_TRANSIENT(ary);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_ary_ptr_use_end(VALUE ary)
|
|
|
|
{
|
|
|
|
#if ARRAY_DEBUG
|
|
|
|
FL_UNSET_RAW(ary, RARRAY_PTR_IN_USE_FLAG);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-04-11 12:47:00 +04:00
|
|
|
void
|
2019-10-04 10:07:46 +03:00
|
|
|
rb_mem_clear(VALUE *mem, long size)
|
2014-04-11 12:47:00 +04:00
|
|
|
{
|
|
|
|
while (size--) {
|
|
|
|
*mem++ = Qnil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ary_mem_clear(VALUE ary, long beg, long size)
|
|
|
|
{
|
2018-12-03 15:36:39 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
2014-04-11 12:47:00 +04:00
|
|
|
rb_mem_clear(ptr + beg, size);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
memfill(register VALUE *mem, register long size, register VALUE val)
|
|
|
|
{
|
|
|
|
while (size--) {
|
|
|
|
*mem++ = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ary_memfill(VALUE ary, long beg, long size, VALUE val)
|
|
|
|
{
|
2018-12-03 15:36:39 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
2014-04-11 12:47:00 +04:00
|
|
|
memfill(ptr + beg, size, val);
|
|
|
|
RB_OBJ_WRITTEN(ary, Qundef, val);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ary_memcpy0(VALUE ary, long beg, long argc, const VALUE *argv, VALUE buff_owner_ary)
|
|
|
|
{
|
|
|
|
assert(!ARY_SHARED_P(buff_owner_ary));
|
|
|
|
|
2014-09-08 08:11:00 +04:00
|
|
|
if (argc > (int)(128/sizeof(VALUE)) /* is magic number (cache line size) */) {
|
2018-10-10 06:52:20 +03:00
|
|
|
rb_gc_writebarrier_remember(buff_owner_ary);
|
2018-12-03 15:36:39 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
2018-10-10 06:52:20 +03:00
|
|
|
MEMCPY(ptr+beg, argv, VALUE, argc);
|
|
|
|
});
|
2014-04-11 12:47:00 +04:00
|
|
|
}
|
|
|
|
else {
|
2018-10-10 06:52:20 +03:00
|
|
|
int i;
|
2018-12-03 15:36:39 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
2018-10-10 06:52:20 +03:00
|
|
|
for (i=0; i<argc; i++) {
|
|
|
|
RB_OBJ_WRITE(buff_owner_ary, &ptr[i+beg], argv[i]);
|
|
|
|
}
|
|
|
|
});
|
2014-04-11 12:47:00 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ary_memcpy(VALUE ary, long beg, long argc, const VALUE *argv)
|
|
|
|
{
|
|
|
|
ary_memcpy0(ary, beg, argc, argv, ary);
|
|
|
|
}
|
|
|
|
|
2018-10-31 00:53:56 +03:00
|
|
|
static VALUE *
|
|
|
|
ary_heap_alloc(VALUE ary, size_t capa)
|
|
|
|
{
|
|
|
|
VALUE *ptr = rb_transient_heap_alloc(ary, sizeof(VALUE) * capa);
|
|
|
|
|
|
|
|
if (ptr != NULL) {
|
2018-11-01 11:53:44 +03:00
|
|
|
RARY_TRANSIENT_SET(ary);
|
2018-10-31 00:53:56 +03:00
|
|
|
}
|
|
|
|
else {
|
2018-11-01 11:53:44 +03:00
|
|
|
RARY_TRANSIENT_UNSET(ary);
|
2018-10-31 00:53:56 +03:00
|
|
|
ptr = ALLOC_N(VALUE, capa);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ary_heap_free_ptr(VALUE ary, const VALUE *ptr, long size)
|
|
|
|
{
|
|
|
|
if (RARRAY_TRANSIENT_P(ary)) {
|
|
|
|
/* ignore it */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ruby_sized_xfree((void *)ptr, size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ary_heap_free(VALUE ary)
|
|
|
|
{
|
|
|
|
if (RARRAY_TRANSIENT_P(ary)) {
|
2018-11-01 11:53:44 +03:00
|
|
|
RARY_TRANSIENT_UNSET(ary);
|
2018-10-31 00:53:56 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
ary_heap_free_ptr(ary, ARY_HEAP_PTR(ary), ARY_HEAP_SIZE(ary));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ary_heap_realloc(VALUE ary, size_t new_capa)
|
|
|
|
{
|
|
|
|
size_t old_capa = ARY_HEAP_CAPA(ary);
|
|
|
|
|
|
|
|
if (RARRAY_TRANSIENT_P(ary)) {
|
|
|
|
if (new_capa <= old_capa) {
|
|
|
|
/* do nothing */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VALUE *new_ptr = rb_transient_heap_alloc(ary, sizeof(VALUE) * new_capa);
|
|
|
|
|
|
|
|
if (new_ptr == NULL) {
|
|
|
|
new_ptr = ALLOC_N(VALUE, new_capa);
|
2018-11-01 11:53:44 +03:00
|
|
|
RARY_TRANSIENT_UNSET(ary);
|
2018-10-31 00:53:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
MEMCPY(new_ptr, ARY_HEAP_PTR(ary), VALUE, old_capa);
|
|
|
|
ARY_SET_PTR(ary, new_ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, new_capa, old_capa);
|
|
|
|
}
|
|
|
|
ary_verify(ary);
|
|
|
|
}
|
|
|
|
|
2018-11-01 11:53:44 +03:00
|
|
|
#if USE_TRANSIENT_HEAP
|
2018-10-31 00:53:56 +03:00
|
|
|
static inline void
|
|
|
|
rb_ary_transient_heap_evacuate_(VALUE ary, int transient, int promote)
|
|
|
|
{
|
|
|
|
if (transient) {
|
|
|
|
VALUE *new_ptr;
|
|
|
|
const VALUE *old_ptr = ARY_HEAP_PTR(ary);
|
|
|
|
long capa = ARY_HEAP_CAPA(ary);
|
|
|
|
long len = ARY_HEAP_LEN(ary);
|
|
|
|
|
|
|
|
if (ARY_SHARED_ROOT_P(ary)) {
|
|
|
|
capa = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(ARY_OWNS_HEAP_P(ary));
|
|
|
|
assert(RARRAY_TRANSIENT_P(ary));
|
|
|
|
assert(!ARY_PTR_USING_P(ary));
|
|
|
|
|
|
|
|
if (promote) {
|
|
|
|
new_ptr = ALLOC_N(VALUE, capa);
|
2018-11-01 11:53:44 +03:00
|
|
|
RARY_TRANSIENT_UNSET(ary);
|
2018-10-31 00:53:56 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
new_ptr = ary_heap_alloc(ary, capa);
|
|
|
|
}
|
|
|
|
|
|
|
|
MEMCPY(new_ptr, old_ptr, VALUE, capa);
|
|
|
|
/* do not use ARY_SET_PTR() because they assert !frozen */
|
|
|
|
RARRAY(ary)->as.heap.ptr = new_ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
ary_verify(ary);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_ary_transient_heap_evacuate(VALUE ary, int promote)
|
|
|
|
{
|
|
|
|
rb_ary_transient_heap_evacuate_(ary, RARRAY_TRANSIENT_P(ary), promote);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_ary_detransient(VALUE ary)
|
|
|
|
{
|
|
|
|
assert(RARRAY_TRANSIENT_P(ary));
|
|
|
|
rb_ary_transient_heap_evacuate_(ary, TRUE, TRUE);
|
|
|
|
}
|
2018-11-01 11:53:44 +03:00
|
|
|
#else
|
|
|
|
void
|
|
|
|
rb_ary_detransient(VALUE ary)
|
|
|
|
{
|
|
|
|
/* do nothing */
|
|
|
|
}
|
|
|
|
#endif
|
2018-10-31 00:53:56 +03:00
|
|
|
|
2008-10-09 09:47:04 +04:00
|
|
|
static void
|
2008-10-17 14:42:11 +04:00
|
|
|
ary_resize_capa(VALUE ary, long capacity)
|
2008-10-09 09:47:04 +04:00
|
|
|
{
|
2008-10-15 17:21:37 +04:00
|
|
|
assert(RARRAY_LEN(ary) <= capacity);
|
2009-02-22 17:23:33 +03:00
|
|
|
assert(!OBJ_FROZEN(ary));
|
|
|
|
assert(!ARY_SHARED_P(ary));
|
2018-10-31 00:53:56 +03:00
|
|
|
|
2008-10-09 09:47:04 +04:00
|
|
|
if (capacity > RARRAY_EMBED_LEN_MAX) {
|
|
|
|
if (ARY_EMBED_P(ary)) {
|
2009-02-22 17:23:33 +03:00
|
|
|
long len = ARY_EMBED_LEN(ary);
|
2018-10-31 00:53:56 +03:00
|
|
|
VALUE *ptr = ary_heap_alloc(ary, capacity);
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
MEMCPY(ptr, ARY_EMBED_PTR(ary), VALUE, len);
|
|
|
|
FL_UNSET_EMBED(ary);
|
|
|
|
ARY_SET_PTR(ary, ptr);
|
|
|
|
ARY_SET_HEAP_LEN(ary, len);
|
2008-10-09 09:47:04 +04:00
|
|
|
}
|
2009-02-22 17:23:33 +03:00
|
|
|
else {
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_heap_realloc(ary, capacity);
|
2008-10-09 09:47:04 +04:00
|
|
|
}
|
2018-10-31 00:53:56 +03:00
|
|
|
ARY_SET_CAPA(ary, capacity);
|
2008-10-09 09:47:04 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (!ARY_EMBED_P(ary)) {
|
2018-10-31 00:53:56 +03:00
|
|
|
long len = ARY_HEAP_LEN(ary);
|
|
|
|
long old_capa = ARY_HEAP_CAPA(ary);
|
2018-10-31 00:54:13 +03:00
|
|
|
const VALUE *ptr = ARY_HEAP_PTR(ary);
|
2013-10-17 12:35:06 +04:00
|
|
|
|
2018-10-31 00:02:12 +03:00
|
|
|
if (len > capacity) len = capacity;
|
2013-06-21 15:53:33 +04:00
|
|
|
MEMCPY((VALUE *)RARRAY(ary)->as.ary, ptr, VALUE, len);
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_heap_free_ptr(ary, ptr, old_capa);
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
FL_SET_EMBED(ary);
|
|
|
|
ARY_SET_LEN(ary, len);
|
2008-10-09 09:47:04 +04:00
|
|
|
}
|
|
|
|
}
|
2018-10-31 00:53:56 +03:00
|
|
|
|
|
|
|
ary_verify(ary);
|
2008-10-09 09:47:04 +04:00
|
|
|
}
|
|
|
|
|
2013-06-12 07:00:17 +04:00
|
|
|
static inline void
|
2013-06-11 11:15:24 +04:00
|
|
|
ary_shrink_capa(VALUE ary)
|
|
|
|
{
|
|
|
|
long capacity = ARY_HEAP_LEN(ary);
|
2018-10-31 00:53:56 +03:00
|
|
|
long old_capa = ARY_HEAP_CAPA(ary);
|
2013-06-12 07:00:17 +04:00
|
|
|
assert(!ARY_SHARED_P(ary));
|
2013-06-11 11:15:24 +04:00
|
|
|
assert(old_capa >= capacity);
|
2018-10-31 00:53:56 +03:00
|
|
|
if (old_capa > capacity) ary_heap_realloc(ary, capacity);
|
|
|
|
|
|
|
|
ary_verify(ary);
|
2013-06-11 11:15:24 +04:00
|
|
|
}
|
|
|
|
|
2009-01-21 18:27:35 +03:00
|
|
|
static void
|
|
|
|
ary_double_capa(VALUE ary, long min)
|
|
|
|
{
|
|
|
|
long new_capa = ARY_CAPA(ary) / 2;
|
|
|
|
|
|
|
|
if (new_capa < ARY_DEFAULT_SIZE) {
|
|
|
|
new_capa = ARY_DEFAULT_SIZE;
|
|
|
|
}
|
|
|
|
if (new_capa >= ARY_MAX_SIZE - min) {
|
|
|
|
new_capa = (ARY_MAX_SIZE - min) / 2;
|
|
|
|
}
|
|
|
|
new_capa += min;
|
|
|
|
ary_resize_capa(ary, new_capa);
|
2018-10-31 00:53:56 +03:00
|
|
|
|
|
|
|
ary_verify(ary);
|
2009-01-21 18:27:35 +03:00
|
|
|
}
|
|
|
|
|
2008-10-17 17:09:33 +04:00
|
|
|
static void
|
2019-07-19 07:02:38 +03:00
|
|
|
rb_ary_decrement_share(VALUE shared_root)
|
2008-10-17 17:09:33 +04:00
|
|
|
{
|
2019-07-19 07:02:38 +03:00
|
|
|
if (shared_root) {
|
2019-07-19 07:10:08 +03:00
|
|
|
long num = ARY_SHARED_ROOT_REFCNT(shared_root) - 1;
|
2008-10-31 06:49:29 +03:00
|
|
|
if (num == 0) {
|
2019-07-19 07:10:08 +03:00
|
|
|
rb_ary_free(shared_root);
|
|
|
|
rb_gc_force_recycle(shared_root);
|
2008-10-17 17:09:33 +04:00
|
|
|
}
|
|
|
|
else if (num > 0) {
|
2019-07-19 07:10:08 +03:00
|
|
|
ARY_SET_SHARED_ROOT_REFCNT(shared_root, num);
|
2008-10-17 17:09:33 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rb_ary_unshare(VALUE ary)
|
|
|
|
{
|
2019-07-19 07:02:38 +03:00
|
|
|
VALUE shared_root = RARRAY(ary)->as.heap.aux.shared_root;
|
|
|
|
rb_ary_decrement_share(shared_root);
|
2008-10-17 17:09:33 +04:00
|
|
|
FL_UNSET_SHARED(ary);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2009-02-11 09:47:12 +03:00
|
|
|
rb_ary_unshare_safe(VALUE ary)
|
|
|
|
{
|
2008-10-17 17:09:33 +04:00
|
|
|
if (ARY_SHARED_P(ary) && !ARY_EMBED_P(ary)) {
|
|
|
|
rb_ary_unshare(ary);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-31 06:49:29 +03:00
|
|
|
static VALUE
|
2019-07-19 07:02:38 +03:00
|
|
|
rb_ary_increment_share(VALUE shared_root)
|
2009-02-11 09:47:12 +03:00
|
|
|
{
|
2019-07-19 07:02:38 +03:00
|
|
|
long num = ARY_SHARED_ROOT_REFCNT(shared_root);
|
2008-10-17 17:09:33 +04:00
|
|
|
if (num >= 0) {
|
2019-07-19 07:10:08 +03:00
|
|
|
ARY_SET_SHARED_ROOT_REFCNT(shared_root, num + 1);
|
2008-10-17 17:09:33 +04:00
|
|
|
}
|
2019-07-19 07:02:38 +03:00
|
|
|
return shared_root;
|
2008-10-31 06:49:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-07-19 07:02:38 +03:00
|
|
|
rb_ary_set_shared(VALUE ary, VALUE shared_root)
|
2008-10-31 06:49:29 +03:00
|
|
|
{
|
2019-07-19 07:02:38 +03:00
|
|
|
rb_ary_increment_share(shared_root);
|
2008-10-17 17:09:33 +04:00
|
|
|
FL_SET_SHARED(ary);
|
2019-07-19 07:02:38 +03:00
|
|
|
RB_DEBUG_COUNTER_INC(obj_ary_shared_create);
|
|
|
|
ARY_SET_SHARED(ary, shared_root);
|
2008-10-17 17:09:33 +04:00
|
|
|
}
|
|
|
|
|
2003-01-08 09:05:08 +03:00
|
|
|
static inline void
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_modify_check(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
* array.c, gc.c, hash.c, object.c, string.c, struct.c,
transcode.c, variable.c, vm.c, vm_insnhelper.c, vm_method.c:
replace calls to rb_error_frozen() with rb_check_frozen(). a
patch from Run Paint Run Run at [ruby-core:32014]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@29583 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2010-10-24 12:14:05 +04:00
|
|
|
rb_check_frozen(ary);
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2011-01-05 23:25:50 +03:00
|
|
|
void
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_modify(VALUE ary)
|
2001-12-10 10:18:16 +03:00
|
|
|
{
|
|
|
|
rb_ary_modify_check(ary);
|
2006-09-02 18:42:08 +04:00
|
|
|
if (ARY_SHARED_P(ary)) {
|
2013-10-15 11:34:05 +04:00
|
|
|
long shared_len, len = RARRAY_LEN(ary);
|
2019-07-19 07:10:08 +03:00
|
|
|
VALUE shared_root = ARY_SHARED_ROOT(ary);
|
2018-10-31 00:53:56 +03:00
|
|
|
|
2019-07-19 07:02:38 +03:00
|
|
|
ary_verify(shared_root);
|
2018-10-31 00:53:56 +03:00
|
|
|
|
2008-10-09 09:47:04 +04:00
|
|
|
if (len <= RARRAY_EMBED_LEN_MAX) {
|
2013-06-21 15:53:33 +04:00
|
|
|
const VALUE *ptr = ARY_HEAP_PTR(ary);
|
2008-10-09 09:47:04 +04:00
|
|
|
FL_UNSET_SHARED(ary);
|
|
|
|
FL_SET_EMBED(ary);
|
2013-06-21 15:53:33 +04:00
|
|
|
MEMCPY((VALUE *)ARY_EMBED_PTR(ary), ptr, VALUE, len);
|
2019-07-19 07:02:38 +03:00
|
|
|
rb_ary_decrement_share(shared_root);
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_EMBED_LEN(ary, len);
|
|
|
|
}
|
2019-07-19 07:10:08 +03:00
|
|
|
else if (ARY_SHARED_ROOT_OCCUPIED(shared_root) && len > ((shared_len = RARRAY_LEN(shared_root))>>1)) {
|
2019-07-19 07:02:38 +03:00
|
|
|
long shift = RARRAY_CONST_PTR_TRANSIENT(ary) - RARRAY_CONST_PTR_TRANSIENT(shared_root);
|
2013-06-12 07:00:24 +04:00
|
|
|
FL_UNSET_SHARED(ary);
|
2019-07-19 07:02:38 +03:00
|
|
|
ARY_SET_PTR(ary, RARRAY_CONST_PTR_TRANSIENT(shared_root));
|
2013-10-15 11:34:05 +04:00
|
|
|
ARY_SET_CAPA(ary, shared_len);
|
2018-12-03 15:36:47 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
2013-08-23 13:42:18 +04:00
|
|
|
MEMMOVE(ptr, ptr+shift, VALUE, len);
|
|
|
|
});
|
2019-07-19 07:10:08 +03:00
|
|
|
FL_SET_EMBED(shared_root);
|
|
|
|
rb_ary_decrement_share(shared_root);
|
2012-11-09 11:08:38 +04:00
|
|
|
}
|
2008-10-09 09:47:04 +04:00
|
|
|
else {
|
2018-10-31 00:53:56 +03:00
|
|
|
VALUE *ptr = ary_heap_alloc(ary, len);
|
|
|
|
MEMCPY(ptr, ARY_HEAP_PTR(ary), VALUE, len);
|
2008-10-17 17:09:33 +04:00
|
|
|
rb_ary_unshare(ary);
|
|
|
|
ARY_SET_CAPA(ary, len);
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_PTR(ary, ptr);
|
|
|
|
}
|
2014-04-10 14:16:24 +04:00
|
|
|
|
2014-09-08 08:11:00 +04:00
|
|
|
rb_gc_writebarrier_remember(ary);
|
2002-05-21 09:39:19 +04:00
|
|
|
}
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2001-12-10 10:18:16 +03:00
|
|
|
}
|
2004-06-16 11:05:24 +04:00
|
|
|
|
2014-04-11 12:47:00 +04:00
|
|
|
static VALUE
|
2012-11-09 11:08:42 +04:00
|
|
|
ary_ensure_room_for_push(VALUE ary, long add_len)
|
|
|
|
{
|
2015-06-11 07:50:22 +03:00
|
|
|
long old_len = RARRAY_LEN(ary);
|
|
|
|
long new_len = old_len + add_len;
|
2012-11-09 11:08:42 +04:00
|
|
|
long capa;
|
|
|
|
|
2015-06-11 07:50:22 +03:00
|
|
|
if (old_len > ARY_MAX_SIZE - add_len) {
|
|
|
|
rb_raise(rb_eIndexError, "index %ld too big", new_len);
|
|
|
|
}
|
2012-11-09 11:08:42 +04:00
|
|
|
if (ARY_SHARED_P(ary)) {
|
|
|
|
if (new_len > RARRAY_EMBED_LEN_MAX) {
|
2019-07-19 07:10:08 +03:00
|
|
|
VALUE shared_root = ARY_SHARED_ROOT(ary);
|
|
|
|
if (ARY_SHARED_ROOT_OCCUPIED(shared_root)) {
|
2019-07-19 07:02:38 +03:00
|
|
|
if (ARY_HEAP_PTR(ary) - RARRAY_CONST_PTR_TRANSIENT(shared_root) + new_len <= RARRAY_LEN(shared_root)) {
|
2012-11-09 11:08:42 +04:00
|
|
|
rb_ary_modify_check(ary);
|
2018-10-31 00:53:56 +03:00
|
|
|
|
|
|
|
ary_verify(ary);
|
2019-07-19 07:02:38 +03:00
|
|
|
ary_verify(shared_root);
|
|
|
|
return shared_root;
|
2012-11-09 11:08:42 +04:00
|
|
|
}
|
|
|
|
else {
|
2013-03-01 21:46:40 +04:00
|
|
|
/* if array is shared, then it is likely it participate in push/shift pattern */
|
2012-11-09 11:08:42 +04:00
|
|
|
rb_ary_modify(ary);
|
|
|
|
capa = ARY_CAPA(ary);
|
|
|
|
if (new_len > capa - (capa >> 6)) {
|
|
|
|
ary_double_capa(ary, new_len);
|
|
|
|
}
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2014-04-11 12:47:00 +04:00
|
|
|
return ary;
|
2012-11-09 11:08:42 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2018-10-31 00:02:12 +03:00
|
|
|
rb_ary_modify(ary);
|
Improve performance in where push the element into non shared Array object
* array.c (ary_ensure_room_for_push): use rb_ary_modify_check() instead of
rb_ary_modify() to check whether the object can be modified for non shared
Array object. rb_ary_modify() has the codes for shared Array object too.
In here, it has condition branch for shared / non shared Array object and
it can use rb_ary_modify_check() which is smaller function than
rb_ary_modify() for non shared object.
rb_ary_modify_check() will be expand as inline function.
If it will compile with GCC, Array#<< will be faster around 8%.
[ruby-core:81082] [Bug #13553] [Fix GH-1609]
## Clang 802.0.42
### Before
Array#<< 9.353M (± 1.7%) i/s - 46.787M in 5.004123s
Array#push 7.702M (± 1.1%) i/s - 38.577M in 5.009338s
Array#values_at 6.133M (± 1.9%) i/s - 30.699M in 5.007772s
### After
Array#<< 9.458M (± 2.0%) i/s - 47.357M in 5.009069s
Array#push 7.921M (± 1.8%) i/s - 39.665M in 5.009151s
Array#values_at 6.377M (± 2.3%) i/s - 31.881M in 5.001888s
### Result
Array#<< -> 1.2% faster
Array#push -> 2.8% faster
Array#values_at -> 3.9% faster
## GCC 7.1.0
### Before
Array#<< 10.497M (± 1.1%) i/s - 52.665M in 5.017601s
Array#push 8.527M (± 1.6%) i/s - 42.777M in 5.018003s
Array#values_at 7.621M (± 1.7%) i/s - 38.152M in 5.007910s
### After
Array#<< 11.403M (± 1.3%) i/s - 57.028M in 5.001849s
Array#push 8.924M (± 1.3%) i/s - 44.609M in 4.999940s
Array#values_at 8.291M (± 1.4%) i/s - 41.487M in 5.004727s
### Result
Array#<< -> 8.3% faster
Array#push -> 4.3% faster
Array#values_at -> 8.7% faster
## Test code
require 'benchmark/ips'
Benchmark.ips do |x|
x.report "Array#<<" do |i|
i.times { [1,2] << 3 }
end
x.report "Array#push" do |i|
i.times { [1,2].push(3) }
end
x.report "Array#values_at" do |i|
ary = [1, 2, 3, 4, 5]
i.times { ary.values_at(0, 2, 4) }
end
end
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58867 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2017-05-24 09:57:08 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_ary_modify_check(ary);
|
2012-11-09 11:08:42 +04:00
|
|
|
}
|
|
|
|
capa = ARY_CAPA(ary);
|
|
|
|
if (new_len > capa) {
|
|
|
|
ary_double_capa(ary, new_len);
|
|
|
|
}
|
2014-04-11 12:47:00 +04:00
|
|
|
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2014-04-11 12:47:00 +04:00
|
|
|
return ary;
|
2012-11-09 11:08:42 +04:00
|
|
|
}
|
|
|
|
|
2012-06-01 03:51:33 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-09 21:57:41 +03:00
|
|
|
* array.freeze -> self
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Freezes +self+; returns +self+:
|
|
|
|
* a = []
|
|
|
|
* a.frozen? # => false
|
|
|
|
* a1 = a.freeze # => []
|
|
|
|
* a.frozen? # => true
|
|
|
|
* a1.equal?(a) # => true # Returned self
|
|
|
|
*
|
|
|
|
* An attempt to modify a frozen \Array raises an exception:
|
|
|
|
* # Raises FrozenError (can't modify frozen Array: [:foo, "bar", 2]):
|
|
|
|
* [:foo, 'bar', 2].freeze.push(:foo)
|
2012-06-01 03:51:33 +04:00
|
|
|
*/
|
|
|
|
|
2000-02-17 10:11:22 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_freeze(VALUE ary)
|
2000-02-17 10:11:22 +03:00
|
|
|
{
|
|
|
|
return rb_obj_freeze(ary);
|
|
|
|
}
|
|
|
|
|
2012-11-05 19:24:07 +04:00
|
|
|
/* This can be used to take a snapshot of an array (with
|
|
|
|
e.g. rb_ary_replace) and check later whether the array has been
|
|
|
|
modified from the snapshot. The snapshot is cheap, though if
|
|
|
|
something does modify the array it will pay the cost of copying
|
2012-11-22 18:55:32 +04:00
|
|
|
it. If Array#pop or Array#shift has been called, the array will
|
|
|
|
be still shared with the snapshot, but the array length will
|
|
|
|
differ. */
|
2012-11-05 19:24:07 +04:00
|
|
|
VALUE
|
|
|
|
rb_ary_shared_with_p(VALUE ary1, VALUE ary2)
|
|
|
|
{
|
2012-11-22 18:55:32 +04:00
|
|
|
if (!ARY_EMBED_P(ary1) && ARY_SHARED_P(ary1) &&
|
|
|
|
!ARY_EMBED_P(ary2) && ARY_SHARED_P(ary2) &&
|
2019-07-19 07:10:08 +03:00
|
|
|
RARRAY(ary1)->as.heap.aux.shared_root == RARRAY(ary2)->as.heap.aux.shared_root &&
|
2012-11-22 18:55:32 +04:00
|
|
|
RARRAY(ary1)->as.heap.len == RARRAY(ary2)->as.heap.len) {
|
2012-11-05 19:24:07 +04:00
|
|
|
return Qtrue;
|
|
|
|
}
|
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
|
2001-10-03 11:19:19 +04:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
ary_alloc(VALUE klass)
|
2001-10-03 11:19:19 +04:00
|
|
|
{
|
2013-07-18 09:54:32 +04:00
|
|
|
NEWOBJ_OF(ary, struct RArray, klass, T_ARRAY | RARRAY_EMBED_FLAG | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0));
|
|
|
|
/* Created array is:
|
|
|
|
* FL_SET_EMBED((VALUE)ary);
|
|
|
|
* ARY_SET_EMBED_LEN((VALUE)ary, 0);
|
|
|
|
*/
|
2001-10-03 11:19:19 +04:00
|
|
|
return (VALUE)ary;
|
|
|
|
}
|
|
|
|
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
static VALUE
|
|
|
|
empty_ary_alloc(VALUE klass)
|
|
|
|
{
|
2015-10-29 08:32:57 +03:00
|
|
|
RUBY_DTRACE_CREATE_HOOK(ARRAY, 0);
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
return ary_alloc(klass);
|
|
|
|
}
|
|
|
|
|
2001-12-10 10:18:16 +03:00
|
|
|
static VALUE
|
2009-05-09 09:44:20 +04:00
|
|
|
ary_new(VALUE klass, long capa)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2013-06-07 06:20:05 +04:00
|
|
|
VALUE ary,*ptr;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2009-05-09 09:44:20 +04:00
|
|
|
if (capa < 0) {
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_raise(rb_eArgError, "negative array size (or size too big)");
|
|
|
|
}
|
2009-05-09 09:44:20 +04:00
|
|
|
if (capa > ARY_MAX_SIZE) {
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_raise(rb_eArgError, "array size too big");
|
|
|
|
}
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
|
2015-10-29 08:32:57 +03:00
|
|
|
RUBY_DTRACE_CREATE_HOOK(ARRAY, capa);
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
|
2014-10-09 08:35:12 +04:00
|
|
|
ary = ary_alloc(klass);
|
2009-05-09 09:44:20 +04:00
|
|
|
if (capa > RARRAY_EMBED_LEN_MAX) {
|
2018-10-31 00:53:56 +03:00
|
|
|
ptr = ary_heap_alloc(ary, capa);
|
2008-10-09 09:47:04 +04:00
|
|
|
FL_UNSET_EMBED(ary);
|
2013-06-07 06:20:05 +04:00
|
|
|
ARY_SET_PTR(ary, ptr);
|
2009-05-09 09:44:20 +04:00
|
|
|
ARY_SET_CAPA(ary, capa);
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_HEAP_LEN(ary, 0);
|
2013-06-07 06:52:42 +04:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-10-03 11:19:19 +04:00
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2001-10-16 07:27:23 +04:00
|
|
|
VALUE
|
2013-05-31 12:04:56 +04:00
|
|
|
rb_ary_new_capa(long capa)
|
2001-10-16 07:27:23 +04:00
|
|
|
{
|
2009-05-09 09:44:20 +04:00
|
|
|
return ary_new(rb_cArray, capa);
|
2001-10-16 07:27:23 +04:00
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_new(void)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2008-10-09 09:47:04 +04:00
|
|
|
return rb_ary_new2(RARRAY_EMBED_LEN_MAX);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
2014-10-09 11:53:54 +04:00
|
|
|
(rb_ary_new_from_args)(long n, ...)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
va_list ar;
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE ary;
|
1999-08-13 09:45:20 +04:00
|
|
|
long i;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2002-05-21 09:39:19 +04:00
|
|
|
ary = rb_ary_new2(n);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
va_start(ar, n);
|
1998-01-16 15:13:05 +03:00
|
|
|
for (i=0; i<n; i++) {
|
2014-04-11 13:55:10 +04:00
|
|
|
ARY_SET(ary, i, va_arg(ar, VALUE));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
va_end(ar);
|
|
|
|
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(ary, n);
|
1998-01-16 15:19:22 +03:00
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
2017-04-20 13:32:08 +03:00
|
|
|
rb_ary_tmp_new_from_values(VALUE klass, long n, const VALUE *elts)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2017-04-20 13:32:08 +03:00
|
|
|
ary = ary_new(klass, n);
|
2001-10-03 11:19:19 +04:00
|
|
|
if (n > 0 && elts) {
|
2013-07-19 14:16:31 +04:00
|
|
|
ary_memcpy(ary, 0, n, elts);
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(ary, n);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2017-04-20 13:32:08 +03:00
|
|
|
VALUE
|
|
|
|
rb_ary_new_from_values(long n, const VALUE *elts)
|
|
|
|
{
|
|
|
|
return rb_ary_tmp_new_from_values(rb_cArray, n, elts);
|
|
|
|
}
|
|
|
|
|
2008-08-04 14:21:46 +04:00
|
|
|
VALUE
|
2009-05-09 09:44:20 +04:00
|
|
|
rb_ary_tmp_new(long capa)
|
2008-08-04 14:21:46 +04:00
|
|
|
{
|
2018-10-31 00:53:56 +03:00
|
|
|
VALUE ary = ary_new(0, capa);
|
|
|
|
rb_ary_transient_heap_evacuate(ary, TRUE);
|
|
|
|
return ary;
|
2008-08-04 14:21:46 +04:00
|
|
|
}
|
|
|
|
|
2014-08-15 14:32:58 +04:00
|
|
|
VALUE
|
|
|
|
rb_ary_tmp_new_fill(long capa)
|
|
|
|
{
|
|
|
|
VALUE ary = ary_new(0, capa);
|
|
|
|
ary_memfill(ary, 0, capa, Qnil);
|
|
|
|
ARY_SET_LEN(ary, capa);
|
2018-10-31 00:53:56 +03:00
|
|
|
rb_ary_transient_heap_evacuate(ary, TRUE);
|
2014-08-15 14:32:58 +04:00
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2006-09-27 02:46:16 +04:00
|
|
|
void
|
|
|
|
rb_ary_free(VALUE ary)
|
|
|
|
{
|
2008-10-09 09:47:04 +04:00
|
|
|
if (ARY_OWNS_HEAP_P(ary)) {
|
2019-09-25 11:12:55 +03:00
|
|
|
if (USE_DEBUG_COUNTER &&
|
|
|
|
!ARY_SHARED_ROOT_P(ary) &&
|
|
|
|
ARY_HEAP_CAPA(ary) > RARRAY_LEN(ary)) {
|
|
|
|
RB_DEBUG_COUNTER_INC(obj_ary_extracapa);
|
|
|
|
}
|
2019-09-25 10:55:54 +03:00
|
|
|
|
2018-10-31 00:53:56 +03:00
|
|
|
if (RARRAY_TRANSIENT_P(ary)) {
|
|
|
|
RB_DEBUG_COUNTER_INC(obj_ary_transient);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
RB_DEBUG_COUNTER_INC(obj_ary_ptr);
|
|
|
|
ary_heap_free(ary);
|
|
|
|
}
|
2006-09-27 02:46:16 +04:00
|
|
|
}
|
2017-05-24 09:46:44 +03:00
|
|
|
else {
|
Use FL_TEST_RAW() to check flags.
FL_TEST() uses FL_ABLE() which test data types. However,
in array.c we don't need to check it (all of them should be
T_ARRAY), so I changed from FL_TEST() to FL_TEST_RAW() which
does not check FL_ABLE(). Instead of FL_ABLE(), add assertion
to check given object is a T_ARRAY object.
For example, rb_ary_free() becomes slim:
with FL_TEST():
0000000000006a30 <rb_ary_free>:
6a30: 40 f6 c7 07 test $0x7,%dil
6a34: 48 8b 07 mov (%rdi),%rax
6a37: 75 09 jne 6a42 <rb_ary_free+0x12>
6a39: 48 f7 c7 f7 ff ff ff test $0xfffffffffffffff7,%rdi
6a40: 75 1e jne 6a60 <rb_ary_free+0x30>
6a42: a9 00 00 00 02 test $0x2000000,%eax
6a47: 74 07 je 6a50 <rb_ary_free+0x20>
6a49: f3 c3 repz retq
6a4b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a50: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a54: e9 00 00 00 00 jmpq 6a59 <rb_ary_free+0x29>
6a59: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
6a60: 89 c2 mov %eax,%edx
6a62: 83 e2 1f and $0x1f,%edx
6a65: 83 fa 1b cmp $0x1b,%edx
6a68: 74 d8 je 6a42 <rb_ary_free+0x12>
6a6a: f6 c4 60 test $0x60,%ah
6a6d: 74 d3 je 6a42 <rb_ary_free+0x12>
6a6f: eb d8 jmp 6a49 <rb_ary_free+0x19>```
with FL_TEST_RAW():
0000000000006a30 <rb_ary_free>:
6a30: 48 f7 07 00 60 00 02 testq $0x2006000,(%rdi)
6a37: 74 07 je 6a40 <rb_ary_free+0x10>
6a39: f3 c3 repz retq
6a3b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
6a40: 48 8b 7f 20 mov 0x20(%rdi),%rdi
6a44: e9 00 00 00 00 jmpq 6a49 <rb_ary_free+0x19>
2019-07-19 08:37:59 +03:00
|
|
|
RB_DEBUG_COUNTER_INC(obj_ary_embed);
|
2017-05-24 09:46:44 +03:00
|
|
|
}
|
2019-07-19 07:02:38 +03:00
|
|
|
|
|
|
|
if (ARY_SHARED_P(ary)) {
|
|
|
|
RB_DEBUG_COUNTER_INC(obj_ary_shared);
|
|
|
|
}
|
|
|
|
if (ARY_SHARED_ROOT_P(ary) && ARY_SHARED_ROOT_OCCUPIED(ary)) {
|
|
|
|
RB_DEBUG_COUNTER_INC(obj_ary_shared_root_occupied);
|
|
|
|
}
|
2006-09-27 02:46:16 +04:00
|
|
|
}
|
|
|
|
|
2010-08-14 10:33:06 +04:00
|
|
|
RUBY_FUNC_EXPORTED size_t
|
2009-06-17 02:36:27 +04:00
|
|
|
rb_ary_memsize(VALUE ary)
|
|
|
|
{
|
|
|
|
if (ARY_OWNS_HEAP_P(ary)) {
|
2017-04-13 09:43:17 +03:00
|
|
|
return ARY_CAPA(ary) * sizeof(VALUE);
|
2009-06-17 02:36:27 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-08 05:07:03 +04:00
|
|
|
static inline void
|
|
|
|
ary_discard(VALUE ary)
|
|
|
|
{
|
|
|
|
rb_ary_free(ary);
|
|
|
|
RBASIC(ary)->flags |= RARRAY_EMBED_FLAG;
|
2018-10-31 00:53:56 +03:00
|
|
|
RBASIC(ary)->flags &= ~(RARRAY_EMBED_LEN_MASK | RARRAY_TRANSIENT_FLAG);
|
2009-05-08 05:07:03 +04:00
|
|
|
}
|
|
|
|
|
2004-09-24 09:53:43 +04:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
ary_make_shared(VALUE ary)
|
2004-05-07 12:44:24 +04:00
|
|
|
{
|
2008-10-09 09:47:04 +04:00
|
|
|
assert(!ARY_EMBED_P(ary));
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
|
|
|
|
2010-08-18 14:13:54 +04:00
|
|
|
if (ARY_SHARED_P(ary)) {
|
2019-07-19 07:02:38 +03:00
|
|
|
return ARY_SHARED_ROOT(ary);
|
2010-08-18 14:13:54 +04:00
|
|
|
}
|
|
|
|
else if (ARY_SHARED_ROOT_P(ary)) {
|
2009-02-11 09:47:12 +03:00
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
else if (OBJ_FROZEN(ary)) {
|
2018-10-31 00:53:56 +03:00
|
|
|
rb_ary_transient_heap_evacuate(ary, TRUE);
|
2013-06-11 11:15:24 +04:00
|
|
|
ary_shrink_capa(ary);
|
2009-02-11 09:47:12 +03:00
|
|
|
FL_SET_SHARED_ROOT(ary);
|
2019-07-19 07:10:08 +03:00
|
|
|
ARY_SET_SHARED_ROOT_REFCNT(ary, 1);
|
2009-02-11 09:47:12 +03:00
|
|
|
return ary;
|
|
|
|
}
|
2006-09-02 18:42:08 +04:00
|
|
|
else {
|
2013-10-15 11:34:05 +04:00
|
|
|
long capa = ARY_CAPA(ary), len = RARRAY_LEN(ary);
|
2018-10-31 00:53:56 +03:00
|
|
|
const VALUE *ptr;
|
2014-04-11 12:47:00 +04:00
|
|
|
NEWOBJ_OF(shared, struct RArray, 0, T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0));
|
2020-04-08 07:28:13 +03:00
|
|
|
VALUE vshared = (VALUE)shared;
|
2018-10-31 00:01:55 +03:00
|
|
|
|
2018-10-31 00:53:56 +03:00
|
|
|
rb_ary_transient_heap_evacuate(ary, TRUE);
|
|
|
|
ptr = ARY_HEAP_PTR(ary);
|
|
|
|
|
2020-04-08 07:28:13 +03:00
|
|
|
FL_UNSET_EMBED(vshared);
|
|
|
|
ARY_SET_LEN(vshared, capa);
|
|
|
|
ARY_SET_PTR(vshared, ptr);
|
|
|
|
ary_mem_clear(vshared, len, capa - len);
|
|
|
|
FL_SET_SHARED_ROOT(vshared);
|
|
|
|
ARY_SET_SHARED_ROOT_REFCNT(vshared, 1);
|
2008-10-09 09:47:04 +04:00
|
|
|
FL_SET_SHARED(ary);
|
2019-07-19 07:02:38 +03:00
|
|
|
RB_DEBUG_COUNTER_INC(obj_ary_shared_create);
|
2020-04-08 07:28:13 +03:00
|
|
|
ARY_SET_SHARED(ary, vshared);
|
|
|
|
OBJ_FREEZE(vshared);
|
2018-10-31 00:53:56 +03:00
|
|
|
|
2020-04-08 07:28:13 +03:00
|
|
|
ary_verify(vshared);
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2019-07-19 07:02:38 +03:00
|
|
|
|
2020-04-08 07:28:13 +03:00
|
|
|
return vshared;
|
2004-09-24 09:53:43 +04:00
|
|
|
}
|
2004-05-07 12:44:24 +04:00
|
|
|
}
|
|
|
|
|
2008-10-09 09:47:04 +04:00
|
|
|
static VALUE
|
|
|
|
ary_make_substitution(VALUE ary)
|
|
|
|
{
|
2013-07-19 16:12:31 +04:00
|
|
|
long len = RARRAY_LEN(ary);
|
|
|
|
|
|
|
|
if (len <= RARRAY_EMBED_LEN_MAX) {
|
|
|
|
VALUE subst = rb_ary_new2(len);
|
2018-10-31 00:54:13 +03:00
|
|
|
ary_memcpy(subst, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary));
|
2013-07-19 16:12:31 +04:00
|
|
|
ARY_SET_EMBED_LEN(subst, len);
|
2008-10-09 09:47:04 +04:00
|
|
|
return subst;
|
|
|
|
}
|
|
|
|
else {
|
2008-10-31 06:49:29 +03:00
|
|
|
return rb_ary_increment_share(ary_make_shared(ary));
|
2008-10-09 09:47:04 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-04-07 06:51:05 +04:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_assoc_new(VALUE car, VALUE cdr)
|
2004-04-07 06:51:05 +04:00
|
|
|
{
|
* sprintf.c (rb_str_format): allow %c to print one character
string (e.g. ?x).
* lib/tempfile.rb (Tempfile::make_tmpname): put dot between
basename and pid. [ruby-talk:196272]
* parse.y (do_block): remove -> style block.
* parse.y (parser_yylex): remove tLAMBDA_ARG.
* eval.c (rb_call0): binding for the return event hook should have
consistent scope. [ruby-core:07928]
* eval.c (proc_invoke): return behavior should depend whether it
is surrounded by a lambda or a mere block.
* eval.c (formal_assign): handles post splat arguments.
* eval.c (rb_call0): ditto.
* st.c (strhash): use FNV-1a hash.
* parse.y (parser_yylex): removed experimental ';;' terminator.
* eval.c (rb_node_arity): should be aware of post splat arguments.
* eval.c (rb_proc_arity): ditto.
* parse.y (f_args): syntax rule enhanced to support arguments
after the splat.
* parse.y (block_param): ditto for block parameters.
* parse.y (f_post_arg): mandatory formal arguments after the splat
argument.
* parse.y (new_args_gen): generate nodes for mandatory formal
arguments after the splat argument.
* eval.c (rb_eval): dispatch mandatory formal arguments after the
splat argument.
* parse.y (args): allow more than one splat in the argument list.
* parse.y (method_call): allow aref [] to accept all kind of
method argument, including assocs, splat, and block argument.
* eval.c (SETUP_ARGS0): prepare block argument as well.
* lib/mathn.rb (Integer): remove Integer#gcd2. [ruby-core:07931]
* eval.c (error_line): print receivers true/false/nil specially.
* eval.c (rb_proc_yield): handles parameters in yield semantics.
* eval.c (nil_yield): gives LocalJumpError to denote no block
error.
* io.c (rb_io_getc): now takes one-character string.
* string.c (rb_str_hash): use FNV-1a hash from Fowler/Noll/Vo
hashing algorithm.
* string.c (rb_str_aref): str[0] now returns 1 character string,
instead of a fixnum. [Ruby2]
* parse.y (parser_yylex): ?c now returns 1 character string,
instead of a fixnum. [Ruby2]
* string.c (rb_str_aset): no longer support fixnum insertion.
* eval.c (umethod_bind): should not update original class.
[ruby-dev:28636]
* eval.c (ev_const_get): should support constant access from
within instance_eval(). [ruby-dev:28327]
* time.c (time_timeval): should round for usec floating
number. [ruby-core:07896]
* time.c (time_add): ditto.
* dir.c (sys_warning): should not call a vararg function
rb_sys_warning() indirectly. [ruby-core:07886]
* numeric.c (flo_divmod): the first element of Float#divmod should
be an integer. [ruby-dev:28589]
* test/ruby/test_float.rb: add tests for divmod, div, modulo and remainder.
* re.c (rb_reg_initialize): should not allow modifying literal
regexps. frozen check moved from rb_reg_initialize_m as well.
* re.c (rb_reg_initialize): should not modify untainted objects in
safe levels higher than 3.
* re.c (rb_memcmp): type change from char* to const void*.
* dir.c (dir_close): should not close untainted dir stream.
* dir.c (GetDIR): add tainted/frozen check for each dir operation.
* lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_symbol_arg):
typo fixed. a patch from Florian Gross <florg at florg.net>.
* eval.c (EXEC_EVENT_HOOK): trace_func may remove itself from
event_hooks. no guarantee for arbitrary hook deletion.
[ruby-dev:28632]
* util.c (ruby_strtod): differ addition to minimize error.
[ruby-dev:28619]
* util.c (ruby_strtod): should not raise ERANGE when the input
string does not have any digits. [ruby-dev:28629]
* eval.c (proc_invoke): should restore old ruby_frame->block.
thanks to ts <decoux at moulon.inra.fr>. [ruby-core:07833]
also fix [ruby-dev:28614] as well.
* signal.c (trap): sig should be less then NSIG. Coverity found
this bug. a patch from Kevin Tew <tewk at tewk.com>.
[ruby-core:07823]
* math.c (math_log2): add new method inspired by
[ruby-talk:191237].
* math.c (math_log): add optional base argument to Math::log().
[ruby-talk:191308]
* ext/syck/emitter.c (syck_scan_scalar): avoid accessing
uninitialized array element. a patch from Pat Eyler
<rubypate at gmail.com>. [ruby-core:07809]
* array.c (rb_ary_fill): initialize local variables first. a
patch from Pat Eyler <rubypate at gmail.com>. [ruby-core:07810]
* ext/syck/yaml2byte.c (syck_yaml2byte_handler): need to free
type_tag. a patch from Pat Eyler <rubypate at gmail.com>.
[ruby-core:07808]
* ext/socket/socket.c (make_hostent_internal): accept ai_family
check from Sam Roberts <sroberts at uniserve.com>.
[ruby-core:07691]
* util.c (ruby_strtod): should not cut off 18 digits for no
reason. [ruby-core:07796]
* array.c (rb_ary_fill): internalize local variable "beg" to
pacify Coverity. [ruby-core:07770]
* pack.c (pack_unpack): now supports CRLF newlines. a patch from
<tommy at tmtm.org>. [ruby-dev:28601]
* applied code clean-up patch from Stefan Huehner
<stefan at huehner.org>. [ruby-core:07764]
* lib/jcode.rb (String::tr_s): should have translated non
squeezing character sequence (i.e. a character) as well. thanks
to Hiroshi Ichikawa <gimite at gimite.ddo.jp> [ruby-list:42090]
* ext/socket/socket.c: document update patch from Sam Roberts
<sroberts at uniserve.com>. [ruby-core:07701]
* lib/mathn.rb (Integer): need not to remove gcd2. a patch from
NARUSE, Yui <naruse at airemix.com>. [ruby-dev:28570]
* parse.y (arg): too much NEW_LIST()
* eval.c (SETUP_ARGS0): remove unnecessary access to nd_alen.
* eval.c (rb_eval): use ARGSCAT for NODE_OP_ASGN1.
[ruby-dev:28585]
* parse.y (arg): use NODE_ARGSCAT for placeholder.
* lib/getoptlong.rb (GetoptLong::get): RDoc update patch from
mathew <meta at pobox.com>. [ruby-core:07738]
* variable.c (rb_const_set): raise error when no target klass is
supplied. [ruby-dev:28582]
* prec.c (prec_prec_f): documentation patch from
<gerardo.santana at gmail.com>. [ruby-core:07689]
* bignum.c (rb_big_pow): second operand may be too big even if
it's a Fixnum. [ruby-talk:187984]
* README.EXT: update symbol description. [ruby-talk:188104]
* COPYING: explicitly note GPLv2. [ruby-talk:187922]
* parse.y: remove some obsolete syntax rules (unparenthesized
method calls in argument list).
* eval.c (rb_call0): insecure calling should be checked for non
NODE_SCOPE method invocations too.
* eval.c (rb_alias): should preserve the current safe level as
well as method definition.
* process.c (rb_f_sleep): remove RDoc description about SIGALRM
which is not valid on the current implementation. [ruby-dev:28464]
Thu Mar 23 21:40:47 2006 K.Kosako <sndgk393 AT ybb.ne.jp>
* eval.c (method_missing): should support argument splat in
super. a bug in combination of super, splat and
method_missing. [ruby-talk:185438]
* configure.in: Solaris SunPro compiler -rapth patch from
<kuwa at labs.fujitsu.com>. [ruby-dev:28443]
* configure.in: remove enable_rpath=no for Solaris.
[ruby-dev:28440]
* ext/win32ole/win32ole.c (ole_val2olevariantdata): change behavior
of converting OLE Variant object with VT_ARRAY|VT_UI1 and Ruby
String object.
* ruby.1: a clarification patch from David Lutterkort
<dlutter at redhat.com>. [ruby-core:7508]
* lib/rdoc/ri/ri_paths.rb (RI::Paths): adding paths from rubygems
directories. a patch from Eric Hodel <drbrain at segment7.net>.
[ruby-core:07423]
* eval.c (rb_clear_cache_by_class): clearing wrong cache.
* ext/extmk.rb: use :remove_destination to install extension libraries
to avoid SEGV. [ruby-dev:28417]
* eval.c (rb_thread_fd_writable): should not re-schedule output
from KILLED thread (must be error printing).
* array.c (rb_ary_flatten_bang): allow specifying recursion
level. [ruby-talk:182170]
* array.c (rb_ary_flatten): ditto.
* gc.c (add_heap): a heap_slots may overflow. a patch from Stefan
Weil <weil at mail.berlios.de>.
* eval.c (rb_call): use separate cache for fcall/vcall
invocation.
* eval.c (rb_eval): NODE_FCALL, NODE_VCALL can call local
functions.
* eval.c (rb_mod_local): a new method to specify newly added
visibility "local".
* eval.c (search_method): search for local methods which are
visible only from the current class.
* class.c (rb_class_local_methods): a method to list local methods.
* object.c (Init_Object): add BasicObject class as a top level
BlankSlate class.
* ruby.h (SYM2ID): should not cast to signed long.
[ruby-core:07414]
* class.c (rb_include_module): allow module duplication.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10235 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2006-06-10 01:20:17 +04:00
|
|
|
return rb_ary_new3(2, car, cdr);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2017-10-26 10:23:23 +03:00
|
|
|
VALUE
|
|
|
|
rb_to_array_type(VALUE ary)
|
2001-10-02 08:31:23 +04:00
|
|
|
{
|
2017-05-31 15:30:57 +03:00
|
|
|
return rb_convert_type_with_id(ary, T_ARRAY, "Array", idTo_ary);
|
2001-10-02 08:31:23 +04:00
|
|
|
}
|
2017-10-26 10:23:23 +03:00
|
|
|
#define to_ary rb_to_array_type
|
2001-10-02 08:31:23 +04:00
|
|
|
|
2002-12-19 12:20:20 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_check_array_type(VALUE ary)
|
2002-12-19 12:20:20 +03:00
|
|
|
{
|
2017-05-31 15:30:57 +03:00
|
|
|
return rb_check_convert_type_with_id(ary, T_ARRAY, "Array", idTo_ary);
|
2002-12-19 12:20:20 +03:00
|
|
|
}
|
|
|
|
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
2018-01-27 12:27:47 +03:00
|
|
|
rb_check_to_array(VALUE ary)
|
|
|
|
{
|
|
|
|
return rb_check_convert_type_with_id(ary, T_ARRAY, "Array", idTo_a);
|
|
|
|
}
|
|
|
|
|
2007-08-24 21:47:09 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-09 21:57:41 +03:00
|
|
|
* Array.try_convert(object) -> new_array or nil
|
2007-08-24 21:47:09 +04:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Tries to convert +object+ to an \Array.
|
2007-08-24 21:47:09 +04:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* When +object+ is an
|
2020-05-16 00:12:40 +03:00
|
|
|
* {Array-convertible object}[doc/implicit_conversion_rdoc.html#label-Array-Convertible+Objects]
|
|
|
|
* (implements +to_ary+),
|
|
|
|
* returns the \Array object created by converting it:
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* class ToAryReturnsArray < Set
|
|
|
|
* def to_ary
|
|
|
|
* self.to_a
|
|
|
|
* end
|
|
|
|
* end
|
|
|
|
* as = ToAryReturnsArray.new([:foo, :bar, :baz])
|
|
|
|
* Array.try_convert(as) # => [:foo, :bar, :baz]
|
2007-08-25 04:43:13 +04:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Returns +nil+ if +object+ is not \Array-convertible:
|
2020-05-16 00:12:40 +03:00
|
|
|
*
|
|
|
|
* Array.try_convert(:foo) # => nil
|
2007-08-24 21:47:09 +04:00
|
|
|
*/
|
2007-08-25 04:43:13 +04:00
|
|
|
|
2007-08-24 21:47:09 +04:00
|
|
|
static VALUE
|
|
|
|
rb_ary_s_try_convert(VALUE dummy, VALUE ary)
|
|
|
|
{
|
|
|
|
return rb_check_array_type(ary);
|
|
|
|
}
|
|
|
|
|
2004-07-13 20:21:23 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-05-16 00:12:40 +03:00
|
|
|
* Array.new -> new_empty_array
|
|
|
|
* Array.new(array) -> new_array
|
|
|
|
* Array.new(size) -> new_array
|
|
|
|
* Array.new(size, default_value) -> new_array
|
|
|
|
* Array.new(size) {|index| ... } -> new_array
|
|
|
|
*
|
|
|
|
* Returns a new \Array.
|
|
|
|
*
|
|
|
|
* Argument +array+, if given, must be an
|
|
|
|
* {Array-convertible object}[doc/implicit_conversion_rdoc.html#label-Array-Convertible+Objects]
|
|
|
|
* (implements +to_ary+).
|
|
|
|
*
|
|
|
|
* Argument +size+, if given must be an
|
|
|
|
* {Integer-convertible object}[doc/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects]
|
|
|
|
* (implements +to_int+).
|
|
|
|
*
|
|
|
|
* Argument +default_value+ may be any object.
|
2004-07-13 20:21:23 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* ---
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* With no block and no arguments, returns a new empty \Array object:
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* a = Array.new
|
|
|
|
* a # => []
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* With no block and a single argument +array+,
|
|
|
|
* returns a new \Array formed from +array+:
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* a = Array.new([:foo, 'bar', 2])
|
|
|
|
* a.class # => Array
|
|
|
|
* a # => [:foo, "bar", 2]
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* With no block and a single argument +size+,
|
|
|
|
* returns a new \Array of the given size
|
|
|
|
* whose elements are all +nil+:
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* a = Array.new(0)
|
|
|
|
* a # => []
|
|
|
|
* a = Array.new(3)
|
|
|
|
* a # => [nil, nil, nil]
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* With no block and arguments +size+ and +default_value+,
|
|
|
|
* returns an \Array of the given size;
|
|
|
|
* each element is that same +default_value+:
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* a = Array.new(3, 'x')
|
|
|
|
* a # => ['x', 'x', 'x']
|
|
|
|
* a[1].equal?(a[0]) # => true # Identity check.
|
|
|
|
* a[2].equal?(a[0]) # => true # Identity check.
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* With a block and argument +size+,
|
|
|
|
* returns an \Array of the given size;
|
|
|
|
* the block is called with each successive integer +index+;
|
|
|
|
* the element for that +index+ is the return value from the block:
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* a = Array.new(3) { |index| "Element #{index}" }
|
|
|
|
* a # => ["Element 0", "Element 1", "Element 2"]
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* With a block and no argument,
|
|
|
|
* or a single argument +0+,
|
|
|
|
* ignores the block and returns a new empty \Array:
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2020-06-10 14:45:29 +03:00
|
|
|
* a = Array.new(0) { |n| raise 'Cannot happen' }
|
2020-05-16 00:12:40 +03:00
|
|
|
* a # => []
|
2020-06-10 14:45:29 +03:00
|
|
|
* a = Array.new { |n| raise 'Cannot happen' }
|
2020-05-16 00:12:40 +03:00
|
|
|
* a # => []
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* With a block and arguments +size+ and +default_value+,
|
|
|
|
* gives a warning message
|
|
|
|
* ('warning: block supersedes default value argument'),
|
|
|
|
* and assigns elements from the block's return values:
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* Array.new(4, :default) {} # => [nil, nil, nil, nil]
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* ---
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* Raises an exception if +size+ is a negative integer:
|
|
|
|
*
|
|
|
|
* # Raises ArgumentError (negative array size):
|
|
|
|
* Array.new(-1)
|
|
|
|
* # Raises ArgumentError (negative array size):
|
|
|
|
* Array.new(-1, :default)
|
|
|
|
* # Raises ArgumentError (negative array size):
|
|
|
|
* Array.new(-1) { |n| }
|
|
|
|
*
|
|
|
|
* Raises an exception if the single argument is neither \Array-convertible
|
|
|
|
* nor \Integer-convertible.
|
|
|
|
*
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* Array.new(:foo)
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2000-02-29 11:05:32 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_initialize(int argc, VALUE *argv, VALUE ary)
|
2000-02-29 11:05:32 +03:00
|
|
|
{
|
|
|
|
long len;
|
|
|
|
VALUE size, val;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2006-09-02 18:42:08 +04:00
|
|
|
rb_ary_modify(ary);
|
2009-02-23 09:54:58 +03:00
|
|
|
if (argc == 0) {
|
2018-10-31 00:53:56 +03:00
|
|
|
if (ARY_OWNS_HEAP_P(ary) && ARY_HEAP_PTR(ary) != NULL) {
|
|
|
|
ary_heap_free(ary);
|
2006-09-02 18:42:08 +04:00
|
|
|
}
|
2008-10-17 17:09:33 +04:00
|
|
|
rb_ary_unshare_safe(ary);
|
2008-10-09 09:47:04 +04:00
|
|
|
FL_SET_EMBED(ary);
|
|
|
|
ARY_SET_EMBED_LEN(ary, 0);
|
2002-01-28 11:44:45 +03:00
|
|
|
if (rb_block_given_p()) {
|
|
|
|
rb_warning("given block not used");
|
|
|
|
}
|
2001-10-02 08:31:23 +04:00
|
|
|
return ary;
|
|
|
|
}
|
2008-03-05 08:22:17 +03:00
|
|
|
rb_scan_args(argc, argv, "02", &size, &val);
|
2002-01-28 11:44:45 +03:00
|
|
|
if (argc == 1 && !FIXNUM_P(size)) {
|
2002-12-19 12:20:20 +03:00
|
|
|
val = rb_check_array_type(size);
|
2002-01-28 11:44:45 +03:00
|
|
|
if (!NIL_P(val)) {
|
|
|
|
rb_ary_replace(ary, val);
|
|
|
|
return ary;
|
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2000-02-29 11:05:32 +03:00
|
|
|
len = NUM2LONG(size);
|
2014-02-06 05:31:27 +04:00
|
|
|
/* NUM2LONG() may call size.to_int, ary can be frozen, modified, etc */
|
2000-02-29 11:05:32 +03:00
|
|
|
if (len < 0) {
|
|
|
|
rb_raise(rb_eArgError, "negative array size");
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
2008-06-20 03:12:46 +04:00
|
|
|
if (len > ARY_MAX_SIZE) {
|
2000-02-29 11:05:32 +03:00
|
|
|
rb_raise(rb_eArgError, "array size too big");
|
|
|
|
}
|
2014-02-06 05:31:27 +04:00
|
|
|
/* recheck after argument conversion */
|
2004-11-18 06:45:23 +03:00
|
|
|
rb_ary_modify(ary);
|
2008-10-17 14:42:11 +04:00
|
|
|
ary_resize_capa(ary, len);
|
2002-01-28 11:44:45 +03:00
|
|
|
if (rb_block_given_p()) {
|
|
|
|
long i;
|
|
|
|
|
2003-11-04 12:13:57 +03:00
|
|
|
if (argc == 2) {
|
|
|
|
rb_warn("block supersedes default value argument");
|
2002-01-28 11:44:45 +03:00
|
|
|
}
|
|
|
|
for (i=0; i<len; i++) {
|
2004-09-21 07:08:33 +04:00
|
|
|
rb_ary_store(ary, i, rb_yield(LONG2NUM(i)));
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(ary, i + 1);
|
2002-01-28 11:44:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2013-07-22 08:00:12 +04:00
|
|
|
ary_memfill(ary, 0, len, val);
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(ary, len);
|
2002-01-28 11:44:45 +03:00
|
|
|
}
|
2000-02-29 11:05:32 +03:00
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2011-10-04 02:31:25 +04:00
|
|
|
* Returns a new array populated with the given objects.
|
|
|
|
*
|
2018-07-11 12:56:49 +03:00
|
|
|
* Array.[]( 1, 'a', /^A/) # => [1, "a", /^A/]
|
2011-10-04 02:31:25 +04:00
|
|
|
* Array[ 1, 'a', /^A/ ] # => [1, "a", /^A/]
|
|
|
|
* [ 1, 'a', /^A/ ] # => [1, "a", /^A/]
|
|
|
|
*/
|
2003-12-16 23:28:44 +03:00
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_s_create(int argc, VALUE *argv, VALUE klass)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2008-10-09 09:47:04 +04:00
|
|
|
VALUE ary = ary_new(klass, argc);
|
|
|
|
if (argc > 0 && argv) {
|
2013-07-19 16:12:31 +04:00
|
|
|
ary_memcpy(ary, 0, argc, argv);
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(ary, argc);
|
2006-09-02 18:42:08 +04:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-10-03 11:19:19 +04:00
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_store(VALUE ary, long idx, VALUE val)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2013-07-19 15:08:13 +04:00
|
|
|
long len = RARRAY_LEN(ary);
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
if (idx < 0) {
|
2013-07-19 15:08:13 +04:00
|
|
|
idx += len;
|
1999-01-20 07:59:39 +03:00
|
|
|
if (idx < 0) {
|
2010-05-08 08:49:53 +04:00
|
|
|
rb_raise(rb_eIndexError, "index %ld too small for array; minimum: %ld",
|
2013-07-19 15:08:13 +04:00
|
|
|
idx - len, -len);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2008-06-20 03:12:46 +04:00
|
|
|
else if (idx >= ARY_MAX_SIZE) {
|
|
|
|
rb_raise(rb_eIndexError, "index %ld too big", idx);
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2004-11-18 06:45:23 +03:00
|
|
|
rb_ary_modify(ary);
|
2006-09-02 18:42:08 +04:00
|
|
|
if (idx >= ARY_CAPA(ary)) {
|
2009-01-21 18:27:35 +03:00
|
|
|
ary_double_capa(ary, idx);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2013-07-19 15:08:13 +04:00
|
|
|
if (idx > len) {
|
|
|
|
ary_mem_clear(ary, len, idx - len + 1);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2013-07-19 15:08:13 +04:00
|
|
|
if (idx >= len) {
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(ary, idx + 1);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2014-04-11 13:55:10 +04:00
|
|
|
ARY_SET(ary, idx, val);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2004-06-16 11:05:24 +04:00
|
|
|
static VALUE
|
2008-11-03 07:13:04 +03:00
|
|
|
ary_make_partial(VALUE ary, VALUE klass, long offset, long len)
|
2006-09-02 18:42:08 +04:00
|
|
|
{
|
2008-10-09 09:47:04 +04:00
|
|
|
assert(offset >= 0);
|
|
|
|
assert(len >= 0);
|
|
|
|
assert(offset+len <= RARRAY_LEN(ary));
|
2006-09-02 18:42:08 +04:00
|
|
|
|
2008-10-09 09:47:04 +04:00
|
|
|
if (len <= RARRAY_EMBED_LEN_MAX) {
|
2008-11-03 07:13:04 +03:00
|
|
|
VALUE result = ary_alloc(klass);
|
2018-10-31 00:54:13 +03:00
|
|
|
ary_memcpy(result, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary) + offset);
|
2008-10-31 12:46:31 +03:00
|
|
|
ARY_SET_EMBED_LEN(result, len);
|
|
|
|
return result;
|
2008-10-09 09:47:04 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-11-03 07:13:04 +03:00
|
|
|
VALUE shared, result = ary_alloc(klass);
|
2008-10-09 09:47:04 +04:00
|
|
|
FL_UNSET_EMBED(result);
|
|
|
|
|
|
|
|
shared = ary_make_shared(ary);
|
2018-10-31 00:53:56 +03:00
|
|
|
ARY_SET_PTR(result, RARRAY_CONST_PTR_TRANSIENT(ary));
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(result, RARRAY_LEN(ary));
|
2008-10-17 17:09:33 +04:00
|
|
|
rb_ary_set_shared(result, shared);
|
2008-10-09 09:47:04 +04:00
|
|
|
|
|
|
|
ARY_INCREASE_PTR(result, offset);
|
|
|
|
ARY_SET_LEN(result, len);
|
2018-10-31 00:53:56 +03:00
|
|
|
|
|
|
|
ary_verify(shared);
|
|
|
|
ary_verify(result);
|
2008-10-09 09:47:04 +04:00
|
|
|
return result;
|
|
|
|
}
|
2006-09-02 18:42:08 +04:00
|
|
|
}
|
|
|
|
|
2009-04-15 15:47:54 +04:00
|
|
|
static VALUE
|
|
|
|
ary_make_shared_copy(VALUE ary)
|
|
|
|
{
|
|
|
|
return ary_make_partial(ary, rb_obj_class(ary), 0, RARRAY_LEN(ary));
|
|
|
|
}
|
|
|
|
|
2008-11-03 07:13:04 +03:00
|
|
|
enum ary_take_pos_flags
|
|
|
|
{
|
|
|
|
ARY_TAKE_FIRST = 0,
|
|
|
|
ARY_TAKE_LAST = 1
|
|
|
|
};
|
|
|
|
|
2006-09-02 18:42:08 +04:00
|
|
|
static VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
ary_take_first_or_last(int argc, const VALUE *argv, VALUE ary, enum ary_take_pos_flags last)
|
2004-06-16 11:05:24 +04:00
|
|
|
{
|
|
|
|
long n;
|
2013-10-15 11:34:05 +04:00
|
|
|
long len;
|
2006-09-02 18:42:08 +04:00
|
|
|
long offset = 0;
|
2004-06-16 11:05:24 +04:00
|
|
|
|
2018-12-04 12:16:49 +03:00
|
|
|
argc = rb_check_arity(argc, 0, 1);
|
2019-03-31 17:46:25 +03:00
|
|
|
/* the case optional argument is omitted should be handled in
|
2018-12-04 12:16:49 +03:00
|
|
|
* callers of this function. if another arity case is added,
|
|
|
|
* this arity check needs to rewrite. */
|
2019-07-15 04:19:25 +03:00
|
|
|
RUBY_ASSERT_ALWAYS(argc == 1);
|
2018-12-04 12:16:49 +03:00
|
|
|
|
|
|
|
n = NUM2LONG(argv[0]);
|
2013-10-15 11:34:05 +04:00
|
|
|
len = RARRAY_LEN(ary);
|
|
|
|
if (n > len) {
|
|
|
|
n = len;
|
2004-06-16 11:05:24 +04:00
|
|
|
}
|
|
|
|
else if (n < 0) {
|
|
|
|
rb_raise(rb_eArgError, "negative array size");
|
|
|
|
}
|
2006-09-02 18:42:08 +04:00
|
|
|
if (last) {
|
2013-10-15 11:34:05 +04:00
|
|
|
offset = len - n;
|
2006-09-02 18:42:08 +04:00
|
|
|
}
|
2008-11-03 07:13:04 +03:00
|
|
|
return ary_make_partial(ary, rb_cArray, offset, n);
|
2004-06-16 11:05:24 +04:00
|
|
|
}
|
|
|
|
|
2004-07-13 20:21:23 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-09 21:57:41 +03:00
|
|
|
* array << object -> self
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Appends +object+ to +self+; returns +self+:
|
2020-05-16 00:12:40 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a << :baz
|
|
|
|
* a1 # => [:foo, "bar", 2, :baz]
|
2020-06-09 21:57:41 +03:00
|
|
|
* a1.equal?(a) # => true # Returned self
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Appends +object+ as one element, even if it is another \Array:
|
2020-05-16 00:12:40 +03:00
|
|
|
*
|
|
|
|
* a = [:foo, 'bar', 2]
|
2020-06-24 21:31:42 +03:00
|
|
|
* a1 = a << [3, 4]
|
2020-05-16 00:12:40 +03:00
|
|
|
* a1 # => [:foo, "bar", 2, [3, 4]]
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_push(VALUE ary, VALUE item)
|
2010-02-10 10:31:06 +03:00
|
|
|
{
|
2018-10-31 00:53:56 +03:00
|
|
|
long idx = RARRAY_LEN((ary_verify(ary), ary));
|
2014-04-11 12:47:00 +04:00
|
|
|
VALUE target_ary = ary_ensure_room_for_push(ary, 1);
|
2018-12-03 15:36:39 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
2014-04-11 12:47:00 +04:00
|
|
|
RB_OBJ_WRITE(target_ary, &ptr[idx], item);
|
|
|
|
});
|
2012-11-09 11:08:42 +04:00
|
|
|
ARY_SET_LEN(ary, idx + 1);
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2012-11-09 11:08:42 +04:00
|
|
|
return ary;
|
2010-02-10 10:31:06 +03:00
|
|
|
}
|
|
|
|
|
2012-03-08 19:25:04 +04:00
|
|
|
VALUE
|
2014-04-11 12:47:00 +04:00
|
|
|
rb_ary_cat(VALUE ary, const VALUE *argv, long len)
|
2012-03-08 19:25:04 +04:00
|
|
|
{
|
2012-11-09 11:08:42 +04:00
|
|
|
long oldlen = RARRAY_LEN(ary);
|
2014-04-11 12:47:00 +04:00
|
|
|
VALUE target_ary = ary_ensure_room_for_push(ary, len);
|
|
|
|
ary_memcpy0(ary, oldlen, len, argv, target_ary);
|
2012-03-08 19:25:04 +04:00
|
|
|
ARY_SET_LEN(ary, oldlen + len);
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2020-06-09 21:57:41 +03:00
|
|
|
* array.push(*objects) -> self
|
|
|
|
* array.append(*objects) -> self
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Appends trailing elements.
|
|
|
|
*
|
|
|
|
* Array#append is an alias for \Array#push.
|
2020-06-09 21:57:41 +03:00
|
|
|
|
|
|
|
* See also:
|
|
|
|
* - #pop: Removes and returns trailing elements.
|
|
|
|
* - #shift: Removes and returns leading elements.
|
|
|
|
* - #unshift: Prepends leading elements.
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Appends each argument in +objects+ to +self+; returns +self+:
|
2020-05-16 00:12:40 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.push(:baz, :bat)
|
|
|
|
* a1 # => [:foo, "bar", 2, :baz, :bat]
|
2020-06-09 21:57:41 +03:00
|
|
|
* a1.equal?(a) # => true # Returned self
|
2020-05-16 00:12:40 +03:00
|
|
|
*
|
|
|
|
* Appends each argument as one element, even if it is another \Array:
|
|
|
|
*
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.push([:baz, :bat], [:bam, :bad])
|
|
|
|
* a1 # => [:foo, "bar", 2, [:baz, :bat], [:bam, :bad]]
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_push_m(int argc, VALUE *argv, VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2012-03-08 19:25:04 +04:00
|
|
|
return rb_ary_cat(ary, argv, argc);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_pop(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2006-09-02 18:42:08 +04:00
|
|
|
long n;
|
2001-12-10 10:18:16 +03:00
|
|
|
rb_ary_modify_check(ary);
|
2013-10-15 11:34:05 +04:00
|
|
|
n = RARRAY_LEN(ary);
|
|
|
|
if (n == 0) return Qnil;
|
2008-10-09 09:47:04 +04:00
|
|
|
if (ARY_OWNS_HEAP_P(ary) &&
|
2013-10-15 11:34:05 +04:00
|
|
|
n * 3 < ARY_CAPA(ary) &&
|
2006-10-16 18:35:51 +04:00
|
|
|
ARY_CAPA(ary) > ARY_DEFAULT_SIZE)
|
|
|
|
{
|
2013-10-15 11:34:05 +04:00
|
|
|
ary_resize_capa(ary, n * 2);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2013-10-15 11:34:05 +04:00
|
|
|
--n;
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(ary, n);
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2013-05-13 13:56:22 +04:00
|
|
|
return RARRAY_AREF(ary, n);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-09 21:57:41 +03:00
|
|
|
* array.pop -> object or nil
|
|
|
|
* array.pop(n) -> new_array
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Removes and returns trailing elements.
|
|
|
|
*
|
|
|
|
* See also:
|
|
|
|
* - #push: Appends trailing elements.
|
|
|
|
* - #shift: Removes and returns leading elements.
|
|
|
|
* - #unshift: Prepends leading elements.
|
2008-04-10 14:25:44 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* Argument +n+, if given, must be an
|
|
|
|
* {Integer-convertible object}[doc/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects]
|
|
|
|
* (implements +to_int+).
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When no argument is given and the array is not empty,
|
|
|
|
* removes and returns the last element in the array:
|
|
|
|
*
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.pop # => 2
|
|
|
|
* a # => [:foo, "bar"]
|
|
|
|
*
|
|
|
|
* Returns +nil+ if the array is empty:
|
|
|
|
*
|
|
|
|
* a = []
|
|
|
|
* a.pop # => nil
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When argument +n+ is given and is non-negative and in range,
|
2020-06-09 21:57:41 +03:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* removes and returns the last +n+ elements in a new \Array:
|
|
|
|
*
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.pop(2)
|
|
|
|
* a1 # => ["bar", 2]
|
|
|
|
* a # => [:foo]
|
|
|
|
* a.pop(0) # => []
|
|
|
|
*
|
|
|
|
* If +n+ is positive and out of range,
|
|
|
|
* removes and returns all elements:
|
|
|
|
*
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.pop(50)
|
|
|
|
* a1 # => [:foo, "bar", 2]
|
|
|
|
* a # => []
|
|
|
|
* a.pop(1) # => []
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if +n+ is negative:
|
|
|
|
*
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises ArgumentError (negative array size):
|
|
|
|
* a1 = a.pop(-1)
|
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Raises an exception if +n+ is not \Integer-convertible (implements +to_int+):
|
2020-05-16 00:12:40 +03:00
|
|
|
*
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises TypeError (no implicit conversion of String into Integer):
|
|
|
|
* a1 = a.pop('x')
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2004-06-16 11:05:24 +04:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_pop_m(int argc, VALUE *argv, VALUE ary)
|
2004-06-16 11:05:24 +04:00
|
|
|
{
|
|
|
|
VALUE result;
|
|
|
|
|
|
|
|
if (argc == 0) {
|
|
|
|
return rb_ary_pop(ary);
|
|
|
|
}
|
|
|
|
|
|
|
|
rb_ary_modify_check(ary);
|
2008-12-17 09:52:18 +03:00
|
|
|
result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_INCREASE_LEN(ary, -RARRAY_LEN(result));
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2004-06-16 11:05:24 +04:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_shift(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
VALUE top;
|
2013-10-15 11:34:05 +04:00
|
|
|
long len = RARRAY_LEN(ary);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-12-10 10:18:16 +03:00
|
|
|
rb_ary_modify_check(ary);
|
2013-10-15 11:34:05 +04:00
|
|
|
if (len == 0) return Qnil;
|
2013-05-13 13:56:22 +04:00
|
|
|
top = RARRAY_AREF(ary, 0);
|
2006-09-27 02:46:16 +04:00
|
|
|
if (!ARY_SHARED_P(ary)) {
|
2013-10-15 11:34:05 +04:00
|
|
|
if (len < ARY_DEFAULT_SIZE) {
|
2018-12-03 15:36:47 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
2013-10-15 11:34:05 +04:00
|
|
|
MEMMOVE(ptr, ptr+1, VALUE, len-1);
|
2013-07-19 16:56:58 +04:00
|
|
|
}); /* WB: no new reference */
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_INCREASE_LEN(ary, -1);
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2007-10-09 16:29:21 +04:00
|
|
|
return top;
|
|
|
|
}
|
2008-10-09 09:47:04 +04:00
|
|
|
assert(!ARY_EMBED_P(ary)); /* ARY_EMBED_LEN_MAX < ARY_DEFAULT_SIZE */
|
|
|
|
|
2014-04-11 13:55:10 +04:00
|
|
|
ARY_SET(ary, 0, Qnil);
|
2006-11-02 03:19:57 +03:00
|
|
|
ary_make_shared(ary);
|
2006-09-02 18:42:08 +04:00
|
|
|
}
|
2019-07-19 07:02:38 +03:00
|
|
|
else if (ARY_SHARED_ROOT_OCCUPIED(ARY_SHARED_ROOT(ary))) {
|
2018-12-03 15:36:47 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, ptr[0] = Qnil);
|
2009-05-15 12:35:35 +04:00
|
|
|
}
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_INCREASE_PTR(ary, 1); /* shift ptr */
|
|
|
|
ARY_INCREASE_LEN(ary, -1);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
return top;
|
|
|
|
}
|
|
|
|
|
2004-06-16 11:05:24 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-09 21:57:41 +03:00
|
|
|
* array.shift -> object or nil
|
|
|
|
* array.shift(n) -> new_array
|
|
|
|
*
|
|
|
|
* Removes and returns leading elements.
|
|
|
|
*
|
|
|
|
* See also:
|
|
|
|
* - #push: Appends trailing elements.
|
|
|
|
* - #pop: Removes and returns trailing elements.
|
|
|
|
* - #unshift: Prepends leading elements.
|
|
|
|
*
|
|
|
|
* Argument +n+, if given, must be an
|
|
|
|
* {Integer-convertible object}[doc/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects]
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When no argument is given, removes and returns the first element:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.shift # => :foo
|
|
|
|
* a # => ['bar', 2]
|
|
|
|
*
|
|
|
|
* Returns +nil+ if +self+ is empty:
|
|
|
|
* [].shift # => nil
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When argument +n+ is given, removes the first +n+ elements;
|
|
|
|
* returns those elements in a new \Array:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.shift(2) # => [:foo, 'bar']
|
|
|
|
* a # => [2]
|
|
|
|
*
|
|
|
|
* If +n+ is as large as or larger than <tt>self.length</tt>,
|
|
|
|
* removes all elements; returns those elements in a new \Array:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.shift(3) # => [:foo, 'bar', 2]
|
|
|
|
* a # => []
|
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* If +n+ is zero, returns a new empty \Array; +self+ is unmodified:
|
2020-06-09 21:57:41 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.shift(0) # => []
|
|
|
|
* a # => [:foo, 'bar', 2]
|
2008-04-10 14:25:44 +04:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* ---
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Raises an exception if +n+ is negative:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises ArgumentError (negative array size):
|
|
|
|
* a1 = a.shift(-1)
|
2004-06-16 11:05:24 +04:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Raises an exception if +n+ is not an
|
|
|
|
* {Integer-convertible object}[doc/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects]:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* a.shift(:foo)
|
2004-06-16 11:05:24 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
|
2004-06-16 11:05:24 +04:00
|
|
|
{
|
|
|
|
VALUE result;
|
|
|
|
long n;
|
|
|
|
|
|
|
|
if (argc == 0) {
|
|
|
|
return rb_ary_shift(ary);
|
|
|
|
}
|
|
|
|
|
|
|
|
rb_ary_modify_check(ary);
|
2008-11-03 07:13:04 +03:00
|
|
|
result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
|
2006-09-02 18:42:08 +04:00
|
|
|
n = RARRAY_LEN(result);
|
2018-08-28 10:06:06 +03:00
|
|
|
rb_ary_behead(ary,n);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-06-10 07:42:30 +03:00
|
|
|
static VALUE
|
|
|
|
behead_shared(VALUE ary, long n)
|
2018-08-28 10:06:06 +03:00
|
|
|
{
|
2020-06-10 07:42:30 +03:00
|
|
|
assert(ARY_SHARED_P(ary));
|
2018-08-28 10:06:06 +03:00
|
|
|
rb_ary_modify_check(ary);
|
2020-06-10 07:42:30 +03:00
|
|
|
if (ARY_SHARED_ROOT_OCCUPIED(ARY_SHARED_ROOT(ary))) {
|
|
|
|
ary_mem_clear(ary, 0, n);
|
2006-09-02 18:42:08 +04:00
|
|
|
}
|
2020-06-10 07:42:30 +03:00
|
|
|
ARY_INCREASE_PTR(ary, n);
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_INCREASE_LEN(ary, -n);
|
2020-06-10 07:42:30 +03:00
|
|
|
ary_verify(ary);
|
|
|
|
return ary;
|
|
|
|
}
|
2004-06-16 11:05:24 +04:00
|
|
|
|
2020-06-10 07:42:30 +03:00
|
|
|
static VALUE
|
|
|
|
behead_transient(VALUE ary, long n)
|
|
|
|
{
|
|
|
|
rb_ary_modify_check(ary);
|
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
|
|
|
MEMMOVE(ptr, ptr+n, VALUE, RARRAY_LEN(ary)-n);
|
|
|
|
}); /* WB: no new reference */
|
|
|
|
ARY_INCREASE_LEN(ary, -n);
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2018-08-28 10:06:06 +03:00
|
|
|
return ary;
|
2004-06-16 11:05:24 +04:00
|
|
|
}
|
|
|
|
|
2020-06-10 07:42:30 +03:00
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
|
|
|
rb_ary_behead(VALUE ary, long n)
|
|
|
|
{
|
|
|
|
if (n <= 0) {
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
else if (ARY_SHARED_P(ary)) {
|
|
|
|
return behead_shared(ary, n);
|
|
|
|
}
|
|
|
|
else if (RARRAY_LEN(ary) >= ARY_DEFAULT_SIZE) {
|
|
|
|
ary_make_shared(ary);
|
|
|
|
return behead_shared(ary, n);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return behead_transient(ary, n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-11 12:47:00 +04:00
|
|
|
static VALUE
|
2020-06-11 04:28:34 +03:00
|
|
|
make_room_for_unshift(VALUE ary, const VALUE *head, VALUE *sharedp, int argc, long capa, long len)
|
|
|
|
{
|
|
|
|
if (head - sharedp < argc) {
|
|
|
|
long room = capa - len - argc;
|
2020-06-12 05:04:46 +03:00
|
|
|
|
2020-06-11 04:28:34 +03:00
|
|
|
room -= room >> 4;
|
|
|
|
MEMMOVE((VALUE *)sharedp + argc + room, head, VALUE, len);
|
|
|
|
head = sharedp + argc + room;
|
|
|
|
}
|
|
|
|
ARY_SET_PTR(ary, head - argc);
|
|
|
|
assert(ARY_SHARED_ROOT_OCCUPIED(ARY_SHARED_ROOT(ary)));
|
2020-06-12 05:04:46 +03:00
|
|
|
|
2020-06-11 04:28:34 +03:00
|
|
|
ary_verify(ary);
|
|
|
|
return ARY_SHARED_ROOT(ary);
|
|
|
|
}
|
2020-06-12 05:04:46 +03:00
|
|
|
|
2020-06-11 04:28:34 +03:00
|
|
|
static VALUE
|
|
|
|
ary_modify_for_unshift(VALUE ary, int argc)
|
2012-11-09 11:08:50 +04:00
|
|
|
{
|
|
|
|
long len = RARRAY_LEN(ary);
|
|
|
|
long new_len = len + argc;
|
|
|
|
long capa;
|
2013-08-23 13:42:18 +04:00
|
|
|
const VALUE *head, *sharedp;
|
2012-11-09 11:08:50 +04:00
|
|
|
|
2019-06-23 05:22:23 +03:00
|
|
|
rb_ary_modify(ary);
|
2012-11-09 11:08:50 +04:00
|
|
|
capa = ARY_CAPA(ary);
|
|
|
|
if (capa - (capa >> 6) <= new_len) {
|
|
|
|
ary_double_capa(ary, new_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* use shared array for big "queues" */
|
|
|
|
if (new_len > ARY_DEFAULT_SIZE * 4) {
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
|
|
|
|
2018-10-31 00:02:12 +03:00
|
|
|
/* make a room for unshifted items */
|
2012-11-09 11:08:50 +04:00
|
|
|
capa = ARY_CAPA(ary);
|
|
|
|
ary_make_shared(ary);
|
|
|
|
|
2018-10-31 00:54:13 +03:00
|
|
|
head = sharedp = RARRAY_CONST_PTR_TRANSIENT(ary);
|
2020-06-11 04:28:34 +03:00
|
|
|
return make_room_for_unshift(ary, head, (void *)sharedp, argc, capa, len);
|
2012-11-09 11:08:50 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* sliding items */
|
2018-12-03 15:36:47 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
2013-07-19 16:56:58 +04:00
|
|
|
MEMMOVE(ptr + argc, ptr, VALUE, len);
|
|
|
|
});
|
2014-04-11 12:47:00 +04:00
|
|
|
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2014-04-11 12:47:00 +04:00
|
|
|
return ary;
|
2012-11-09 11:08:50 +04:00
|
|
|
}
|
|
|
|
}
|
2020-06-12 05:04:46 +03:00
|
|
|
|
2020-06-11 04:28:34 +03:00
|
|
|
static VALUE
|
|
|
|
ary_ensure_room_for_unshift(VALUE ary, int argc)
|
|
|
|
{
|
|
|
|
long len = RARRAY_LEN(ary);
|
|
|
|
long new_len = len + argc;
|
2020-06-12 05:04:46 +03:00
|
|
|
|
2020-06-11 04:28:34 +03:00
|
|
|
if (len > ARY_MAX_SIZE - argc) {
|
|
|
|
rb_raise(rb_eIndexError, "index %ld too big", new_len);
|
|
|
|
}
|
|
|
|
else if (! ARY_SHARED_P(ary)) {
|
|
|
|
return ary_modify_for_unshift(ary, argc);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VALUE shared_root = ARY_SHARED_ROOT(ary);
|
|
|
|
long capa = RARRAY_LEN(shared_root);
|
2020-06-12 05:04:46 +03:00
|
|
|
|
2020-06-11 04:28:34 +03:00
|
|
|
if (! ARY_SHARED_ROOT_OCCUPIED(shared_root)) {
|
|
|
|
return ary_modify_for_unshift(ary, argc);
|
|
|
|
}
|
|
|
|
else if (new_len > capa) {
|
|
|
|
return ary_modify_for_unshift(ary, argc);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const VALUE * head = RARRAY_CONST_PTR_TRANSIENT(ary);
|
|
|
|
void *sharedp = (void *)RARRAY_CONST_PTR_TRANSIENT(shared_root);
|
2020-06-12 05:04:46 +03:00
|
|
|
|
|
|
|
rb_ary_modify_check(ary);
|
2020-06-11 04:28:34 +03:00
|
|
|
return make_room_for_unshift(ary, head, sharedp, argc, capa, len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-11-09 11:08:50 +04:00
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-09 21:57:41 +03:00
|
|
|
* array.unshift(*objects) -> self
|
|
|
|
* array.prepend(*objects) -> self
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Prepends leading elements.
|
|
|
|
*
|
|
|
|
* Array#prepend is an alias for \Array#unshift.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* See also:
|
|
|
|
* - #push: Appends trailing elements.
|
|
|
|
* - #pop: Removes and returns trailing elements.
|
|
|
|
* - #shift: Removes and returns leading elements.
|
|
|
|
*
|
|
|
|
* Prepends the given +objects+ to +self+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.unshift(:bam, :bat)
|
|
|
|
* a1 # => [:bam, :bat, :foo, "bar", 2]
|
|
|
|
* a1.equal?(a) # => true # Returned self
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2000-05-01 13:42:38 +04:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
|
2000-05-01 13:42:38 +04:00
|
|
|
{
|
2012-11-09 11:08:50 +04:00
|
|
|
long len = RARRAY_LEN(ary);
|
2014-04-11 12:47:00 +04:00
|
|
|
VALUE target_ary;
|
2006-10-16 18:35:51 +04:00
|
|
|
|
2012-11-09 11:08:50 +04:00
|
|
|
if (argc == 0) {
|
|
|
|
rb_ary_modify_check(ary);
|
|
|
|
return ary;
|
2006-09-27 02:46:16 +04:00
|
|
|
}
|
|
|
|
|
2014-04-11 12:47:00 +04:00
|
|
|
target_ary = ary_ensure_room_for_unshift(ary, argc);
|
|
|
|
ary_memcpy0(ary, 0, argc, argv, target_ary);
|
2012-11-09 11:08:50 +04:00
|
|
|
ARY_SET_LEN(ary, len + argc);
|
2000-05-01 13:42:38 +04:00
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2006-09-27 02:46:16 +04:00
|
|
|
VALUE
|
|
|
|
rb_ary_unshift(VALUE ary, VALUE item)
|
|
|
|
{
|
|
|
|
return rb_ary_unshift_m(1,&item,ary);
|
|
|
|
}
|
|
|
|
|
2004-09-21 07:08:33 +04:00
|
|
|
/* faster version - use this if you don't need to treat negative offset */
|
|
|
|
static inline VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_elt(VALUE ary, long offset)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2013-10-15 11:34:05 +04:00
|
|
|
long len = RARRAY_LEN(ary);
|
|
|
|
if (len == 0) return Qnil;
|
|
|
|
if (offset < 0 || len <= offset) {
|
1998-01-16 15:13:05 +03:00
|
|
|
return Qnil;
|
|
|
|
}
|
2013-05-13 13:56:22 +04:00
|
|
|
return RARRAY_AREF(ary, offset);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2004-09-21 07:08:33 +04:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_entry(VALUE ary, long offset)
|
2004-09-21 07:08:33 +04:00
|
|
|
{
|
2018-02-12 18:25:58 +03:00
|
|
|
return rb_ary_entry_internal(ary, offset);
|
2004-09-21 07:08:33 +04:00
|
|
|
}
|
|
|
|
|
2007-10-18 10:58:35 +04:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_subseq(VALUE ary, long beg, long len)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2008-10-09 09:47:04 +04:00
|
|
|
VALUE klass;
|
2013-10-15 11:34:05 +04:00
|
|
|
long alen = RARRAY_LEN(ary);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2013-10-15 11:34:05 +04:00
|
|
|
if (beg > alen) return Qnil;
|
2000-11-20 10:31:55 +03:00
|
|
|
if (beg < 0 || len < 0) return Qnil;
|
|
|
|
|
2013-10-15 11:34:05 +04:00
|
|
|
if (alen < len || alen < beg + len) {
|
|
|
|
len = alen - beg;
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
2001-10-16 07:27:23 +04:00
|
|
|
klass = rb_obj_class(ary);
|
2002-05-21 09:39:19 +04:00
|
|
|
if (len == 0) return ary_new(klass, 0);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2008-11-03 07:13:04 +03:00
|
|
|
return ary_make_partial(ary, klass, beg, len);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2019-11-18 06:13:08 +03:00
|
|
|
static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2020-06-09 21:57:41 +03:00
|
|
|
* array[index] -> object or nil
|
|
|
|
* array[start, length] -> object or nil
|
2020-06-14 17:59:48 +03:00
|
|
|
* array[range] -> object or nil
|
2020-06-09 21:57:41 +03:00
|
|
|
* array.slice(index) -> object or nil
|
|
|
|
* array.slice(start, length) -> object or nil
|
2020-06-14 17:59:48 +03:00
|
|
|
* array.slice(range) -> object or nil
|
2020-06-09 21:57:41 +03:00
|
|
|
*
|
|
|
|
* Returns elements from +self+; does not modify +self+.
|
|
|
|
*
|
|
|
|
* - Arguments +index+, +start+, and +length+, if given, must be
|
|
|
|
* {Integer-convertible objects}[doc/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects].
|
|
|
|
* - Argument +range+, if given, must be a \Range object.
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When a single argument +index+ is given, returns the element at offset +index+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[0] # => :foo
|
|
|
|
* a[2] # => 2
|
|
|
|
* a # => [:foo, "bar", 2]
|
|
|
|
*
|
|
|
|
* If +index+ is negative, counts relative to the end of +self+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[-1] # => 2
|
|
|
|
* a[-2] # => "bar"
|
|
|
|
*
|
|
|
|
* If +index+ is out of range, returns +nil+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[50] # => nil
|
|
|
|
* a[-50] # => nil
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When two arguments +start+ and +length+ are given,
|
|
|
|
* returns a new \Array of size +length+ containing successive elements beginning at offset +start+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[0, 2] # => [:foo, "bar"]
|
|
|
|
* a[1, 2] # => ["bar", 2]
|
|
|
|
*
|
|
|
|
* If <tt>start + length</tt> is greater than <tt>self.length</tt>,
|
|
|
|
* returns all elements from offset +start+ to the end:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[0, 4] # => [:foo, "bar", 2]
|
|
|
|
* a[1, 3] # => ["bar", 2]
|
|
|
|
* a[2, 2] # => [2]
|
|
|
|
*
|
|
|
|
* If <tt>start == self.size</tt> and <tt>length >= 0</tt>,
|
|
|
|
* returns a new empty \Array:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[a.size, 0] # => []
|
|
|
|
* a[a.size, 50] # => []
|
|
|
|
*
|
|
|
|
* If +length+ is negative, returns +nil+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[2, -1] # => nil
|
|
|
|
* a[1, -2] # => nil
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When a single argument +range+ is given,
|
|
|
|
* treats <tt>range.min</tt> as +start+ above
|
|
|
|
* and <tt>range.size</tt> as +length+ above:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[0..1] # => [:foo, "bar"]
|
|
|
|
* a[1..2] # => ["bar", 2]
|
|
|
|
*
|
|
|
|
* Special case: If <tt>range.start == a.size</tt>, returns a new empty \Array:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[a.size..0] # => []
|
|
|
|
* a[a.size..50] # => []
|
|
|
|
* a[a.size..-1] # => []
|
|
|
|
* a[a.size..-50] # => []
|
|
|
|
*
|
|
|
|
* If <tt>range.end</tt> is negative, calculates the end index from the end:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[0..-1] # => [:foo, "bar", 2]
|
|
|
|
* a[0..-2] # => [:foo, "bar"]
|
|
|
|
* a[0..-3] # => [:foo]
|
|
|
|
* a[0..-4] # => []
|
|
|
|
*
|
|
|
|
* If <tt>range.start</tt> is negative, calculates the start index from the end:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[-1..2] # => [2]
|
|
|
|
* a[-2..2] # => ["bar", 2]
|
|
|
|
* a[-3..2] # => [:foo, "bar", 2]
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if given a single argument
|
|
|
|
* that is not an \Integer-convertible object or a \Range object:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* a[:foo]
|
|
|
|
*
|
|
|
|
* Raises an exception if given two arguments that are not both \Integer-convertible objects:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* a[:foo, 3]
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* a[1, :bar]
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
rb_ary_aref(int argc, const VALUE *argv, VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2017-10-22 03:19:12 +03:00
|
|
|
rb_check_arity(argc, 1, 2);
|
2001-07-02 12:46:28 +04:00
|
|
|
if (argc == 2) {
|
2017-10-22 03:19:12 +03:00
|
|
|
return rb_ary_aref2(ary, argv[0], argv[1]);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2017-10-22 03:19:12 +03:00
|
|
|
return rb_ary_aref1(ary, argv[0]);
|
|
|
|
}
|
|
|
|
|
2020-05-19 07:09:26 +03:00
|
|
|
static VALUE
|
2017-10-22 03:19:12 +03:00
|
|
|
rb_ary_aref2(VALUE ary, VALUE b, VALUE e)
|
|
|
|
{
|
|
|
|
long beg = NUM2LONG(b);
|
|
|
|
long len = NUM2LONG(e);
|
|
|
|
if (beg < 0) {
|
|
|
|
beg += RARRAY_LEN(ary);
|
2001-07-02 12:46:28 +04:00
|
|
|
}
|
2017-10-22 03:19:12 +03:00
|
|
|
return rb_ary_subseq(ary, beg, len);
|
|
|
|
}
|
|
|
|
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
2017-10-22 03:19:12 +03:00
|
|
|
rb_ary_aref1(VALUE ary, VALUE arg)
|
|
|
|
{
|
|
|
|
long beg, len;
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
/* special case - speeding up */
|
2001-07-02 12:46:28 +04:00
|
|
|
if (FIXNUM_P(arg)) {
|
|
|
|
return rb_ary_entry(ary, FIX2LONG(arg));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2002-05-21 09:39:19 +04:00
|
|
|
/* check if idx is Range */
|
2006-09-02 18:42:08 +04:00
|
|
|
switch (rb_range_beg_len(arg, &beg, &len, RARRAY_LEN(ary), 0)) {
|
2002-05-21 09:39:19 +04:00
|
|
|
case Qfalse:
|
|
|
|
break;
|
|
|
|
case Qnil:
|
|
|
|
return Qnil;
|
|
|
|
default:
|
|
|
|
return rb_ary_subseq(ary, beg, len);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2001-07-02 12:46:28 +04:00
|
|
|
return rb_ary_entry(ary, NUM2LONG(arg));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2020-06-09 21:57:41 +03:00
|
|
|
* array.at(index) -> object
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Argument +index+ must be an
|
|
|
|
* {Integer-convertible object}[doc/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects].
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Returns the element at offset +index+; does not modify +self+.
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.at(0) # => :foo
|
|
|
|
* a.at(2) # => 2
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if +index+ is not an \Integer-convertible object:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* a.at(:foo)
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2015-11-09 15:27:26 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_at(VALUE ary, VALUE pos)
|
1999-10-13 10:44:42 +04:00
|
|
|
{
|
|
|
|
return rb_ary_entry(ary, NUM2LONG(pos));
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-09 21:57:41 +03:00
|
|
|
* array.first -> object or nil
|
|
|
|
* array.first(n) -> new_array
|
|
|
|
*
|
|
|
|
* Returns elements from +self+; does not modify +self+.
|
|
|
|
* See also #last.
|
|
|
|
*
|
|
|
|
* Argument +n+, if given, must be an
|
|
|
|
* {Integer-convertible object}[doc/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects].
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When no argument is given, returns the first element:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.first # => :foo
|
|
|
|
* a # => [:foo, "bar", 2]
|
|
|
|
*
|
|
|
|
* If +self+ is empty, returns +nil+:
|
|
|
|
* [].first # => nil
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When argument +n+ is given, returns the first +n+ elements in a new \Array:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.first(2) # => [:foo, "bar"]
|
|
|
|
*
|
|
|
|
* If <tt>n >= ary.size</tt>, returns all elements:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.first(50) # => [:foo, "bar", 2]
|
|
|
|
*
|
|
|
|
* If <tt>n == 0</tt> returns an new empty \Array:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.first(0) # []
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if +n+ is negative:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises ArgumentError (negative array size):
|
|
|
|
* a.first(-1)
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Raises an exception if +n+ is not an \Integer-convertible object:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises TypeError (no implicit conversion of String into Integer):
|
|
|
|
* a.first(:X)
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
1999-10-13 10:44:42 +04:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_first(int argc, VALUE *argv, VALUE ary)
|
1999-10-13 10:44:42 +04:00
|
|
|
{
|
2003-06-06 13:24:59 +04:00
|
|
|
if (argc == 0) {
|
2006-09-02 18:42:08 +04:00
|
|
|
if (RARRAY_LEN(ary) == 0) return Qnil;
|
2013-05-13 13:56:22 +04:00
|
|
|
return RARRAY_AREF(ary, 0);
|
2003-06-06 13:24:59 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-11-03 07:13:04 +03:00
|
|
|
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
|
2003-06-06 13:24:59 +04:00
|
|
|
}
|
1999-10-13 10:44:42 +04:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-09 21:57:41 +03:00
|
|
|
* array.last -> object or nil
|
|
|
|
* array.last(n) -> new_array
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Returns elements from +self+; +self+ is not modified.
|
|
|
|
* See also #first.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* Argument +n+, if given, must be an
|
|
|
|
* {Integer-convertible object}[doc/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects].
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When no argument is given, returns the last element:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.last # => 2
|
|
|
|
* a # => [:foo, "bar", 2]
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-09 21:57:41 +03:00
|
|
|
* If +self+ is empty, returns +nil+:
|
|
|
|
* [].last # => nil
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When argument +n+ is given, returns the last +n+ elements in a new \Array:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.last(2) # => ["bar", 2]
|
|
|
|
*
|
|
|
|
* If <tt>n >= ary.size</tt>, returns all elements:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.last(50) # => [:foo, "bar", 2]
|
|
|
|
*
|
|
|
|
* If <tt>n == 0</tt>, returns an new empty \Array:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.last(0) # []
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if +n+ is negative:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises ArgumentError (negative array size):
|
|
|
|
* a.last(-1)
|
|
|
|
*
|
|
|
|
* Raises an exception if +n+ is not an \Integer-convertible object:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* a.last(:X)
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2007-10-18 10:58:35 +04:00
|
|
|
VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
rb_ary_last(int argc, const VALUE *argv, VALUE ary)
|
1999-10-13 10:44:42 +04:00
|
|
|
{
|
2003-06-06 13:24:59 +04:00
|
|
|
if (argc == 0) {
|
2013-10-15 11:34:05 +04:00
|
|
|
long len = RARRAY_LEN(ary);
|
|
|
|
if (len == 0) return Qnil;
|
|
|
|
return RARRAY_AREF(ary, len-1);
|
2003-06-06 13:24:59 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-11-03 07:13:04 +03:00
|
|
|
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
|
2003-06-06 13:24:59 +04:00
|
|
|
}
|
1999-10-13 10:44:42 +04:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-10 14:45:29 +03:00
|
|
|
* array.fetch(index) -> element
|
|
|
|
* array.fetch(index, default_value) -> element
|
|
|
|
* array.fetch(index) {|index| ... } -> element
|
|
|
|
*
|
|
|
|
* Returns the element at offset +index+.
|
|
|
|
*
|
|
|
|
* Argument +index+ must be an
|
|
|
|
* {Integer-convertible object}[doc/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects]
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* With the single argument +index+, returns the element at offset +index+:
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
2020-06-10 14:45:29 +03:00
|
|
|
* a.fetch(1) # => "bar"
|
|
|
|
*
|
|
|
|
* If +index+ is negative, counts from the end of the array:
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
2020-06-10 14:45:29 +03:00
|
|
|
* a.fetch(-1) # => 2
|
|
|
|
* a.fetch(-2) # => "bar"
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* With arguments +index+ and +default_value+,
|
|
|
|
* returns the element at offset +index+ if index is in range,
|
|
|
|
* otherwise returns +default_value+:
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
2020-06-10 14:45:29 +03:00
|
|
|
* a.fetch(1, nil) # => "bar"
|
|
|
|
* a.fetch(50, nil) # => nil
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* With argument +index+ and a block,
|
|
|
|
* returns the element at offset +index+ if index is in range
|
|
|
|
* (and the block is not called); otherwise calls the block with index and returns its return value:
|
|
|
|
*
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
2020-06-10 14:45:29 +03:00
|
|
|
* a.fetch(1) { |index| raise 'Cannot happen' } # => "bar"
|
|
|
|
* a.fetch(50) { |index| "Value for #{index}" } # => "Value for 50"
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if +index+ is not an \Integer-convertible object.
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
2020-06-10 14:45:29 +03:00
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* a.fetch(:foo)
|
|
|
|
*
|
|
|
|
* Raises an exception if +index+ is out of range and neither default_value nor a block given:
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
2020-06-10 14:45:29 +03:00
|
|
|
* # Raises IndexError (index 50 outside of array bounds: -3...3):
|
|
|
|
* a.fetch(50)
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2001-02-02 14:38:20 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_fetch(int argc, VALUE *argv, VALUE ary)
|
2001-02-02 14:38:20 +03:00
|
|
|
{
|
|
|
|
VALUE pos, ifnone;
|
2003-11-06 10:22:39 +03:00
|
|
|
long block_given;
|
2001-02-02 14:38:20 +03:00
|
|
|
long idx;
|
|
|
|
|
|
|
|
rb_scan_args(argc, argv, "11", &pos, &ifnone);
|
2003-11-06 10:22:39 +03:00
|
|
|
block_given = rb_block_given_p();
|
|
|
|
if (block_given && argc == 2) {
|
|
|
|
rb_warn("block supersedes default value argument");
|
|
|
|
}
|
2001-02-02 14:38:20 +03:00
|
|
|
idx = NUM2LONG(pos);
|
|
|
|
|
|
|
|
if (idx < 0) {
|
2006-09-02 18:42:08 +04:00
|
|
|
idx += RARRAY_LEN(ary);
|
2001-02-02 14:38:20 +03:00
|
|
|
}
|
2006-09-02 18:42:08 +04:00
|
|
|
if (idx < 0 || RARRAY_LEN(ary) <= idx) {
|
2003-11-06 10:22:39 +03:00
|
|
|
if (block_given) return rb_yield(pos);
|
2002-01-25 11:22:11 +03:00
|
|
|
if (argc == 1) {
|
2010-05-08 08:49:53 +04:00
|
|
|
rb_raise(rb_eIndexError, "index %ld outside of array bounds: %ld...%ld",
|
|
|
|
idx - (idx < 0 ? RARRAY_LEN(ary) : 0), -RARRAY_LEN(ary), RARRAY_LEN(ary));
|
2002-01-25 11:22:11 +03:00
|
|
|
}
|
|
|
|
return ifnone;
|
2001-02-02 14:38:20 +03:00
|
|
|
}
|
2013-05-13 13:56:22 +04:00
|
|
|
return RARRAY_AREF(ary, idx);
|
2001-02-02 14:38:20 +03:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-10 14:45:29 +03:00
|
|
|
* array.index(object) -> integer or nil
|
|
|
|
* array.index {|element| ... } -> integer or nil
|
|
|
|
* array.index -> new_enumerator
|
|
|
|
* array.find_index(object) -> integer or nil
|
|
|
|
* array.find_index {|element| ... } -> integer or nil
|
|
|
|
* array.find_index -> new_enumerator
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Array#find_index is an alias for Array#index.
|
2020-06-11 18:55:11 +03:00
|
|
|
* See also Array#rindex.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-10 14:45:29 +03:00
|
|
|
* ---
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2020-06-10 14:45:29 +03:00
|
|
|
* When argument +object+ is given but no block,
|
|
|
|
* returns the index of the first element +element+
|
|
|
|
* for which <tt>object == element</tt>:
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2, 'bar']
|
2020-06-10 14:45:29 +03:00
|
|
|
* a.index('bar') # => 1
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-10 14:45:29 +03:00
|
|
|
* Returns +nil+ if no such element found:
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
2020-06-10 14:45:29 +03:00
|
|
|
* a.index(:nosuch) # => nil
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-10 14:45:29 +03:00
|
|
|
* ---
|
2020-02-25 21:43:17 +03:00
|
|
|
*
|
2020-06-10 14:45:29 +03:00
|
|
|
* When both argument +object+ and a block are given,
|
|
|
|
* calls the block with each successive element;
|
|
|
|
* returns the index of the first element for which the block returns a truthy value:
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2, 'bar']
|
2020-06-10 14:45:29 +03:00
|
|
|
* a.index { |element| element == 'bar' } # => 1
|
|
|
|
*
|
|
|
|
* Returns +nil+ if the block never returns a truthy value:
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
2020-06-10 14:45:29 +03:00
|
|
|
* a.index { |element| element == :X } # => nil
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When neither an argument nor a block is given, returns a new Enumerator:
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
2020-06-10 14:45:29 +03:00
|
|
|
* e = a.index
|
|
|
|
* e # => #<Enumerator: [:foo, "bar", 2]:index>
|
|
|
|
* e.each { |element| element == 'bar' } # => 1
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When both an argument and a block given, gives a warning (warning: given block not used)
|
|
|
|
* and ignores the block:
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2, 'bar']
|
2020-06-10 14:45:29 +03:00
|
|
|
* index = a.index('bar') { raise 'Cannot happen' }
|
|
|
|
* index # => 1
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_index(int argc, VALUE *argv, VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2004-10-05 05:37:46 +04:00
|
|
|
VALUE val;
|
Improve performance of rb_equal()
* object.c (rb_equal): add optimized path to compare the objects using
rb_equal_opt(). Previously, if not same objects were given, rb_equal() would
call `==' method via rb_funcall() which took a long time.
rb_equal_opt() has provided faster comparing for Fixnum/Float/String objects.
Now, Time#eql? uses rb_equal() to compare with argument object and it will
be faster around 40% on 64-bit environment.
* array.c (rb_ary_index): remove redundant rb_equal_opt() calling.
Now, rb_equal() was optimized using rb_equal_opt().
If rb_equal_opt() returns Qundef, it will invoke rb_equal() -> rb_equal_opt(),
and it will cause the performance regression.
So, this patch will remove first redundant rb_equal_opt() calling.
* array.c (rb_ary_rindex): ditto.
* array.c (rb_ary_includes): ditto.
[ruby-core:80360] [Bug #13365] [Fix GH-#1552]
### Before
Time#eql? with other 7.309M (± 1.4%) i/s - 36.647M in 5.014964s
Array#index(val) 1.433M (± 1.2%) i/s - 7.207M in 5.030942s
Array#rindex(val) 1.418M (± 1.6%) i/s - 7.103M in 5.009164s
Array#include?(val) 1.451M (± 0.9%) i/s - 7.295M in 5.026392s
### After
Time#eql? with other 10.321M (± 1.9%) i/s - 51.684M in 5.009203s
Array#index(val) 1.474M (± 0.9%) i/s - 7.433M in 5.044384s
Array#rindex(val) 1.449M (± 1.7%) i/s - 7.292M in 5.034436s
Array#include?(val) 1.466M (± 1.7%) i/s - 7.373M in 5.030047s
### Test code
require 'benchmark/ips'
Benchmark.ips do |x|
t1 = Time.now
t2 = Time.now
x.report "Time#eql? with other" do |i|
i.times { t1.eql?(t2) }
end
# Benchmarks to check whether it didn't introduce the regression
obj = Object.new
x.report "Array#index(val)" do |i|
ary = [1, 2, true, false, obj]
i.times { ary.index(obj) }
end
x.report "Array#rindex(val)" do |i|
ary = [1, 2, true, false, obj].reverse
i.times { ary.rindex(obj) }
end
x.report "Array#include?(val)" do |i|
ary = [1, 2, true, false, obj]
i.times { ary.include?(obj) }
end
end
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58880 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2017-05-25 07:25:37 +03:00
|
|
|
long i;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2009-02-23 09:54:58 +03:00
|
|
|
if (argc == 0) {
|
2005-08-30 18:49:51 +04:00
|
|
|
RETURN_ENUMERATOR(ary, 0, 0);
|
2006-09-02 18:42:08 +04:00
|
|
|
for (i=0; i<RARRAY_LEN(ary); i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) {
|
2004-10-05 05:37:46 +04:00
|
|
|
return LONG2NUM(i);
|
|
|
|
}
|
|
|
|
}
|
2008-03-05 08:22:17 +03:00
|
|
|
return Qnil;
|
2004-10-05 05:37:46 +04:00
|
|
|
}
|
2013-08-27 11:46:08 +04:00
|
|
|
rb_check_arity(argc, 0, 1);
|
|
|
|
val = argv[0];
|
2009-02-24 18:02:01 +03:00
|
|
|
if (rb_block_given_p())
|
|
|
|
rb_warn("given block not used");
|
Improve performance of rb_equal()
* object.c (rb_equal): add optimized path to compare the objects using
rb_equal_opt(). Previously, if not same objects were given, rb_equal() would
call `==' method via rb_funcall() which took a long time.
rb_equal_opt() has provided faster comparing for Fixnum/Float/String objects.
Now, Time#eql? uses rb_equal() to compare with argument object and it will
be faster around 40% on 64-bit environment.
* array.c (rb_ary_index): remove redundant rb_equal_opt() calling.
Now, rb_equal() was optimized using rb_equal_opt().
If rb_equal_opt() returns Qundef, it will invoke rb_equal() -> rb_equal_opt(),
and it will cause the performance regression.
So, this patch will remove first redundant rb_equal_opt() calling.
* array.c (rb_ary_rindex): ditto.
* array.c (rb_ary_includes): ditto.
[ruby-core:80360] [Bug #13365] [Fix GH-#1552]
### Before
Time#eql? with other 7.309M (± 1.4%) i/s - 36.647M in 5.014964s
Array#index(val) 1.433M (± 1.2%) i/s - 7.207M in 5.030942s
Array#rindex(val) 1.418M (± 1.6%) i/s - 7.103M in 5.009164s
Array#include?(val) 1.451M (± 0.9%) i/s - 7.295M in 5.026392s
### After
Time#eql? with other 10.321M (± 1.9%) i/s - 51.684M in 5.009203s
Array#index(val) 1.474M (± 0.9%) i/s - 7.433M in 5.044384s
Array#rindex(val) 1.449M (± 1.7%) i/s - 7.292M in 5.034436s
Array#include?(val) 1.466M (± 1.7%) i/s - 7.373M in 5.030047s
### Test code
require 'benchmark/ips'
Benchmark.ips do |x|
t1 = Time.now
t2 = Time.now
x.report "Time#eql? with other" do |i|
i.times { t1.eql?(t2) }
end
# Benchmarks to check whether it didn't introduce the regression
obj = Object.new
x.report "Array#index(val)" do |i|
ary = [1, 2, true, false, obj]
i.times { ary.index(obj) }
end
x.report "Array#rindex(val)" do |i|
ary = [1, 2, true, false, obj].reverse
i.times { ary.rindex(obj) }
end
x.report "Array#include?(val)" do |i|
ary = [1, 2, true, false, obj]
i.times { ary.include?(obj) }
end
end
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58880 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2017-05-25 07:25:37 +03:00
|
|
|
for (i=0; i<RARRAY_LEN(ary); i++) {
|
|
|
|
VALUE e = RARRAY_AREF(ary, i);
|
|
|
|
if (rb_equal(e, val)) {
|
2008-03-05 08:22:17 +03:00
|
|
|
return LONG2NUM(i);
|
2013-08-27 11:46:08 +04:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-11 18:55:11 +03:00
|
|
|
* array.rindex(object) -> integer or nil
|
|
|
|
* array.rindex {|element| ... } -> integer or nil
|
|
|
|
* array.rindex -> new_enumerator
|
|
|
|
*
|
|
|
|
* Returns the index of the last element for which <tt>object == element</tt>.
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When argument +object+ is given but no block, returns the index of the last such element found:
|
|
|
|
* a = [:foo, 'bar', 2, 'bar']
|
|
|
|
* a.rindex('bar') # => 3
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-11 18:55:11 +03:00
|
|
|
* Returns +nil+ if no such object found:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.rindex(:nosuch) # => nil
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-11 18:55:11 +03:00
|
|
|
* ---
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-11 18:55:11 +03:00
|
|
|
* When a block is given but no argument, calls the block with each successive element;
|
|
|
|
* returns the index of the last element for which the block returns a truthy value:
|
|
|
|
* a = [:foo, 'bar', 2, 'bar']
|
|
|
|
* a.rindex {|element| element == 'bar' } # => 3
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-11 18:55:11 +03:00
|
|
|
* Returns +nil+ if the block never returns a truthy value:
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.rindex {|element| element == :X } # => nil
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-11 18:55:11 +03:00
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When neither an argument nor a block is given, returns a new \Enumerator:
|
|
|
|
*
|
|
|
|
* a = [:foo, 'bar', 2, 'bar']
|
|
|
|
* e = a.rindex
|
|
|
|
* e # => #<Enumerator: [:foo, "bar", 2, "bar"]:rindex>
|
|
|
|
* e.each { |element| element == 'bar' } # => 3
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When both an argument and a block given, gives a warning (warning: given block not used)
|
|
|
|
* and ignores the block:
|
|
|
|
* a = [:foo, 'bar', 2, 'bar']
|
|
|
|
* index = a.rindex('bar') { raise 'Cannot happen' }
|
|
|
|
* index # => 3
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_rindex(int argc, VALUE *argv, VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2004-10-05 05:37:46 +04:00
|
|
|
VALUE val;
|
2013-08-27 11:46:08 +04:00
|
|
|
long i = RARRAY_LEN(ary), len;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2008-03-05 08:22:17 +03:00
|
|
|
if (argc == 0) {
|
2007-08-20 18:46:03 +04:00
|
|
|
RETURN_ENUMERATOR(ary, 0, 0);
|
2004-10-05 05:37:46 +04:00
|
|
|
while (i--) {
|
2013-05-13 13:56:22 +04:00
|
|
|
if (RTEST(rb_yield(RARRAY_AREF(ary, i))))
|
2004-10-05 05:37:46 +04:00
|
|
|
return LONG2NUM(i);
|
2013-10-15 11:34:05 +04:00
|
|
|
if (i > (len = RARRAY_LEN(ary))) {
|
|
|
|
i = len;
|
2004-10-05 05:37:46 +04:00
|
|
|
}
|
|
|
|
}
|
2008-03-05 08:22:17 +03:00
|
|
|
return Qnil;
|
2004-10-05 05:37:46 +04:00
|
|
|
}
|
2013-08-27 11:46:08 +04:00
|
|
|
rb_check_arity(argc, 0, 1);
|
|
|
|
val = argv[0];
|
2009-02-24 18:02:01 +03:00
|
|
|
if (rb_block_given_p())
|
|
|
|
rb_warn("given block not used");
|
2008-03-05 08:22:17 +03:00
|
|
|
while (i--) {
|
Improve performance of rb_equal()
* object.c (rb_equal): add optimized path to compare the objects using
rb_equal_opt(). Previously, if not same objects were given, rb_equal() would
call `==' method via rb_funcall() which took a long time.
rb_equal_opt() has provided faster comparing for Fixnum/Float/String objects.
Now, Time#eql? uses rb_equal() to compare with argument object and it will
be faster around 40% on 64-bit environment.
* array.c (rb_ary_index): remove redundant rb_equal_opt() calling.
Now, rb_equal() was optimized using rb_equal_opt().
If rb_equal_opt() returns Qundef, it will invoke rb_equal() -> rb_equal_opt(),
and it will cause the performance regression.
So, this patch will remove first redundant rb_equal_opt() calling.
* array.c (rb_ary_rindex): ditto.
* array.c (rb_ary_includes): ditto.
[ruby-core:80360] [Bug #13365] [Fix GH-#1552]
### Before
Time#eql? with other 7.309M (± 1.4%) i/s - 36.647M in 5.014964s
Array#index(val) 1.433M (± 1.2%) i/s - 7.207M in 5.030942s
Array#rindex(val) 1.418M (± 1.6%) i/s - 7.103M in 5.009164s
Array#include?(val) 1.451M (± 0.9%) i/s - 7.295M in 5.026392s
### After
Time#eql? with other 10.321M (± 1.9%) i/s - 51.684M in 5.009203s
Array#index(val) 1.474M (± 0.9%) i/s - 7.433M in 5.044384s
Array#rindex(val) 1.449M (± 1.7%) i/s - 7.292M in 5.034436s
Array#include?(val) 1.466M (± 1.7%) i/s - 7.373M in 5.030047s
### Test code
require 'benchmark/ips'
Benchmark.ips do |x|
t1 = Time.now
t2 = Time.now
x.report "Time#eql? with other" do |i|
i.times { t1.eql?(t2) }
end
# Benchmarks to check whether it didn't introduce the regression
obj = Object.new
x.report "Array#index(val)" do |i|
ary = [1, 2, true, false, obj]
i.times { ary.index(obj) }
end
x.report "Array#rindex(val)" do |i|
ary = [1, 2, true, false, obj].reverse
i.times { ary.rindex(obj) }
end
x.report "Array#include?(val)" do |i|
ary = [1, 2, true, false, obj]
i.times { ary.include?(obj) }
end
end
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58880 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2017-05-25 07:25:37 +03:00
|
|
|
VALUE e = RARRAY_AREF(ary, i);
|
|
|
|
if (rb_equal(e, val)) {
|
2008-03-05 08:22:17 +03:00
|
|
|
return LONG2NUM(i);
|
2004-09-21 07:08:33 +04:00
|
|
|
}
|
2019-06-22 18:25:52 +03:00
|
|
|
if (i > RARRAY_LEN(ary)) {
|
|
|
|
break;
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qnil;
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-10-02 08:31:23 +04:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_to_ary(VALUE obj)
|
2001-10-02 08:31:23 +04:00
|
|
|
{
|
2009-10-29 07:55:10 +03:00
|
|
|
VALUE tmp = rb_check_array_type(obj);
|
|
|
|
|
|
|
|
if (!NIL_P(tmp)) return tmp;
|
2001-10-02 08:31:23 +04:00
|
|
|
return rb_ary_new3(1, obj);
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static void
|
2016-08-21 07:03:22 +03:00
|
|
|
rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen)
|
2001-05-02 08:22:21 +04:00
|
|
|
{
|
2013-10-15 11:34:05 +04:00
|
|
|
long olen;
|
2016-08-22 07:21:54 +03:00
|
|
|
long rofs;
|
2001-05-06 19:06:00 +04:00
|
|
|
|
2002-05-28 22:11:07 +04:00
|
|
|
if (len < 0) rb_raise(rb_eIndexError, "negative length (%ld)", len);
|
2013-10-15 11:34:05 +04:00
|
|
|
olen = RARRAY_LEN(ary);
|
1999-08-13 09:45:20 +04:00
|
|
|
if (beg < 0) {
|
2013-10-15 11:34:05 +04:00
|
|
|
beg += olen;
|
2002-05-21 09:39:19 +04:00
|
|
|
if (beg < 0) {
|
2010-05-08 08:49:53 +04:00
|
|
|
rb_raise(rb_eIndexError, "index %ld too small for array; minimum: %ld",
|
2013-10-15 11:34:05 +04:00
|
|
|
beg - olen, -olen);
|
2002-05-21 09:39:19 +04:00
|
|
|
}
|
1999-08-13 09:45:20 +04:00
|
|
|
}
|
2013-10-15 11:34:05 +04:00
|
|
|
if (olen < len || olen < beg + len) {
|
|
|
|
len = olen - beg;
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2016-08-22 07:21:54 +03:00
|
|
|
{
|
2018-10-31 00:54:13 +03:00
|
|
|
const VALUE *optr = RARRAY_CONST_PTR_TRANSIENT(ary);
|
2016-08-22 07:21:54 +03:00
|
|
|
rofs = (rptr >= optr && rptr < optr + olen) ? rptr - optr : -1;
|
|
|
|
}
|
2016-08-21 07:03:22 +03:00
|
|
|
|
2013-10-15 11:34:05 +04:00
|
|
|
if (beg >= olen) {
|
2014-04-11 12:47:00 +04:00
|
|
|
VALUE target_ary;
|
2008-06-20 10:42:07 +04:00
|
|
|
if (beg > ARY_MAX_SIZE - rlen) {
|
2008-06-20 03:12:46 +04:00
|
|
|
rb_raise(rb_eIndexError, "index %ld too big", beg);
|
|
|
|
}
|
2014-04-11 12:47:00 +04:00
|
|
|
target_ary = ary_ensure_room_for_push(ary, rlen-len); /* len is 0 or negative */
|
2008-06-20 10:42:07 +04:00
|
|
|
len = beg + rlen;
|
2013-10-15 11:34:05 +04:00
|
|
|
ary_mem_clear(ary, olen, beg - olen);
|
2003-01-07 10:36:40 +03:00
|
|
|
if (rlen > 0) {
|
2018-10-31 00:54:13 +03:00
|
|
|
if (rofs != -1) rptr = RARRAY_CONST_PTR_TRANSIENT(ary) + rofs;
|
2016-08-21 07:03:22 +03:00
|
|
|
ary_memcpy0(ary, beg, rlen, rptr, target_ary);
|
2003-01-07 10:36:40 +03:00
|
|
|
}
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(ary, len);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
else {
|
1999-08-13 09:45:20 +04:00
|
|
|
long alen;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2015-06-11 07:50:22 +03:00
|
|
|
if (olen - len > ARY_MAX_SIZE - rlen) {
|
|
|
|
rb_raise(rb_eIndexError, "index %ld too big", olen + rlen - len);
|
|
|
|
}
|
2012-11-09 11:08:45 +04:00
|
|
|
rb_ary_modify(ary);
|
2013-10-15 11:34:05 +04:00
|
|
|
alen = olen + rlen - len;
|
2006-09-02 18:42:08 +04:00
|
|
|
if (alen >= ARY_CAPA(ary)) {
|
2009-01-21 18:27:35 +03:00
|
|
|
ary_double_capa(ary, alen);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2001-05-02 08:22:21 +04:00
|
|
|
if (len != rlen) {
|
2018-12-03 15:36:47 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr,
|
2018-12-03 15:36:39 +03:00
|
|
|
MEMMOVE(ptr + beg + rlen, ptr + beg + len,
|
|
|
|
VALUE, olen - (beg + len)));
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(ary, alen);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2003-01-07 10:36:40 +03:00
|
|
|
if (rlen > 0) {
|
2018-10-31 00:54:13 +03:00
|
|
|
if (rofs != -1) rptr = RARRAY_CONST_PTR_TRANSIENT(ary) + rofs;
|
2018-10-10 06:52:20 +03:00
|
|
|
/* give up wb-protected ary */
|
2018-12-23 17:58:41 +03:00
|
|
|
RB_OBJ_WB_UNPROTECT_FOR(ARRAY, ary);
|
|
|
|
|
|
|
|
/* do not use RARRAY_PTR() because it can causes GC.
|
|
|
|
* ary can contain T_NONE object because it is not cleared.
|
|
|
|
*/
|
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr,
|
|
|
|
MEMMOVE(ptr + beg, rptr, VALUE, rlen));
|
2003-01-07 10:36:40 +03:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-29 18:53:51 +04:00
|
|
|
void
|
|
|
|
rb_ary_set_len(VALUE ary, long len)
|
|
|
|
{
|
|
|
|
long capa;
|
|
|
|
|
|
|
|
rb_ary_modify_check(ary);
|
|
|
|
if (ARY_SHARED_P(ary)) {
|
|
|
|
rb_raise(rb_eRuntimeError, "can't set length of shared ");
|
|
|
|
}
|
|
|
|
if (len > (capa = (long)ARY_CAPA(ary))) {
|
|
|
|
rb_bug("probable buffer overflow: %ld for %ld", len, capa);
|
|
|
|
}
|
|
|
|
ARY_SET_LEN(ary, len);
|
|
|
|
}
|
|
|
|
|
2011-01-05 23:10:59 +03:00
|
|
|
/*!
|
|
|
|
* expands or shrinks \a ary to \a len elements.
|
|
|
|
* expanded region will be filled with Qnil.
|
2011-01-11 09:34:14 +03:00
|
|
|
* \param ary an array
|
2011-01-05 23:10:59 +03:00
|
|
|
* \param len new size
|
|
|
|
* \return \a ary
|
|
|
|
* \post the size of \a ary is \a len.
|
|
|
|
*/
|
|
|
|
VALUE
|
|
|
|
rb_ary_resize(VALUE ary, long len)
|
|
|
|
{
|
|
|
|
long olen;
|
|
|
|
|
|
|
|
rb_ary_modify(ary);
|
|
|
|
olen = RARRAY_LEN(ary);
|
|
|
|
if (len == olen) return ary;
|
|
|
|
if (len > ARY_MAX_SIZE) {
|
|
|
|
rb_raise(rb_eIndexError, "index %ld too big", len);
|
|
|
|
}
|
|
|
|
if (len > olen) {
|
|
|
|
if (len >= ARY_CAPA(ary)) {
|
|
|
|
ary_double_capa(ary, len);
|
|
|
|
}
|
2013-07-19 15:08:13 +04:00
|
|
|
ary_mem_clear(ary, olen, len - olen);
|
|
|
|
ARY_SET_LEN(ary, len);
|
2011-01-05 23:10:59 +03:00
|
|
|
}
|
|
|
|
else if (ARY_EMBED_P(ary)) {
|
|
|
|
ARY_SET_EMBED_LEN(ary, len);
|
|
|
|
}
|
|
|
|
else if (len <= RARRAY_EMBED_LEN_MAX) {
|
|
|
|
VALUE tmp[RARRAY_EMBED_LEN_MAX];
|
|
|
|
MEMCPY(tmp, ARY_HEAP_PTR(ary), VALUE, len);
|
|
|
|
ary_discard(ary);
|
2013-07-20 10:24:11 +04:00
|
|
|
MEMCPY((VALUE *)ARY_EMBED_PTR(ary), tmp, VALUE, len); /* WB: no new reference */
|
2011-01-05 23:10:59 +03:00
|
|
|
ARY_SET_EMBED_LEN(ary, len);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (olen > len + ARY_DEFAULT_SIZE) {
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_heap_realloc(ary, len);
|
2011-01-11 07:09:02 +03:00
|
|
|
ARY_SET_CAPA(ary, len);
|
2011-01-05 23:10:59 +03:00
|
|
|
}
|
|
|
|
ARY_SET_HEAP_LEN(ary, len);
|
|
|
|
}
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2011-01-05 23:10:59 +03:00
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2020-06-11 04:48:59 +03:00
|
|
|
static VALUE
|
|
|
|
ary_aset_by_rb_ary_store(VALUE ary, long key, VALUE val)
|
|
|
|
{
|
|
|
|
rb_ary_store(ary, key, val);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
ary_aset_by_rb_ary_splice(VALUE ary, long beg, long len, VALUE val)
|
|
|
|
{
|
|
|
|
VALUE rpl = rb_ary_to_ary(val);
|
|
|
|
rb_ary_splice(ary, beg, len, RARRAY_CONST_PTR_TRANSIENT(rpl), RARRAY_LEN(rpl));
|
|
|
|
RB_GC_GUARD(rpl);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2020-06-11 18:55:11 +03:00
|
|
|
* array[index] = object -> object
|
|
|
|
* array[start, length] = object -> object
|
|
|
|
* array[range] = object -> object
|
|
|
|
*
|
|
|
|
* Assigns elements in +self+; returns the given +object+.
|
|
|
|
*
|
|
|
|
* - Arguments +index+, +start+, and +length+, if given, must be
|
|
|
|
* {Integer-convertible objects}[doc/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects].
|
|
|
|
* - Argument +range+, if given, must be a \Range object.
|
|
|
|
* - If +object+ is an
|
|
|
|
* {Array-convertible object}[doc/implicit_conversion_rdoc.html#label-Array-Convertible+Objects]
|
|
|
|
* it will be converted to an \Array.
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When +index+ is given, assigns +object+ to an element in +self+.
|
|
|
|
*
|
|
|
|
* If +index+ is non-negative, assigns +object+ the element at offset +index+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[0] = 'foo' # => "foo"
|
|
|
|
* a # => ["foo", "bar", 2]
|
|
|
|
*
|
|
|
|
* If +index+ is greater than <tt>self.length</tt>, extends the array:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[7] = 'foo' # => "foo"
|
|
|
|
* a # => [:foo, "bar", 2, nil, nil, nil, nil, "foo"]
|
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* If +index+ is negative, counts backwards from the end of the array:
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[-1] = 'two' # => "two"
|
|
|
|
* a # => [:foo, "bar", "two"]
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When +start+ and +length+ are given and +object+ is not an Array-convertible object,
|
|
|
|
* removes <tt>length - 1</tt> elements beginning at offset +start+,
|
|
|
|
* and assigns +object+ at offset +start+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[0, 2] = 'foo' # => "foo"
|
|
|
|
* a # => ["foo", 2]
|
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* If +start+ is negative, counts backwards from the end of the array:
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[-2, 2] = 'foo' # => "foo"
|
|
|
|
* a # => [:foo, "foo"]
|
|
|
|
*
|
|
|
|
* If +start+ is non-negative and outside the array (<tt> >= self.size</tt>),
|
|
|
|
* extends the array with +nil+, assigns +object+ at offset +start+,
|
|
|
|
* and ignores +length+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[6, 50] = 'foo' # => "foo"
|
|
|
|
* a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
|
|
|
|
*
|
|
|
|
* If +length+ is zero, shifts elements at and following offset +start+
|
|
|
|
* and assigns +object+ at offset +start+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[1, 0] = 'foo' # => "foo"
|
|
|
|
* a # => [:foo, "foo", "bar", 2]
|
|
|
|
*
|
|
|
|
* If +length+ is too large for the existing array, does not extend the array:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[1, 5] = 'foo' # => "foo"
|
|
|
|
* a # => [:foo, "foo"]
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When +range+ is given and +object+ is an \Array-convertible object,
|
|
|
|
* removes <tt>length - 1</tt> elements beginning at offset +start+,
|
|
|
|
* and assigns +object+ at offset +start+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[0..1] = 'foo' # => "foo"
|
|
|
|
* a # => ["foo", 2]
|
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* if <tt>range.begin</tt> is negative, counts backwards from the end of the array:
|
2020-06-11 18:55:11 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[-2..2] = 'foo' # => "foo"
|
|
|
|
* a # => [:foo, "foo"]
|
|
|
|
*
|
|
|
|
* If the array length is less than <tt>range.begin</tt>,
|
|
|
|
* assigns +object+ at offset <tt>range.begin</tt>, and ignores +length+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[6..50] = 'foo' # => "foo"
|
|
|
|
* a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
|
|
|
|
*
|
|
|
|
* If <tt>range.end</tt> is zero, shifts elements at and following offset +start+
|
|
|
|
* and assigns +object+ at offset +start+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[1..0] = 'foo' # => "foo"
|
|
|
|
* a # => [:foo, "foo", "bar", 2]
|
|
|
|
*
|
|
|
|
* If <tt>range.end</tt> is negative, assigns +object+ at offset +start+,
|
|
|
|
* retains <tt>range.end.abs -1</tt> elements past that, and removes those beyond:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[1..-1] = 'foo' # => "foo"
|
|
|
|
* a # => [:foo, "foo"]
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[1..-2] = 'foo' # => "foo"
|
|
|
|
* a # => [:foo, "foo", 2]
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[1..-3] = 'foo' # => "foo"
|
|
|
|
* a # => [:foo, "foo", "bar", 2]
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
*
|
|
|
|
* If <tt>range.end</tt> is too large for the existing array,
|
|
|
|
* replaces array elements, but does not extend the array with +nil+ values:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a[1..5] = 'foo' # => "foo"
|
|
|
|
* a # => [:foo, "foo"]
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if given a single argument
|
|
|
|
* that is not an \Integer-convertible object or a \Range:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* a[:nosuch] = 'two'
|
|
|
|
*
|
|
|
|
* Raises an exception if given two arguments that are not both \Integer-convertible objects:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* a[:nosuch, 2] = 'two'
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* a[0, :nosuch] = 'two'
|
|
|
|
*
|
|
|
|
* Raises an exception if a negative +index+ is out of range:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises IndexError (index -4 too small for array; minimum: -3):
|
|
|
|
* a[-4] = 'two'
|
|
|
|
*
|
|
|
|
* Raises an exception if +start+ is too small for the array:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises IndexError (index -5 too small for array; minimum: -3):
|
|
|
|
* a[-5, 2] = 'foo'
|
|
|
|
*
|
|
|
|
* Raises an exception if +length+ is negative:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises IndexError (negative length (-1)):
|
|
|
|
* a[1, -1] = 'foo'
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_aset(int argc, VALUE *argv, VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-08-13 09:45:20 +04:00
|
|
|
long offset, beg, len;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2020-06-11 04:48:59 +03:00
|
|
|
rb_check_arity(argc, 2, 3);
|
|
|
|
rb_ary_modify_check(ary);
|
2000-05-24 08:34:26 +04:00
|
|
|
if (argc == 3) {
|
2009-01-26 10:00:43 +03:00
|
|
|
beg = NUM2LONG(argv[0]);
|
|
|
|
len = NUM2LONG(argv[1]);
|
2020-06-11 04:48:59 +03:00
|
|
|
return ary_aset_by_rb_ary_splice(ary, beg, len, argv[2]);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2000-05-24 08:34:26 +04:00
|
|
|
if (FIXNUM_P(argv[0])) {
|
|
|
|
offset = FIX2LONG(argv[0]);
|
2020-06-11 04:48:59 +03:00
|
|
|
return ary_aset_by_rb_ary_store(ary, offset, argv[1]);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2006-09-02 18:42:08 +04:00
|
|
|
if (rb_range_beg_len(argv[0], &beg, &len, RARRAY_LEN(ary), 1)) {
|
1998-01-16 15:13:05 +03:00
|
|
|
/* check if idx is Range */
|
2020-06-11 04:48:59 +03:00
|
|
|
return ary_aset_by_rb_ary_splice(ary, beg, len, argv[1]);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2000-05-24 08:34:26 +04:00
|
|
|
offset = NUM2LONG(argv[0]);
|
2020-06-11 04:48:59 +03:00
|
|
|
return ary_aset_by_rb_ary_store(ary, offset, argv[1]);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-12 19:32:31 +03:00
|
|
|
* array.insert(index, *objects) -> self
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* Inserts given +objects+ before or after the element at +offset+ index;
|
|
|
|
* returns +self+.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* Argument +index+ must be an
|
|
|
|
* {Integer-convertible object}[doc/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects].
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When +index+ is non-negative, inserts all given +objects+
|
|
|
|
* before the element at offset +index+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.insert(1, :bat, :bam)
|
|
|
|
* a # => [:foo, :bat, :bam, "bar", 2]
|
|
|
|
* a1.object_id == a.object_id # => true
|
|
|
|
*
|
|
|
|
* Extends the array if +index+ is beyond the array (<tt>index >= self.size</tt>):
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.insert(5, :bat, :bam)
|
|
|
|
* a # => [:foo, "bar", 2, nil, nil, :bat, :bam]
|
|
|
|
*
|
|
|
|
* Does nothing if no objects given:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.insert(1)
|
|
|
|
* a.insert(50)
|
|
|
|
* a.insert(-50)
|
|
|
|
* a # => [:foo, "bar", 2]
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When +index+ is negative, inserts all given +objects+
|
|
|
|
* _after_ the element at offset <tt>index+self.size</tt>:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.insert(-2, :bat, :bam)
|
|
|
|
* a # => [:foo, "bar", :bat, :bam, 2]
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if +index+ is not an Integer-convertible object:
|
|
|
|
* a = [:foo, 'bar', 2, 'bar']
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* a.insert(:foo)
|
|
|
|
*
|
|
|
|
* Raises an exception if +index+ is too small (<tt>index+self.size < 0</tt>):
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises IndexError (index -5 too small for array; minimum: -4):
|
|
|
|
* a.insert(-5, :bat, :bam)
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2001-05-02 08:22:21 +04:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_insert(int argc, VALUE *argv, VALUE ary)
|
2001-05-02 08:22:21 +04:00
|
|
|
{
|
2001-05-06 19:06:00 +04:00
|
|
|
long pos;
|
|
|
|
|
2012-03-15 01:10:34 +04:00
|
|
|
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
|
2010-02-10 10:31:06 +03:00
|
|
|
rb_ary_modify_check(ary);
|
2001-05-06 19:06:00 +04:00
|
|
|
pos = NUM2LONG(argv[0]);
|
2017-05-12 20:02:48 +03:00
|
|
|
if (argc == 1) return ary;
|
2001-05-06 19:06:00 +04:00
|
|
|
if (pos == -1) {
|
2006-09-02 18:42:08 +04:00
|
|
|
pos = RARRAY_LEN(ary);
|
2001-05-06 19:06:00 +04:00
|
|
|
}
|
2017-05-12 20:23:46 +03:00
|
|
|
else if (pos < 0) {
|
|
|
|
long minpos = -RARRAY_LEN(ary) - 1;
|
|
|
|
if (pos < minpos) {
|
|
|
|
rb_raise(rb_eIndexError, "index %ld too small for array; minimum: %ld",
|
|
|
|
pos, minpos);
|
|
|
|
}
|
2001-05-06 19:06:00 +04:00
|
|
|
pos++;
|
|
|
|
}
|
2016-08-21 07:03:22 +03:00
|
|
|
rb_ary_splice(ary, pos, 0, argv + 1, argc - 1);
|
2001-05-02 08:22:21 +04:00
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2012-11-06 21:11:21 +04:00
|
|
|
static VALUE
|
|
|
|
rb_ary_length(VALUE ary);
|
|
|
|
|
2013-06-26 17:43:22 +04:00
|
|
|
static VALUE
|
|
|
|
ary_enum_length(VALUE ary, VALUE args, VALUE eobj)
|
|
|
|
{
|
|
|
|
return rb_ary_length(ary);
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-12 19:32:31 +03:00
|
|
|
* array.each {|element| ... } -> self
|
|
|
|
* array.each -> Enumerator
|
|
|
|
*
|
|
|
|
* Iterates over array elements.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* ---
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* When a block given, passes each successive array element to the block;
|
|
|
|
* returns +self+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.each {|element| puts "#{element.class} #{element}" }
|
|
|
|
* a1.equal?(a) # => true # Returned self
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* Output:
|
|
|
|
* Symbol foo
|
|
|
|
* String bar
|
|
|
|
* Integer 2
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* Allows the array to be modified during iteration:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.each {|element| puts element; a.clear if element.to_s.start_with?('b') }
|
|
|
|
* a # => []
|
|
|
|
*
|
|
|
|
* Output:
|
|
|
|
* foo
|
|
|
|
* bar
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When no block given, returns a new \Enumerator:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* e = a.each
|
|
|
|
* e # => #<Enumerator: [:foo, "bar", 2]:each>
|
|
|
|
* a1 = e.each { |element| puts "#{element.class} #{element}" }
|
|
|
|
*
|
|
|
|
* Output:
|
|
|
|
* Symbol foo
|
|
|
|
* String bar
|
|
|
|
* Integer 2
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
2015-07-13 13:52:11 +03:00
|
|
|
rb_ary_each(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2006-10-11 12:06:16 +04:00
|
|
|
long i;
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2013-06-26 17:43:22 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
|
2006-10-11 12:06:16 +04:00
|
|
|
for (i=0; i<RARRAY_LEN(ary); i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
rb_yield(RARRAY_AREF(ary, i));
|
2006-10-11 12:06:16 +04:00
|
|
|
}
|
1999-08-13 09:45:20 +04:00
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-12 19:32:31 +03:00
|
|
|
* array.each_index {|index| ... } -> self
|
|
|
|
* array.each_index -> Enumerator
|
|
|
|
*
|
|
|
|
* Iterates over array indexes.
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When a block given, passes each successive array index to the block;
|
|
|
|
* returns +self+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.each_index {|index| puts "#{index} #{a[index]}" }
|
|
|
|
* a1.equal?(a) # => true # Returned self
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* Output:
|
|
|
|
* 0 foo
|
|
|
|
* 1 bar
|
|
|
|
* 2 2
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* Allows the array to be modified during iteration:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.each_index {|index| puts index; a.clear if index > 0 }
|
|
|
|
* a # => []
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* Output:
|
|
|
|
* 0
|
|
|
|
* 1
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When no block given, returns a new \Enumerator:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* e = a.each_index
|
|
|
|
* e # => #<Enumerator: [:foo, "bar", 2]:each_index>
|
|
|
|
* a1 = e.each {|index| puts "#{index} #{a[index]}"}
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* Output:
|
|
|
|
* 0 foo
|
|
|
|
* 1 bar
|
|
|
|
* 2 2
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_each_index(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2008-01-24 09:18:18 +03:00
|
|
|
long i;
|
2013-06-26 17:43:22 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
|
* array.c (ary_iter_check): should check modification (size
change) during iteration.
* array.c (rb_ary_initialize, rb_ary_shift, rb_ary_unshift,
rb_ary_splice, rb_ary_reverse, rb_ary_sort, rb_ary_delete,
rb_ary_delete_at, rb_ary_reject_bang, rb_ary_replace,
rb_ary_clear, rb_ary_fill, rb_ary_uniq_bang, rb_ary_compact,
rb_ary_shuffle): add iteration check.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11429 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2006-12-29 22:25:11 +03:00
|
|
|
|
2008-01-24 09:18:18 +03:00
|
|
|
for (i=0; i<RARRAY_LEN(ary); i++) {
|
|
|
|
rb_yield(LONG2NUM(i));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1999-08-13 09:45:20 +04:00
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-12 19:32:31 +03:00
|
|
|
* array.reverse_each {|element| ... } -> self
|
|
|
|
* array.reverse_each -> Enumerator
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* Iterates backwards over array elements.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When a block given, passes, in reverse order, each element to the block;
|
|
|
|
* returns +self+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.reverse_each {|element| puts "#{element.class} #{element}" }
|
|
|
|
* a1.equal?(a) # => true # Returned self
|
|
|
|
*
|
|
|
|
* Output:
|
|
|
|
* Integer 2
|
|
|
|
* String bar
|
|
|
|
* Symbol foo
|
|
|
|
*
|
|
|
|
* Allows the array to be modified during iteration:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.reverse_each {|element| puts element; a.clear if element.to_s.start_with?('b') }
|
|
|
|
* a # => []
|
|
|
|
*
|
|
|
|
* Output:
|
|
|
|
* 2
|
|
|
|
* bar
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* ---
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* When no block given, returns a new \Enumerator:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* e = a.reverse_each
|
|
|
|
* e # => #<Enumerator: [:foo, "bar", 2]:reverse_each>
|
|
|
|
* a1 = e.each { |element| puts "#{element.class} #{element}" }
|
|
|
|
* Output:
|
|
|
|
* Integer 2
|
|
|
|
* String bar
|
|
|
|
* Symbol foo
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_reverse_each(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2008-01-24 09:18:18 +03:00
|
|
|
long len;
|
|
|
|
|
2013-06-26 17:43:22 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
|
2008-01-24 09:18:18 +03:00
|
|
|
len = RARRAY_LEN(ary);
|
|
|
|
while (len--) {
|
2013-10-15 11:34:05 +04:00
|
|
|
long nlen;
|
2013-05-13 13:56:22 +04:00
|
|
|
rb_yield(RARRAY_AREF(ary, len));
|
2013-10-15 11:34:05 +04:00
|
|
|
nlen = RARRAY_LEN(ary);
|
|
|
|
if (nlen < len) {
|
|
|
|
len = nlen;
|
2008-01-24 09:18:18 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-12 19:32:31 +03:00
|
|
|
* array.length -> an_integer
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* Returns the count of elements in the array:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.length # => 3
|
|
|
|
* [].length # => 0
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_length(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2006-09-02 18:42:08 +04:00
|
|
|
long len = RARRAY_LEN(ary);
|
|
|
|
return LONG2NUM(len);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-12 19:32:31 +03:00
|
|
|
* array.empty? -> true or false
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-12 19:32:31 +03:00
|
|
|
* Returns +true+ if the count of elements in the array is zero,
|
|
|
|
* +false+ otherwise:
|
|
|
|
* [].empty? # => true
|
|
|
|
* [:foo, 'bar', 2].empty? # => false
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_empty_p(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2006-09-02 18:42:08 +04:00
|
|
|
if (RARRAY_LEN(ary) == 0)
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qtrue;
|
|
|
|
return Qfalse;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2010-01-21 05:12:07 +03:00
|
|
|
VALUE
|
|
|
|
rb_ary_dup(VALUE ary)
|
|
|
|
{
|
2013-07-19 14:10:31 +04:00
|
|
|
long len = RARRAY_LEN(ary);
|
|
|
|
VALUE dup = rb_ary_new2(len);
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_memcpy(dup, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary));
|
2013-07-19 14:10:31 +04:00
|
|
|
ARY_SET_LEN(dup, len);
|
2018-10-31 00:53:56 +03:00
|
|
|
|
|
|
|
ary_verify(ary);
|
|
|
|
ary_verify(dup);
|
2001-07-14 19:17:19 +04:00
|
|
|
return dup;
|
|
|
|
}
|
|
|
|
|
2009-02-18 08:33:36 +03:00
|
|
|
VALUE
|
|
|
|
rb_ary_resurrect(VALUE ary)
|
|
|
|
{
|
Use a shared array for the `duparray` instruction
In this example code:
```ruby
def foo
[1, 2, 3, 4]
end
```
The array literal uses a `duparray` instruction. Before this patch,
`rb_ary_resurrect` would malloc and memcpy a new array buffer. This
patch changes `rb_ary_resurrect` to use `ary_make_partial` so that the
new array object shares the underlying buffer with the array stored in
the instruction sequences.
Before this patch, the new array object is not shared:
```
$ ruby -r objspace -e'p ObjectSpace.dump([1, 2, 3, 4])'
"{\"address\":\"0x7fa2718372d0\", \"type\":\"ARRAY\", \"class\":\"0x7fa26f8b0010\", \"length\":4, \"memsize\":72, \"flags\":{\"wb_protected\":true}}\n"
```
After this patch:
```
$ ./ruby -r objspace -e'p ObjectSpace.dump([1, 2, 3, 4])'
"{\"address\":\"0x7f9a76883638\", \"type\":\"ARRAY\", \"class\":\"0x7f9a758af900\", \"length\":4, \"shared\":true, \"references\":[\"0x7f9a768837c8\"], \"memsize\":40, \"flags\":{\"wb_protected\":true}}\n"
```
[Feature #15289] [ruby-core:90097]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66095 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-11-29 23:39:51 +03:00
|
|
|
return ary_make_partial(ary, rb_cArray, 0, RARRAY_LEN(ary));
|
2009-02-18 08:33:36 +03:00
|
|
|
}
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
extern VALUE rb_output_fs;
|
|
|
|
|
2011-02-15 10:08:24 +03:00
|
|
|
static void ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first);
|
2009-07-03 22:14:33 +04:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
2009-07-03 22:14:33 +04:00
|
|
|
recursive_join(VALUE obj, VALUE argp, int recur)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2005-10-11 16:30:48 +04:00
|
|
|
VALUE *arg = (VALUE *)argp;
|
2009-07-03 22:14:33 +04:00
|
|
|
VALUE ary = arg[0];
|
|
|
|
VALUE sep = arg[1];
|
|
|
|
VALUE result = arg[2];
|
2011-02-15 10:08:24 +03:00
|
|
|
int *first = (int *)arg[3];
|
2009-07-03 22:14:33 +04:00
|
|
|
|
* array.c: replace rb_protect_inspect() and rb_inspecting_p() by
rb_exec_recursive() in eval.c.
* eval.c (rb_exec_recursive): new function.
* array.c (rb_ary_join): use rb_exec_recursive().
* array.c (rb_ary_inspect, rb_ary_hash): ditto.
* file.c (rb_file_join): ditto.
* hash.c (rb_hash_inspect, rb_hash_to_s, rb_hash_hash): ditto.
* io.c (rb_io_puts): ditto.
* object.c (rb_obj_inspect): ditto
* struct.c (rb_struct_inspect): ditto.
* lib/set.rb (SortedSet::setup): a hack to shut up warning.
[ruby-talk:132866]
* lib/time.rb (Time::strptime): add new function. inspired by
[ruby-talk:132815].
* lib/parsedate.rb (ParseDate::strptime): ditto.
* regparse.c: move st_*_strend() functions from st.c. fixed some
potential memory leaks.
* exception error messages updated. [ruby-core:04497]
* ext/socket/socket.c (Init_socket): add bunch of Socket
constants. Patch from Sam Roberts <sroberts@uniserve.com>.
[ruby-core:04409]
* array.c (rb_ary_s_create): no need for negative argc check.
[ruby-core:04463]
* array.c (rb_ary_unshift_m): ditto.
* lib/xmlrpc/parser.rb (XMLRPC::FaultException): make it subclass
of StandardError class, not Exception class. [ruby-core:04429]
* parse.y (fcall_gen): lvar(arg) will be evaluated as
lvar.call(arg) when lvar is a defined local variable. [new]
* object.c (rb_class_initialize): call inherited method before
calling initializing block.
* eval.c (rb_thread_start_1): initialize newly pushed frame.
* lib/open3.rb (Open3::popen3): $? should not be EXIT_FAILURE.
fixed: [ruby-core:04444]
* eval.c (is_defined): NODE_IASGN is an assignment.
* ext/readline/readline.c (Readline.readline): use rl_outstream
and rl_instream. [ruby-dev:25699]
* ext/etc/etc.c (Init_etc): sGroup needs HAVE_ST_GR_PASSWD check
[ruby-dev:25675]
* misc/ruby-mode.el: [ruby-core:04415]
* lib/rdoc/generators/html_generator.rb: [ruby-core:04412]
* lib/rdoc/generators/ri_generator.rb: ditto.
* struct.c (make_struct): fixed: [ruby-core:04402]
* ext/curses/curses.c (window_color_set): [ruby-core:04393]
* ext/socket/socket.c (Init_socket): SO_REUSEPORT added.
[ruby-talk:130092]
* object.c: [ruby-doc:818]
* parse.y (open_args): fix too verbose warnings for the space
before argument parentheses. [ruby-dev:25492]
* parse.y (parser_yylex): ditto.
* parse.y (parser_yylex): the first expression in the parentheses
should not be a command. [ruby-dev:25492]
* lib/irb/context.rb (IRB::Context::initialize): [ruby-core:04330]
* object.c (Init_Object): remove Object#type. [ruby-core:04335]
* st.c (st_foreach): report success/failure by return value.
[ruby-Bugs-1396]
* parse.y: forgot to initialize parser struct. [ruby-dev:25492]
* parse.y (parser_yylex): no tLABEL on EXPR_BEG.
[ruby-talk:127711]
* document updates - [ruby-core:04296], [ruby-core:04301],
[ruby-core:04302], [ruby-core:04307]
* dir.c (rb_push_glob): should work for NUL delimited patterns.
* dir.c (rb_glob2): should aware of offset in the pattern.
* string.c (rb_str_new4): should propagate taintedness.
* env.h: rename member names in struct FRAME; last_func -> callee,
orig_func -> this_func, last_class -> this_class.
* struct.c (rb_struct_set): use original method name, not callee
name, to retrieve member slot. [ruby-core:04268]
* time.c (time_strftime): protect from format modification from GC
finalizers.
* object.c (Init_Object): remove rb_obj_id_obsolete()
* eval.c (rb_mod_define_method): incomplete subclass check.
[ruby-dev:25464]
* gc.c (rb_data_object_alloc): klass may be NULL.
[ruby-list:40498]
* bignum.c (rb_big_rand): should return positive random number.
[ruby-dev:25401]
* bignum.c (rb_big_rand): do not use rb_big_modulo to generate
random bignums. [ruby-dev:25396]
* variable.c (rb_autoload): [ruby-dev:25373]
* eval.c (svalue_to_avalue): [ruby-dev:25366]
* string.c (rb_str_justify): [ruby-dev:25367]
* io.c (rb_f_select): [ruby-dev:25312]
* ext/socket/socket.c (sock_s_getservbyport): [ruby-talk:124072]
* struct.c (make_struct): [ruby-dev:25249]
* dir.c (dir_open_dir): new function. [ruby-dev:25242]
* io.c (rb_f_open): add type check for return value from to_open.
* lib/pstore.rb (PStore#transaction): Use the empty content when a
file is not found. [ruby-dev:24561]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8068 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-03-04 09:47:45 +03:00
|
|
|
if (recur) {
|
2009-07-17 06:04:37 +04:00
|
|
|
rb_raise(rb_eArgError, "recursive array join");
|
2009-07-03 22:14:33 +04:00
|
|
|
}
|
|
|
|
else {
|
2011-02-15 10:08:24 +03:00
|
|
|
ary_join_1(obj, ary, sep, 0, result, first);
|
2009-07-03 22:14:33 +04:00
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2020-01-19 18:29:40 +03:00
|
|
|
static long
|
2009-07-03 22:14:33 +04:00
|
|
|
ary_join_0(VALUE ary, VALUE sep, long max, VALUE result)
|
|
|
|
{
|
|
|
|
long i;
|
|
|
|
VALUE val;
|
|
|
|
|
2013-05-13 13:56:22 +04:00
|
|
|
if (max > 0) rb_enc_copy(result, RARRAY_AREF(ary, 0));
|
2009-07-03 22:14:33 +04:00
|
|
|
for (i=0; i<max; i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
val = RARRAY_AREF(ary, i);
|
2020-01-19 18:29:40 +03:00
|
|
|
if (!RB_TYPE_P(val, T_STRING)) break;
|
2009-07-03 22:14:33 +04:00
|
|
|
if (i > 0 && !NIL_P(sep))
|
|
|
|
rb_str_buf_append(result, sep);
|
|
|
|
rb_str_buf_append(result, val);
|
|
|
|
}
|
2020-01-19 18:29:40 +03:00
|
|
|
return i;
|
2009-07-03 22:14:33 +04:00
|
|
|
}
|
|
|
|
|
2020-06-11 05:31:27 +03:00
|
|
|
static void
|
|
|
|
ary_join_1_str(VALUE dst, VALUE src, int *first)
|
|
|
|
{
|
|
|
|
rb_str_buf_append(dst, src);
|
|
|
|
if (*first) {
|
|
|
|
rb_enc_copy(dst, src);
|
|
|
|
*first = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ary_join_1_ary(VALUE obj, VALUE ary, VALUE sep, VALUE result, VALUE val, int *first)
|
|
|
|
{
|
|
|
|
if (val == ary) {
|
|
|
|
rb_raise(rb_eArgError, "recursive array join");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VALUE args[4];
|
|
|
|
|
|
|
|
*first = FALSE;
|
|
|
|
args[0] = val;
|
|
|
|
args[1] = sep;
|
|
|
|
args[2] = result;
|
|
|
|
args[3] = (VALUE)first;
|
|
|
|
rb_exec_recursive(recursive_join, obj, (VALUE)args);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-03 22:14:33 +04:00
|
|
|
static void
|
2011-02-15 10:08:24 +03:00
|
|
|
ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first)
|
2009-07-03 22:14:33 +04:00
|
|
|
{
|
|
|
|
VALUE val, tmp;
|
|
|
|
|
|
|
|
for (; i<RARRAY_LEN(ary); i++) {
|
|
|
|
if (i > 0 && !NIL_P(sep))
|
|
|
|
rb_str_buf_append(result, sep);
|
|
|
|
|
2013-05-13 13:56:22 +04:00
|
|
|
val = RARRAY_AREF(ary, i);
|
2013-04-04 12:23:10 +04:00
|
|
|
if (RB_TYPE_P(val, T_STRING)) {
|
2020-06-11 05:31:27 +03:00
|
|
|
ary_join_1_str(result, val, first);
|
2013-04-04 12:23:10 +04:00
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(val, T_ARRAY)) {
|
2020-06-11 05:31:27 +03:00
|
|
|
ary_join_1_ary(val, ary, sep, result, val, first);
|
2013-04-04 12:23:10 +04:00
|
|
|
}
|
2020-06-11 05:31:27 +03:00
|
|
|
else if (!NIL_P(tmp = rb_check_string_type(val))) {
|
|
|
|
ary_join_1_str(result, tmp, first);
|
|
|
|
}
|
|
|
|
else if (!NIL_P(tmp = rb_check_array_type(val))) {
|
|
|
|
ary_join_1_ary(val, ary, sep, result, tmp, first);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ary_join_1_str(result, rb_obj_as_string(val), first);
|
2009-07-03 22:14:33 +04:00
|
|
|
}
|
* array.c: replace rb_protect_inspect() and rb_inspecting_p() by
rb_exec_recursive() in eval.c.
* eval.c (rb_exec_recursive): new function.
* array.c (rb_ary_join): use rb_exec_recursive().
* array.c (rb_ary_inspect, rb_ary_hash): ditto.
* file.c (rb_file_join): ditto.
* hash.c (rb_hash_inspect, rb_hash_to_s, rb_hash_hash): ditto.
* io.c (rb_io_puts): ditto.
* object.c (rb_obj_inspect): ditto
* struct.c (rb_struct_inspect): ditto.
* lib/set.rb (SortedSet::setup): a hack to shut up warning.
[ruby-talk:132866]
* lib/time.rb (Time::strptime): add new function. inspired by
[ruby-talk:132815].
* lib/parsedate.rb (ParseDate::strptime): ditto.
* regparse.c: move st_*_strend() functions from st.c. fixed some
potential memory leaks.
* exception error messages updated. [ruby-core:04497]
* ext/socket/socket.c (Init_socket): add bunch of Socket
constants. Patch from Sam Roberts <sroberts@uniserve.com>.
[ruby-core:04409]
* array.c (rb_ary_s_create): no need for negative argc check.
[ruby-core:04463]
* array.c (rb_ary_unshift_m): ditto.
* lib/xmlrpc/parser.rb (XMLRPC::FaultException): make it subclass
of StandardError class, not Exception class. [ruby-core:04429]
* parse.y (fcall_gen): lvar(arg) will be evaluated as
lvar.call(arg) when lvar is a defined local variable. [new]
* object.c (rb_class_initialize): call inherited method before
calling initializing block.
* eval.c (rb_thread_start_1): initialize newly pushed frame.
* lib/open3.rb (Open3::popen3): $? should not be EXIT_FAILURE.
fixed: [ruby-core:04444]
* eval.c (is_defined): NODE_IASGN is an assignment.
* ext/readline/readline.c (Readline.readline): use rl_outstream
and rl_instream. [ruby-dev:25699]
* ext/etc/etc.c (Init_etc): sGroup needs HAVE_ST_GR_PASSWD check
[ruby-dev:25675]
* misc/ruby-mode.el: [ruby-core:04415]
* lib/rdoc/generators/html_generator.rb: [ruby-core:04412]
* lib/rdoc/generators/ri_generator.rb: ditto.
* struct.c (make_struct): fixed: [ruby-core:04402]
* ext/curses/curses.c (window_color_set): [ruby-core:04393]
* ext/socket/socket.c (Init_socket): SO_REUSEPORT added.
[ruby-talk:130092]
* object.c: [ruby-doc:818]
* parse.y (open_args): fix too verbose warnings for the space
before argument parentheses. [ruby-dev:25492]
* parse.y (parser_yylex): ditto.
* parse.y (parser_yylex): the first expression in the parentheses
should not be a command. [ruby-dev:25492]
* lib/irb/context.rb (IRB::Context::initialize): [ruby-core:04330]
* object.c (Init_Object): remove Object#type. [ruby-core:04335]
* st.c (st_foreach): report success/failure by return value.
[ruby-Bugs-1396]
* parse.y: forgot to initialize parser struct. [ruby-dev:25492]
* parse.y (parser_yylex): no tLABEL on EXPR_BEG.
[ruby-talk:127711]
* document updates - [ruby-core:04296], [ruby-core:04301],
[ruby-core:04302], [ruby-core:04307]
* dir.c (rb_push_glob): should work for NUL delimited patterns.
* dir.c (rb_glob2): should aware of offset in the pattern.
* string.c (rb_str_new4): should propagate taintedness.
* env.h: rename member names in struct FRAME; last_func -> callee,
orig_func -> this_func, last_class -> this_class.
* struct.c (rb_struct_set): use original method name, not callee
name, to retrieve member slot. [ruby-core:04268]
* time.c (time_strftime): protect from format modification from GC
finalizers.
* object.c (Init_Object): remove rb_obj_id_obsolete()
* eval.c (rb_mod_define_method): incomplete subclass check.
[ruby-dev:25464]
* gc.c (rb_data_object_alloc): klass may be NULL.
[ruby-list:40498]
* bignum.c (rb_big_rand): should return positive random number.
[ruby-dev:25401]
* bignum.c (rb_big_rand): do not use rb_big_modulo to generate
random bignums. [ruby-dev:25396]
* variable.c (rb_autoload): [ruby-dev:25373]
* eval.c (svalue_to_avalue): [ruby-dev:25366]
* string.c (rb_str_justify): [ruby-dev:25367]
* io.c (rb_f_select): [ruby-dev:25312]
* ext/socket/socket.c (sock_s_getservbyport): [ruby-talk:124072]
* struct.c (make_struct): [ruby-dev:25249]
* dir.c (dir_open_dir): new function. [ruby-dev:25242]
* io.c (rb_f_open): add type check for return value from to_open.
* lib/pstore.rb (PStore#transaction): Use the empty content when a
file is not found. [ruby-dev:24561]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8068 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-03-04 09:47:45 +03:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_join(VALUE ary, VALUE sep)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2002-05-21 09:39:19 +04:00
|
|
|
long len = 1, i;
|
2009-07-03 22:14:33 +04:00
|
|
|
VALUE val, tmp, result;
|
2000-01-05 07:41:21 +03:00
|
|
|
|
2011-01-29 18:33:50 +03:00
|
|
|
if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new(0, 0);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-11-15 18:56:08 +03:00
|
|
|
if (!NIL_P(sep)) {
|
|
|
|
StringValue(sep);
|
2006-09-02 18:42:08 +04:00
|
|
|
len += RSTRING_LEN(sep) * (RARRAY_LEN(ary) - 1);
|
2001-05-16 13:05:54 +04:00
|
|
|
}
|
2006-09-02 18:42:08 +04:00
|
|
|
for (i=0; i<RARRAY_LEN(ary); i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
val = RARRAY_AREF(ary, i);
|
2009-07-03 22:14:33 +04:00
|
|
|
tmp = rb_check_string_type(val);
|
|
|
|
|
|
|
|
if (NIL_P(tmp) || tmp != val) {
|
2011-02-15 10:08:24 +03:00
|
|
|
int first;
|
2020-01-19 18:41:56 +03:00
|
|
|
long n = RARRAY_LEN(ary);
|
|
|
|
if (i > n) i = n;
|
|
|
|
result = rb_str_buf_new(len + (n-i)*10);
|
2011-02-15 10:08:24 +03:00
|
|
|
rb_enc_associate(result, rb_usascii_encoding());
|
2020-01-19 18:29:40 +03:00
|
|
|
i = ary_join_0(ary, sep, i, result);
|
2011-02-15 10:08:24 +03:00
|
|
|
first = i == 0;
|
|
|
|
ary_join_1(ary, ary, sep, i, result, &first);
|
2009-07-03 22:14:33 +04:00
|
|
|
return result;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2009-07-03 22:14:33 +04:00
|
|
|
|
|
|
|
len += RSTRING_LEN(tmp);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
Allow Array#join to allocate smaller strings
rb_str_buf_new always allocates at least 127 bytes of capacity, even
when less is requested.
> ObjectSpace.dump(%w[a b c].join)
{"address":"0x7f935f06ebf0", "type":"STRING", "class":"0x7f935d8b7bb0", "bytesize":3, "capacity":127, "value":"abc", "encoding":"UTF-8", "memsize":168, "flags":{"wb_protected":true}}
Instead, by using rb_str_new and then setting the length to 0, we can
allocate the exact amount of memory needed, without extra capacity.
> ObjectSpace.dump(%w[a b c].join)
{"address":"0x7f903fcab530", "type":"STRING", "class":"0x7f903f8b7988", "embedded":true, "bytesize":3, "value":"abc", "encoding":"UTF-8", "memsize":40, "flags":{"wb_protected":true}}
2019-06-26 19:52:30 +03:00
|
|
|
result = rb_str_new(0, len);
|
|
|
|
rb_str_set_len(result, 0);
|
|
|
|
|
2009-07-03 22:14:33 +04:00
|
|
|
ary_join_0(ary, sep, RARRAY_LEN(ary), result);
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-13 17:14:17 +03:00
|
|
|
* array.join ->new_string
|
|
|
|
* array.join(separator = $,) -> new_string
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-13 17:14:17 +03:00
|
|
|
* Returns the new \String formed by joining the array elements after conversion.
|
|
|
|
* For each element +element+
|
|
|
|
* - Uses <tt>element.to_s</tt> if +element+ is not a <tt>kind_of?(Array)</tt>.
|
|
|
|
* - Uses recursive <tt>element.join(separator)</tt> if +element+ is a <tt>kind_of?(Array)</tt>.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-13 17:14:17 +03:00
|
|
|
* Argument +separator+, if given, must be a
|
|
|
|
* {String-convertible object}[doc/implicit_conversion_rdoc.html#label-String-Convertible+Objects].
|
mention behavior of Array#join for nested arrays [ci skip]
The current documentation for Array#join does not mention the
special treatment of nested arrays.
It says:
> Returns a string created by converting each element of the
> array to a string, separated by the given separator.
Expected behavior according to the docs would be:
[ "a", [1, 2, [:x, :y]], "b" ].join("-") #=> "a-[1, 2, [:x, :y]]-b"
# because of:
[1, 2, [:x, :y]].to_s #=> "[1, 2, [:x, :y]]"
Actual behavior:
[ "a", [1, 2, [:x, :y]], "b" ].join("-") #=> "a-1-2-x-y-b"
because join is applied recursively for nested arrays.
The patch clarifies this behavior.
(Also: small markup and grammar fix.)
Patch by Marcus Stollsteimer <sto.mar@web.de>
[ruby-talk:437238] [ruby-core:79079] [Bug #13130]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57329 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2017-01-15 02:09:55 +03:00
|
|
|
*
|
2020-06-13 17:14:17 +03:00
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* With no argument, joins using the output field separator, <tt>$,</tt>:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* $, # => nil
|
|
|
|
* a.join # => "foobar2"
|
|
|
|
*
|
|
|
|
* With argument +separator+, joins using that separator:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.join("\n") # => "foo\nbar\n2"
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Joins recursively for nested Arrays:
|
|
|
|
* a = [:foo, [:bar, [:baz, :bat]]]
|
|
|
|
* a.join # => "foobarbazbat"
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if +separator+ is not a String-convertible object:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into String):
|
|
|
|
* a.join(:foo)
|
mention behavior of Array#join for nested arrays [ci skip]
The current documentation for Array#join does not mention the
special treatment of nested arrays.
It says:
> Returns a string created by converting each element of the
> array to a string, separated by the given separator.
Expected behavior according to the docs would be:
[ "a", [1, 2, [:x, :y]], "b" ].join("-") #=> "a-[1, 2, [:x, :y]]-b"
# because of:
[1, 2, [:x, :y]].to_s #=> "[1, 2, [:x, :y]]"
Actual behavior:
[ "a", [1, 2, [:x, :y]], "b" ].join("-") #=> "a-1-2-x-y-b"
because join is applied recursively for nested arrays.
The patch clarifies this behavior.
(Also: small markup and grammar fix.)
Patch by Marcus Stollsteimer <sto.mar@web.de>
[ruby-talk:437238] [ruby-core:79079] [Bug #13130]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57329 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2017-01-15 02:09:55 +03:00
|
|
|
*
|
2020-06-13 17:14:17 +03:00
|
|
|
* Raises an exception if any element lacks instance method +#to_s+:
|
|
|
|
* a = [:foo, 'bar', 2, BasicObject.new]
|
|
|
|
* # Raises NoMethodError (undefined method `to_s' for #<BasicObject>):
|
|
|
|
* a.join
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_join_m(int argc, VALUE *argv, VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
VALUE sep;
|
|
|
|
|
2019-04-19 00:56:55 +03:00
|
|
|
if (rb_check_arity(argc, 0, 1) == 0 || NIL_P(sep = argv[0])) {
|
2018-12-05 04:09:44 +03:00
|
|
|
sep = rb_output_fs;
|
2019-04-19 00:56:55 +03:00
|
|
|
if (!NIL_P(sep)) {
|
|
|
|
rb_warn("$, is set to non-nil value");
|
|
|
|
}
|
2018-12-05 04:09:44 +03:00
|
|
|
}
|
2009-02-22 17:23:33 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
return rb_ary_join(ary, sep);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
inspect_ary(VALUE ary, VALUE dummy, int recur)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2002-05-21 09:39:19 +04:00
|
|
|
long i;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE s, str;
|
|
|
|
|
2011-02-15 10:08:18 +03:00
|
|
|
if (recur) return rb_usascii_str_new_cstr("[...]");
|
2001-05-30 13:12:34 +04:00
|
|
|
str = rb_str_buf_new2("[");
|
2006-09-02 18:42:08 +04:00
|
|
|
for (i=0; i<RARRAY_LEN(ary); i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
s = rb_inspect(RARRAY_AREF(ary, i));
|
2001-05-30 13:12:34 +04:00
|
|
|
if (i > 0) rb_str_buf_cat2(str, ", ");
|
2011-02-15 10:08:24 +03:00
|
|
|
else rb_enc_copy(str, s);
|
2001-05-30 13:12:34 +04:00
|
|
|
rb_str_buf_append(str, s);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2001-05-30 13:12:34 +04:00
|
|
|
rb_str_buf_cat2(str, "]");
|
1998-01-16 15:13:05 +03:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2003-12-29 05:02:08 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2020-06-13 17:14:17 +03:00
|
|
|
* array.inspect -> new_string
|
|
|
|
* array.to_s => new_string
|
2003-12-29 05:02:08 +03:00
|
|
|
*
|
2020-06-13 17:14:17 +03:00
|
|
|
* Returns the new String formed by calling method <tt>#inspect</tt>
|
|
|
|
* on each array element:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.inspect # => "[:foo, \"bar\", 2]"
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-13 17:14:17 +03:00
|
|
|
* Raises an exception if any element lacks instance method <tt>#inspect</tt>:
|
|
|
|
* a = [:foo, 'bar', 2, BasicObject.new]
|
|
|
|
* a.inspect
|
|
|
|
* # Raises NoMethodError (undefined method `inspect' for #<BasicObject>)
|
2003-12-29 05:02:08 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_inspect(VALUE ary)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
* string.c (rb_str_usascii_new{,2}: defined.
(rb_str_new): set US-ASCII and ENC_CODERANGE_7BIT when empty
string.
* encoding.c (rb_usascii_encoding, rb_usascii_encindex): defined.
(rb_enc_inspect, enc_name, rb_locale_charmap, rb_enc_name_list_i):
use rb_str_ascii_new.
* array.c (recursive_join, inspect_ary): ditto.
* object.c (nil_to_s, nil_inspect, true_to_s, false_to_s,
rb_mod_to_s): ditto.
* hash.c (inspect_hash, rb_hash_inspect, rb_f_getenv, env_fetch,
env_clear, env_to_s, env_inspect): ditto.
* numeric.c (flo_to_s, int_chr, rb_fix2str): ditto.
* bignum.c (rb_big2str): ditto.
* file.c (rb_file_ftype, rb_file_s_dirname, rb_file_s_extname,
file_inspect_join, Init_file): ditto.
* test/ruby/test_ruby_m17n.rb: add checks for encoding of string.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@15244 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-01-25 19:40:02 +03:00
|
|
|
if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new2("[]");
|
* array.c: replace rb_protect_inspect() and rb_inspecting_p() by
rb_exec_recursive() in eval.c.
* eval.c (rb_exec_recursive): new function.
* array.c (rb_ary_join): use rb_exec_recursive().
* array.c (rb_ary_inspect, rb_ary_hash): ditto.
* file.c (rb_file_join): ditto.
* hash.c (rb_hash_inspect, rb_hash_to_s, rb_hash_hash): ditto.
* io.c (rb_io_puts): ditto.
* object.c (rb_obj_inspect): ditto
* struct.c (rb_struct_inspect): ditto.
* lib/set.rb (SortedSet::setup): a hack to shut up warning.
[ruby-talk:132866]
* lib/time.rb (Time::strptime): add new function. inspired by
[ruby-talk:132815].
* lib/parsedate.rb (ParseDate::strptime): ditto.
* regparse.c: move st_*_strend() functions from st.c. fixed some
potential memory leaks.
* exception error messages updated. [ruby-core:04497]
* ext/socket/socket.c (Init_socket): add bunch of Socket
constants. Patch from Sam Roberts <sroberts@uniserve.com>.
[ruby-core:04409]
* array.c (rb_ary_s_create): no need for negative argc check.
[ruby-core:04463]
* array.c (rb_ary_unshift_m): ditto.
* lib/xmlrpc/parser.rb (XMLRPC::FaultException): make it subclass
of StandardError class, not Exception class. [ruby-core:04429]
* parse.y (fcall_gen): lvar(arg) will be evaluated as
lvar.call(arg) when lvar is a defined local variable. [new]
* object.c (rb_class_initialize): call inherited method before
calling initializing block.
* eval.c (rb_thread_start_1): initialize newly pushed frame.
* lib/open3.rb (Open3::popen3): $? should not be EXIT_FAILURE.
fixed: [ruby-core:04444]
* eval.c (is_defined): NODE_IASGN is an assignment.
* ext/readline/readline.c (Readline.readline): use rl_outstream
and rl_instream. [ruby-dev:25699]
* ext/etc/etc.c (Init_etc): sGroup needs HAVE_ST_GR_PASSWD check
[ruby-dev:25675]
* misc/ruby-mode.el: [ruby-core:04415]
* lib/rdoc/generators/html_generator.rb: [ruby-core:04412]
* lib/rdoc/generators/ri_generator.rb: ditto.
* struct.c (make_struct): fixed: [ruby-core:04402]
* ext/curses/curses.c (window_color_set): [ruby-core:04393]
* ext/socket/socket.c (Init_socket): SO_REUSEPORT added.
[ruby-talk:130092]
* object.c: [ruby-doc:818]
* parse.y (open_args): fix too verbose warnings for the space
before argument parentheses. [ruby-dev:25492]
* parse.y (parser_yylex): ditto.
* parse.y (parser_yylex): the first expression in the parentheses
should not be a command. [ruby-dev:25492]
* lib/irb/context.rb (IRB::Context::initialize): [ruby-core:04330]
* object.c (Init_Object): remove Object#type. [ruby-core:04335]
* st.c (st_foreach): report success/failure by return value.
[ruby-Bugs-1396]
* parse.y: forgot to initialize parser struct. [ruby-dev:25492]
* parse.y (parser_yylex): no tLABEL on EXPR_BEG.
[ruby-talk:127711]
* document updates - [ruby-core:04296], [ruby-core:04301],
[ruby-core:04302], [ruby-core:04307]
* dir.c (rb_push_glob): should work for NUL delimited patterns.
* dir.c (rb_glob2): should aware of offset in the pattern.
* string.c (rb_str_new4): should propagate taintedness.
* env.h: rename member names in struct FRAME; last_func -> callee,
orig_func -> this_func, last_class -> this_class.
* struct.c (rb_struct_set): use original method name, not callee
name, to retrieve member slot. [ruby-core:04268]
* time.c (time_strftime): protect from format modification from GC
finalizers.
* object.c (Init_Object): remove rb_obj_id_obsolete()
* eval.c (rb_mod_define_method): incomplete subclass check.
[ruby-dev:25464]
* gc.c (rb_data_object_alloc): klass may be NULL.
[ruby-list:40498]
* bignum.c (rb_big_rand): should return positive random number.
[ruby-dev:25401]
* bignum.c (rb_big_rand): do not use rb_big_modulo to generate
random bignums. [ruby-dev:25396]
* variable.c (rb_autoload): [ruby-dev:25373]
* eval.c (svalue_to_avalue): [ruby-dev:25366]
* string.c (rb_str_justify): [ruby-dev:25367]
* io.c (rb_f_select): [ruby-dev:25312]
* ext/socket/socket.c (sock_s_getservbyport): [ruby-talk:124072]
* struct.c (make_struct): [ruby-dev:25249]
* dir.c (dir_open_dir): new function. [ruby-dev:25242]
* io.c (rb_f_open): add type check for return value from to_open.
* lib/pstore.rb (PStore#transaction): Use the empty content when a
file is not found. [ruby-dev:24561]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8068 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-03-04 09:47:45 +03:00
|
|
|
return rb_exec_recursive(inspect_ary, ary, 0);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2006-09-07 20:33:08 +04:00
|
|
|
VALUE
|
|
|
|
rb_ary_to_s(VALUE ary)
|
|
|
|
{
|
|
|
|
return rb_ary_inspect(ary);
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-13 17:14:17 +03:00
|
|
|
* to_a -> self or new_array
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-18 16:30:04 +03:00
|
|
|
* When +self+ is an instance of \Array, returns +self+:
|
2020-06-13 17:14:17 +03:00
|
|
|
* a = [:foo, 'bar', 2]
|
2020-06-18 16:30:04 +03:00
|
|
|
* a.instance_of?(Array) # => true
|
2020-06-13 17:14:17 +03:00
|
|
|
* a1 = a.to_a
|
|
|
|
* a1.equal?(a) # => true # Returned self
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-18 16:30:04 +03:00
|
|
|
* Otherwise, returns a new \Array containing the elements of +self+:
|
2020-06-13 17:14:17 +03:00
|
|
|
* class MyArray < Array; end
|
2020-06-18 16:30:04 +03:00
|
|
|
* a = MyArray.new(['foo', 'bar', 'two'])
|
|
|
|
* a.instance_of?(Array) # => false
|
|
|
|
* a.kind_of?(Array) # => true
|
2020-06-13 17:14:17 +03:00
|
|
|
* a1 = a.to_a
|
2020-06-18 16:30:04 +03:00
|
|
|
* a1 # => ["foo", "bar", "two"]
|
|
|
|
* a1.class # => Array # Not MyArray
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_to_a(VALUE ary)
|
2003-02-10 12:40:13 +03:00
|
|
|
{
|
|
|
|
if (rb_obj_class(ary) != rb_cArray) {
|
2006-09-02 18:42:08 +04:00
|
|
|
VALUE dup = rb_ary_new2(RARRAY_LEN(ary));
|
2003-02-10 12:40:13 +03:00
|
|
|
rb_ary_replace(dup, ary);
|
|
|
|
return dup;
|
|
|
|
}
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2013-10-23 19:10:48 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-18 16:30:04 +03:00
|
|
|
* array.to_h -> new_hash
|
|
|
|
* array.to_h {|item| ... } -> new_hash
|
2013-10-23 19:10:48 +04:00
|
|
|
*
|
2020-06-18 16:30:04 +03:00
|
|
|
* Returns a new \Hash formed from +self+.
|
2013-10-23 19:10:48 +04:00
|
|
|
*
|
2020-06-18 16:30:04 +03:00
|
|
|
* When a block is given, calls the block with each array element;
|
|
|
|
* the block must return a 2-element \Array whose two elements
|
|
|
|
* form a key-value pair in the returned \Hash:
|
|
|
|
* a = ['foo', :bar, 1, [2, 3], {baz: 4}]
|
|
|
|
* h = a.to_h {|item| [item, item] }
|
|
|
|
* h # => {"foo"=>"foo", :bar=>:bar, 1=>1, [2, 3]=>[2, 3], {:baz=>4}=>{:baz=>4}}
|
2018-09-20 18:06:56 +03:00
|
|
|
*
|
2020-06-18 16:30:04 +03:00
|
|
|
* When no block is given, +self+ must be an \Array of 2-element sub-arrays,
|
|
|
|
* each sub-array is formed into a key-value pair in the new \Hash:
|
|
|
|
* [].to_h # => {}
|
|
|
|
* a = [['foo', 'zero'], ['bar', 'one'], ['baz', 'two']]
|
|
|
|
* h = a.to_h
|
|
|
|
* h # => {"foo"=>"zero", "bar"=>"one", "baz"=>"two"}
|
2018-09-20 18:06:56 +03:00
|
|
|
*
|
2020-06-18 16:30:04 +03:00
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if no block is given
|
|
|
|
* and any element in +self+ is not a 2-element \Array:
|
|
|
|
* # Raises TypeError (wrong element type Symbol at 0 (expected array):
|
|
|
|
* [:foo].to_h
|
|
|
|
* # Raises ArgumentError (wrong array length at 0 (expected 2, was 1)):
|
|
|
|
* [[:foo]].to_h
|
|
|
|
*
|
|
|
|
* Raises an exception if for some 2-element \Array +element+ in +self+,
|
|
|
|
* <tt>element.first</tt> would be an invalid hash key:
|
|
|
|
* # Raises NoMethodError (undefined method `hash' for #<BasicObject:>):
|
|
|
|
* [[BasicObject.new, 0]].to_h
|
2013-10-23 19:10:48 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_to_h(VALUE ary)
|
|
|
|
{
|
|
|
|
long i;
|
2017-09-30 16:14:09 +03:00
|
|
|
VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary));
|
2018-09-20 18:06:56 +03:00
|
|
|
int block_given = rb_block_given_p();
|
|
|
|
|
2013-10-23 19:10:48 +04:00
|
|
|
for (i=0; i<RARRAY_LEN(ary); i++) {
|
2018-09-20 18:06:56 +03:00
|
|
|
const VALUE e = rb_ary_elt(ary, i);
|
|
|
|
const VALUE elt = block_given ? rb_yield_force_blockarg(e) : e;
|
2015-09-28 05:40:46 +03:00
|
|
|
const VALUE key_value_pair = rb_check_array_type(elt);
|
2013-12-23 07:42:29 +04:00
|
|
|
if (NIL_P(key_value_pair)) {
|
2015-09-28 05:40:46 +03:00
|
|
|
rb_raise(rb_eTypeError, "wrong element type %"PRIsVALUE" at %ld (expected array)",
|
|
|
|
rb_obj_class(elt), i);
|
2013-10-23 19:10:48 +04:00
|
|
|
}
|
2013-12-23 07:42:29 +04:00
|
|
|
if (RARRAY_LEN(key_value_pair) != 2) {
|
|
|
|
rb_raise(rb_eArgError, "wrong array length at %ld (expected 2, was %ld)",
|
|
|
|
i, RARRAY_LEN(key_value_pair));
|
|
|
|
}
|
|
|
|
rb_hash_aset(hash, RARRAY_AREF(key_value_pair, 0), RARRAY_AREF(key_value_pair, 1));
|
2013-10-23 19:10:48 +04:00
|
|
|
}
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-18 16:30:04 +03:00
|
|
|
* array.to_ary -> self
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-18 16:30:04 +03:00
|
|
|
* Returns +self+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.to_ary
|
|
|
|
* a1.equal?(a) # => true # Returned self
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2003-02-10 12:40:13 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_to_ary_m(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2010-01-21 05:15:48 +03:00
|
|
|
static void
|
2012-06-20 01:24:19 +04:00
|
|
|
ary_reverse(VALUE *p1, VALUE *p2)
|
2010-01-21 05:15:48 +03:00
|
|
|
{
|
|
|
|
while (p1 < p2) {
|
|
|
|
VALUE tmp = *p1;
|
|
|
|
*p1++ = *p2;
|
|
|
|
*p2-- = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_reverse(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2013-11-06 16:09:31 +04:00
|
|
|
VALUE *p2;
|
|
|
|
long len = RARRAY_LEN(ary);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-10-18 13:03:16 +04:00
|
|
|
rb_ary_modify(ary);
|
2013-11-06 16:09:31 +04:00
|
|
|
if (len > 1) {
|
2018-12-03 15:36:39 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, p1, {
|
|
|
|
p2 = p1 + len - 1; /* points last item */
|
|
|
|
ary_reverse(p1, p2);
|
2013-11-06 16:09:31 +04:00
|
|
|
}); /* WB: no new reference */
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-18 16:30:04 +03:00
|
|
|
* array.reverse! -> self
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-18 16:30:04 +03:00
|
|
|
* Reverses +self+ in place:
|
|
|
|
* a = ['foo', 'bar', 'two']
|
|
|
|
* a1 = a.reverse!
|
|
|
|
* a1 # => ["two", "bar", "foo"]
|
|
|
|
* a1.equal?(a) # => true # Returned self
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2000-08-24 10:21:43 +04:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_reverse_bang(VALUE ary)
|
2000-08-24 10:21:43 +04:00
|
|
|
{
|
|
|
|
return rb_ary_reverse(ary);
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-18 16:30:04 +03:00
|
|
|
* array.reverse -> new_array
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-18 16:30:04 +03:00
|
|
|
* Returns a new \Array whose elements are in reverse order:
|
|
|
|
* a = ['foo', 'bar', 'two']
|
|
|
|
* a1 = a.reverse
|
|
|
|
* a1 # => ["two", "bar", "foo"]
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_reverse_m(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2010-01-21 05:12:07 +03:00
|
|
|
long len = RARRAY_LEN(ary);
|
2010-12-09 09:46:25 +03:00
|
|
|
VALUE dup = rb_ary_new2(len);
|
2010-01-21 05:12:07 +03:00
|
|
|
|
|
|
|
if (len > 0) {
|
2018-10-31 00:54:13 +03:00
|
|
|
const VALUE *p1 = RARRAY_CONST_PTR_TRANSIENT(ary);
|
|
|
|
VALUE *p2 = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(dup) + len - 1;
|
2010-01-21 05:12:07 +03:00
|
|
|
do *p2-- = *p1++; while (--len > 0);
|
|
|
|
}
|
2010-12-09 09:46:25 +03:00
|
|
|
ARY_SET_LEN(dup, RARRAY_LEN(ary));
|
2010-01-21 05:12:07 +03:00
|
|
|
return dup;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2010-01-21 05:15:48 +03:00
|
|
|
static inline long
|
|
|
|
rotate_count(long cnt, long len)
|
|
|
|
{
|
|
|
|
return (cnt < 0) ? (len - (~cnt % len) - 1) : (cnt % len);
|
|
|
|
}
|
|
|
|
|
2018-10-10 06:52:20 +03:00
|
|
|
static void
|
|
|
|
ary_rotate_ptr(VALUE *ptr, long len, long cnt)
|
|
|
|
{
|
2019-11-29 23:59:47 +03:00
|
|
|
if (cnt == 1) {
|
|
|
|
VALUE tmp = *ptr;
|
|
|
|
memmove(ptr, ptr + 1, sizeof(VALUE)*(len - 1));
|
|
|
|
*(ptr + len - 1) = tmp;
|
|
|
|
} else if (cnt == len - 1) {
|
|
|
|
VALUE tmp = *(ptr + len - 1);
|
|
|
|
memmove(ptr + 1, ptr, sizeof(VALUE)*(len - 1));
|
|
|
|
*ptr = tmp;
|
|
|
|
} else {
|
|
|
|
--len;
|
|
|
|
if (cnt < len) ary_reverse(ptr + cnt, ptr + len);
|
|
|
|
if (--cnt > 0) ary_reverse(ptr, ptr + cnt);
|
|
|
|
if (len > 0) ary_reverse(ptr, ptr + len);
|
|
|
|
}
|
2018-10-10 06:52:20 +03:00
|
|
|
}
|
|
|
|
|
2010-01-21 05:15:48 +03:00
|
|
|
VALUE
|
|
|
|
rb_ary_rotate(VALUE ary, long cnt)
|
|
|
|
{
|
|
|
|
rb_ary_modify(ary);
|
|
|
|
|
|
|
|
if (cnt != 0) {
|
2018-10-10 06:52:20 +03:00
|
|
|
long len = RARRAY_LEN(ary);
|
2019-11-29 23:59:47 +03:00
|
|
|
if (len > 1 && (cnt = rotate_count(cnt, len)) > 0) {
|
2018-12-03 15:36:39 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, ary_rotate_ptr(ptr, len, cnt));
|
2018-10-10 06:52:20 +03:00
|
|
|
return ary;
|
|
|
|
}
|
2010-01-21 05:15:48 +03:00
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
2010-05-29 22:51:39 +04:00
|
|
|
|
2010-01-21 05:15:48 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-23 16:58:26 +03:00
|
|
|
* array.rotate! -> self
|
|
|
|
* array.rotate!(count) -> self
|
2010-01-21 05:15:48 +03:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* Rotates +self+ in place by moving elements from one end to the other; returns +self+.
|
|
|
|
*
|
|
|
|
* Argument +count+, if given, must be an
|
|
|
|
* {Integer-convertible object}[doc/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects].
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When no argument given, rotates the first element to the last position:
|
|
|
|
* a = [:foo, 'bar', 2, 'bar']
|
|
|
|
* a1 = a.rotate!
|
|
|
|
* a1 # => ["bar", 2, "bar", :foo]
|
|
|
|
* a1.equal?(a1) # => true # Retruned self
|
|
|
|
*
|
|
|
|
* ---
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* When given a non-negative +count+, rotates +count+ elements from the beginning to the end:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.rotate!(2)
|
|
|
|
* a # => [2, :foo, "bar"]
|
|
|
|
*
|
|
|
|
* If +count+ is large, uses <tt>count % ary.size</tt> as the count:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.rotate!(20)
|
|
|
|
* a # => [2, :foo, "bar"]
|
|
|
|
*
|
|
|
|
* If +count+ is zero, returns +self+ unmodified:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.rotate!(0)
|
|
|
|
* a # => [:foo, "bar", 2]
|
|
|
|
*
|
|
|
|
* ---
|
2010-01-21 05:15:48 +03:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* When given a negative +count+, rotates in the opposite direction,
|
|
|
|
* from end to beginning:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.rotate!(-2)
|
|
|
|
* a # => ["bar", 2, :foo]
|
|
|
|
*
|
|
|
|
* If +count+ is small (far from zero), uses <tt>count % ary.size</tt> as the count:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.rotate!(-5)
|
|
|
|
* a # => ["bar", 2, :foo]
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if +count+ is not an Integer-convertible object:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* a1 = a.rotate!(:foo)
|
2010-01-21 05:15:48 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_rotate_bang(int argc, VALUE *argv, VALUE ary)
|
|
|
|
{
|
2018-12-04 05:24:15 +03:00
|
|
|
long n = (rb_check_arity(argc, 0, 1) ? NUM2LONG(argv[0]) : 1);
|
2010-01-21 05:15:48 +03:00
|
|
|
rb_ary_rotate(ary, n);
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-23 16:58:26 +03:00
|
|
|
* array.rotate -> new_array
|
|
|
|
* array.rotate(count) -> new_array
|
|
|
|
*
|
|
|
|
* Returns a new \Array formed from +self+ with elements
|
|
|
|
* rotated from one end to the other.
|
|
|
|
*
|
|
|
|
* Argument +count+, if given, must be an
|
|
|
|
* {Integer-convertible object}[doc/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects].
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
* When no argument given, returns a new \Array that is like +self+,
|
|
|
|
* except that the first element has been rotated to the last position:
|
|
|
|
* a = [:foo, 'bar', 2, 'bar']
|
|
|
|
* a1 = a.rotate
|
|
|
|
* a1 # => ["bar", 2, "bar", :foo]
|
|
|
|
*
|
|
|
|
* ---
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* When given a non-negative +count+,
|
|
|
|
* returns a new \Array with +count+ elements rotated from the beginning to the end:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.rotate(2)
|
|
|
|
* a1 # => [2, :foo, "bar"]
|
|
|
|
*
|
|
|
|
* If +count+ is large, uses <tt>count % ary.size</tt> as the count:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.rotate(20)
|
|
|
|
* a1 # => [2, :foo, "bar"]
|
2010-01-21 05:15:48 +03:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* If +count+ is zero, returns a copy of +self+, unmodified:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.rotate(0)
|
|
|
|
* a1 # => [:foo, "bar", 2]
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* When given a negative +count+, rotates in the opposite direction,
|
|
|
|
* from end to beginning:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.rotate(-2)
|
|
|
|
* a1 # => ["bar", 2, :foo]
|
2010-01-21 05:15:48 +03:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* If +count+ is small (far from zero), uses <tt>count % ary.size</tt> as the count:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.rotate(-5)
|
|
|
|
* a1 # => ["bar", 2, :foo]
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if +count+ is not an Integer-convertible object:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* a1 = a.rotate(:foo)
|
2010-01-21 05:15:48 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_rotate_m(int argc, VALUE *argv, VALUE ary)
|
|
|
|
{
|
2013-07-19 16:12:31 +04:00
|
|
|
VALUE rotated;
|
|
|
|
const VALUE *ptr;
|
2018-12-04 05:24:15 +03:00
|
|
|
long len;
|
|
|
|
long cnt = (rb_check_arity(argc, 0, 1) ? NUM2LONG(argv[0]) : 1);
|
2010-01-21 05:15:48 +03:00
|
|
|
|
|
|
|
len = RARRAY_LEN(ary);
|
2010-12-09 09:46:25 +03:00
|
|
|
rotated = rb_ary_new2(len);
|
2010-01-21 05:15:48 +03:00
|
|
|
if (len > 0) {
|
|
|
|
cnt = rotate_count(cnt, len);
|
2018-10-31 00:54:13 +03:00
|
|
|
ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
|
2010-01-21 05:15:48 +03:00
|
|
|
len -= cnt;
|
2013-07-19 16:12:31 +04:00
|
|
|
ary_memcpy(rotated, 0, len, ptr + cnt);
|
|
|
|
ary_memcpy(rotated, len, cnt, ptr);
|
2010-01-21 05:15:48 +03:00
|
|
|
}
|
2010-12-09 09:46:25 +03:00
|
|
|
ARY_SET_LEN(rotated, RARRAY_LEN(ary));
|
2010-01-21 05:15:48 +03:00
|
|
|
return rotated;
|
|
|
|
}
|
|
|
|
|
2008-08-04 22:29:55 +04:00
|
|
|
struct ary_sort_data {
|
|
|
|
VALUE ary;
|
2016-03-17 15:03:48 +03:00
|
|
|
struct cmp_opt_data cmp_opt;
|
2008-08-04 22:29:55 +04:00
|
|
|
};
|
|
|
|
|
2008-05-08 04:51:55 +04:00
|
|
|
static VALUE
|
2008-08-04 22:29:55 +04:00
|
|
|
sort_reentered(VALUE ary)
|
2008-05-08 03:56:33 +04:00
|
|
|
{
|
2008-08-04 22:29:55 +04:00
|
|
|
if (RBASIC(ary)->klass) {
|
2015-06-04 07:49:26 +03:00
|
|
|
rb_raise(rb_eRuntimeError, "sort reentered");
|
2008-05-08 03:56:33 +04:00
|
|
|
}
|
2008-05-08 04:51:55 +04:00
|
|
|
return Qnil;
|
2008-05-08 03:56:33 +04:00
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static int
|
2008-01-24 09:50:22 +03:00
|
|
|
sort_1(const void *ap, const void *bp, void *dummy)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2008-08-04 22:29:55 +04:00
|
|
|
struct ary_sort_data *data = dummy;
|
|
|
|
VALUE retval = sort_reentered(data->ary);
|
2005-10-11 16:30:48 +04:00
|
|
|
VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp;
|
2017-04-13 12:25:38 +03:00
|
|
|
VALUE args[2];
|
2004-09-23 04:51:32 +04:00
|
|
|
int n;
|
2004-09-21 07:08:33 +04:00
|
|
|
|
2017-04-13 12:25:38 +03:00
|
|
|
args[0] = a;
|
|
|
|
args[1] = b;
|
|
|
|
retval = rb_yield_values2(2, args);
|
2005-10-11 16:30:48 +04:00
|
|
|
n = rb_cmpint(retval, a, b);
|
2008-08-04 22:29:55 +04:00
|
|
|
sort_reentered(data->ary);
|
2004-09-23 04:51:32 +04:00
|
|
|
return n;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2008-01-24 09:50:22 +03:00
|
|
|
sort_2(const void *ap, const void *bp, void *dummy)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2008-08-04 22:29:55 +04:00
|
|
|
struct ary_sort_data *data = dummy;
|
|
|
|
VALUE retval = sort_reentered(data->ary);
|
2005-10-11 16:30:48 +04:00
|
|
|
VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp;
|
2004-09-23 04:51:32 +04:00
|
|
|
int n;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2020-03-21 10:59:55 +03:00
|
|
|
if (FIXNUM_P(a) && FIXNUM_P(b) && CMP_OPTIMIZABLE(data->cmp_opt, Integer)) {
|
2004-09-23 04:51:32 +04:00
|
|
|
if ((long)a > (long)b) return 1;
|
|
|
|
if ((long)a < (long)b) return -1;
|
2002-08-19 10:41:02 +04:00
|
|
|
return 0;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2016-03-17 15:03:48 +03:00
|
|
|
if (STRING_P(a) && STRING_P(b) && CMP_OPTIMIZABLE(data->cmp_opt, String)) {
|
2008-08-04 22:29:55 +04:00
|
|
|
return rb_str_cmp(a, b);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2017-04-13 10:22:35 +03:00
|
|
|
if (RB_FLOAT_TYPE_P(a) && CMP_OPTIMIZABLE(data->cmp_opt, Float)) {
|
|
|
|
return rb_float_cmp(a, b);
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2013-09-29 18:51:03 +04:00
|
|
|
retval = rb_funcallv(a, id_cmp, 1, &b);
|
2004-09-23 04:51:32 +04:00
|
|
|
n = rb_cmpint(retval, a, b);
|
2008-08-04 22:29:55 +04:00
|
|
|
sort_reentered(data->ary);
|
2004-09-23 04:51:32 +04:00
|
|
|
|
|
|
|
return n;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-23 16:58:26 +03:00
|
|
|
* array.sort! -> self
|
|
|
|
* array.sort! {|a, b| ... } -> self
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* Returns +self+ with its elements sorted in place.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* ---
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* With no block, compares elements using operator <tt><=></tt>
|
|
|
|
* (see Comparable):
|
|
|
|
* a = 'abcde'.split('').shuffle
|
|
|
|
* a # => ["e", "b", "d", "a", "c"]
|
|
|
|
* a.sort!
|
|
|
|
* a # => ["a", "b", "c", "d", "e"]
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* ---
|
2016-10-13 05:35:34 +03:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* With a block, calls the block with each element pair;
|
|
|
|
* for each element pair +a+ and +b+, the block should return an integer:
|
|
|
|
* - Negative when +b+ is to follow +a+.
|
|
|
|
* - Zero when +a+ and +b+ are equivalent.
|
|
|
|
* - Positive when +a+ is to follow +b+.
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
* a = 'abcde'.split('').shuffle
|
|
|
|
* a # => ["e", "b", "d", "a", "c"]
|
|
|
|
* a.sort! {|a, b| a <=> b }
|
|
|
|
* a # => ["a", "b", "c", "d", "e"]
|
|
|
|
* a.sort! {|a, b| b <=> a }
|
|
|
|
* a # => ["e", "d", "c", "b", "a"]
|
|
|
|
*
|
|
|
|
* When the block returns zero, the order for +a+ and +b+ is indeterminate,
|
|
|
|
* and may be unstable:
|
|
|
|
* a = 'abcde'.split('').shuffle
|
|
|
|
* a # => ["e", "b", "d", "a", "c"]
|
|
|
|
* a.sort! {|a, b| 0 }
|
|
|
|
* a # => ["d", "e", "c", "a", "b"]
|
2017-03-04 16:13:50 +03:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if the block returns a non-Integer:
|
|
|
|
* a = 'abcde'.split('').shuffle
|
|
|
|
* # Raises ArgumentError (comparison of Symbol with 0 failed):
|
|
|
|
* a1 = a.sort! {|a, b| :foo }
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2003-12-29 05:02:08 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_sort_bang(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-10-16 14:33:06 +04:00
|
|
|
rb_ary_modify(ary);
|
2008-10-09 09:47:04 +04:00
|
|
|
assert(!ARY_SHARED_P(ary));
|
2006-09-02 18:42:08 +04:00
|
|
|
if (RARRAY_LEN(ary) > 1) {
|
2008-10-09 09:47:04 +04:00
|
|
|
VALUE tmp = ary_make_substitution(ary); /* only ary refers tmp */
|
2008-08-04 22:29:55 +04:00
|
|
|
struct ary_sort_data data;
|
2012-11-09 11:08:38 +04:00
|
|
|
long len = RARRAY_LEN(ary);
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_CLEAR_CLASS(tmp);
|
2008-08-04 22:29:55 +04:00
|
|
|
data.ary = tmp;
|
2016-03-17 15:03:48 +03:00
|
|
|
data.cmp_opt.opt_methods = 0;
|
|
|
|
data.cmp_opt.opt_inited = 0;
|
2013-07-19 16:56:58 +04:00
|
|
|
RARRAY_PTR_USE(tmp, ptr, {
|
2018-12-03 15:36:39 +03:00
|
|
|
ruby_qsort(ptr, len, sizeof(VALUE),
|
|
|
|
rb_block_given_p()?sort_1:sort_2, &data);
|
2013-07-19 16:56:58 +04:00
|
|
|
}); /* WB: no new reference */
|
2013-06-12 07:03:46 +04:00
|
|
|
rb_ary_modify(ary);
|
2008-10-29 17:58:30 +03:00
|
|
|
if (ARY_EMBED_P(tmp)) {
|
|
|
|
if (ARY_SHARED_P(ary)) { /* ary might be destructively operated in the given block */
|
|
|
|
rb_ary_unshare(ary);
|
2015-07-05 04:51:51 +03:00
|
|
|
FL_SET_EMBED(ary);
|
2008-10-29 17:58:30 +03:00
|
|
|
}
|
2013-07-19 14:10:31 +04:00
|
|
|
ary_memcpy(ary, 0, ARY_EMBED_LEN(tmp), ARY_EMBED_PTR(tmp));
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp));
|
|
|
|
}
|
|
|
|
else {
|
2013-06-12 11:41:40 +04:00
|
|
|
if (!ARY_EMBED_P(ary) && ARY_HEAP_PTR(ary) == ARY_HEAP_PTR(tmp)) {
|
2008-11-08 14:09:20 +03:00
|
|
|
FL_UNSET_SHARED(ary);
|
2012-11-09 11:08:38 +04:00
|
|
|
ARY_SET_CAPA(ary, RARRAY_LEN(tmp));
|
2008-11-08 14:09:20 +03:00
|
|
|
}
|
|
|
|
else {
|
2008-10-09 09:47:04 +04:00
|
|
|
assert(!ARY_SHARED_P(tmp));
|
2008-10-29 20:24:44 +03:00
|
|
|
if (ARY_EMBED_P(ary)) {
|
|
|
|
FL_UNSET_EMBED(ary);
|
|
|
|
}
|
|
|
|
else if (ARY_SHARED_P(ary)) {
|
2008-11-08 14:09:20 +03:00
|
|
|
/* ary might be destructively operated in the given block */
|
2008-10-17 17:09:33 +04:00
|
|
|
rb_ary_unshare(ary);
|
2008-10-09 09:47:04 +04:00
|
|
|
}
|
|
|
|
else {
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_heap_free(ary);
|
2008-10-09 09:47:04 +04:00
|
|
|
}
|
2018-10-31 00:53:56 +03:00
|
|
|
ARY_SET_PTR(ary, ARY_HEAP_PTR(tmp));
|
2012-11-09 11:08:38 +04:00
|
|
|
ARY_SET_HEAP_LEN(ary, len);
|
2018-10-31 00:53:56 +03:00
|
|
|
ARY_SET_CAPA(ary, ARY_HEAP_LEN(tmp));
|
2009-02-22 17:23:33 +03:00
|
|
|
}
|
2008-10-09 09:47:04 +04:00
|
|
|
/* tmp was lost ownership for the ptr */
|
|
|
|
FL_UNSET(tmp, FL_FREEZE);
|
|
|
|
FL_SET_EMBED(tmp);
|
|
|
|
ARY_SET_EMBED_LEN(tmp, 0);
|
|
|
|
FL_SET(tmp, FL_FREEZE);
|
2018-10-31 00:02:12 +03:00
|
|
|
}
|
2008-10-09 09:47:04 +04:00
|
|
|
/* tmp will be GC'ed. */
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_SET_CLASS_RAW(tmp, rb_cArray); /* rb_cArray must be marked */
|
2003-09-05 09:07:54 +04:00
|
|
|
}
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
1998-01-16 15:19:22 +03:00
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-23 16:58:26 +03:00
|
|
|
* array.sort -> new_array
|
|
|
|
* array.sort {|a, b| ... } -> new_array
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* Returns a new \Array whose elements are those from +self+, sorted.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* See also Enumerable#sort_by.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* ---
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* With no block, compares elements using operator <tt><=></tt>
|
|
|
|
* (see Comparable):
|
|
|
|
* a = 'abcde'.split('').shuffle
|
|
|
|
* a # => ["e", "b", "d", "a", "c"]
|
|
|
|
* a1 = a.sort
|
|
|
|
* a1 # => ["a", "b", "c", "d", "e"]
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* ---
|
2017-03-04 16:13:50 +03:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* With a block, calls the block with each element pair;
|
|
|
|
* for each element pair +a+ and +b+, the block should return an integer:
|
|
|
|
* - Negative when +b+ is to follow +a+.
|
|
|
|
* - Zero when +a+ and +b+ are equivalent.
|
|
|
|
* - Positive when +a+ is to follow +b+.
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
* a = 'abcde'.split('').shuffle
|
|
|
|
* a # => ["e", "b", "d", "a", "c"]
|
|
|
|
* a1 = a.sort {|a, b| a <=> b }
|
|
|
|
* a1 # => ["a", "b", "c", "d", "e"]
|
|
|
|
* a2 = a.sort {|a, b| b <=> a }
|
|
|
|
* a2 # => ["e", "d", "c", "b", "a"]
|
|
|
|
*
|
|
|
|
* When the block returns zero, the order for +a+ and +b+ is indeterminate,
|
|
|
|
* and may be unstable:
|
|
|
|
* a = 'abcde'.split('').shuffle
|
|
|
|
* a # => ["e", "b", "d", "a", "c"]
|
|
|
|
* a1 = a.sort {|a, b| 0 }
|
|
|
|
* a1 # => ["c", "e", "b", "d", "a"]
|
2019-06-13 09:30:03 +03:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* ---
|
2019-06-13 09:30:03 +03:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* Raises an exception if the block returns a non-Integer:
|
|
|
|
* a = 'abcde'.split('').shuffle
|
|
|
|
* # Raises ArgumentError (comparison of Symbol with 0 failed):
|
|
|
|
* a1 = a.sort {|a, b| :foo }
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_sort(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2002-08-27 12:31:08 +04:00
|
|
|
ary = rb_ary_dup(ary);
|
1999-10-20 11:10:23 +04:00
|
|
|
rb_ary_sort_bang(ary);
|
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2015-06-12 11:19:24 +03:00
|
|
|
static VALUE rb_ary_bsearch_index(VALUE ary);
|
2015-06-12 10:28:21 +03:00
|
|
|
|
2012-11-14 19:53:50 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-23 16:58:26 +03:00
|
|
|
* array.bsearch {|element| ... } -> object
|
|
|
|
* array.bsearch -> new_enumerator
|
|
|
|
*
|
|
|
|
* Returns an element from +self+ selected by a binary search.
|
|
|
|
* +self+ should be sorted, but this is not checked.
|
2012-11-14 19:53:50 +04:00
|
|
|
*
|
|
|
|
* By using binary search, finds a value from this array which meets
|
2020-06-23 16:58:26 +03:00
|
|
|
* the given condition in <tt>O(log n)</tt> where +n+ is the size of the array.
|
|
|
|
*
|
|
|
|
* There are two search modes:
|
|
|
|
* - <b>Find-minimum mode</b>: the block should return +true+ or +false+.
|
|
|
|
* - <b>Find-any mode</b>: the block should return a numeric value.
|
|
|
|
*
|
|
|
|
* The block should not mix the modes by and sometimes returning +true+ or +false+
|
|
|
|
* and sometimes returning a numeric value, but this is not checked.
|
|
|
|
*
|
|
|
|
* ====== Find-Minimum Mode
|
|
|
|
*
|
|
|
|
* In find-minimum mode, the block always returns +true+ or +false+.
|
|
|
|
* The further requirement (though not checked) is that
|
|
|
|
* there are no indexes +i+ and +j+ such that:
|
|
|
|
* - <tt>0 <= i < j <= self.size</tt>.
|
|
|
|
* - The block returns +true+ for <tt>self[i]</tt> and +false+ for <tt>self[j]</tt>.
|
|
|
|
*
|
|
|
|
* In find-minimum mode, method bsearch returns the first element for which the block returns true.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
* a = [0, 4, 7, 10, 12]
|
|
|
|
* a.bsearch {|x| x >= 4 } # => 4
|
|
|
|
* a.bsearch {|x| x >= 6 } # => 7
|
|
|
|
* a.bsearch {|x| x >= -1 } # => 0
|
|
|
|
* a.bsearch {|x| x >= 100 } # => nil
|
|
|
|
*
|
|
|
|
* Less formally: the block is such that all +false+-evaluating elements
|
|
|
|
* precede all +true+-evaluating elements.
|
|
|
|
*
|
|
|
|
* These make sense as blocks in find-minimum mode:
|
|
|
|
* a = [0, 4, 7, 10, 12]
|
|
|
|
* a.map {|x| x >= 4 } # => [false, true, true, true, true]
|
|
|
|
* a.map {|x| x >= 6 } # => [false, false, true, true, true]
|
|
|
|
* a.map {|x| x >= -1 } # => [true, true, true, true, true]
|
|
|
|
* a.map {|x| x >= 100 } # => [false, false, false, false, false]
|
|
|
|
*
|
|
|
|
* This would not make sense:
|
|
|
|
* a = [0, 4, 7, 10, 12]
|
|
|
|
* a.map {|x| x == 7 } # => [false, false, true, false, false]
|
|
|
|
*
|
|
|
|
* ====== Find-Any Mode
|
|
|
|
*
|
|
|
|
* In find-any mode, the block always returns a numeric value.
|
|
|
|
* The further requirement (though not checked) is that
|
|
|
|
* there are no indexes +i+ and +j+ such that:
|
|
|
|
* - <tt>0 <= i < j <= self.size</tt>.
|
|
|
|
* - The block returns a negative value for <tt>self[i]</tt>
|
|
|
|
* and a positive value for <tt>self[j]</tt>.
|
|
|
|
* - The block returns a negative value for <tt>self[i]</tt> and zero <tt>self[j]</tt>.
|
|
|
|
* - The block returns zero for <tt>self[i]</tt> and a positive value for <tt>self[j]</tt>.
|
|
|
|
*
|
|
|
|
* In find-any mode, method bsearch returns some element
|
|
|
|
* for which the block returns zero, or +nil+ if no such element is found.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
* a = [0, 4, 7, 10, 12]
|
|
|
|
* a.bsearch {|element| 7 <=> element } # => 7
|
|
|
|
* a.bsearch {|element| -1 <=> element } # => nil
|
|
|
|
* a.bsearch {|element| 5 <=> element } # => nil
|
|
|
|
* a.bsearch {|element| 15 <=> element } # => nil
|
|
|
|
*
|
|
|
|
* Less formally: the block is such that:
|
|
|
|
* - All positive-evaluating elements precede all zero-evaluating elements.
|
|
|
|
* - All positive-evaluating elements precede all negative-evaluating elements.
|
|
|
|
* - All zero-evaluating elements precede all negative-evaluating elements.
|
|
|
|
*
|
|
|
|
* These make sense as blocks in find-any mode:
|
|
|
|
* a = [0, 4, 7, 10, 12]
|
|
|
|
* a.map {|element| 7 <=> element } # => [1, 1, 0, -1, -1]
|
|
|
|
* a.map {|element| -1 <=> element } # => [-1, -1, -1, -1, -1]
|
|
|
|
* a.map {|element| 5 <=> element } # => [1, 1, -1, -1, -1]
|
|
|
|
* a.map {|element| 15 <=> element } # => [1, 1, 1, 1, 1]
|
|
|
|
*
|
|
|
|
* This would not make sense:
|
|
|
|
* a = [0, 4, 7, 10, 12]
|
|
|
|
* a.map {|element| element <=> 7 } # => [-1, -1, 0, 1, 1]
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Returns an enumerator if no block given:
|
|
|
|
* a = [0, 4, 7, 10, 12]
|
|
|
|
* a.bsearch # => #<Enumerator: [0, 4, 7, 10, 12]:bsearch>
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if the block returns an invalid value:
|
|
|
|
* a = 'abcde'.split('').shuffle
|
|
|
|
* # Raises TypeError (wrong argument type Symbol (must be numeric, true, false or nil)):
|
|
|
|
* a.bsearch {|element| :foo }
|
2012-11-14 19:53:50 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_bsearch(VALUE ary)
|
2015-06-12 10:28:21 +03:00
|
|
|
{
|
2015-06-12 11:19:24 +03:00
|
|
|
VALUE index_result = rb_ary_bsearch_index(ary);
|
2015-06-12 10:28:21 +03:00
|
|
|
|
2015-06-12 11:19:24 +03:00
|
|
|
if (FIXNUM_P(index_result)) {
|
|
|
|
return rb_ary_entry(ary, FIX2LONG(index_result));
|
|
|
|
}
|
|
|
|
return index_result;
|
2015-06-12 10:28:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-23 16:58:26 +03:00
|
|
|
* array.bsearch_index {|element| ... } -> integer or nil
|
|
|
|
* array.bsearch_index -> new_enumerator
|
2015-06-12 10:28:21 +03:00
|
|
|
*
|
2020-06-23 16:58:26 +03:00
|
|
|
* Searches +self+ as described at method #bsearch,
|
|
|
|
* but returns the _index_ of the found element instead of the element itself.
|
2015-06-12 10:28:21 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_bsearch_index(VALUE ary)
|
2012-11-14 19:53:50 +04:00
|
|
|
{
|
|
|
|
long low = 0, high = RARRAY_LEN(ary), mid;
|
2015-06-12 10:28:21 +03:00
|
|
|
int smaller = 0, satisfied = 0;
|
|
|
|
VALUE v, val;
|
2012-11-14 19:53:50 +04:00
|
|
|
|
2013-01-30 09:11:03 +04:00
|
|
|
RETURN_ENUMERATOR(ary, 0, 0);
|
2012-11-14 19:53:50 +04:00
|
|
|
while (low < high) {
|
|
|
|
mid = low + ((high - low) / 2);
|
|
|
|
val = rb_ary_entry(ary, mid);
|
|
|
|
v = rb_yield(val);
|
|
|
|
if (FIXNUM_P(v)) {
|
2015-06-12 11:19:24 +03:00
|
|
|
if (v == INT2FIX(0)) return INT2FIX(mid);
|
2015-01-12 04:25:26 +03:00
|
|
|
smaller = (SIGNED_VALUE)v < 0; /* Fixnum preserves its sign-bit */
|
2012-11-14 19:53:50 +04:00
|
|
|
}
|
|
|
|
else if (v == Qtrue) {
|
2015-06-12 10:28:21 +03:00
|
|
|
satisfied = 1;
|
2012-11-14 19:53:50 +04:00
|
|
|
smaller = 1;
|
|
|
|
}
|
|
|
|
else if (v == Qfalse || v == Qnil) {
|
|
|
|
smaller = 0;
|
|
|
|
}
|
|
|
|
else if (rb_obj_is_kind_of(v, rb_cNumeric)) {
|
2013-09-29 18:51:03 +04:00
|
|
|
const VALUE zero = INT2FIX(0);
|
2015-01-12 04:25:26 +03:00
|
|
|
switch (rb_cmpint(rb_funcallv(v, id_cmp, 1, &zero), v, zero)) {
|
2015-06-12 11:19:24 +03:00
|
|
|
case 0: return INT2FIX(mid);
|
2015-01-12 02:48:10 +03:00
|
|
|
case 1: smaller = 1; break;
|
|
|
|
case -1: smaller = 0;
|
2012-11-14 19:53:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2015-01-12 02:48:10 +03:00
|
|
|
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE
|
|
|
|
" (must be numeric, true, false or nil)",
|
|
|
|
rb_obj_class(v));
|
2012-11-14 19:53:50 +04:00
|
|
|
}
|
|
|
|
if (smaller) {
|
|
|
|
high = mid;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
low = mid + 1;
|
|
|
|
}
|
|
|
|
}
|
2015-06-12 11:19:24 +03:00
|
|
|
if (!satisfied) return Qnil;
|
|
|
|
return INT2FIX(low);
|
2012-11-14 19:53:50 +04:00
|
|
|
}
|
|
|
|
|
* array.c (ary_iter_check): should check modification (size
change) during iteration.
* array.c (rb_ary_initialize, rb_ary_shift, rb_ary_unshift,
rb_ary_splice, rb_ary_reverse, rb_ary_sort, rb_ary_delete,
rb_ary_delete_at, rb_ary_reject_bang, rb_ary_replace,
rb_ary_clear, rb_ary_fill, rb_ary_uniq_bang, rb_ary_compact,
rb_ary_shuffle): add iteration check.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11429 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2006-12-29 22:25:11 +03:00
|
|
|
|
2009-02-02 13:43:27 +03:00
|
|
|
static VALUE
|
2013-11-29 11:59:14 +04:00
|
|
|
sort_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, dummy))
|
2009-02-02 13:43:27 +03:00
|
|
|
{
|
|
|
|
return rb_yield(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-24 21:31:42 +03:00
|
|
|
* array.sort_by! {|element| ... } -> self
|
|
|
|
* array.sort_by! -> new_enumerator
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Sorts the elements of +self+ in place,
|
|
|
|
* using an ordering determined by the block; returns self.
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Calls the block with each successive element;
|
|
|
|
* sorts elements based on the values returned from the block.
|
2016-10-13 05:35:34 +03:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* For duplicates returned by the block, the ordering is indeterminate, and may be unstable.
|
2009-02-02 13:43:27 +03:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* This example sorts strings based on their sizes:
|
|
|
|
* a = ['aaaa', 'bbb', 'cc', 'd']
|
|
|
|
* a.sort_by! {|element| element.size }
|
|
|
|
* a # => ["d", "cc", "bbb", "aaaa"]
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Returns a new \Enumerator if no block given:
|
|
|
|
*
|
|
|
|
* a = ['aaaa', 'bbb', 'cc', 'd']
|
|
|
|
* a.sort_by! # => #<Enumerator: ["aaaa", "bbb", "cc", "d"]:sort_by!>
|
2009-02-02 13:43:27 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_sort_by_bang(VALUE ary)
|
|
|
|
{
|
|
|
|
VALUE sorted;
|
|
|
|
|
2013-06-26 17:43:22 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
|
2009-02-02 13:43:27 +03:00
|
|
|
rb_ary_modify(ary);
|
|
|
|
sorted = rb_block_call(ary, rb_intern("sort_by"), 0, 0, sort_by_i, 0);
|
|
|
|
rb_ary_replace(ary, sorted);
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-24 21:31:42 +03:00
|
|
|
* array.map {|element| ... } -> new_array
|
|
|
|
* array.map -> new_enumerator
|
|
|
|
* array.collect {|element| ... } -> new_array
|
|
|
|
* array.collect -> new_enumerator
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Array#map is an alias for Array#collect.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Calls the block, if given, with each element of +self+;
|
|
|
|
* returns a new \Array whose elements are the return values from the block:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.collect {|element| element.class }
|
|
|
|
* a1 # => [Symbol, String, Integer]
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* ---
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Returns a new \Enumerator if no block given:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.collect
|
|
|
|
* a1 # => #<Enumerator: [:foo, "bar", 2]:collect>
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1999-10-29 13:25:48 +04:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_collect(VALUE ary)
|
1999-10-29 13:25:48 +04:00
|
|
|
{
|
2003-07-31 10:30:35 +04:00
|
|
|
long i;
|
2008-01-24 09:18:18 +03:00
|
|
|
VALUE collect;
|
1999-10-29 13:25:48 +04:00
|
|
|
|
2013-06-26 17:43:22 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
|
2008-01-24 09:18:18 +03:00
|
|
|
collect = rb_ary_new2(RARRAY_LEN(ary));
|
2006-09-02 18:42:08 +04:00
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
2018-11-22 12:18:43 +03:00
|
|
|
rb_ary_push(collect, rb_yield(RARRAY_AREF(ary, i)));
|
1999-10-29 13:25:48 +04:00
|
|
|
}
|
2008-01-24 09:18:18 +03:00
|
|
|
return collect;
|
1999-10-29 13:25:48 +04:00
|
|
|
}
|
|
|
|
|
2008-01-24 09:18:18 +03:00
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2020-06-24 21:31:42 +03:00
|
|
|
* array.map! {|element| ... } -> self
|
|
|
|
* array.map! -> new_enumerator
|
|
|
|
* array.collect! {|element| ... } -> self
|
|
|
|
* array.collect! -> new_enumerator
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Array#map! is an alias for Array#collect!.
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Calls the block, if given, with each element;
|
|
|
|
* replaces the element with the block's return value:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.collect! { |element| element.class }
|
|
|
|
* a1 # => [Symbol, String, Integer]
|
|
|
|
* a1.equal?(a) # => true # Returned self
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* ---
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Returns a new \Enumerator if no block given:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a1 = a.collect!
|
|
|
|
* a1 # => #<Enumerator: [:foo, "bar", 2]:collect!>
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2000-05-01 13:42:38 +04:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_collect_bang(VALUE ary)
|
2000-05-01 13:42:38 +04:00
|
|
|
{
|
2008-01-24 09:18:18 +03:00
|
|
|
long i;
|
|
|
|
|
2013-06-26 17:43:22 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
|
2008-01-24 09:18:18 +03:00
|
|
|
rb_ary_modify(ary);
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
rb_ary_store(ary, i, rb_yield(RARRAY_AREF(ary, i)));
|
2008-01-24 09:18:18 +03:00
|
|
|
}
|
|
|
|
return ary;
|
2000-05-01 13:42:38 +04:00
|
|
|
}
|
|
|
|
|
2003-07-03 15:02:53 +04:00
|
|
|
VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
rb_get_values_at(VALUE obj, long olen, int argc, const VALUE *argv, VALUE (*func) (VALUE, long))
|
2003-06-02 08:49:46 +04:00
|
|
|
{
|
2003-07-03 15:02:53 +04:00
|
|
|
VALUE result = rb_ary_new2(argc);
|
|
|
|
long beg, len, i, j;
|
2003-06-02 08:49:46 +04:00
|
|
|
|
2003-07-03 15:02:53 +04:00
|
|
|
for (i=0; i<argc; i++) {
|
|
|
|
if (FIXNUM_P(argv[i])) {
|
|
|
|
rb_ary_push(result, (*func)(obj, FIX2LONG(argv[i])));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* check if idx is Range */
|
2012-07-14 13:18:51 +04:00
|
|
|
if (rb_range_beg_len(argv[i], &beg, &len, olen, 1)) {
|
|
|
|
long end = olen < beg+len ? olen : beg+len;
|
|
|
|
for (j = beg; j < end; j++) {
|
|
|
|
rb_ary_push(result, (*func)(obj, j));
|
2003-07-03 15:02:53 +04:00
|
|
|
}
|
2012-07-14 13:18:51 +04:00
|
|
|
if (beg + len > j)
|
|
|
|
rb_ary_resize(result, RARRAY_LEN(result) + (beg + len) - j);
|
2003-07-03 15:02:53 +04:00
|
|
|
continue;
|
2003-06-02 08:49:46 +04:00
|
|
|
}
|
2003-07-03 15:02:53 +04:00
|
|
|
rb_ary_push(result, (*func)(obj, NUM2LONG(argv[i])));
|
2003-06-02 08:49:46 +04:00
|
|
|
}
|
2003-07-03 15:02:53 +04:00
|
|
|
return result;
|
2003-06-02 08:49:46 +04:00
|
|
|
}
|
|
|
|
|
2018-02-15 13:00:57 +03:00
|
|
|
static VALUE
|
|
|
|
append_values_at_single(VALUE result, VALUE ary, long olen, VALUE idx)
|
|
|
|
{
|
|
|
|
long beg, len;
|
|
|
|
if (FIXNUM_P(idx)) {
|
|
|
|
beg = FIX2LONG(idx);
|
|
|
|
}
|
|
|
|
/* check if idx is Range */
|
|
|
|
else if (rb_range_beg_len(idx, &beg, &len, olen, 1)) {
|
|
|
|
if (len > 0) {
|
2018-10-31 00:54:13 +03:00
|
|
|
const VALUE *const src = RARRAY_CONST_PTR_TRANSIENT(ary);
|
2018-02-15 13:00:57 +03:00
|
|
|
const long end = beg + len;
|
|
|
|
const long prevlen = RARRAY_LEN(result);
|
|
|
|
if (beg < olen) {
|
|
|
|
rb_ary_cat(result, src + beg, end > olen ? olen-beg : len);
|
|
|
|
}
|
|
|
|
if (end > olen) {
|
|
|
|
rb_ary_store(result, prevlen + len - 1, Qnil);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
beg = NUM2LONG(idx);
|
|
|
|
}
|
|
|
|
return rb_ary_push(result, rb_ary_entry(ary, beg));
|
|
|
|
}
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2020-06-24 21:31:42 +03:00
|
|
|
* array.values_at(*indexes) -> new_array
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Returns a new \Array whose elements are the elements
|
|
|
|
* of +self+ at the given +indexes+.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Each +index+ given in +indexes+ must be an
|
|
|
|
* {Integer-convertible object}[doc/implicit_conversion_rdoc.html#label-Integer-Convertible+Objects].
|
|
|
|
*
|
|
|
|
* ---
|
2004-07-09 17:38:34 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* For each positive +index+, returns the element at offset +index+:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.values_at(0, 2) # => [:foo, 2]
|
|
|
|
*
|
|
|
|
* The given +indexes+ may be in any order, and may repeat:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.values_at(2, 0, 1, 0, 2) # => [2, :foo, "bar", :foo, 2]
|
|
|
|
*
|
|
|
|
* Assigns +nil+ for an +index+ that is too large:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.values_at(0, 3, 1, 3) # => [:foo, nil, "bar", nil]
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Returns a new empty \Array if no arguments given:
|
|
|
|
* [].values_at # => []
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* For each negative +index+, counts backward from the end of the array:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.values_at(-1, -3) # => [2, :foo]
|
|
|
|
*
|
|
|
|
* Assigns +nil+ for an +index+ that is too small:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.values_at(0, -5, 1, -6, 2) # => [:foo, nil, "bar", nil, 2]
|
|
|
|
*
|
|
|
|
* The given +indexes+ may have a mixture of signs:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* a.values_at(0, -2, 1, -1) # => [:foo, "bar", "bar", 2]
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* Raises an exception if any +index+ is not an Integer-convertible object:
|
|
|
|
* a = [:foo, 'bar', 2]
|
|
|
|
* # Raises TypeError (no implicit conversion of Symbol into Integer):
|
|
|
|
* a.values_at(0, :foo)
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2003-05-04 20:03:24 +04:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_values_at(int argc, VALUE *argv, VALUE ary)
|
2003-05-04 20:03:24 +04:00
|
|
|
{
|
2018-02-15 13:00:57 +03:00
|
|
|
long i, olen = RARRAY_LEN(ary);
|
|
|
|
VALUE result = rb_ary_new_capa(argc);
|
|
|
|
for (i = 0; i < argc; ++i) {
|
|
|
|
append_values_at_single(result, ary, olen, argv[i]);
|
|
|
|
}
|
|
|
|
RB_GC_GUARD(ary);
|
|
|
|
return result;
|
2003-05-04 20:03:24 +04:00
|
|
|
}
|
|
|
|
|
* array.c (ary_iter_check): should check modification (size
change) during iteration.
* array.c (rb_ary_initialize, rb_ary_shift, rb_ary_unshift,
rb_ary_splice, rb_ary_reverse, rb_ary_sort, rb_ary_delete,
rb_ary_delete_at, rb_ary_reject_bang, rb_ary_replace,
rb_ary_clear, rb_ary_fill, rb_ary_uniq_bang, rb_ary_compact,
rb_ary_shuffle): add iteration check.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11429 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2006-12-29 22:25:11 +03:00
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-24 21:31:42 +03:00
|
|
|
* array.select {|element| ... } -> new_array
|
|
|
|
* array.select -> new_enumerator
|
|
|
|
* array.filter {|element| ... } -> new_array
|
|
|
|
* array.filter -> new_enumerator
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Array#filter is an alias for Array#select.
|
2012-09-13 22:32:07 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Calls the block, if given, with each element of +self+;
|
|
|
|
* returns a new \Array containing those elements of +self+
|
|
|
|
* for which the block returns a truthy value:
|
|
|
|
* a = [:foo, 'bar', 2, :bam]
|
|
|
|
* a1 = a.select {|element| element.to_s.start_with?('b') }
|
|
|
|
* a1 # => ["bar", :bam]
|
2012-09-13 22:32:07 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* ---
|
2018-11-04 14:40:32 +03:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Returns a new \Enumerator if no block given:
|
|
|
|
* a = [:foo, 'bar', 2, :bam]
|
|
|
|
* a.select # => #<Enumerator: [:foo, "bar", 2, :bam]:select>
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2001-12-11 06:48:08 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_select(VALUE ary)
|
2001-12-11 06:48:08 +03:00
|
|
|
{
|
2008-01-24 09:18:18 +03:00
|
|
|
VALUE result;
|
|
|
|
long i;
|
|
|
|
|
2013-06-26 17:43:22 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
|
2008-01-24 09:18:18 +03:00
|
|
|
result = rb_ary_new2(RARRAY_LEN(ary));
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) {
|
2008-01-24 09:18:18 +03:00
|
|
|
rb_ary_push(result, rb_ary_elt(ary, i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
2001-12-11 06:48:08 +03:00
|
|
|
}
|
|
|
|
|
2015-01-15 04:44:57 +03:00
|
|
|
struct select_bang_arg {
|
|
|
|
VALUE ary;
|
|
|
|
long len[2];
|
|
|
|
};
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
select_bang_i(VALUE a)
|
|
|
|
{
|
|
|
|
volatile struct select_bang_arg *arg = (void *)a;
|
|
|
|
VALUE ary = arg->ary;
|
|
|
|
long i1, i2;
|
|
|
|
|
|
|
|
for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); arg->len[0] = ++i1) {
|
|
|
|
VALUE v = RARRAY_AREF(ary, i1);
|
|
|
|
if (!RTEST(rb_yield(v))) continue;
|
|
|
|
if (i1 != i2) {
|
|
|
|
rb_ary_store(ary, i2, v);
|
|
|
|
}
|
|
|
|
arg->len[1] = ++i2;
|
|
|
|
}
|
|
|
|
return (i1 == i2) ? Qnil : ary;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
select_bang_ensure(VALUE a)
|
|
|
|
{
|
|
|
|
volatile struct select_bang_arg *arg = (void *)a;
|
|
|
|
VALUE ary = arg->ary;
|
|
|
|
long len = RARRAY_LEN(ary);
|
|
|
|
long i1 = arg->len[0], i2 = arg->len[1];
|
|
|
|
|
2016-12-20 09:53:44 +03:00
|
|
|
if (i2 < len && i2 < i1) {
|
|
|
|
long tail = 0;
|
2015-01-15 04:44:57 +03:00
|
|
|
if (i1 < len) {
|
2016-12-20 09:53:44 +03:00
|
|
|
tail = len - i1;
|
2018-12-03 15:36:47 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
2016-12-20 09:53:44 +03:00
|
|
|
MEMMOVE(ptr + i2, ptr + i1, VALUE, tail);
|
2015-01-15 04:44:57 +03:00
|
|
|
});
|
|
|
|
}
|
2016-12-20 09:53:44 +03:00
|
|
|
ARY_SET_LEN(ary, i2 + tail);
|
2015-01-15 04:44:57 +03:00
|
|
|
}
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2010-03-03 08:35:08 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2020-06-24 21:31:42 +03:00
|
|
|
* array.select! {|element| ... } -> self or nil
|
|
|
|
* array.select! -> new_enumerator
|
|
|
|
* array.filter! {|element| ... } -> self or nil
|
|
|
|
* array.filter! -> new_enumerator
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Array#filter! is an alias for Array#select!.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Calls the block, if given with each element of +self+;
|
|
|
|
* removes from +self+ those elements for which the block returns +false+ or +nil+.
|
2015-01-15 04:44:57 +03:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Returns +self+ if any elements were removed:
|
|
|
|
* a = [:foo, 'bar', 2, :bam]
|
|
|
|
* a1 = a.select! {|element| element.to_s.start_with?('b') }
|
|
|
|
* a1 # => ["bar", :bam]
|
|
|
|
* a1.equal?(a) # => true # Returned self
|
2010-03-03 08:35:08 +03:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Returns +nil+ if no elements were removed:
|
|
|
|
* a = [:foo, 'bar', 2, :bam]
|
|
|
|
* a.select! { |element| element.kind_of?(Object) } # => nil
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* ---
|
2018-11-04 14:40:32 +03:00
|
|
|
*
|
2020-06-24 21:31:42 +03:00
|
|
|
* Returns a new \Enumerator if no block given:
|
|
|
|
* a = [:foo, 'bar', 2, :bam]
|
|
|
|
* a.select! # => #<Enumerator: [:foo, "bar", 2, :bam]:select!>
|
2010-03-03 08:35:08 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_select_bang(VALUE ary)
|
|
|
|
{
|
2015-01-15 04:44:57 +03:00
|
|
|
struct select_bang_arg args;
|
2010-03-03 08:35:08 +03:00
|
|
|
|
2013-06-26 17:43:22 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
|
2010-03-03 08:35:08 +03:00
|
|
|
rb_ary_modify(ary);
|
2015-01-15 04:44:57 +03:00
|
|
|
|
|
|
|
args.ary = ary;
|
|
|
|
args.len[0] = args.len[1] = 0;
|
|
|
|
return rb_ensure(select_bang_i, (VALUE)&args, select_bang_ensure, (VALUE)&args);
|
2010-03-03 08:35:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.keep_if {|item| block} -> ary
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.keep_if -> Enumerator
|
|
|
|
*
|
|
|
|
* Deletes every element of +self+ for which the given block evaluates to
|
2018-11-04 14:39:28 +03:00
|
|
|
* +false+, and returns +self+.
|
2010-03-03 08:35:08 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* If no block is given, an Enumerator is returned instead.
|
2010-03-03 08:35:08 +03:00
|
|
|
*
|
2018-11-04 14:39:28 +03:00
|
|
|
* a = %w[ a b c d e f ]
|
|
|
|
* a.keep_if {|v| v =~ /[aeiou]/ } #=> ["a", "e"]
|
|
|
|
* a #=> ["a", "e"]
|
|
|
|
*
|
|
|
|
* See also Array#select!.
|
2010-03-03 08:35:08 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_keep_if(VALUE ary)
|
|
|
|
{
|
2013-06-26 17:43:22 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
|
2010-03-03 08:35:08 +03:00
|
|
|
rb_ary_select_bang(ary);
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2012-11-25 17:39:26 +04:00
|
|
|
static void
|
|
|
|
ary_resize_smaller(VALUE ary, long len)
|
|
|
|
{
|
|
|
|
rb_ary_modify(ary);
|
|
|
|
if (RARRAY_LEN(ary) > len) {
|
|
|
|
ARY_SET_LEN(ary, len);
|
|
|
|
if (len * 2 < ARY_CAPA(ary) &&
|
|
|
|
ARY_CAPA(ary) > ARY_DEFAULT_SIZE) {
|
|
|
|
ary_resize_capa(ary, len * 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2012-11-27 00:14:49 +04:00
|
|
|
* ary.delete(obj) -> item or nil
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.delete(obj) {block} -> item or result of block
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Deletes all items from +self+ that are equal to +obj+.
|
|
|
|
*
|
2012-11-27 00:14:49 +04:00
|
|
|
* Returns the last deleted item, or +nil+ if no matching item is found.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
|
|
|
* If the optional code block is given, the result of the block is returned if
|
|
|
|
* the item is not found. (To remove +nil+ elements and get an informative
|
|
|
|
* return value, use Array#compact!)
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* a = [ "a", "b", "b", "b", "c" ]
|
|
|
|
* a.delete("b") #=> "b"
|
|
|
|
* a #=> ["a", "c"]
|
|
|
|
* a.delete("z") #=> nil
|
2018-07-11 12:56:49 +03:00
|
|
|
* a.delete("z") {"not found"} #=> "not found"
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_delete(VALUE ary, VALUE item)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2008-08-12 13:12:24 +04:00
|
|
|
VALUE v = item;
|
1999-08-13 09:45:20 +04:00
|
|
|
long i1, i2;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2006-09-02 18:42:08 +04:00
|
|
|
for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
VALUE e = RARRAY_AREF(ary, i1);
|
2004-09-21 07:08:33 +04:00
|
|
|
|
2008-08-12 13:12:24 +04:00
|
|
|
if (rb_equal(e, item)) {
|
|
|
|
v = e;
|
|
|
|
continue;
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
if (i1 != i2) {
|
2004-09-29 09:15:33 +04:00
|
|
|
rb_ary_store(ary, i2, e);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
i2++;
|
|
|
|
}
|
2006-09-02 18:42:08 +04:00
|
|
|
if (RARRAY_LEN(ary) == i2) {
|
2000-05-24 08:34:26 +04:00
|
|
|
if (rb_block_given_p()) {
|
1999-01-20 07:59:39 +03:00
|
|
|
return rb_yield(item);
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
return Qnil;
|
|
|
|
}
|
2002-05-21 09:39:19 +04:00
|
|
|
|
2012-11-25 17:39:26 +04:00
|
|
|
ary_resize_smaller(ary, i2);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2008-08-12 13:12:24 +04:00
|
|
|
return v;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2012-11-25 17:39:26 +04:00
|
|
|
void
|
|
|
|
rb_ary_delete_same(VALUE ary, VALUE item)
|
2012-11-24 16:26:54 +04:00
|
|
|
{
|
|
|
|
long i1, i2;
|
|
|
|
|
|
|
|
for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
VALUE e = RARRAY_AREF(ary, i1);
|
2012-11-24 16:26:54 +04:00
|
|
|
|
|
|
|
if (e == item) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (i1 != i2) {
|
|
|
|
rb_ary_store(ary, i2, e);
|
|
|
|
}
|
|
|
|
i2++;
|
|
|
|
}
|
|
|
|
if (RARRAY_LEN(ary) == i2) {
|
2012-11-25 17:39:26 +04:00
|
|
|
return;
|
2012-11-24 16:26:54 +04:00
|
|
|
}
|
|
|
|
|
2012-11-25 17:39:26 +04:00
|
|
|
ary_resize_smaller(ary, i2);
|
2012-11-24 16:26:54 +04:00
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_delete_at(VALUE ary, long pos)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
* this commit is a result of refactoring. only renaming functions,
moving definitions place, add/remove prototypes, deleting
unused variables and removing yarv.h.
This commit doesn't change any behavior of ruby/vm.
* yarv.h, common.mk: remove yarv.h (contents are moved to yarvcore.h).
* error.c, eval_intern.h: include yarvcore.h instead yarv.h
* rename some functions:
* debug.[ch]: debug_*() -> ruby_debug_*()
* iseq.c: iseq_*() -> rb_iseq_*(), ruby_iseq_disasm()
* iseq.c: node_name() -> ruby_node_name()
* vm.c: yarv_check_redefinition_opt_method() ->
rb_vm_check_redefinition_opt_method()
* some refactoring with checking -Wall.
* array.c: remove rb_ary_ptr() (unused) and remove unused
local variables.
* object.c: add a prototype of rb_mod_module_exec().
* eval_intern.h (ruby_cref): set it inline.
* eval_load.c (rb_load), yarvcore.c: yarv_load() -> rb_load_internal().
* parse.y: add a prototype of rb_parse_in_eval() (in eval.c).
* process.c: add a prototype of rb_thread_stop_timer_thread() (in thread.c).
* thread.c: remove raw_gets() function (unused) and fix some format
mismatch (format mismatchs have remained yet. this is todo).
* thread.c (rb_thread_wait_fd_rw): fix typo on label name.
* thread_pthread.ci: comment out codes with USE_THREAD_CACHE.
* vm.c (rb_svar, rb_backref_get, rb_backref_get,
rb_lastline_get, rb_lastline_set) : moved from yarvcore.c.
* vm.c (yarv_init_redefined_flag): add a prototype and rename
yarv_opt_method_table to vm_opt_method_table.
* vm.c (rb_thread_eval): moved from yarvcore.c.
* yarvcore.c: remove unused global variables and fix to use nsdr().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11652 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-07 04:25:05 +03:00
|
|
|
long len = RARRAY_LEN(ary);
|
2002-05-21 09:39:19 +04:00
|
|
|
VALUE del;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-10-13 10:44:42 +04:00
|
|
|
if (pos >= len) return Qnil;
|
2002-05-21 09:39:19 +04:00
|
|
|
if (pos < 0) {
|
|
|
|
pos += len;
|
|
|
|
if (pos < 0) return Qnil;
|
|
|
|
}
|
1999-10-13 10:44:42 +04:00
|
|
|
|
2004-11-18 06:45:23 +03:00
|
|
|
rb_ary_modify(ary);
|
2013-05-13 13:56:22 +04:00
|
|
|
del = RARRAY_AREF(ary, pos);
|
2018-12-03 15:36:39 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
|
|
|
|
MEMMOVE(ptr+pos, ptr+pos+1, VALUE, len-pos-1);
|
2013-07-19 16:56:58 +04:00
|
|
|
});
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_INCREASE_LEN(ary, -1);
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
1998-01-16 15:13:05 +03:00
|
|
|
return del;
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary.delete_at(index) -> obj or nil
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Deletes the element at the specified +index+, returning that element, or
|
|
|
|
* +nil+ if the +index+ is out of range.
|
|
|
|
*
|
|
|
|
* See also Array#slice!
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-07-21 12:31:44 +04:00
|
|
|
* a = ["ant", "bat", "cat", "dog"]
|
2003-12-16 23:28:44 +03:00
|
|
|
* a.delete_at(2) #=> "cat"
|
|
|
|
* a #=> ["ant", "bat", "dog"]
|
|
|
|
* a.delete_at(99) #=> nil
|
|
|
|
*/
|
|
|
|
|
2001-03-13 08:45:13 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_delete_at_m(VALUE ary, VALUE pos)
|
2000-05-30 08:24:17 +04:00
|
|
|
{
|
|
|
|
return rb_ary_delete_at(ary, NUM2LONG(pos));
|
|
|
|
}
|
|
|
|
|
2020-06-11 05:45:03 +03:00
|
|
|
static VALUE
|
|
|
|
ary_slice_bang_by_rb_ary_splice(VALUE ary, long pos, long len)
|
|
|
|
{
|
|
|
|
const long orig_len = RARRAY_LEN(ary);
|
|
|
|
|
|
|
|
if (len < 0) {
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
else if (pos < -orig_len) {
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
else if (pos < 0) {
|
|
|
|
pos += orig_len;
|
|
|
|
}
|
|
|
|
else if (orig_len < pos) {
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
else if (orig_len < pos + len) {
|
|
|
|
len = orig_len - pos;
|
|
|
|
}
|
|
|
|
if (len == 0) {
|
|
|
|
return rb_ary_new2(0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VALUE arg2 = rb_ary_new4(len, RARRAY_CONST_PTR_TRANSIENT(ary)+pos);
|
|
|
|
RBASIC_SET_CLASS(arg2, rb_obj_class(ary));
|
|
|
|
rb_ary_splice(ary, pos, len, 0, 0);
|
|
|
|
return arg2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary.slice!(index) -> obj or nil
|
|
|
|
* ary.slice!(start, length) -> new_ary or nil
|
|
|
|
* ary.slice!(range) -> new_ary or nil
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Deletes the element(s) given by an +index+ (optionally up to +length+
|
|
|
|
* elements) or by a +range+.
|
|
|
|
*
|
|
|
|
* Returns the deleted object (or objects), or +nil+ if the +index+ is out of
|
|
|
|
* range.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* a = [ "a", "b", "c" ]
|
|
|
|
* a.slice!(1) #=> "b"
|
|
|
|
* a #=> ["a", "c"]
|
|
|
|
* a.slice!(-1) #=> "c"
|
|
|
|
* a #=> ["a"]
|
|
|
|
* a.slice!(100) #=> nil
|
|
|
|
* a #=> ["a"]
|
|
|
|
*/
|
|
|
|
|
2000-01-05 07:41:21 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_slice_bang(int argc, VALUE *argv, VALUE ary)
|
2000-01-05 07:41:21 +03:00
|
|
|
{
|
2020-06-11 05:45:03 +03:00
|
|
|
VALUE arg1;
|
|
|
|
long pos, len;
|
2000-01-05 07:41:21 +03:00
|
|
|
|
2008-05-28 11:52:34 +04:00
|
|
|
rb_ary_modify_check(ary);
|
2020-06-11 05:45:03 +03:00
|
|
|
rb_check_arity(argc, 1, 2);
|
|
|
|
arg1 = argv[0];
|
|
|
|
|
2009-05-22 02:35:43 +04:00
|
|
|
if (argc == 2) {
|
|
|
|
pos = NUM2LONG(argv[0]);
|
|
|
|
len = NUM2LONG(argv[1]);
|
2020-06-11 05:45:03 +03:00
|
|
|
return ary_slice_bang_by_rb_ary_splice(ary, pos, len);
|
2000-01-05 07:41:21 +03:00
|
|
|
}
|
|
|
|
|
2007-12-10 16:25:39 +03:00
|
|
|
if (!FIXNUM_P(arg1)) {
|
|
|
|
switch (rb_range_beg_len(arg1, &pos, &len, RARRAY_LEN(ary), 0)) {
|
|
|
|
case Qtrue:
|
|
|
|
/* valid range */
|
2020-06-11 05:45:03 +03:00
|
|
|
return ary_slice_bang_by_rb_ary_splice(ary, pos, len);
|
2007-12-10 16:25:39 +03:00
|
|
|
case Qnil:
|
|
|
|
/* invalid range */
|
|
|
|
return Qnil;
|
|
|
|
default:
|
|
|
|
/* not a range */
|
|
|
|
break;
|
|
|
|
}
|
2000-01-05 07:41:21 +03:00
|
|
|
}
|
|
|
|
|
2002-05-22 09:57:08 +04:00
|
|
|
return rb_ary_delete_at(ary, NUM2LONG(arg1));
|
2000-01-05 07:41:21 +03:00
|
|
|
}
|
2000-02-01 06:12:21 +03:00
|
|
|
|
2011-07-02 02:17:46 +04:00
|
|
|
static VALUE
|
|
|
|
ary_reject(VALUE orig, VALUE result)
|
|
|
|
{
|
|
|
|
long i;
|
|
|
|
|
|
|
|
for (i = 0; i < RARRAY_LEN(orig); i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
VALUE v = RARRAY_AREF(orig, i);
|
2018-10-31 00:53:56 +03:00
|
|
|
|
2018-10-31 00:02:12 +03:00
|
|
|
if (!RTEST(rb_yield(v))) {
|
2014-04-11 07:44:52 +04:00
|
|
|
rb_ary_push(result, v);
|
2011-07-02 02:17:46 +04:00
|
|
|
}
|
|
|
|
}
|
2011-07-03 08:44:53 +04:00
|
|
|
return result;
|
2011-07-02 02:17:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2015-01-15 04:44:57 +03:00
|
|
|
reject_bang_i(VALUE a)
|
2011-07-02 02:17:46 +04:00
|
|
|
{
|
2015-01-15 04:44:57 +03:00
|
|
|
volatile struct select_bang_arg *arg = (void *)a;
|
|
|
|
VALUE ary = arg->ary;
|
|
|
|
long i1, i2;
|
2011-07-02 02:17:46 +04:00
|
|
|
|
2015-01-15 04:44:57 +03:00
|
|
|
for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); arg->len[0] = ++i1) {
|
|
|
|
VALUE v = RARRAY_AREF(ary, i1);
|
|
|
|
if (RTEST(rb_yield(v))) continue;
|
|
|
|
if (i1 != i2) {
|
|
|
|
rb_ary_store(ary, i2, v);
|
2011-07-03 08:44:53 +04:00
|
|
|
}
|
2015-01-15 04:44:57 +03:00
|
|
|
arg->len[1] = ++i2;
|
2011-07-02 02:17:46 +04:00
|
|
|
}
|
2015-01-15 04:44:57 +03:00
|
|
|
return (i1 == i2) ? Qnil : ary;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
ary_reject_bang(VALUE ary)
|
|
|
|
{
|
|
|
|
struct select_bang_arg args;
|
|
|
|
rb_ary_modify_check(ary);
|
|
|
|
args.ary = ary;
|
|
|
|
args.len[0] = args.len[1] = 0;
|
|
|
|
return rb_ensure(reject_bang_i, (VALUE)&args, select_bang_ensure, (VALUE)&args);
|
2011-07-02 02:17:46 +04:00
|
|
|
}
|
|
|
|
|
2008-01-24 09:18:18 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.reject! {|item| block} -> ary or nil
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.reject! -> Enumerator
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2015-11-06 17:01:30 +03:00
|
|
|
* Deletes every element of +self+ for which the block evaluates to +true+,
|
|
|
|
* if no changes were made returns +nil+.
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2015-01-15 04:44:57 +03:00
|
|
|
* The array may not be changed instantly every time the block is called.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
|
|
|
* See also Enumerable#reject and Array#delete_if.
|
|
|
|
*
|
|
|
|
* If no block is given, an Enumerator is returned instead.
|
2008-01-24 09:18:18 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2008-01-24 09:18:18 +03:00
|
|
|
rb_ary_reject_bang(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2013-06-26 17:43:22 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
|
2019-01-08 22:22:05 +03:00
|
|
|
rb_ary_modify(ary);
|
2011-07-02 02:17:46 +04:00
|
|
|
return ary_reject_bang(ary);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.reject {|item| block } -> new_ary
|
|
|
|
* ary.reject -> Enumerator
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Returns a new array containing the items in +self+ for which the given
|
2015-01-04 06:45:24 +03:00
|
|
|
* block is not +true+. The ordering of non-rejected elements is maintained.
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* See also Array#delete_if
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* If no block is given, an Enumerator is returned instead.
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2001-10-16 07:27:23 +04:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_reject(VALUE ary)
|
2001-10-16 07:27:23 +04:00
|
|
|
{
|
2011-07-02 02:17:46 +04:00
|
|
|
VALUE rejected_ary;
|
|
|
|
|
2013-06-26 17:43:22 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
|
2011-07-02 02:17:46 +04:00
|
|
|
rejected_ary = rb_ary_new();
|
|
|
|
ary_reject(ary, rejected_ary);
|
|
|
|
return rejected_ary;
|
2001-10-16 07:27:23 +04:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.delete_if {|item| block} -> ary
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.delete_if -> Enumerator
|
|
|
|
*
|
|
|
|
* Deletes every element of +self+ for which block evaluates to +true+.
|
|
|
|
*
|
|
|
|
* The array is changed instantly every time the block is called, not after
|
|
|
|
* the iteration is over.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-10-07 01:36:17 +04:00
|
|
|
* See also Array#reject!
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* If no block is given, an Enumerator is returned instead.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2013-04-22 13:35:27 +04:00
|
|
|
* scores = [ 97, 42, 75 ]
|
|
|
|
* scores.delete_if {|score| score < 80 } #=> [97]
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2000-08-07 09:05:04 +04:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_delete_if(VALUE ary)
|
2000-08-07 09:05:04 +04:00
|
|
|
{
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2013-06-26 17:43:22 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
|
2011-07-02 02:17:46 +04:00
|
|
|
ary_reject_bang(ary);
|
2000-08-07 09:05:04 +04:00
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2008-01-08 12:50:01 +03:00
|
|
|
static VALUE
|
2013-11-29 11:59:14 +04:00
|
|
|
take_i(RB_BLOCK_CALL_FUNC_ARGLIST(val, cbarg))
|
2008-01-08 12:50:01 +03:00
|
|
|
{
|
2013-11-29 11:45:00 +04:00
|
|
|
VALUE *args = (VALUE *)cbarg;
|
2018-11-19 09:48:09 +03:00
|
|
|
if (args[1] == 0) rb_iter_break();
|
|
|
|
else args[1]--;
|
2013-03-23 12:39:55 +04:00
|
|
|
if (argc > 1) val = rb_ary_new4(argc, argv);
|
|
|
|
rb_ary_push(args[0], val);
|
2008-01-08 12:50:01 +03:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
take_items(VALUE obj, long n)
|
|
|
|
{
|
2009-01-21 08:43:04 +03:00
|
|
|
VALUE result = rb_check_array_type(obj);
|
2013-03-23 12:39:55 +04:00
|
|
|
VALUE args[2];
|
2008-01-08 12:50:01 +03:00
|
|
|
|
2009-01-20 00:47:48 +03:00
|
|
|
if (!NIL_P(result)) return rb_ary_subseq(result, 0, n);
|
|
|
|
result = rb_ary_new2(n);
|
2013-03-23 12:39:55 +04:00
|
|
|
args[0] = result; args[1] = (VALUE)n;
|
|
|
|
if (rb_check_block_call(obj, idEach, 0, 0, take_i, (VALUE)args) == Qundef)
|
2013-03-23 12:45:32 +04:00
|
|
|
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (must respond to :each)",
|
|
|
|
rb_obj_class(obj));
|
2008-01-08 12:50:01 +03:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-03-23 12:39:55 +04:00
|
|
|
|
2008-01-08 12:50:01 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.zip(arg, ...) -> new_ary
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.zip(arg, ...) {|arr| block} -> nil
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
|
|
|
* Converts any arguments to arrays, then merges elements of +self+ with
|
|
|
|
* corresponding elements from each argument.
|
|
|
|
*
|
|
|
|
* This generates a sequence of <code>ary.size</code> _n_-element arrays,
|
2013-06-23 21:46:50 +04:00
|
|
|
* where _n_ is one more than the count of arguments.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
|
|
|
* If the size of any argument is less than the size of the initial array,
|
|
|
|
* +nil+ values are supplied.
|
|
|
|
*
|
|
|
|
* If a block is given, it is invoked for each output +array+, otherwise an
|
|
|
|
* array of arrays is returned.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2008-01-08 12:50:01 +03:00
|
|
|
* a = [ 4, 5, 6 ]
|
|
|
|
* b = [ 7, 8, 9 ]
|
2012-06-01 03:51:33 +04:00
|
|
|
* [1, 2, 3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
|
|
|
|
* [1, 2].zip(a, b) #=> [[1, 4, 7], [2, 5, 8]]
|
|
|
|
* a.zip([1, 2], [8]) #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
|
2008-01-08 12:50:01 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2008-06-11 21:43:52 +04:00
|
|
|
rb_ary_zip(int argc, VALUE *argv, VALUE ary)
|
2008-01-08 12:50:01 +03:00
|
|
|
{
|
2013-10-29 18:08:48 +04:00
|
|
|
int i, j;
|
|
|
|
long len = RARRAY_LEN(ary);
|
2008-01-08 12:50:01 +03:00
|
|
|
VALUE result = Qnil;
|
|
|
|
|
|
|
|
for (i=0; i<argc; i++) {
|
|
|
|
argv[i] = take_items(argv[i], len);
|
|
|
|
}
|
2013-08-02 18:56:39 +04:00
|
|
|
|
2013-10-29 18:08:48 +04:00
|
|
|
if (rb_block_given_p()) {
|
|
|
|
int arity = rb_block_arity();
|
2008-01-08 12:50:01 +03:00
|
|
|
|
2014-01-01 19:55:51 +04:00
|
|
|
if (arity > 1) {
|
|
|
|
VALUE work, *tmp;
|
|
|
|
|
|
|
|
tmp = ALLOCV_N(VALUE, work, argc+1);
|
2008-01-08 12:50:01 +03:00
|
|
|
|
2013-10-29 18:08:48 +04:00
|
|
|
for (i=0; i<RARRAY_LEN(ary); i++) {
|
|
|
|
tmp[0] = RARRAY_AREF(ary, i);
|
|
|
|
for (j=0; j<argc; j++) {
|
|
|
|
tmp[j+1] = rb_ary_elt(argv[j], i);
|
|
|
|
}
|
|
|
|
rb_yield_values2(argc+1, tmp);
|
|
|
|
}
|
2014-01-01 19:55:51 +04:00
|
|
|
|
|
|
|
if (work) ALLOCV_END(work);
|
2013-10-29 18:08:48 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (i=0; i<RARRAY_LEN(ary); i++) {
|
|
|
|
VALUE tmp = rb_ary_new2(argc+1);
|
|
|
|
|
|
|
|
rb_ary_push(tmp, RARRAY_AREF(ary, i));
|
|
|
|
for (j=0; j<argc; j++) {
|
|
|
|
rb_ary_push(tmp, rb_ary_elt(argv[j], i));
|
|
|
|
}
|
|
|
|
rb_yield(tmp);
|
2013-08-02 18:56:39 +04:00
|
|
|
}
|
2008-01-08 12:50:01 +03:00
|
|
|
}
|
2013-08-02 18:56:39 +04:00
|
|
|
}
|
|
|
|
else {
|
2013-10-29 18:08:48 +04:00
|
|
|
result = rb_ary_new_capa(len);
|
|
|
|
|
|
|
|
for (i=0; i<len; i++) {
|
|
|
|
VALUE tmp = rb_ary_new_capa(argc+1);
|
2013-08-02 18:56:39 +04:00
|
|
|
|
|
|
|
rb_ary_push(tmp, RARRAY_AREF(ary, i));
|
|
|
|
for (j=0; j<argc; j++) {
|
|
|
|
rb_ary_push(tmp, rb_ary_elt(argv[j], i));
|
|
|
|
}
|
2013-10-29 18:08:48 +04:00
|
|
|
rb_ary_push(result, tmp);
|
2008-01-08 12:50:01 +03:00
|
|
|
}
|
|
|
|
}
|
2013-08-02 18:56:39 +04:00
|
|
|
|
2008-01-08 12:50:01 +03:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary.transpose -> new_ary
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Assumes that +self+ is an array of arrays and transposes the rows and
|
|
|
|
* columns.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* a = [[1,2], [3,4], [5,6]]
|
|
|
|
* a.transpose #=> [[1, 3, 5], [2, 4, 6]]
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
|
|
|
* If the length of the subarrays don't match, an IndexError is raised.
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2002-11-19 11:07:51 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_transpose(VALUE ary)
|
2002-11-19 11:07:51 +03:00
|
|
|
{
|
|
|
|
long elen = -1, alen, i, j;
|
2003-07-24 22:33:50 +04:00
|
|
|
VALUE tmp, result = 0;
|
2002-11-19 11:07:51 +03:00
|
|
|
|
2006-09-02 18:42:08 +04:00
|
|
|
alen = RARRAY_LEN(ary);
|
2002-11-19 11:07:51 +03:00
|
|
|
if (alen == 0) return rb_ary_dup(ary);
|
|
|
|
for (i=0; i<alen; i++) {
|
2004-09-21 07:08:33 +04:00
|
|
|
tmp = to_ary(rb_ary_elt(ary, i));
|
2002-11-19 11:07:51 +03:00
|
|
|
if (elen < 0) { /* first element */
|
2006-09-02 18:42:08 +04:00
|
|
|
elen = RARRAY_LEN(tmp);
|
2002-11-19 11:07:51 +03:00
|
|
|
result = rb_ary_new2(elen);
|
|
|
|
for (j=0; j<elen; j++) {
|
|
|
|
rb_ary_store(result, j, rb_ary_new2(alen));
|
|
|
|
}
|
|
|
|
}
|
2006-09-02 18:42:08 +04:00
|
|
|
else if (elen != RARRAY_LEN(tmp)) {
|
2005-09-24 04:17:43 +04:00
|
|
|
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
|
2006-09-02 18:42:08 +04:00
|
|
|
RARRAY_LEN(tmp), elen);
|
2002-11-19 11:07:51 +03:00
|
|
|
}
|
|
|
|
for (j=0; j<elen; j++) {
|
2004-09-21 07:08:33 +04:00
|
|
|
rb_ary_store(rb_ary_elt(result, j), i, rb_ary_elt(tmp, j));
|
2002-11-19 11:07:51 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary.replace(other_ary) -> ary
|
2013-04-24 07:28:06 +04:00
|
|
|
* ary.initialize_copy(other_ary) -> ary
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Replaces the contents of +self+ with the contents of +other_ary+,
|
|
|
|
* truncating or expanding if necessary.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* a = [ "a", "b", "c", "d", "e" ]
|
|
|
|
* a.replace([ "x", "y", "z" ]) #=> ["x", "y", "z"]
|
|
|
|
* a #=> ["x", "y", "z"]
|
|
|
|
*/
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_replace(VALUE copy, VALUE orig)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2007-01-09 18:11:01 +03:00
|
|
|
rb_ary_modify_check(copy);
|
2010-02-10 10:31:06 +03:00
|
|
|
orig = to_ary(orig);
|
2002-09-03 09:20:14 +04:00
|
|
|
if (copy == orig) return copy;
|
|
|
|
|
2008-10-09 09:47:04 +04:00
|
|
|
if (RARRAY_LEN(orig) <= RARRAY_EMBED_LEN_MAX) {
|
2019-07-19 07:02:38 +03:00
|
|
|
VALUE shared_root = 0;
|
2009-02-22 17:23:33 +03:00
|
|
|
|
2008-10-17 17:09:33 +04:00
|
|
|
if (ARY_OWNS_HEAP_P(copy)) {
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_heap_free(copy);
|
2013-07-19 16:56:58 +04:00
|
|
|
}
|
2008-10-17 17:09:33 +04:00
|
|
|
else if (ARY_SHARED_P(copy)) {
|
2019-07-19 07:02:38 +03:00
|
|
|
shared_root = ARY_SHARED_ROOT(copy);
|
2008-10-17 17:09:33 +04:00
|
|
|
FL_UNSET_SHARED(copy);
|
|
|
|
}
|
2008-10-09 09:47:04 +04:00
|
|
|
FL_SET_EMBED(copy);
|
2018-10-31 00:54:13 +03:00
|
|
|
ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR_TRANSIENT(orig));
|
2019-07-19 07:02:38 +03:00
|
|
|
if (shared_root) {
|
|
|
|
rb_ary_decrement_share(shared_root);
|
2008-10-17 17:09:33 +04:00
|
|
|
}
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(copy, RARRAY_LEN(orig));
|
|
|
|
}
|
|
|
|
else {
|
2019-07-19 07:02:38 +03:00
|
|
|
VALUE shared_root = ary_make_shared(orig);
|
2008-10-09 09:47:04 +04:00
|
|
|
if (ARY_OWNS_HEAP_P(copy)) {
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_heap_free(copy);
|
2009-02-11 09:47:12 +03:00
|
|
|
}
|
|
|
|
else {
|
2008-10-17 17:09:33 +04:00
|
|
|
rb_ary_unshare_safe(copy);
|
2008-10-09 09:47:04 +04:00
|
|
|
}
|
|
|
|
FL_UNSET_EMBED(copy);
|
2018-10-31 00:53:56 +03:00
|
|
|
ARY_SET_PTR(copy, ARY_HEAP_PTR(orig));
|
|
|
|
ARY_SET_LEN(copy, ARY_HEAP_LEN(orig));
|
2019-07-19 07:02:38 +03:00
|
|
|
rb_ary_set_shared(copy, shared_root);
|
2008-10-09 09:47:04 +04:00
|
|
|
}
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(copy);
|
2002-09-03 09:20:14 +04:00
|
|
|
return copy;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 19:34:34 +04:00
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary.clear -> ary
|
2004-07-13 19:34:34 +04:00
|
|
|
*
|
2010-05-13 09:49:55 +04:00
|
|
|
* Removes all elements from +self+.
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
|
|
|
* a = [ "a", "b", "c", "d", "e" ]
|
|
|
|
* a.clear #=> [ ]
|
|
|
|
*/
|
|
|
|
|
2001-03-13 08:45:13 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_clear(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2010-07-18 16:20:14 +04:00
|
|
|
rb_ary_modify_check(ary);
|
|
|
|
if (ARY_SHARED_P(ary)) {
|
2010-07-19 07:33:33 +04:00
|
|
|
if (!ARY_EMBED_P(ary)) {
|
|
|
|
rb_ary_unshare(ary);
|
|
|
|
FL_SET_EMBED(ary);
|
2018-10-31 00:53:56 +03:00
|
|
|
ARY_SET_EMBED_LEN(ary, 0);
|
2010-07-19 07:33:33 +04:00
|
|
|
}
|
2010-07-18 16:20:14 +04:00
|
|
|
}
|
2018-10-31 00:53:56 +03:00
|
|
|
else {
|
|
|
|
ARY_SET_LEN(ary, 0);
|
|
|
|
if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) {
|
|
|
|
ary_resize_capa(ary, ARY_DEFAULT_SIZE * 2);
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
1998-01-16 15:19:22 +03:00
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.fill(obj) -> ary
|
|
|
|
* ary.fill(obj, start [, length]) -> ary
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.fill(obj, range) -> ary
|
|
|
|
* ary.fill {|index| block} -> ary
|
|
|
|
* ary.fill(start [, length]) {|index| block} -> ary
|
|
|
|
* ary.fill(range) {|index| block} -> ary
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
|
|
|
* The first three forms set the selected elements of +self+ (which
|
2012-06-01 03:51:33 +04:00
|
|
|
* may be the entire array) to +obj+.
|
|
|
|
*
|
|
|
|
* A +start+ of +nil+ is equivalent to zero.
|
|
|
|
*
|
|
|
|
* A +length+ of +nil+ is equivalent to the length of the array.
|
|
|
|
*
|
|
|
|
* The last three forms fill the array with the value of the given block,
|
|
|
|
* which is passed the absolute index of each element to be filled.
|
|
|
|
*
|
|
|
|
* Negative values of +start+ count from the end of the array, where +-1+ is
|
|
|
|
* the last element.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* a = [ "a", "b", "c", "d" ]
|
|
|
|
* a.fill("x") #=> ["x", "x", "x", "x"]
|
|
|
|
* a.fill("z", 2, 2) #=> ["x", "x", "z", "z"]
|
|
|
|
* a.fill("y", 0..1) #=> ["y", "y", "z", "z"]
|
2018-07-11 12:56:49 +03:00
|
|
|
* a.fill {|i| i*i} #=> [0, 1, 4, 9]
|
|
|
|
* a.fill(-2) {|i| i*i*i} #=> [0, 1, 8, 27]
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_fill(int argc, VALUE *argv, VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2016-05-23 06:23:24 +03:00
|
|
|
VALUE item = Qundef, arg1, arg2;
|
* sprintf.c (rb_str_format): allow %c to print one character
string (e.g. ?x).
* lib/tempfile.rb (Tempfile::make_tmpname): put dot between
basename and pid. [ruby-talk:196272]
* parse.y (do_block): remove -> style block.
* parse.y (parser_yylex): remove tLAMBDA_ARG.
* eval.c (rb_call0): binding for the return event hook should have
consistent scope. [ruby-core:07928]
* eval.c (proc_invoke): return behavior should depend whether it
is surrounded by a lambda or a mere block.
* eval.c (formal_assign): handles post splat arguments.
* eval.c (rb_call0): ditto.
* st.c (strhash): use FNV-1a hash.
* parse.y (parser_yylex): removed experimental ';;' terminator.
* eval.c (rb_node_arity): should be aware of post splat arguments.
* eval.c (rb_proc_arity): ditto.
* parse.y (f_args): syntax rule enhanced to support arguments
after the splat.
* parse.y (block_param): ditto for block parameters.
* parse.y (f_post_arg): mandatory formal arguments after the splat
argument.
* parse.y (new_args_gen): generate nodes for mandatory formal
arguments after the splat argument.
* eval.c (rb_eval): dispatch mandatory formal arguments after the
splat argument.
* parse.y (args): allow more than one splat in the argument list.
* parse.y (method_call): allow aref [] to accept all kind of
method argument, including assocs, splat, and block argument.
* eval.c (SETUP_ARGS0): prepare block argument as well.
* lib/mathn.rb (Integer): remove Integer#gcd2. [ruby-core:07931]
* eval.c (error_line): print receivers true/false/nil specially.
* eval.c (rb_proc_yield): handles parameters in yield semantics.
* eval.c (nil_yield): gives LocalJumpError to denote no block
error.
* io.c (rb_io_getc): now takes one-character string.
* string.c (rb_str_hash): use FNV-1a hash from Fowler/Noll/Vo
hashing algorithm.
* string.c (rb_str_aref): str[0] now returns 1 character string,
instead of a fixnum. [Ruby2]
* parse.y (parser_yylex): ?c now returns 1 character string,
instead of a fixnum. [Ruby2]
* string.c (rb_str_aset): no longer support fixnum insertion.
* eval.c (umethod_bind): should not update original class.
[ruby-dev:28636]
* eval.c (ev_const_get): should support constant access from
within instance_eval(). [ruby-dev:28327]
* time.c (time_timeval): should round for usec floating
number. [ruby-core:07896]
* time.c (time_add): ditto.
* dir.c (sys_warning): should not call a vararg function
rb_sys_warning() indirectly. [ruby-core:07886]
* numeric.c (flo_divmod): the first element of Float#divmod should
be an integer. [ruby-dev:28589]
* test/ruby/test_float.rb: add tests for divmod, div, modulo and remainder.
* re.c (rb_reg_initialize): should not allow modifying literal
regexps. frozen check moved from rb_reg_initialize_m as well.
* re.c (rb_reg_initialize): should not modify untainted objects in
safe levels higher than 3.
* re.c (rb_memcmp): type change from char* to const void*.
* dir.c (dir_close): should not close untainted dir stream.
* dir.c (GetDIR): add tainted/frozen check for each dir operation.
* lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_symbol_arg):
typo fixed. a patch from Florian Gross <florg at florg.net>.
* eval.c (EXEC_EVENT_HOOK): trace_func may remove itself from
event_hooks. no guarantee for arbitrary hook deletion.
[ruby-dev:28632]
* util.c (ruby_strtod): differ addition to minimize error.
[ruby-dev:28619]
* util.c (ruby_strtod): should not raise ERANGE when the input
string does not have any digits. [ruby-dev:28629]
* eval.c (proc_invoke): should restore old ruby_frame->block.
thanks to ts <decoux at moulon.inra.fr>. [ruby-core:07833]
also fix [ruby-dev:28614] as well.
* signal.c (trap): sig should be less then NSIG. Coverity found
this bug. a patch from Kevin Tew <tewk at tewk.com>.
[ruby-core:07823]
* math.c (math_log2): add new method inspired by
[ruby-talk:191237].
* math.c (math_log): add optional base argument to Math::log().
[ruby-talk:191308]
* ext/syck/emitter.c (syck_scan_scalar): avoid accessing
uninitialized array element. a patch from Pat Eyler
<rubypate at gmail.com>. [ruby-core:07809]
* array.c (rb_ary_fill): initialize local variables first. a
patch from Pat Eyler <rubypate at gmail.com>. [ruby-core:07810]
* ext/syck/yaml2byte.c (syck_yaml2byte_handler): need to free
type_tag. a patch from Pat Eyler <rubypate at gmail.com>.
[ruby-core:07808]
* ext/socket/socket.c (make_hostent_internal): accept ai_family
check from Sam Roberts <sroberts at uniserve.com>.
[ruby-core:07691]
* util.c (ruby_strtod): should not cut off 18 digits for no
reason. [ruby-core:07796]
* array.c (rb_ary_fill): internalize local variable "beg" to
pacify Coverity. [ruby-core:07770]
* pack.c (pack_unpack): now supports CRLF newlines. a patch from
<tommy at tmtm.org>. [ruby-dev:28601]
* applied code clean-up patch from Stefan Huehner
<stefan at huehner.org>. [ruby-core:07764]
* lib/jcode.rb (String::tr_s): should have translated non
squeezing character sequence (i.e. a character) as well. thanks
to Hiroshi Ichikawa <gimite at gimite.ddo.jp> [ruby-list:42090]
* ext/socket/socket.c: document update patch from Sam Roberts
<sroberts at uniserve.com>. [ruby-core:07701]
* lib/mathn.rb (Integer): need not to remove gcd2. a patch from
NARUSE, Yui <naruse at airemix.com>. [ruby-dev:28570]
* parse.y (arg): too much NEW_LIST()
* eval.c (SETUP_ARGS0): remove unnecessary access to nd_alen.
* eval.c (rb_eval): use ARGSCAT for NODE_OP_ASGN1.
[ruby-dev:28585]
* parse.y (arg): use NODE_ARGSCAT for placeholder.
* lib/getoptlong.rb (GetoptLong::get): RDoc update patch from
mathew <meta at pobox.com>. [ruby-core:07738]
* variable.c (rb_const_set): raise error when no target klass is
supplied. [ruby-dev:28582]
* prec.c (prec_prec_f): documentation patch from
<gerardo.santana at gmail.com>. [ruby-core:07689]
* bignum.c (rb_big_pow): second operand may be too big even if
it's a Fixnum. [ruby-talk:187984]
* README.EXT: update symbol description. [ruby-talk:188104]
* COPYING: explicitly note GPLv2. [ruby-talk:187922]
* parse.y: remove some obsolete syntax rules (unparenthesized
method calls in argument list).
* eval.c (rb_call0): insecure calling should be checked for non
NODE_SCOPE method invocations too.
* eval.c (rb_alias): should preserve the current safe level as
well as method definition.
* process.c (rb_f_sleep): remove RDoc description about SIGALRM
which is not valid on the current implementation. [ruby-dev:28464]
Thu Mar 23 21:40:47 2006 K.Kosako <sndgk393 AT ybb.ne.jp>
* eval.c (method_missing): should support argument splat in
super. a bug in combination of super, splat and
method_missing. [ruby-talk:185438]
* configure.in: Solaris SunPro compiler -rapth patch from
<kuwa at labs.fujitsu.com>. [ruby-dev:28443]
* configure.in: remove enable_rpath=no for Solaris.
[ruby-dev:28440]
* ext/win32ole/win32ole.c (ole_val2olevariantdata): change behavior
of converting OLE Variant object with VT_ARRAY|VT_UI1 and Ruby
String object.
* ruby.1: a clarification patch from David Lutterkort
<dlutter at redhat.com>. [ruby-core:7508]
* lib/rdoc/ri/ri_paths.rb (RI::Paths): adding paths from rubygems
directories. a patch from Eric Hodel <drbrain at segment7.net>.
[ruby-core:07423]
* eval.c (rb_clear_cache_by_class): clearing wrong cache.
* ext/extmk.rb: use :remove_destination to install extension libraries
to avoid SEGV. [ruby-dev:28417]
* eval.c (rb_thread_fd_writable): should not re-schedule output
from KILLED thread (must be error printing).
* array.c (rb_ary_flatten_bang): allow specifying recursion
level. [ruby-talk:182170]
* array.c (rb_ary_flatten): ditto.
* gc.c (add_heap): a heap_slots may overflow. a patch from Stefan
Weil <weil at mail.berlios.de>.
* eval.c (rb_call): use separate cache for fcall/vcall
invocation.
* eval.c (rb_eval): NODE_FCALL, NODE_VCALL can call local
functions.
* eval.c (rb_mod_local): a new method to specify newly added
visibility "local".
* eval.c (search_method): search for local methods which are
visible only from the current class.
* class.c (rb_class_local_methods): a method to list local methods.
* object.c (Init_Object): add BasicObject class as a top level
BlankSlate class.
* ruby.h (SYM2ID): should not cast to signed long.
[ruby-core:07414]
* class.c (rb_include_module): allow module duplication.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10235 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2006-06-10 01:20:17 +04:00
|
|
|
long beg = 0, end = 0, len = 0;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2002-01-28 11:44:45 +03:00
|
|
|
if (rb_block_given_p()) {
|
|
|
|
rb_scan_args(argc, argv, "02", &arg1, &arg2);
|
|
|
|
argc += 1; /* hackish */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_scan_args(argc, argv, "12", &item, &arg1, &arg2);
|
|
|
|
}
|
1999-08-13 09:45:20 +04:00
|
|
|
switch (argc) {
|
|
|
|
case 1:
|
|
|
|
beg = 0;
|
2006-09-02 18:42:08 +04:00
|
|
|
len = RARRAY_LEN(ary);
|
1999-08-13 09:45:20 +04:00
|
|
|
break;
|
|
|
|
case 2:
|
2006-09-02 18:42:08 +04:00
|
|
|
if (rb_range_beg_len(arg1, &beg, &len, RARRAY_LEN(ary), 1)) {
|
1999-08-13 09:45:20 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* fall through */
|
|
|
|
case 3:
|
2002-05-21 09:39:19 +04:00
|
|
|
beg = NIL_P(arg1) ? 0 : NUM2LONG(arg1);
|
1998-01-16 15:13:05 +03:00
|
|
|
if (beg < 0) {
|
2006-09-02 18:42:08 +04:00
|
|
|
beg = RARRAY_LEN(ary) + beg;
|
1998-01-16 15:13:05 +03:00
|
|
|
if (beg < 0) beg = 0;
|
|
|
|
}
|
2006-09-02 18:42:08 +04:00
|
|
|
len = NIL_P(arg2) ? RARRAY_LEN(ary) - beg : NUM2LONG(arg2);
|
1999-08-13 09:45:20 +04:00
|
|
|
break;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_ary_modify(ary);
|
2008-07-09 16:01:08 +04:00
|
|
|
if (len < 0) {
|
|
|
|
return ary;
|
|
|
|
}
|
2008-07-01 08:19:47 +04:00
|
|
|
if (beg >= ARY_MAX_SIZE || len > ARY_MAX_SIZE - beg) {
|
2007-09-05 17:37:18 +04:00
|
|
|
rb_raise(rb_eArgError, "argument too big");
|
|
|
|
}
|
2008-06-25 10:28:53 +04:00
|
|
|
end = beg + len;
|
2007-09-05 17:37:18 +04:00
|
|
|
if (RARRAY_LEN(ary) < end) {
|
2006-09-02 18:42:08 +04:00
|
|
|
if (end >= ARY_CAPA(ary)) {
|
2008-10-17 14:42:11 +04:00
|
|
|
ary_resize_capa(ary, end);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2013-07-19 15:08:13 +04:00
|
|
|
ary_mem_clear(ary, RARRAY_LEN(ary), end - RARRAY_LEN(ary));
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(ary, end);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2016-05-23 06:23:24 +03:00
|
|
|
if (item == Qundef) {
|
2003-08-01 06:52:21 +04:00
|
|
|
VALUE v;
|
|
|
|
long i;
|
|
|
|
|
2004-09-29 09:15:33 +04:00
|
|
|
for (i=beg; i<end; i++) {
|
2003-08-07 01:50:06 +04:00
|
|
|
v = rb_yield(LONG2NUM(i));
|
2006-09-02 18:42:08 +04:00
|
|
|
if (i>=RARRAY_LEN(ary)) break;
|
2014-04-11 13:55:10 +04:00
|
|
|
ARY_SET(ary, i, v);
|
2002-01-28 11:44:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2013-07-22 08:00:12 +04:00
|
|
|
ary_memfill(ary, beg, len, item);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary + other_ary -> new_ary
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Concatenation --- Returns a new array built by concatenating the
|
2004-07-13 20:21:23 +04:00
|
|
|
* two arrays together to produce a third array.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* [ 1, 2, 3 ] + [ 4, 5 ] #=> [ 1, 2, 3, 4, 5 ]
|
2012-06-01 03:51:33 +04:00
|
|
|
* a = [ "a", "b", "c" ]
|
2013-06-04 20:16:36 +04:00
|
|
|
* c = a + [ "d", "e", "f" ]
|
|
|
|
* c #=> [ "a", "b", "c", "d", "e", "f" ]
|
|
|
|
* a #=> [ "a", "b", "c" ]
|
2012-09-13 23:08:45 +04:00
|
|
|
*
|
2014-12-02 09:30:05 +03:00
|
|
|
* Note that
|
|
|
|
* x += y
|
|
|
|
* is the same as
|
|
|
|
* x = x + y
|
|
|
|
* This means that it produces a new array. As a consequence,
|
2014-12-02 09:59:25 +03:00
|
|
|
* repeated use of <code>+=</code> on arrays can be quite inefficient.
|
2014-12-02 09:30:05 +03:00
|
|
|
*
|
2012-09-13 23:08:45 +04:00
|
|
|
* See also Array#concat.
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_plus(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2005-08-10 05:39:24 +04:00
|
|
|
VALUE z;
|
2013-07-19 14:10:31 +04:00
|
|
|
long len, xlen, ylen;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2005-08-10 05:39:24 +04:00
|
|
|
y = to_ary(y);
|
2013-07-19 14:10:31 +04:00
|
|
|
xlen = RARRAY_LEN(x);
|
|
|
|
ylen = RARRAY_LEN(y);
|
|
|
|
len = xlen + ylen;
|
2002-05-21 09:39:19 +04:00
|
|
|
z = rb_ary_new2(len);
|
2013-07-19 14:10:31 +04:00
|
|
|
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR_TRANSIENT(x));
|
|
|
|
ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR_TRANSIENT(y));
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(z, len);
|
1998-01-16 15:19:22 +03:00
|
|
|
return z;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2016-08-27 04:26:17 +03:00
|
|
|
static VALUE
|
|
|
|
ary_append(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
long n = RARRAY_LEN(y);
|
|
|
|
if (n > 0) {
|
2018-10-31 00:54:13 +03:00
|
|
|
rb_ary_splice(x, RARRAY_LEN(x), 0, RARRAY_CONST_PTR_TRANSIENT(y), n);
|
2016-08-27 04:26:17 +03:00
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2018-10-20 00:35:51 +03:00
|
|
|
* ary.concat(other_ary1, other_ary2, ...) -> ary
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2018-10-13 22:01:22 +03:00
|
|
|
* Appends the elements of <code>other_ary</code>s to +self+.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2018-07-11 12:56:49 +03:00
|
|
|
* [ "a", "b" ].concat( ["c", "d"]) #=> [ "a", "b", "c", "d" ]
|
|
|
|
* [ "a" ].concat( ["b"], ["c", "d"]) #=> [ "a", "b", "c", "d" ]
|
2016-08-27 04:26:17 +03:00
|
|
|
* [ "a" ].concat #=> [ "a" ]
|
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* a = [ 1, 2, 3 ]
|
2018-07-11 12:56:49 +03:00
|
|
|
* a.concat( [ 4, 5 ])
|
2012-06-01 03:51:33 +04:00
|
|
|
* a #=> [ 1, 2, 3, 4, 5 ]
|
2012-09-13 23:08:45 +04:00
|
|
|
*
|
2016-08-27 04:26:17 +03:00
|
|
|
* a = [ 1, 2 ]
|
|
|
|
* a.concat(a, a) #=> [1, 2, 1, 2, 1, 2]
|
|
|
|
*
|
2012-09-13 23:08:45 +04:00
|
|
|
* See also Array#+.
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2016-08-27 04:26:17 +03:00
|
|
|
static VALUE
|
|
|
|
rb_ary_concat_multi(int argc, VALUE *argv, VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2016-08-27 04:26:17 +03:00
|
|
|
rb_ary_modify_check(ary);
|
|
|
|
|
2017-05-26 20:10:01 +03:00
|
|
|
if (argc == 1) {
|
|
|
|
rb_ary_concat(ary, argv[0]);
|
|
|
|
}
|
|
|
|
else if (argc > 1) {
|
2016-08-27 04:26:17 +03:00
|
|
|
int i;
|
|
|
|
VALUE args = rb_ary_tmp_new(argc);
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
rb_ary_concat(args, argv[i]);
|
|
|
|
}
|
|
|
|
ary_append(ary, args);
|
2000-10-10 11:03:36 +04:00
|
|
|
}
|
2016-08-27 04:26:17 +03:00
|
|
|
|
2018-10-31 00:53:56 +03:00
|
|
|
ary_verify(ary);
|
2016-08-27 04:26:17 +03:00
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2016-08-27 04:26:17 +03:00
|
|
|
VALUE
|
|
|
|
rb_ary_concat(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
return ary_append(x, to_ary(y));
|
|
|
|
}
|
2003-12-16 23:28:44 +03:00
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary * int -> new_ary
|
|
|
|
* ary * str -> new_string
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Repetition --- With a String argument, equivalent to
|
|
|
|
* <code>ary.join(str)</code>.
|
|
|
|
*
|
|
|
|
* Otherwise, returns a new array built by concatenating the +int+ copies of
|
|
|
|
* +self+.
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* [ 1, 2, 3 ] * 3 #=> [ 1, 2, 3, 1, 2, 3, 1, 2, 3 ]
|
2004-07-13 19:34:34 +04:00
|
|
|
* [ 1, 2, 3 ] * "," #=> "1,2,3"
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_times(VALUE ary, VALUE times)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2013-07-19 16:12:31 +04:00
|
|
|
VALUE ary2, tmp;
|
|
|
|
const VALUE *ptr;
|
2011-01-17 17:37:05 +03:00
|
|
|
long t, len;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2003-01-07 10:36:40 +03:00
|
|
|
tmp = rb_check_string_type(times);
|
|
|
|
if (!NIL_P(tmp)) {
|
|
|
|
return rb_ary_join(ary, tmp);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
1999-08-13 09:45:20 +04:00
|
|
|
len = NUM2LONG(times);
|
2008-11-25 17:29:39 +03:00
|
|
|
if (len == 0) {
|
|
|
|
ary2 = ary_new(rb_obj_class(ary), 0);
|
|
|
|
goto out;
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
if (len < 0) {
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_raise(rb_eArgError, "negative argument");
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2008-06-20 03:12:46 +04:00
|
|
|
if (ARY_MAX_SIZE/len < RARRAY_LEN(ary)) {
|
2003-04-10 13:48:15 +04:00
|
|
|
rb_raise(rb_eArgError, "argument too big");
|
|
|
|
}
|
2006-09-02 18:42:08 +04:00
|
|
|
len *= RARRAY_LEN(ary);
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2001-12-10 10:18:16 +03:00
|
|
|
ary2 = ary_new(rb_obj_class(ary), len);
|
2008-10-09 09:47:04 +04:00
|
|
|
ARY_SET_LEN(ary2, len);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2018-10-31 00:53:56 +03:00
|
|
|
ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
|
* array.c (rb_ary_{times, shuffle_bang, sample}): reducing macro
calls inside of the loop by keeping pointers in local
variables. a patch from Masahiro Kanai (CanI) in [ruby-dev:39406].
It was found and fixed at Security and Programming camp 2009.
* string.c (rb_str_{times, split_m}): ditto.
* struct.c (rb_struct_{getmember, set, aref_id, aset_id}, {make,
inspect}_struct, recursive_{equal, hash, eql}): ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@25237 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-10-05 18:35:39 +04:00
|
|
|
t = RARRAY_LEN(ary);
|
2011-01-17 17:37:05 +03:00
|
|
|
if (0 < t) {
|
2013-07-19 16:12:31 +04:00
|
|
|
ary_memcpy(ary2, 0, t, ptr);
|
|
|
|
while (t <= len/2) {
|
2018-10-31 00:54:13 +03:00
|
|
|
ary_memcpy(ary2, t, t, RARRAY_CONST_PTR_TRANSIENT(ary2));
|
2011-01-17 17:37:05 +03:00
|
|
|
t *= 2;
|
|
|
|
}
|
|
|
|
if (t < len) {
|
2018-10-31 00:54:13 +03:00
|
|
|
ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR_TRANSIENT(ary2));
|
2011-01-17 17:37:05 +03:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2008-11-25 17:29:39 +03:00
|
|
|
out:
|
1998-01-16 15:19:22 +03:00
|
|
|
return ary2;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2015-05-15 12:28:24 +03:00
|
|
|
* ary.assoc(obj) -> element_ary or nil
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Searches through an array whose elements are also arrays comparing +obj+
|
|
|
|
* with the first element of each contained array using <code>obj.==</code>.
|
|
|
|
*
|
|
|
|
* Returns the first contained array that matches (that is, the first
|
|
|
|
* associated array), or +nil+ if no match is found.
|
|
|
|
*
|
|
|
|
* See also Array#rassoc
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
|
|
|
* s1 = [ "colors", "red", "blue", "green" ]
|
|
|
|
* s2 = [ "letters", "a", "b", "c" ]
|
|
|
|
* s3 = "foo"
|
|
|
|
* a = [ s1, s2, s3 ]
|
|
|
|
* a.assoc("letters") #=> [ "letters", "a", "b", "c" ]
|
|
|
|
* a.assoc("foo") #=> nil
|
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_assoc(VALUE ary, VALUE key)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2004-09-17 13:24:13 +04:00
|
|
|
long i;
|
|
|
|
VALUE v;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2006-09-02 18:42:08 +04:00
|
|
|
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
2013-05-13 13:56:22 +04:00
|
|
|
v = rb_check_array_type(RARRAY_AREF(ary, i));
|
2007-10-25 20:52:40 +04:00
|
|
|
if (!NIL_P(v) && RARRAY_LEN(v) > 0 &&
|
2013-05-13 13:56:22 +04:00
|
|
|
rb_equal(RARRAY_AREF(v, 0), key))
|
2004-09-17 13:24:13 +04:00
|
|
|
return v;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2015-05-15 12:28:24 +03:00
|
|
|
* ary.rassoc(obj) -> element_ary or nil
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Searches through the array whose elements are also arrays.
|
|
|
|
*
|
|
|
|
* Compares +obj+ with the second element of each contained array using
|
|
|
|
* <code>obj.==</code>.
|
|
|
|
*
|
|
|
|
* Returns the first contained array that matches +obj+.
|
|
|
|
*
|
|
|
|
* See also Array#assoc.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ]
|
|
|
|
* a.rassoc("two") #=> [2, "two"]
|
|
|
|
* a.rassoc("four") #=> nil
|
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_rassoc(VALUE ary, VALUE value)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2004-09-17 13:24:13 +04:00
|
|
|
long i;
|
|
|
|
VALUE v;
|
|
|
|
|
2006-09-02 18:42:08 +04:00
|
|
|
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
2013-05-13 13:56:22 +04:00
|
|
|
v = RARRAY_AREF(ary, i);
|
2011-09-29 15:07:45 +04:00
|
|
|
if (RB_TYPE_P(v, T_ARRAY) &&
|
2006-09-02 18:42:08 +04:00
|
|
|
RARRAY_LEN(v) > 1 &&
|
2013-05-13 13:56:22 +04:00
|
|
|
rb_equal(RARRAY_AREF(v, 1), value))
|
2004-09-17 13:24:13 +04:00
|
|
|
return v;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2007-09-24 17:43:58 +04:00
|
|
|
static VALUE
|
|
|
|
recursive_equal(VALUE ary1, VALUE ary2, int recur)
|
|
|
|
{
|
2012-11-03 07:21:47 +04:00
|
|
|
long i, len1;
|
2013-07-19 10:21:12 +04:00
|
|
|
const VALUE *p1, *p2;
|
2007-09-24 17:43:58 +04:00
|
|
|
|
2009-05-24 17:48:23 +04:00
|
|
|
if (recur) return Qtrue; /* Subtle! */
|
2012-11-02 11:04:39 +04:00
|
|
|
|
2018-10-31 00:53:56 +03:00
|
|
|
/* rb_equal() can evacuate ptrs */
|
* include/ruby/ruby.h: rename RARRAY_RAWPTR() to RARRAY_CONST_PTR().
RARRAY_RAWPTR(ary) returns (const VALUE *) type pointer and
usecase of this macro is not acquire raw pointer, but acquire
read-only pointer. So we rename to better name.
RSTRUCT_RAWPTR() is also renamed to RSTRUCT_CONST_PTR()
(I expect that nobody use it).
* array.c, compile.c, cont.c, enumerator.c, gc.c, proc.c, random.c,
string.c, struct.c, thread.c, vm_eval.c, vm_insnhelper.c:
catch up this change.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43043 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-25 12:24:34 +04:00
|
|
|
p1 = RARRAY_CONST_PTR(ary1);
|
|
|
|
p2 = RARRAY_CONST_PTR(ary2);
|
2012-11-03 07:21:47 +04:00
|
|
|
len1 = RARRAY_LEN(ary1);
|
2012-11-02 11:04:39 +04:00
|
|
|
|
2012-11-03 07:21:47 +04:00
|
|
|
for (i = 0; i < len1; i++) {
|
2012-11-02 11:04:39 +04:00
|
|
|
if (*p1 != *p2) {
|
|
|
|
if (rb_equal(*p1, *p2)) {
|
2012-11-03 07:21:47 +04:00
|
|
|
len1 = RARRAY_LEN(ary1);
|
2012-11-04 06:44:58 +04:00
|
|
|
if (len1 != RARRAY_LEN(ary2))
|
2012-11-02 11:04:39 +04:00
|
|
|
return Qfalse;
|
2012-11-04 06:44:58 +04:00
|
|
|
if (len1 < i)
|
|
|
|
return Qtrue;
|
2018-10-31 00:02:12 +03:00
|
|
|
p1 = RARRAY_CONST_PTR(ary1) + i;
|
|
|
|
p2 = RARRAY_CONST_PTR(ary2) + i;
|
2012-11-02 11:04:39 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p1++;
|
|
|
|
p2++;
|
2007-09-24 17:43:58 +04:00
|
|
|
}
|
|
|
|
return Qtrue;
|
|
|
|
}
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary == other_ary -> bool
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Equality --- Two arrays are equal if they contain the same number of
|
|
|
|
* elements and if each element is equal to (according to Object#==) the
|
|
|
|
* corresponding element in +other_ary+.
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
|
|
|
* [ "a", "c" ] == [ "a", "c", 7 ] #=> false
|
|
|
|
* [ "a", "c", 7 ] == [ "a", "c", 7 ] #=> true
|
|
|
|
* [ "a", "c", 7 ] == [ "a", "d", "f" ] #=> false
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_equal(VALUE ary1, VALUE ary2)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2001-08-29 10:28:51 +04:00
|
|
|
if (ary1 == ary2) return Qtrue;
|
2011-09-29 15:07:45 +04:00
|
|
|
if (!RB_TYPE_P(ary2, T_ARRAY)) {
|
2014-05-20 12:28:31 +04:00
|
|
|
if (!rb_respond_to(ary2, idTo_ary)) {
|
2003-02-04 10:27:43 +03:00
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
return rb_equal(ary2, ary1);
|
|
|
|
}
|
2006-09-02 18:42:08 +04:00
|
|
|
if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
|
2018-10-31 00:53:56 +03:00
|
|
|
if (RARRAY_CONST_PTR_TRANSIENT(ary1) == RARRAY_CONST_PTR_TRANSIENT(ary2)) return Qtrue;
|
2009-05-24 17:48:23 +04:00
|
|
|
return rb_exec_recursive_paired(recursive_equal, ary1, ary2, ary2);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2008-02-26 09:30:38 +03:00
|
|
|
static VALUE
|
|
|
|
recursive_eql(VALUE ary1, VALUE ary2, int recur)
|
|
|
|
{
|
|
|
|
long i;
|
|
|
|
|
2009-05-24 17:48:23 +04:00
|
|
|
if (recur) return Qtrue; /* Subtle! */
|
2008-02-26 09:30:38 +03:00
|
|
|
for (i=0; i<RARRAY_LEN(ary1); i++) {
|
|
|
|
if (!rb_eql(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
|
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
return Qtrue;
|
|
|
|
}
|
|
|
|
|
2003-12-29 05:02:08 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary.eql?(other) -> true or false
|
2003-12-29 05:02:08 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Returns +true+ if +self+ and +other+ are the same object,
|
2013-04-25 02:12:31 +04:00
|
|
|
* or are both arrays with the same content (according to Object#eql?).
|
2003-12-29 05:02:08 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_eql(VALUE ary1, VALUE ary2)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2003-01-07 10:36:40 +03:00
|
|
|
if (ary1 == ary2) return Qtrue;
|
2011-09-29 15:07:45 +04:00
|
|
|
if (!RB_TYPE_P(ary2, T_ARRAY)) return Qfalse;
|
2006-09-02 18:42:08 +04:00
|
|
|
if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
|
2018-10-31 00:53:56 +03:00
|
|
|
if (RARRAY_CONST_PTR_TRANSIENT(ary1) == RARRAY_CONST_PTR_TRANSIENT(ary2)) return Qtrue;
|
2009-05-24 17:48:23 +04:00
|
|
|
return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
* array.c: replace rb_protect_inspect() and rb_inspecting_p() by
rb_exec_recursive() in eval.c.
* eval.c (rb_exec_recursive): new function.
* array.c (rb_ary_join): use rb_exec_recursive().
* array.c (rb_ary_inspect, rb_ary_hash): ditto.
* file.c (rb_file_join): ditto.
* hash.c (rb_hash_inspect, rb_hash_to_s, rb_hash_hash): ditto.
* io.c (rb_io_puts): ditto.
* object.c (rb_obj_inspect): ditto
* struct.c (rb_struct_inspect): ditto.
* lib/set.rb (SortedSet::setup): a hack to shut up warning.
[ruby-talk:132866]
* lib/time.rb (Time::strptime): add new function. inspired by
[ruby-talk:132815].
* lib/parsedate.rb (ParseDate::strptime): ditto.
* regparse.c: move st_*_strend() functions from st.c. fixed some
potential memory leaks.
* exception error messages updated. [ruby-core:04497]
* ext/socket/socket.c (Init_socket): add bunch of Socket
constants. Patch from Sam Roberts <sroberts@uniserve.com>.
[ruby-core:04409]
* array.c (rb_ary_s_create): no need for negative argc check.
[ruby-core:04463]
* array.c (rb_ary_unshift_m): ditto.
* lib/xmlrpc/parser.rb (XMLRPC::FaultException): make it subclass
of StandardError class, not Exception class. [ruby-core:04429]
* parse.y (fcall_gen): lvar(arg) will be evaluated as
lvar.call(arg) when lvar is a defined local variable. [new]
* object.c (rb_class_initialize): call inherited method before
calling initializing block.
* eval.c (rb_thread_start_1): initialize newly pushed frame.
* lib/open3.rb (Open3::popen3): $? should not be EXIT_FAILURE.
fixed: [ruby-core:04444]
* eval.c (is_defined): NODE_IASGN is an assignment.
* ext/readline/readline.c (Readline.readline): use rl_outstream
and rl_instream. [ruby-dev:25699]
* ext/etc/etc.c (Init_etc): sGroup needs HAVE_ST_GR_PASSWD check
[ruby-dev:25675]
* misc/ruby-mode.el: [ruby-core:04415]
* lib/rdoc/generators/html_generator.rb: [ruby-core:04412]
* lib/rdoc/generators/ri_generator.rb: ditto.
* struct.c (make_struct): fixed: [ruby-core:04402]
* ext/curses/curses.c (window_color_set): [ruby-core:04393]
* ext/socket/socket.c (Init_socket): SO_REUSEPORT added.
[ruby-talk:130092]
* object.c: [ruby-doc:818]
* parse.y (open_args): fix too verbose warnings for the space
before argument parentheses. [ruby-dev:25492]
* parse.y (parser_yylex): ditto.
* parse.y (parser_yylex): the first expression in the parentheses
should not be a command. [ruby-dev:25492]
* lib/irb/context.rb (IRB::Context::initialize): [ruby-core:04330]
* object.c (Init_Object): remove Object#type. [ruby-core:04335]
* st.c (st_foreach): report success/failure by return value.
[ruby-Bugs-1396]
* parse.y: forgot to initialize parser struct. [ruby-dev:25492]
* parse.y (parser_yylex): no tLABEL on EXPR_BEG.
[ruby-talk:127711]
* document updates - [ruby-core:04296], [ruby-core:04301],
[ruby-core:04302], [ruby-core:04307]
* dir.c (rb_push_glob): should work for NUL delimited patterns.
* dir.c (rb_glob2): should aware of offset in the pattern.
* string.c (rb_str_new4): should propagate taintedness.
* env.h: rename member names in struct FRAME; last_func -> callee,
orig_func -> this_func, last_class -> this_class.
* struct.c (rb_struct_set): use original method name, not callee
name, to retrieve member slot. [ruby-core:04268]
* time.c (time_strftime): protect from format modification from GC
finalizers.
* object.c (Init_Object): remove rb_obj_id_obsolete()
* eval.c (rb_mod_define_method): incomplete subclass check.
[ruby-dev:25464]
* gc.c (rb_data_object_alloc): klass may be NULL.
[ruby-list:40498]
* bignum.c (rb_big_rand): should return positive random number.
[ruby-dev:25401]
* bignum.c (rb_big_rand): do not use rb_big_modulo to generate
random bignums. [ruby-dev:25396]
* variable.c (rb_autoload): [ruby-dev:25373]
* eval.c (svalue_to_avalue): [ruby-dev:25366]
* string.c (rb_str_justify): [ruby-dev:25367]
* io.c (rb_f_select): [ruby-dev:25312]
* ext/socket/socket.c (sock_s_getservbyport): [ruby-talk:124072]
* struct.c (make_struct): [ruby-dev:25249]
* dir.c (dir_open_dir): new function. [ruby-dev:25242]
* io.c (rb_f_open): add type check for return value from to_open.
* lib/pstore.rb (PStore#transaction): Use the empty content when a
file is not found. [ruby-dev:24561]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8068 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-03-04 09:47:45 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2016-09-08 07:57:49 +03:00
|
|
|
* ary.hash -> integer
|
* array.c: replace rb_protect_inspect() and rb_inspecting_p() by
rb_exec_recursive() in eval.c.
* eval.c (rb_exec_recursive): new function.
* array.c (rb_ary_join): use rb_exec_recursive().
* array.c (rb_ary_inspect, rb_ary_hash): ditto.
* file.c (rb_file_join): ditto.
* hash.c (rb_hash_inspect, rb_hash_to_s, rb_hash_hash): ditto.
* io.c (rb_io_puts): ditto.
* object.c (rb_obj_inspect): ditto
* struct.c (rb_struct_inspect): ditto.
* lib/set.rb (SortedSet::setup): a hack to shut up warning.
[ruby-talk:132866]
* lib/time.rb (Time::strptime): add new function. inspired by
[ruby-talk:132815].
* lib/parsedate.rb (ParseDate::strptime): ditto.
* regparse.c: move st_*_strend() functions from st.c. fixed some
potential memory leaks.
* exception error messages updated. [ruby-core:04497]
* ext/socket/socket.c (Init_socket): add bunch of Socket
constants. Patch from Sam Roberts <sroberts@uniserve.com>.
[ruby-core:04409]
* array.c (rb_ary_s_create): no need for negative argc check.
[ruby-core:04463]
* array.c (rb_ary_unshift_m): ditto.
* lib/xmlrpc/parser.rb (XMLRPC::FaultException): make it subclass
of StandardError class, not Exception class. [ruby-core:04429]
* parse.y (fcall_gen): lvar(arg) will be evaluated as
lvar.call(arg) when lvar is a defined local variable. [new]
* object.c (rb_class_initialize): call inherited method before
calling initializing block.
* eval.c (rb_thread_start_1): initialize newly pushed frame.
* lib/open3.rb (Open3::popen3): $? should not be EXIT_FAILURE.
fixed: [ruby-core:04444]
* eval.c (is_defined): NODE_IASGN is an assignment.
* ext/readline/readline.c (Readline.readline): use rl_outstream
and rl_instream. [ruby-dev:25699]
* ext/etc/etc.c (Init_etc): sGroup needs HAVE_ST_GR_PASSWD check
[ruby-dev:25675]
* misc/ruby-mode.el: [ruby-core:04415]
* lib/rdoc/generators/html_generator.rb: [ruby-core:04412]
* lib/rdoc/generators/ri_generator.rb: ditto.
* struct.c (make_struct): fixed: [ruby-core:04402]
* ext/curses/curses.c (window_color_set): [ruby-core:04393]
* ext/socket/socket.c (Init_socket): SO_REUSEPORT added.
[ruby-talk:130092]
* object.c: [ruby-doc:818]
* parse.y (open_args): fix too verbose warnings for the space
before argument parentheses. [ruby-dev:25492]
* parse.y (parser_yylex): ditto.
* parse.y (parser_yylex): the first expression in the parentheses
should not be a command. [ruby-dev:25492]
* lib/irb/context.rb (IRB::Context::initialize): [ruby-core:04330]
* object.c (Init_Object): remove Object#type. [ruby-core:04335]
* st.c (st_foreach): report success/failure by return value.
[ruby-Bugs-1396]
* parse.y: forgot to initialize parser struct. [ruby-dev:25492]
* parse.y (parser_yylex): no tLABEL on EXPR_BEG.
[ruby-talk:127711]
* document updates - [ruby-core:04296], [ruby-core:04301],
[ruby-core:04302], [ruby-core:04307]
* dir.c (rb_push_glob): should work for NUL delimited patterns.
* dir.c (rb_glob2): should aware of offset in the pattern.
* string.c (rb_str_new4): should propagate taintedness.
* env.h: rename member names in struct FRAME; last_func -> callee,
orig_func -> this_func, last_class -> this_class.
* struct.c (rb_struct_set): use original method name, not callee
name, to retrieve member slot. [ruby-core:04268]
* time.c (time_strftime): protect from format modification from GC
finalizers.
* object.c (Init_Object): remove rb_obj_id_obsolete()
* eval.c (rb_mod_define_method): incomplete subclass check.
[ruby-dev:25464]
* gc.c (rb_data_object_alloc): klass may be NULL.
[ruby-list:40498]
* bignum.c (rb_big_rand): should return positive random number.
[ruby-dev:25401]
* bignum.c (rb_big_rand): do not use rb_big_modulo to generate
random bignums. [ruby-dev:25396]
* variable.c (rb_autoload): [ruby-dev:25373]
* eval.c (svalue_to_avalue): [ruby-dev:25366]
* string.c (rb_str_justify): [ruby-dev:25367]
* io.c (rb_f_select): [ruby-dev:25312]
* ext/socket/socket.c (sock_s_getservbyport): [ruby-talk:124072]
* struct.c (make_struct): [ruby-dev:25249]
* dir.c (dir_open_dir): new function. [ruby-dev:25242]
* io.c (rb_f_open): add type check for return value from to_open.
* lib/pstore.rb (PStore#transaction): Use the empty content when a
file is not found. [ruby-dev:24561]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8068 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-03-04 09:47:45 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Compute a hash-code for this array.
|
|
|
|
*
|
|
|
|
* Two arrays with the same content will have the same hash code (and will
|
|
|
|
* compare using #eql?).
|
2014-03-14 05:27:43 +04:00
|
|
|
*
|
|
|
|
* See also Object#hash.
|
* array.c: replace rb_protect_inspect() and rb_inspecting_p() by
rb_exec_recursive() in eval.c.
* eval.c (rb_exec_recursive): new function.
* array.c (rb_ary_join): use rb_exec_recursive().
* array.c (rb_ary_inspect, rb_ary_hash): ditto.
* file.c (rb_file_join): ditto.
* hash.c (rb_hash_inspect, rb_hash_to_s, rb_hash_hash): ditto.
* io.c (rb_io_puts): ditto.
* object.c (rb_obj_inspect): ditto
* struct.c (rb_struct_inspect): ditto.
* lib/set.rb (SortedSet::setup): a hack to shut up warning.
[ruby-talk:132866]
* lib/time.rb (Time::strptime): add new function. inspired by
[ruby-talk:132815].
* lib/parsedate.rb (ParseDate::strptime): ditto.
* regparse.c: move st_*_strend() functions from st.c. fixed some
potential memory leaks.
* exception error messages updated. [ruby-core:04497]
* ext/socket/socket.c (Init_socket): add bunch of Socket
constants. Patch from Sam Roberts <sroberts@uniserve.com>.
[ruby-core:04409]
* array.c (rb_ary_s_create): no need for negative argc check.
[ruby-core:04463]
* array.c (rb_ary_unshift_m): ditto.
* lib/xmlrpc/parser.rb (XMLRPC::FaultException): make it subclass
of StandardError class, not Exception class. [ruby-core:04429]
* parse.y (fcall_gen): lvar(arg) will be evaluated as
lvar.call(arg) when lvar is a defined local variable. [new]
* object.c (rb_class_initialize): call inherited method before
calling initializing block.
* eval.c (rb_thread_start_1): initialize newly pushed frame.
* lib/open3.rb (Open3::popen3): $? should not be EXIT_FAILURE.
fixed: [ruby-core:04444]
* eval.c (is_defined): NODE_IASGN is an assignment.
* ext/readline/readline.c (Readline.readline): use rl_outstream
and rl_instream. [ruby-dev:25699]
* ext/etc/etc.c (Init_etc): sGroup needs HAVE_ST_GR_PASSWD check
[ruby-dev:25675]
* misc/ruby-mode.el: [ruby-core:04415]
* lib/rdoc/generators/html_generator.rb: [ruby-core:04412]
* lib/rdoc/generators/ri_generator.rb: ditto.
* struct.c (make_struct): fixed: [ruby-core:04402]
* ext/curses/curses.c (window_color_set): [ruby-core:04393]
* ext/socket/socket.c (Init_socket): SO_REUSEPORT added.
[ruby-talk:130092]
* object.c: [ruby-doc:818]
* parse.y (open_args): fix too verbose warnings for the space
before argument parentheses. [ruby-dev:25492]
* parse.y (parser_yylex): ditto.
* parse.y (parser_yylex): the first expression in the parentheses
should not be a command. [ruby-dev:25492]
* lib/irb/context.rb (IRB::Context::initialize): [ruby-core:04330]
* object.c (Init_Object): remove Object#type. [ruby-core:04335]
* st.c (st_foreach): report success/failure by return value.
[ruby-Bugs-1396]
* parse.y: forgot to initialize parser struct. [ruby-dev:25492]
* parse.y (parser_yylex): no tLABEL on EXPR_BEG.
[ruby-talk:127711]
* document updates - [ruby-core:04296], [ruby-core:04301],
[ruby-core:04302], [ruby-core:04307]
* dir.c (rb_push_glob): should work for NUL delimited patterns.
* dir.c (rb_glob2): should aware of offset in the pattern.
* string.c (rb_str_new4): should propagate taintedness.
* env.h: rename member names in struct FRAME; last_func -> callee,
orig_func -> this_func, last_class -> this_class.
* struct.c (rb_struct_set): use original method name, not callee
name, to retrieve member slot. [ruby-core:04268]
* time.c (time_strftime): protect from format modification from GC
finalizers.
* object.c (Init_Object): remove rb_obj_id_obsolete()
* eval.c (rb_mod_define_method): incomplete subclass check.
[ruby-dev:25464]
* gc.c (rb_data_object_alloc): klass may be NULL.
[ruby-list:40498]
* bignum.c (rb_big_rand): should return positive random number.
[ruby-dev:25401]
* bignum.c (rb_big_rand): do not use rb_big_modulo to generate
random bignums. [ruby-dev:25396]
* variable.c (rb_autoload): [ruby-dev:25373]
* eval.c (svalue_to_avalue): [ruby-dev:25366]
* string.c (rb_str_justify): [ruby-dev:25367]
* io.c (rb_f_select): [ruby-dev:25312]
* ext/socket/socket.c (sock_s_getservbyport): [ruby-talk:124072]
* struct.c (make_struct): [ruby-dev:25249]
* dir.c (dir_open_dir): new function. [ruby-dev:25242]
* io.c (rb_f_open): add type check for return value from to_open.
* lib/pstore.rb (PStore#transaction): Use the empty content when a
file is not found. [ruby-dev:24561]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8068 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-03-04 09:47:45 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_hash(VALUE ary)
|
* array.c: replace rb_protect_inspect() and rb_inspecting_p() by
rb_exec_recursive() in eval.c.
* eval.c (rb_exec_recursive): new function.
* array.c (rb_ary_join): use rb_exec_recursive().
* array.c (rb_ary_inspect, rb_ary_hash): ditto.
* file.c (rb_file_join): ditto.
* hash.c (rb_hash_inspect, rb_hash_to_s, rb_hash_hash): ditto.
* io.c (rb_io_puts): ditto.
* object.c (rb_obj_inspect): ditto
* struct.c (rb_struct_inspect): ditto.
* lib/set.rb (SortedSet::setup): a hack to shut up warning.
[ruby-talk:132866]
* lib/time.rb (Time::strptime): add new function. inspired by
[ruby-talk:132815].
* lib/parsedate.rb (ParseDate::strptime): ditto.
* regparse.c: move st_*_strend() functions from st.c. fixed some
potential memory leaks.
* exception error messages updated. [ruby-core:04497]
* ext/socket/socket.c (Init_socket): add bunch of Socket
constants. Patch from Sam Roberts <sroberts@uniserve.com>.
[ruby-core:04409]
* array.c (rb_ary_s_create): no need for negative argc check.
[ruby-core:04463]
* array.c (rb_ary_unshift_m): ditto.
* lib/xmlrpc/parser.rb (XMLRPC::FaultException): make it subclass
of StandardError class, not Exception class. [ruby-core:04429]
* parse.y (fcall_gen): lvar(arg) will be evaluated as
lvar.call(arg) when lvar is a defined local variable. [new]
* object.c (rb_class_initialize): call inherited method before
calling initializing block.
* eval.c (rb_thread_start_1): initialize newly pushed frame.
* lib/open3.rb (Open3::popen3): $? should not be EXIT_FAILURE.
fixed: [ruby-core:04444]
* eval.c (is_defined): NODE_IASGN is an assignment.
* ext/readline/readline.c (Readline.readline): use rl_outstream
and rl_instream. [ruby-dev:25699]
* ext/etc/etc.c (Init_etc): sGroup needs HAVE_ST_GR_PASSWD check
[ruby-dev:25675]
* misc/ruby-mode.el: [ruby-core:04415]
* lib/rdoc/generators/html_generator.rb: [ruby-core:04412]
* lib/rdoc/generators/ri_generator.rb: ditto.
* struct.c (make_struct): fixed: [ruby-core:04402]
* ext/curses/curses.c (window_color_set): [ruby-core:04393]
* ext/socket/socket.c (Init_socket): SO_REUSEPORT added.
[ruby-talk:130092]
* object.c: [ruby-doc:818]
* parse.y (open_args): fix too verbose warnings for the space
before argument parentheses. [ruby-dev:25492]
* parse.y (parser_yylex): ditto.
* parse.y (parser_yylex): the first expression in the parentheses
should not be a command. [ruby-dev:25492]
* lib/irb/context.rb (IRB::Context::initialize): [ruby-core:04330]
* object.c (Init_Object): remove Object#type. [ruby-core:04335]
* st.c (st_foreach): report success/failure by return value.
[ruby-Bugs-1396]
* parse.y: forgot to initialize parser struct. [ruby-dev:25492]
* parse.y (parser_yylex): no tLABEL on EXPR_BEG.
[ruby-talk:127711]
* document updates - [ruby-core:04296], [ruby-core:04301],
[ruby-core:04302], [ruby-core:04307]
* dir.c (rb_push_glob): should work for NUL delimited patterns.
* dir.c (rb_glob2): should aware of offset in the pattern.
* string.c (rb_str_new4): should propagate taintedness.
* env.h: rename member names in struct FRAME; last_func -> callee,
orig_func -> this_func, last_class -> this_class.
* struct.c (rb_struct_set): use original method name, not callee
name, to retrieve member slot. [ruby-core:04268]
* time.c (time_strftime): protect from format modification from GC
finalizers.
* object.c (Init_Object): remove rb_obj_id_obsolete()
* eval.c (rb_mod_define_method): incomplete subclass check.
[ruby-dev:25464]
* gc.c (rb_data_object_alloc): klass may be NULL.
[ruby-list:40498]
* bignum.c (rb_big_rand): should return positive random number.
[ruby-dev:25401]
* bignum.c (rb_big_rand): do not use rb_big_modulo to generate
random bignums. [ruby-dev:25396]
* variable.c (rb_autoload): [ruby-dev:25373]
* eval.c (svalue_to_avalue): [ruby-dev:25366]
* string.c (rb_str_justify): [ruby-dev:25367]
* io.c (rb_f_select): [ruby-dev:25312]
* ext/socket/socket.c (sock_s_getservbyport): [ruby-talk:124072]
* struct.c (make_struct): [ruby-dev:25249]
* dir.c (dir_open_dir): new function. [ruby-dev:25242]
* io.c (rb_f_open): add type check for return value from to_open.
* lib/pstore.rb (PStore#transaction): Use the empty content when a
file is not found. [ruby-dev:24561]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8068 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-03-04 09:47:45 +03:00
|
|
|
{
|
2013-12-03 17:18:30 +04:00
|
|
|
long i;
|
|
|
|
st_index_t h;
|
|
|
|
VALUE n;
|
|
|
|
|
|
|
|
h = rb_hash_start(RARRAY_LEN(ary));
|
2013-12-10 18:44:51 +04:00
|
|
|
h = rb_hash_uint(h, (st_index_t)rb_ary_hash);
|
2013-12-03 17:18:30 +04:00
|
|
|
for (i=0; i<RARRAY_LEN(ary); i++) {
|
|
|
|
n = rb_hash(RARRAY_AREF(ary, i));
|
|
|
|
h = rb_hash_uint(h, NUM2LONG(n));
|
|
|
|
}
|
|
|
|
h = rb_hash_end(h);
|
2016-10-04 19:25:01 +03:00
|
|
|
return ST2FIX(h);
|
* array.c: replace rb_protect_inspect() and rb_inspecting_p() by
rb_exec_recursive() in eval.c.
* eval.c (rb_exec_recursive): new function.
* array.c (rb_ary_join): use rb_exec_recursive().
* array.c (rb_ary_inspect, rb_ary_hash): ditto.
* file.c (rb_file_join): ditto.
* hash.c (rb_hash_inspect, rb_hash_to_s, rb_hash_hash): ditto.
* io.c (rb_io_puts): ditto.
* object.c (rb_obj_inspect): ditto
* struct.c (rb_struct_inspect): ditto.
* lib/set.rb (SortedSet::setup): a hack to shut up warning.
[ruby-talk:132866]
* lib/time.rb (Time::strptime): add new function. inspired by
[ruby-talk:132815].
* lib/parsedate.rb (ParseDate::strptime): ditto.
* regparse.c: move st_*_strend() functions from st.c. fixed some
potential memory leaks.
* exception error messages updated. [ruby-core:04497]
* ext/socket/socket.c (Init_socket): add bunch of Socket
constants. Patch from Sam Roberts <sroberts@uniserve.com>.
[ruby-core:04409]
* array.c (rb_ary_s_create): no need for negative argc check.
[ruby-core:04463]
* array.c (rb_ary_unshift_m): ditto.
* lib/xmlrpc/parser.rb (XMLRPC::FaultException): make it subclass
of StandardError class, not Exception class. [ruby-core:04429]
* parse.y (fcall_gen): lvar(arg) will be evaluated as
lvar.call(arg) when lvar is a defined local variable. [new]
* object.c (rb_class_initialize): call inherited method before
calling initializing block.
* eval.c (rb_thread_start_1): initialize newly pushed frame.
* lib/open3.rb (Open3::popen3): $? should not be EXIT_FAILURE.
fixed: [ruby-core:04444]
* eval.c (is_defined): NODE_IASGN is an assignment.
* ext/readline/readline.c (Readline.readline): use rl_outstream
and rl_instream. [ruby-dev:25699]
* ext/etc/etc.c (Init_etc): sGroup needs HAVE_ST_GR_PASSWD check
[ruby-dev:25675]
* misc/ruby-mode.el: [ruby-core:04415]
* lib/rdoc/generators/html_generator.rb: [ruby-core:04412]
* lib/rdoc/generators/ri_generator.rb: ditto.
* struct.c (make_struct): fixed: [ruby-core:04402]
* ext/curses/curses.c (window_color_set): [ruby-core:04393]
* ext/socket/socket.c (Init_socket): SO_REUSEPORT added.
[ruby-talk:130092]
* object.c: [ruby-doc:818]
* parse.y (open_args): fix too verbose warnings for the space
before argument parentheses. [ruby-dev:25492]
* parse.y (parser_yylex): ditto.
* parse.y (parser_yylex): the first expression in the parentheses
should not be a command. [ruby-dev:25492]
* lib/irb/context.rb (IRB::Context::initialize): [ruby-core:04330]
* object.c (Init_Object): remove Object#type. [ruby-core:04335]
* st.c (st_foreach): report success/failure by return value.
[ruby-Bugs-1396]
* parse.y: forgot to initialize parser struct. [ruby-dev:25492]
* parse.y (parser_yylex): no tLABEL on EXPR_BEG.
[ruby-talk:127711]
* document updates - [ruby-core:04296], [ruby-core:04301],
[ruby-core:04302], [ruby-core:04307]
* dir.c (rb_push_glob): should work for NUL delimited patterns.
* dir.c (rb_glob2): should aware of offset in the pattern.
* string.c (rb_str_new4): should propagate taintedness.
* env.h: rename member names in struct FRAME; last_func -> callee,
orig_func -> this_func, last_class -> this_class.
* struct.c (rb_struct_set): use original method name, not callee
name, to retrieve member slot. [ruby-core:04268]
* time.c (time_strftime): protect from format modification from GC
finalizers.
* object.c (Init_Object): remove rb_obj_id_obsolete()
* eval.c (rb_mod_define_method): incomplete subclass check.
[ruby-dev:25464]
* gc.c (rb_data_object_alloc): klass may be NULL.
[ruby-list:40498]
* bignum.c (rb_big_rand): should return positive random number.
[ruby-dev:25401]
* bignum.c (rb_big_rand): do not use rb_big_modulo to generate
random bignums. [ruby-dev:25396]
* variable.c (rb_autoload): [ruby-dev:25373]
* eval.c (svalue_to_avalue): [ruby-dev:25366]
* string.c (rb_str_justify): [ruby-dev:25367]
* io.c (rb_f_select): [ruby-dev:25312]
* ext/socket/socket.c (sock_s_getservbyport): [ruby-talk:124072]
* struct.c (make_struct): [ruby-dev:25249]
* dir.c (dir_open_dir): new function. [ruby-dev:25242]
* io.c (rb_f_open): add type check for return value from to_open.
* lib/pstore.rb (PStore#transaction): Use the empty content when a
file is not found. [ruby-dev:24561]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8068 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-03-04 09:47:45 +03:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2011-10-07 01:36:17 +04:00
|
|
|
* ary.include?(object) -> true or false
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Returns +true+ if the given +object+ is present in +self+ (that is, if any
|
2013-04-13 08:31:15 +04:00
|
|
|
* element <code>==</code> +object+), otherwise returns +false+.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* a = [ "a", "b", "c" ]
|
|
|
|
* a.include?("b") #=> true
|
|
|
|
* a.include?("z") #=> false
|
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_includes(VALUE ary, VALUE item)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-08-13 09:45:20 +04:00
|
|
|
long i;
|
2014-09-21 06:23:32 +04:00
|
|
|
VALUE e;
|
2009-02-22 17:23:33 +03:00
|
|
|
|
2006-09-02 18:42:08 +04:00
|
|
|
for (i=0; i<RARRAY_LEN(ary); i++) {
|
2014-09-21 06:23:32 +04:00
|
|
|
e = RARRAY_AREF(ary, i);
|
Improve performance of rb_equal()
* object.c (rb_equal): add optimized path to compare the objects using
rb_equal_opt(). Previously, if not same objects were given, rb_equal() would
call `==' method via rb_funcall() which took a long time.
rb_equal_opt() has provided faster comparing for Fixnum/Float/String objects.
Now, Time#eql? uses rb_equal() to compare with argument object and it will
be faster around 40% on 64-bit environment.
* array.c (rb_ary_index): remove redundant rb_equal_opt() calling.
Now, rb_equal() was optimized using rb_equal_opt().
If rb_equal_opt() returns Qundef, it will invoke rb_equal() -> rb_equal_opt(),
and it will cause the performance regression.
So, this patch will remove first redundant rb_equal_opt() calling.
* array.c (rb_ary_rindex): ditto.
* array.c (rb_ary_includes): ditto.
[ruby-core:80360] [Bug #13365] [Fix GH-#1552]
### Before
Time#eql? with other 7.309M (± 1.4%) i/s - 36.647M in 5.014964s
Array#index(val) 1.433M (± 1.2%) i/s - 7.207M in 5.030942s
Array#rindex(val) 1.418M (± 1.6%) i/s - 7.103M in 5.009164s
Array#include?(val) 1.451M (± 0.9%) i/s - 7.295M in 5.026392s
### After
Time#eql? with other 10.321M (± 1.9%) i/s - 51.684M in 5.009203s
Array#index(val) 1.474M (± 0.9%) i/s - 7.433M in 5.044384s
Array#rindex(val) 1.449M (± 1.7%) i/s - 7.292M in 5.034436s
Array#include?(val) 1.466M (± 1.7%) i/s - 7.373M in 5.030047s
### Test code
require 'benchmark/ips'
Benchmark.ips do |x|
t1 = Time.now
t2 = Time.now
x.report "Time#eql? with other" do |i|
i.times { t1.eql?(t2) }
end
# Benchmarks to check whether it didn't introduce the regression
obj = Object.new
x.report "Array#index(val)" do |i|
ary = [1, 2, true, false, obj]
i.times { ary.index(obj) }
end
x.report "Array#rindex(val)" do |i|
ary = [1, 2, true, false, obj].reverse
i.times { ary.rindex(obj) }
end
x.report "Array#include?(val)" do |i|
ary = [1, 2, true, false, obj]
i.times { ary.include?(obj) }
end
end
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58880 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2017-05-25 07:25:37 +03:00
|
|
|
if (rb_equal(e, item)) {
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qtrue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
|
2017-09-29 10:43:22 +03:00
|
|
|
static VALUE
|
|
|
|
rb_ary_includes_by_eql(VALUE ary, VALUE item)
|
|
|
|
{
|
|
|
|
long i;
|
|
|
|
VALUE e;
|
|
|
|
|
|
|
|
for (i=0; i<RARRAY_LEN(ary); i++) {
|
|
|
|
e = RARRAY_AREF(ary, i);
|
|
|
|
if (rb_eql(item, e)) {
|
|
|
|
return Qtrue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Qfalse;
|
|
|
|
}
|
2003-12-16 23:28:44 +03:00
|
|
|
|
2008-02-26 09:30:38 +03:00
|
|
|
static VALUE
|
|
|
|
recursive_cmp(VALUE ary1, VALUE ary2, int recur)
|
|
|
|
{
|
|
|
|
long i, len;
|
|
|
|
|
2009-05-24 17:48:23 +04:00
|
|
|
if (recur) return Qundef; /* Subtle! */
|
2008-02-26 09:30:38 +03:00
|
|
|
len = RARRAY_LEN(ary1);
|
|
|
|
if (len > RARRAY_LEN(ary2)) {
|
|
|
|
len = RARRAY_LEN(ary2);
|
|
|
|
}
|
2008-02-26 10:38:13 +03:00
|
|
|
for (i=0; i<len; i++) {
|
2013-09-29 18:51:03 +04:00
|
|
|
VALUE e1 = rb_ary_elt(ary1, i), e2 = rb_ary_elt(ary2, i);
|
|
|
|
VALUE v = rb_funcallv(e1, id_cmp, 1, &e2);
|
2008-02-26 09:30:38 +03:00
|
|
|
if (v != INT2FIX(0)) {
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Qundef;
|
|
|
|
}
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary <=> other_ary -> -1, 0, +1 or nil
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Comparison --- Returns an integer (+-1+, +0+, or <code>+1</code>) if this
|
|
|
|
* array is less than, equal to, or greater than +other_ary+.
|
|
|
|
*
|
|
|
|
* Each object in each array is compared (using the <=> operator).
|
|
|
|
*
|
2014-01-09 21:33:47 +04:00
|
|
|
* Arrays are compared in an "element-wise" manner; the first element of +ary+
|
|
|
|
* is compared with the first one of +other_ary+ using the <=> operator, then
|
|
|
|
* each of the second elements, etc...
|
|
|
|
* As soon as the result of any such comparison is non zero (i.e. the two
|
|
|
|
* corresponding elements are not equal), that result is returned for the
|
|
|
|
* whole array comparison.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2014-01-09 21:33:47 +04:00
|
|
|
* If all the elements are equal, then the result is based on a comparison of
|
2012-06-01 03:51:33 +04:00
|
|
|
* the array lengths. Thus, two arrays are "equal" according to Array#<=> if,
|
|
|
|
* and only if, they have the same length and the value of each element is
|
|
|
|
* equal to the value of the corresponding element in the other array.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2014-01-09 21:33:47 +04:00
|
|
|
* +nil+ is returned if the +other_ary+ is not an array or if the comparison
|
|
|
|
* of two elements returned +nil+.
|
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* [ "a", "a", "c" ] <=> [ "a", "b", "c" ] #=> -1
|
|
|
|
* [ 1, 2, 3, 4, 5, 6 ] <=> [ 1, 2 ] #=> +1
|
2014-01-09 21:33:47 +04:00
|
|
|
* [ 1, 2 ] <=> [ 1, :two ] #=> nil
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2001-08-23 10:02:15 +04:00
|
|
|
VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_cmp(VALUE ary1, VALUE ary2)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2008-02-26 09:30:38 +03:00
|
|
|
long len;
|
|
|
|
VALUE v;
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2009-10-26 14:06:17 +03:00
|
|
|
ary2 = rb_check_array_type(ary2);
|
|
|
|
if (NIL_P(ary2)) return Qnil;
|
2008-02-26 09:30:38 +03:00
|
|
|
if (ary1 == ary2) return INT2FIX(0);
|
2009-05-24 17:48:23 +04:00
|
|
|
v = rb_exec_recursive_paired(recursive_cmp, ary1, ary2, ary2);
|
2008-02-26 09:30:38 +03:00
|
|
|
if (v != Qundef) return v;
|
2006-09-02 18:42:08 +04:00
|
|
|
len = RARRAY_LEN(ary1) - RARRAY_LEN(ary2);
|
1999-01-20 07:59:39 +03:00
|
|
|
if (len == 0) return INT2FIX(0);
|
|
|
|
if (len > 0) return INT2FIX(1);
|
|
|
|
return INT2FIX(-1);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2000-12-08 10:10:38 +03:00
|
|
|
static VALUE
|
2009-02-05 06:01:55 +03:00
|
|
|
ary_add_hash(VALUE hash, VALUE ary)
|
2000-12-05 12:36:54 +03:00
|
|
|
{
|
2002-08-23 11:48:48 +04:00
|
|
|
long i;
|
2000-12-05 12:36:54 +03:00
|
|
|
|
2009-02-05 06:01:55 +03:00
|
|
|
for (i=0; i<RARRAY_LEN(ary); i++) {
|
2013-12-03 08:55:51 +04:00
|
|
|
VALUE elt = RARRAY_AREF(ary, i);
|
2016-07-20 11:35:25 +03:00
|
|
|
rb_hash_add_new_element(hash, elt, elt);
|
2000-12-05 12:36:54 +03:00
|
|
|
}
|
2000-12-08 10:10:38 +03:00
|
|
|
return hash;
|
2000-12-05 12:36:54 +03:00
|
|
|
}
|
|
|
|
|
2009-02-14 18:45:43 +03:00
|
|
|
static inline VALUE
|
2017-09-30 16:14:09 +03:00
|
|
|
ary_tmp_hash_new(VALUE ary)
|
2009-02-05 06:01:55 +03:00
|
|
|
{
|
2017-09-30 16:14:09 +03:00
|
|
|
long size = RARRAY_LEN(ary);
|
|
|
|
VALUE hash = rb_hash_new_with_size(size);
|
2009-02-05 06:01:55 +03:00
|
|
|
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_CLEAR_CLASS(hash);
|
2009-02-14 18:45:43 +03:00
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
ary_make_hash(VALUE ary)
|
|
|
|
{
|
2017-09-30 16:14:09 +03:00
|
|
|
VALUE hash = ary_tmp_hash_new(ary);
|
2009-02-05 06:01:55 +03:00
|
|
|
return ary_add_hash(hash, ary);
|
|
|
|
}
|
|
|
|
|
2009-02-14 18:45:43 +03:00
|
|
|
static VALUE
|
|
|
|
ary_add_hash_by(VALUE hash, VALUE ary)
|
|
|
|
{
|
|
|
|
long i;
|
|
|
|
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
|
|
|
VALUE v = rb_ary_elt(ary, i), k = rb_yield(v);
|
2016-07-20 11:35:25 +03:00
|
|
|
rb_hash_add_new_element(hash, k, v);
|
2009-02-14 18:45:43 +03:00
|
|
|
}
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
ary_make_hash_by(VALUE ary)
|
|
|
|
{
|
2017-09-30 16:14:09 +03:00
|
|
|
VALUE hash = ary_tmp_hash_new(ary);
|
2009-02-14 18:45:43 +03:00
|
|
|
return ary_add_hash_by(hash, ary);
|
|
|
|
}
|
|
|
|
|
2009-02-05 06:01:55 +03:00
|
|
|
static inline void
|
|
|
|
ary_recycle_hash(VALUE hash)
|
|
|
|
{
|
2017-02-13 05:04:26 +03:00
|
|
|
assert(RBASIC_CLASS(hash) == 0);
|
2018-12-14 04:10:15 +03:00
|
|
|
if (RHASH_ST_TABLE_P(hash)) {
|
2018-10-31 01:12:12 +03:00
|
|
|
st_table *tbl = RHASH_ST_TABLE(hash);
|
2009-02-05 06:01:55 +03:00
|
|
|
st_free_table(tbl);
|
2018-12-14 04:10:15 +03:00
|
|
|
RHASH_ST_CLEAR(hash);
|
2009-02-05 06:01:55 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary - other_ary -> new_ary
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2012-09-13 23:08:45 +04:00
|
|
|
* Array Difference
|
|
|
|
*
|
Clarify Array#- and Array#difference documentation
Currently we are not explicit enough regarding the potentially confusing
behavior of `Array#-` and `Array#difference` when it comes to duplicate items
within receiver arrays.
Although the original documentation for these methods does use an array with
multiple instance of the same integers, the explanation for the behavior is
actually imprecise.
> removing any items that also appear in +other_ary+
Not only does `Array#-` remove any items that also appear in `other_ary` but
it also remove any instance of any item in `other_ary`.
One may expect `Array#-` to behave like mathematical subtraction or difference
when it doesn't. One could be forgiven to expect the following behavior:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> [1,2,3,4]
```
In reality this is the result:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> []
```
I hope that I've prevented this potential confusion with the clarifications
in this change. I can offer this as evidence of likeliness for confusion:
https://twitter.com/olivierlacan/status/1084930269533085696
I'll freely admit I was surprised by this behavior myself since I needed to
obtain an Array with only one instance of each item in the argument array
removed.
[Fix GH-2068] [ci skip]
From: Olivier Lacan <hi@olivierlacan.com>
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66831 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2019-01-15 16:52:38 +03:00
|
|
|
* Returns a new array that is a copy of the original array, removing all
|
2019-09-18 11:24:24 +03:00
|
|
|
* occurrences of any item that also appear in +other_ary+. The order is
|
2019-08-15 18:42:17 +03:00
|
|
|
* preserved from the original array.
|
2012-09-13 23:08:45 +04:00
|
|
|
*
|
2013-01-29 14:32:27 +04:00
|
|
|
* It compares elements using their #hash and #eql? methods for efficiency.
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
|
|
|
* [ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ]
|
2012-09-13 23:08:45 +04:00
|
|
|
*
|
Clarify Array#- and Array#difference documentation
Currently we are not explicit enough regarding the potentially confusing
behavior of `Array#-` and `Array#difference` when it comes to duplicate items
within receiver arrays.
Although the original documentation for these methods does use an array with
multiple instance of the same integers, the explanation for the behavior is
actually imprecise.
> removing any items that also appear in +other_ary+
Not only does `Array#-` remove any items that also appear in `other_ary` but
it also remove any instance of any item in `other_ary`.
One may expect `Array#-` to behave like mathematical subtraction or difference
when it doesn't. One could be forgiven to expect the following behavior:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> [1,2,3,4]
```
In reality this is the result:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> []
```
I hope that I've prevented this potential confusion with the clarifications
in this change. I can offer this as evidence of likeliness for confusion:
https://twitter.com/olivierlacan/status/1084930269533085696
I'll freely admit I was surprised by this behavior myself since I needed to
obtain an Array with only one instance of each item in the argument array
removed.
[Fix GH-2068] [ci skip]
From: Olivier Lacan <hi@olivierlacan.com>
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66831 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2019-01-15 16:52:38 +03:00
|
|
|
* Note that while 1 and 2 were only present once in the array argument, and
|
2019-09-18 11:24:24 +03:00
|
|
|
* were present twice in the receiver array, all occurrences of each Integer are
|
Clarify Array#- and Array#difference documentation
Currently we are not explicit enough regarding the potentially confusing
behavior of `Array#-` and `Array#difference` when it comes to duplicate items
within receiver arrays.
Although the original documentation for these methods does use an array with
multiple instance of the same integers, the explanation for the behavior is
actually imprecise.
> removing any items that also appear in +other_ary+
Not only does `Array#-` remove any items that also appear in `other_ary` but
it also remove any instance of any item in `other_ary`.
One may expect `Array#-` to behave like mathematical subtraction or difference
when it doesn't. One could be forgiven to expect the following behavior:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> [1,2,3,4]
```
In reality this is the result:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> []
```
I hope that I've prevented this potential confusion with the clarifications
in this change. I can offer this as evidence of likeliness for confusion:
https://twitter.com/olivierlacan/status/1084930269533085696
I'll freely admit I was surprised by this behavior myself since I needed to
obtain an Array with only one instance of each item in the argument array
removed.
[Fix GH-2068] [ci skip]
From: Olivier Lacan <hi@olivierlacan.com>
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66831 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2019-01-15 16:52:38 +03:00
|
|
|
* removed in the returned array.
|
|
|
|
*
|
2012-09-13 23:08:45 +04:00
|
|
|
* If you need set-like behavior, see the library class Set.
|
2018-10-05 09:23:34 +03:00
|
|
|
*
|
2018-10-20 00:26:15 +03:00
|
|
|
* See also Array#difference.
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
2003-02-03 08:34:16 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_diff(VALUE ary1, VALUE ary2)
|
2003-02-03 08:34:16 +03:00
|
|
|
{
|
2005-12-12 19:47:17 +03:00
|
|
|
VALUE ary3;
|
2014-10-13 01:53:01 +04:00
|
|
|
VALUE hash;
|
2003-02-03 08:34:16 +03:00
|
|
|
long i;
|
|
|
|
|
2017-09-29 10:43:22 +03:00
|
|
|
ary2 = to_ary(ary2);
|
2003-02-03 08:34:16 +03:00
|
|
|
ary3 = rb_ary_new();
|
|
|
|
|
2017-12-19 04:08:52 +03:00
|
|
|
if (RARRAY_LEN(ary1) <= SMALL_ARRAY_LEN || RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) {
|
2017-09-29 10:43:22 +03:00
|
|
|
for (i=0; i<RARRAY_LEN(ary1); i++) {
|
|
|
|
VALUE elt = rb_ary_elt(ary1, i);
|
|
|
|
if (rb_ary_includes_by_eql(ary2, elt)) continue;
|
|
|
|
rb_ary_push(ary3, elt);
|
|
|
|
}
|
|
|
|
return ary3;
|
|
|
|
}
|
|
|
|
|
|
|
|
hash = ary_make_hash(ary2);
|
2006-09-02 18:42:08 +04:00
|
|
|
for (i=0; i<RARRAY_LEN(ary1); i++) {
|
2018-10-31 01:12:12 +03:00
|
|
|
if (rb_hash_stlike_lookup(hash, RARRAY_AREF(ary1, i), NULL)) continue;
|
2004-09-21 07:08:33 +04:00
|
|
|
rb_ary_push(ary3, rb_ary_elt(ary1, i));
|
2003-02-03 08:34:16 +03:00
|
|
|
}
|
2009-02-05 06:01:55 +03:00
|
|
|
ary_recycle_hash(hash);
|
2003-02-03 08:34:16 +03:00
|
|
|
return ary3;
|
|
|
|
}
|
|
|
|
|
2018-10-05 09:23:34 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2019-06-24 11:33:30 +03:00
|
|
|
* ary.difference(other_ary1, other_ary2, ...) -> new_ary
|
2018-10-05 09:23:34 +03:00
|
|
|
*
|
|
|
|
* Array Difference
|
|
|
|
*
|
Clarify Array#- and Array#difference documentation
Currently we are not explicit enough regarding the potentially confusing
behavior of `Array#-` and `Array#difference` when it comes to duplicate items
within receiver arrays.
Although the original documentation for these methods does use an array with
multiple instance of the same integers, the explanation for the behavior is
actually imprecise.
> removing any items that also appear in +other_ary+
Not only does `Array#-` remove any items that also appear in `other_ary` but
it also remove any instance of any item in `other_ary`.
One may expect `Array#-` to behave like mathematical subtraction or difference
when it doesn't. One could be forgiven to expect the following behavior:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> [1,2,3,4]
```
In reality this is the result:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> []
```
I hope that I've prevented this potential confusion with the clarifications
in this change. I can offer this as evidence of likeliness for confusion:
https://twitter.com/olivierlacan/status/1084930269533085696
I'll freely admit I was surprised by this behavior myself since I needed to
obtain an Array with only one instance of each item in the argument array
removed.
[Fix GH-2068] [ci skip]
From: Olivier Lacan <hi@olivierlacan.com>
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66831 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2019-01-15 16:52:38 +03:00
|
|
|
* Returns a new array that is a copy of the original array, removing all
|
2019-09-18 11:24:24 +03:00
|
|
|
* occurrences of any item that also appear in +other_ary+. The order is
|
Clarify Array#- and Array#difference documentation
Currently we are not explicit enough regarding the potentially confusing
behavior of `Array#-` and `Array#difference` when it comes to duplicate items
within receiver arrays.
Although the original documentation for these methods does use an array with
multiple instance of the same integers, the explanation for the behavior is
actually imprecise.
> removing any items that also appear in +other_ary+
Not only does `Array#-` remove any items that also appear in `other_ary` but
it also remove any instance of any item in `other_ary`.
One may expect `Array#-` to behave like mathematical subtraction or difference
when it doesn't. One could be forgiven to expect the following behavior:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> [1,2,3,4]
```
In reality this is the result:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> []
```
I hope that I've prevented this potential confusion with the clarifications
in this change. I can offer this as evidence of likeliness for confusion:
https://twitter.com/olivierlacan/status/1084930269533085696
I'll freely admit I was surprised by this behavior myself since I needed to
obtain an Array with only one instance of each item in the argument array
removed.
[Fix GH-2068] [ci skip]
From: Olivier Lacan <hi@olivierlacan.com>
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66831 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2019-01-15 16:52:38 +03:00
|
|
|
* preserved from the original array.
|
2018-10-05 09:23:34 +03:00
|
|
|
*
|
|
|
|
* It compares elements using their #hash and #eql? methods for efficiency.
|
|
|
|
*
|
2018-10-20 00:26:15 +03:00
|
|
|
* [ 1, 1, 2, 2, 3, 3, 4, 5 ].difference([ 1, 2, 4 ]) #=> [ 3, 3, 5 ]
|
Clarify Array#- and Array#difference documentation
Currently we are not explicit enough regarding the potentially confusing
behavior of `Array#-` and `Array#difference` when it comes to duplicate items
within receiver arrays.
Although the original documentation for these methods does use an array with
multiple instance of the same integers, the explanation for the behavior is
actually imprecise.
> removing any items that also appear in +other_ary+
Not only does `Array#-` remove any items that also appear in `other_ary` but
it also remove any instance of any item in `other_ary`.
One may expect `Array#-` to behave like mathematical subtraction or difference
when it doesn't. One could be forgiven to expect the following behavior:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> [1,2,3,4]
```
In reality this is the result:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> []
```
I hope that I've prevented this potential confusion with the clarifications
in this change. I can offer this as evidence of likeliness for confusion:
https://twitter.com/olivierlacan/status/1084930269533085696
I'll freely admit I was surprised by this behavior myself since I needed to
obtain an Array with only one instance of each item in the argument array
removed.
[Fix GH-2068] [ci skip]
From: Olivier Lacan <hi@olivierlacan.com>
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66831 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2019-01-15 16:52:38 +03:00
|
|
|
*
|
|
|
|
* Note that while 1 and 2 were only present once in the array argument, and
|
2019-09-18 11:24:24 +03:00
|
|
|
* were present twice in the receiver array, all occurrences of each Integer are
|
Clarify Array#- and Array#difference documentation
Currently we are not explicit enough regarding the potentially confusing
behavior of `Array#-` and `Array#difference` when it comes to duplicate items
within receiver arrays.
Although the original documentation for these methods does use an array with
multiple instance of the same integers, the explanation for the behavior is
actually imprecise.
> removing any items that also appear in +other_ary+
Not only does `Array#-` remove any items that also appear in `other_ary` but
it also remove any instance of any item in `other_ary`.
One may expect `Array#-` to behave like mathematical subtraction or difference
when it doesn't. One could be forgiven to expect the following behavior:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> [1,2,3,4]
```
In reality this is the result:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> []
```
I hope that I've prevented this potential confusion with the clarifications
in this change. I can offer this as evidence of likeliness for confusion:
https://twitter.com/olivierlacan/status/1084930269533085696
I'll freely admit I was surprised by this behavior myself since I needed to
obtain an Array with only one instance of each item in the argument array
removed.
[Fix GH-2068] [ci skip]
From: Olivier Lacan <hi@olivierlacan.com>
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66831 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2019-01-15 16:52:38 +03:00
|
|
|
* removed in the returned array.
|
|
|
|
*
|
2019-09-18 11:24:24 +03:00
|
|
|
* Multiple array arguments can be supplied and all occurrences of any element
|
Clarify Array#- and Array#difference documentation
Currently we are not explicit enough regarding the potentially confusing
behavior of `Array#-` and `Array#difference` when it comes to duplicate items
within receiver arrays.
Although the original documentation for these methods does use an array with
multiple instance of the same integers, the explanation for the behavior is
actually imprecise.
> removing any items that also appear in +other_ary+
Not only does `Array#-` remove any items that also appear in `other_ary` but
it also remove any instance of any item in `other_ary`.
One may expect `Array#-` to behave like mathematical subtraction or difference
when it doesn't. One could be forgiven to expect the following behavior:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> [1,2,3,4]
```
In reality this is the result:
```ruby
[1,1,2,2,3,3,4,4] - [1,2,3,4]
=> []
```
I hope that I've prevented this potential confusion with the clarifications
in this change. I can offer this as evidence of likeliness for confusion:
https://twitter.com/olivierlacan/status/1084930269533085696
I'll freely admit I was surprised by this behavior myself since I needed to
obtain an Array with only one instance of each item in the argument array
removed.
[Fix GH-2068] [ci skip]
From: Olivier Lacan <hi@olivierlacan.com>
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66831 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2019-01-15 16:52:38 +03:00
|
|
|
* in those supplied arrays that match the receiver will be removed from the
|
|
|
|
* returned array.
|
|
|
|
*
|
2018-10-20 00:26:15 +03:00
|
|
|
* [ 1, 'c', :s, 'yep' ].difference([ 1 ], [ 'a', 'c' ]) #=> [ :s, "yep" ]
|
2018-10-05 09:23:34 +03:00
|
|
|
*
|
|
|
|
* If you need set-like behavior, see the library class Set.
|
|
|
|
*
|
2018-10-20 00:26:15 +03:00
|
|
|
* See also Array#-.
|
2018-10-05 09:23:34 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_difference_multi(int argc, VALUE *argv, VALUE ary)
|
|
|
|
{
|
|
|
|
VALUE ary_diff;
|
|
|
|
long i, length;
|
|
|
|
volatile VALUE t0;
|
|
|
|
bool *is_hash = ALLOCV_N(bool, t0, argc);
|
|
|
|
ary_diff = rb_ary_new();
|
|
|
|
length = RARRAY_LEN(ary);
|
|
|
|
|
|
|
|
for (i = 0; i < argc; i++) {
|
2018-10-05 09:23:37 +03:00
|
|
|
argv[i] = to_ary(argv[i]);
|
|
|
|
is_hash[i] = (length > SMALL_ARRAY_LEN && RARRAY_LEN(argv[i]) > SMALL_ARRAY_LEN);
|
|
|
|
if (is_hash[i]) argv[i] = ary_make_hash(argv[i]);
|
2018-10-05 09:23:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
2018-10-05 09:23:37 +03:00
|
|
|
int j;
|
|
|
|
VALUE elt = rb_ary_elt(ary, i);
|
2019-01-09 16:58:49 +03:00
|
|
|
for (j = 0; j < argc; j++) {
|
2018-10-05 09:23:37 +03:00
|
|
|
if (is_hash[j]) {
|
2018-10-31 01:11:51 +03:00
|
|
|
if (rb_hash_stlike_lookup(argv[j], RARRAY_AREF(ary, i), NULL))
|
2018-10-05 09:23:37 +03:00
|
|
|
break;
|
2018-10-05 09:23:34 +03:00
|
|
|
}
|
|
|
|
else {
|
2018-10-05 09:23:37 +03:00
|
|
|
if (rb_ary_includes_by_eql(argv[j], elt)) break;
|
|
|
|
}
|
2018-10-05 09:23:34 +03:00
|
|
|
}
|
|
|
|
if (j == argc) rb_ary_push(ary_diff, elt);
|
|
|
|
}
|
|
|
|
|
|
|
|
ALLOCV_END(t0);
|
|
|
|
|
|
|
|
return ary_diff;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary & other_ary -> new_ary
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2016-02-28 04:20:39 +03:00
|
|
|
* Set Intersection --- Returns a new array containing unique elements common to the
|
|
|
|
* two arrays. The order is preserved from the original array.
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2013-01-29 14:32:27 +04:00
|
|
|
* It compares elements using their #hash and #eql? methods for efficiency.
|
|
|
|
*
|
2016-02-28 04:20:39 +03:00
|
|
|
* [ 1, 1, 3, 5 ] & [ 3, 2, 1 ] #=> [ 1, 3 ]
|
2012-06-01 03:51:33 +04:00
|
|
|
* [ 'a', 'b', 'b', 'z' ] & [ 'a', 'b', 'c' ] #=> [ 'a', 'b' ]
|
2012-09-13 23:08:45 +04:00
|
|
|
*
|
|
|
|
* See also Array#uniq.
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_and(VALUE ary1, VALUE ary2)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2010-10-14 02:22:18 +04:00
|
|
|
VALUE hash, ary3, v;
|
|
|
|
st_data_t vv;
|
1999-08-13 09:45:20 +04:00
|
|
|
long i;
|
2000-12-08 10:10:38 +03:00
|
|
|
|
2005-08-10 05:39:24 +04:00
|
|
|
ary2 = to_ary(ary2);
|
2013-11-06 05:39:55 +04:00
|
|
|
ary3 = rb_ary_new();
|
2018-09-16 05:42:26 +03:00
|
|
|
if (RARRAY_LEN(ary1) == 0 || RARRAY_LEN(ary2) == 0) return ary3;
|
2017-09-29 10:43:22 +03:00
|
|
|
|
|
|
|
if (RARRAY_LEN(ary1) <= SMALL_ARRAY_LEN && RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) {
|
|
|
|
for (i=0; i<RARRAY_LEN(ary1); i++) {
|
|
|
|
v = RARRAY_AREF(ary1, i);
|
|
|
|
if (!rb_ary_includes_by_eql(ary2, v)) continue;
|
|
|
|
if (rb_ary_includes_by_eql(ary3, v)) continue;
|
|
|
|
rb_ary_push(ary3, v);
|
|
|
|
}
|
|
|
|
return ary3;
|
|
|
|
}
|
|
|
|
|
2009-02-05 06:01:55 +03:00
|
|
|
hash = ary_make_hash(ary2);
|
2007-08-30 03:12:21 +04:00
|
|
|
|
2006-09-02 18:42:08 +04:00
|
|
|
for (i=0; i<RARRAY_LEN(ary1); i++) {
|
2013-11-06 05:39:55 +04:00
|
|
|
v = RARRAY_AREF(ary1, i);
|
|
|
|
vv = (st_data_t)v;
|
2018-10-31 01:12:12 +03:00
|
|
|
if (rb_hash_stlike_delete(hash, &vv, 0)) {
|
2004-09-21 07:08:33 +04:00
|
|
|
rb_ary_push(ary3, v);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
2009-02-05 06:01:55 +03:00
|
|
|
ary_recycle_hash(hash);
|
2000-12-05 12:36:54 +03:00
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
return ary3;
|
|
|
|
}
|
|
|
|
|
2019-10-07 08:12:29 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* ary.intersection(other_ary1, other_ary2, ...) -> new_ary
|
|
|
|
*
|
|
|
|
* Set Intersection --- Returns a new array containing unique elements common
|
|
|
|
* to +self+ and <code>other_ary</code>s. Order is preserved from the original
|
|
|
|
* array.
|
|
|
|
*
|
|
|
|
* It compares elements using their #hash and #eql? methods for efficiency.
|
|
|
|
*
|
|
|
|
* [ 1, 1, 3, 5 ].intersection([ 3, 2, 1 ]) # => [ 1, 3 ]
|
|
|
|
* [ "a", "b", "z" ].intersection([ "a", "b", "c" ], [ "b" ]) # => [ "b" ]
|
|
|
|
* [ "a" ].intersection #=> [ "a" ]
|
|
|
|
*
|
|
|
|
* See also Array#&.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_intersection_multi(int argc, VALUE *argv, VALUE ary)
|
|
|
|
{
|
|
|
|
VALUE result = rb_ary_dup(ary);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
result = rb_ary_and(result, argv[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-12-05 16:53:31 +04:00
|
|
|
static int
|
|
|
|
ary_hash_orset(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
|
|
|
|
{
|
|
|
|
if (existing) return ST_STOP;
|
|
|
|
*key = *value = (VALUE)arg;
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2018-09-20 06:18:53 +03:00
|
|
|
static void
|
|
|
|
rb_ary_union(VALUE ary_union, VALUE ary)
|
|
|
|
{
|
|
|
|
long i;
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
|
|
|
VALUE elt = rb_ary_elt(ary, i);
|
|
|
|
if (rb_ary_includes_by_eql(ary_union, elt)) continue;
|
|
|
|
rb_ary_push(ary_union, elt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-20 06:18:54 +03:00
|
|
|
static void
|
|
|
|
rb_ary_union_hash(VALUE hash, VALUE ary2)
|
|
|
|
{
|
|
|
|
long i;
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary2); i++) {
|
|
|
|
VALUE elt = RARRAY_AREF(ary2, i);
|
2018-10-31 01:11:51 +03:00
|
|
|
if (!rb_hash_stlike_update(hash, (st_data_t)elt, ary_hash_orset, (st_data_t)elt)) {
|
2018-09-20 06:18:54 +03:00
|
|
|
RB_OBJ_WRITTEN(hash, Qundef, elt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary | other_ary -> new_ary
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Set Union --- Returns a new array by joining +ary+ with +other_ary+,
|
2016-02-28 04:20:39 +03:00
|
|
|
* excluding any duplicates and preserving the order from the given arrays.
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2013-01-29 14:32:27 +04:00
|
|
|
* It compares elements using their #hash and #eql? methods for efficiency.
|
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* [ "a", "b", "c" ] | [ "c", "d", "a" ] #=> [ "a", "b", "c", "d" ]
|
2016-02-28 04:20:39 +03:00
|
|
|
* [ "c", "d", "a" ] | [ "a", "b", "c" ] #=> [ "c", "d", "a", "b" ]
|
2012-09-13 23:08:45 +04:00
|
|
|
*
|
2018-09-20 06:18:54 +03:00
|
|
|
* See also Array#union.
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_or(VALUE ary1, VALUE ary2)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2013-10-10 18:04:55 +04:00
|
|
|
VALUE hash, ary3;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2005-08-10 05:39:24 +04:00
|
|
|
ary2 = to_ary(ary2);
|
2017-09-29 10:43:22 +03:00
|
|
|
if (RARRAY_LEN(ary1) + RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) {
|
|
|
|
ary3 = rb_ary_new();
|
2018-09-20 06:18:53 +03:00
|
|
|
rb_ary_union(ary3, ary1);
|
|
|
|
rb_ary_union(ary3, ary2);
|
2017-09-29 10:43:22 +03:00
|
|
|
return ary3;
|
|
|
|
}
|
2013-12-05 16:53:31 +04:00
|
|
|
|
2017-09-29 10:43:22 +03:00
|
|
|
hash = ary_make_hash(ary1);
|
2018-09-20 06:18:54 +03:00
|
|
|
rb_ary_union_hash(hash, ary2);
|
|
|
|
|
2013-12-03 08:55:51 +04:00
|
|
|
ary3 = rb_hash_values(hash);
|
2009-02-05 06:01:55 +03:00
|
|
|
ary_recycle_hash(hash);
|
1998-01-16 15:13:05 +03:00
|
|
|
return ary3;
|
|
|
|
}
|
|
|
|
|
2018-09-20 06:18:52 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2019-02-18 14:44:01 +03:00
|
|
|
* ary.union(other_ary1, other_ary2, ...) -> new_ary
|
2018-09-20 06:18:52 +03:00
|
|
|
*
|
2018-10-13 22:01:22 +03:00
|
|
|
* Set Union --- Returns a new array by joining <code>other_ary</code>s with +self+,
|
2018-09-20 06:18:52 +03:00
|
|
|
* excluding any duplicates and preserving the order from the given arrays.
|
|
|
|
*
|
|
|
|
* It compares elements using their #hash and #eql? methods for efficiency.
|
|
|
|
*
|
|
|
|
* [ "a", "b", "c" ].union( [ "c", "d", "a" ] ) #=> [ "a", "b", "c", "d" ]
|
2018-09-21 11:53:11 +03:00
|
|
|
* [ "a" ].union( ["e", "b"], ["a", "c", "b"] ) #=> [ "a", "e", "b", "c" ]
|
2018-09-20 06:18:52 +03:00
|
|
|
* [ "a" ].union #=> [ "a" ]
|
|
|
|
*
|
|
|
|
* See also Array#|.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_union_multi(int argc, VALUE *argv, VALUE ary)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
long sum;
|
|
|
|
VALUE hash, ary_union;
|
|
|
|
|
|
|
|
sum = RARRAY_LEN(ary);
|
2019-01-09 16:58:49 +03:00
|
|
|
for (i = 0; i < argc; i++) {
|
2018-09-20 06:18:52 +03:00
|
|
|
argv[i] = to_ary(argv[i]);
|
|
|
|
sum += RARRAY_LEN(argv[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sum <= SMALL_ARRAY_LEN) {
|
|
|
|
ary_union = rb_ary_new();
|
|
|
|
|
2018-09-20 06:18:53 +03:00
|
|
|
rb_ary_union(ary_union, ary);
|
|
|
|
for (i = 0; i < argc; i++) rb_ary_union(ary_union, argv[i]);
|
2018-09-20 06:18:52 +03:00
|
|
|
|
|
|
|
return ary_union;
|
|
|
|
}
|
|
|
|
|
|
|
|
hash = ary_make_hash(ary);
|
2018-09-20 06:18:54 +03:00
|
|
|
for (i = 0; i < argc; i++) rb_ary_union_hash(hash, argv[i]);
|
2018-09-20 06:18:52 +03:00
|
|
|
|
|
|
|
ary_union = rb_hash_values(hash);
|
|
|
|
ary_recycle_hash(hash);
|
|
|
|
return ary_union;
|
|
|
|
}
|
|
|
|
|
2016-03-17 15:14:21 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2016-03-17 15:52:47 +03:00
|
|
|
* ary.max -> obj
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.max {|a, b| block} -> obj
|
2016-03-17 15:52:47 +03:00
|
|
|
* ary.max(n) -> array
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.max(n) {|a, b| block} -> array
|
2016-03-17 15:14:21 +03:00
|
|
|
*
|
|
|
|
* Returns the object in _ary_ with the maximum value. The
|
2020-05-27 09:48:46 +03:00
|
|
|
* first form assumes all objects implement <code><=></code>;
|
2016-03-17 15:14:21 +03:00
|
|
|
* the second uses the block to return <em>a <=> b</em>.
|
|
|
|
*
|
2017-10-25 15:57:34 +03:00
|
|
|
* ary = %w(albatross dog horse)
|
|
|
|
* ary.max #=> "horse"
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.max {|a, b| a.length <=> b.length} #=> "albatross"
|
2016-03-17 15:14:21 +03:00
|
|
|
*
|
|
|
|
* If the +n+ argument is given, maximum +n+ elements are returned
|
|
|
|
* as an array.
|
|
|
|
*
|
2017-10-25 15:57:34 +03:00
|
|
|
* ary = %w[albatross dog horse]
|
|
|
|
* ary.max(2) #=> ["horse", "dog"]
|
|
|
|
* ary.max(2) {|a, b| a.length <=> b.length } #=> ["albatross", "horse"]
|
2016-03-17 15:14:21 +03:00
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
rb_ary_max(int argc, VALUE *argv, VALUE ary)
|
|
|
|
{
|
|
|
|
struct cmp_opt_data cmp_opt = { 0, 0 };
|
|
|
|
VALUE result = Qundef, v;
|
|
|
|
VALUE num;
|
|
|
|
long i;
|
|
|
|
|
2018-12-05 04:09:44 +03:00
|
|
|
if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
|
2016-03-17 15:37:20 +03:00
|
|
|
return rb_nmin_run(ary, num, 0, 1, 1);
|
2016-03-17 15:14:21 +03:00
|
|
|
|
2016-03-17 15:25:40 +03:00
|
|
|
if (rb_block_given_p()) {
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
|
|
|
v = RARRAY_AREF(ary, i);
|
|
|
|
if (result == Qundef || rb_cmpint(rb_yield_values(2, v, result), v, result) > 0) {
|
|
|
|
result = v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
|
|
|
v = RARRAY_AREF(ary, i);
|
|
|
|
if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) > 0) {
|
|
|
|
result = v;
|
|
|
|
}
|
|
|
|
}
|
2016-03-17 15:14:21 +03:00
|
|
|
}
|
|
|
|
if (result == Qundef) return Qnil;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* ary.min -> obj
|
|
|
|
* ary.min {| a,b | block } -> obj
|
|
|
|
* ary.min(n) -> array
|
|
|
|
* ary.min(n) {| a,b | block } -> array
|
|
|
|
*
|
|
|
|
* Returns the object in _ary_ with the minimum value. The
|
2020-05-27 09:48:46 +03:00
|
|
|
* first form assumes all objects implement <code><=></code>;
|
2016-03-17 15:14:21 +03:00
|
|
|
* the second uses the block to return <em>a <=> b</em>.
|
|
|
|
*
|
2017-10-25 15:57:34 +03:00
|
|
|
* ary = %w(albatross dog horse)
|
|
|
|
* ary.min #=> "albatross"
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.min {|a, b| a.length <=> b.length} #=> "dog"
|
2016-03-17 15:14:21 +03:00
|
|
|
*
|
|
|
|
* If the +n+ argument is given, minimum +n+ elements are returned
|
|
|
|
* as an array.
|
|
|
|
*
|
2017-10-25 15:57:34 +03:00
|
|
|
* ary = %w[albatross dog horse]
|
|
|
|
* ary.min(2) #=> ["albatross", "dog"]
|
|
|
|
* ary.min(2) {|a, b| a.length <=> b.length } #=> ["dog", "horse"]
|
2016-03-17 15:14:21 +03:00
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
rb_ary_min(int argc, VALUE *argv, VALUE ary)
|
|
|
|
{
|
|
|
|
struct cmp_opt_data cmp_opt = { 0, 0 };
|
|
|
|
VALUE result = Qundef, v;
|
|
|
|
VALUE num;
|
|
|
|
long i;
|
|
|
|
|
2018-12-05 04:09:44 +03:00
|
|
|
if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
|
2016-03-17 15:37:20 +03:00
|
|
|
return rb_nmin_run(ary, num, 0, 0, 1);
|
2016-03-17 15:14:21 +03:00
|
|
|
|
2016-03-17 15:25:40 +03:00
|
|
|
if (rb_block_given_p()) {
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
|
|
|
v = RARRAY_AREF(ary, i);
|
|
|
|
if (result == Qundef || rb_cmpint(rb_yield_values(2, v, result), v, result) < 0) {
|
|
|
|
result = v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
|
|
|
v = RARRAY_AREF(ary, i);
|
|
|
|
if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) < 0) {
|
|
|
|
result = v;
|
|
|
|
}
|
|
|
|
}
|
2016-03-17 15:14:21 +03:00
|
|
|
}
|
|
|
|
if (result == Qundef) return Qnil;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-06-17 21:33:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* ary.minmax -> [obj, obj]
|
|
|
|
* ary.minmax {| a,b | block } -> [obj, obj]
|
|
|
|
*
|
|
|
|
* Returns a two element array which contains the minimum and the
|
|
|
|
* maximum value in the array.
|
|
|
|
*
|
|
|
|
* Can be given an optional block to override the default comparison
|
|
|
|
* method <code>a <=> b</code>.
|
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
rb_ary_minmax(VALUE ary)
|
|
|
|
{
|
|
|
|
if (rb_block_given_p()) {
|
|
|
|
return rb_call_super(0, NULL);
|
|
|
|
}
|
|
|
|
return rb_assoc_new(rb_ary_min(0, 0, ary), rb_ary_max(0, 0, ary));
|
|
|
|
}
|
|
|
|
|
2009-02-14 18:45:43 +03:00
|
|
|
static int
|
|
|
|
push_value(st_data_t key, st_data_t val, st_data_t ary)
|
|
|
|
{
|
|
|
|
rb_ary_push((VALUE)ary, (VALUE)val);
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2011-10-11 03:50:02 +04:00
|
|
|
* ary.uniq! -> ary or nil
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.uniq! {|item| ...} -> ary or nil
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Removes duplicate elements from +self+.
|
|
|
|
*
|
|
|
|
* If a block is given, it will use the return value of the block for
|
|
|
|
* comparison.
|
|
|
|
*
|
2013-01-29 14:32:27 +04:00
|
|
|
* It compares values using their #hash and #eql? methods for efficiency.
|
|
|
|
*
|
2015-03-07 03:36:09 +03:00
|
|
|
* +self+ is traversed in order, and the first occurrence is kept.
|
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Returns +nil+ if no changes are made (that is, no duplicates are found).
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* a = [ "a", "a", "b", "b", "c" ]
|
2011-10-11 03:50:02 +04:00
|
|
|
* a.uniq! # => ["a", "b", "c"]
|
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* b = [ "a", "b", "c" ]
|
2011-10-11 03:50:02 +04:00
|
|
|
* b.uniq! # => nil
|
|
|
|
*
|
|
|
|
* c = [["student","sam"], ["student","george"], ["teacher","matz"]]
|
2018-07-11 12:56:49 +03:00
|
|
|
* c.uniq! {|s| s.first} # => [["student", "sam"], ["teacher", "matz"]]
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_uniq_bang(VALUE ary)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2013-10-29 17:14:19 +04:00
|
|
|
VALUE hash;
|
|
|
|
long hash_size;
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2010-02-10 10:31:06 +03:00
|
|
|
rb_ary_modify_check(ary);
|
2010-03-20 07:27:32 +03:00
|
|
|
if (RARRAY_LEN(ary) <= 1)
|
|
|
|
return Qnil;
|
2013-12-03 09:13:19 +04:00
|
|
|
if (rb_block_given_p())
|
2009-02-14 18:45:43 +03:00
|
|
|
hash = ary_make_hash_by(ary);
|
2013-12-03 09:13:19 +04:00
|
|
|
else
|
2009-02-14 18:45:43 +03:00
|
|
|
hash = ary_make_hash(ary);
|
2013-12-03 09:13:19 +04:00
|
|
|
|
|
|
|
hash_size = RHASH_SIZE(hash);
|
|
|
|
if (RARRAY_LEN(ary) == hash_size) {
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
rb_ary_modify_check(ary);
|
|
|
|
ARY_SET_LEN(ary, 0);
|
|
|
|
if (ARY_SHARED_P(ary) && !ARY_EMBED_P(ary)) {
|
|
|
|
rb_ary_unshare(ary);
|
|
|
|
FL_SET_EMBED(ary);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
2013-12-03 09:13:19 +04:00
|
|
|
ary_resize_capa(ary, hash_size);
|
2018-10-31 01:11:51 +03:00
|
|
|
rb_hash_foreach(hash, push_value, ary);
|
2009-02-05 06:01:55 +03:00
|
|
|
ary_recycle_hash(hash);
|
1999-01-20 07:59:39 +03:00
|
|
|
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2012-11-07 23:45:59 +04:00
|
|
|
* ary.uniq -> new_ary
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.uniq {|item| ...} -> new_ary
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-09-13 23:08:45 +04:00
|
|
|
* Returns a new array by removing duplicate values in +self+.
|
|
|
|
*
|
|
|
|
* If a block is given, it will use the return value of the block for comparison.
|
|
|
|
*
|
2013-01-29 14:32:27 +04:00
|
|
|
* It compares values using their #hash and #eql? methods for efficiency.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2015-03-07 03:36:09 +03:00
|
|
|
* +self+ is traversed in order, and the first occurrence is kept.
|
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* a = [ "a", "a", "b", "b", "c" ]
|
2011-10-11 03:50:02 +04:00
|
|
|
* a.uniq # => ["a", "b", "c"]
|
|
|
|
*
|
|
|
|
* b = [["student","sam"], ["student","george"], ["teacher","matz"]]
|
2018-07-11 12:56:49 +03:00
|
|
|
* b.uniq {|s| s.first} # => [["student", "sam"], ["teacher", "matz"]]
|
2011-10-11 03:50:02 +04:00
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_uniq(VALUE ary)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2013-10-08 09:19:57 +04:00
|
|
|
VALUE hash, uniq;
|
2009-02-05 06:24:20 +03:00
|
|
|
|
2019-07-16 00:03:28 +03:00
|
|
|
if (RARRAY_LEN(ary) <= 1) {
|
|
|
|
hash = 0;
|
|
|
|
uniq = rb_ary_dup(ary);
|
|
|
|
}
|
|
|
|
else if (rb_block_given_p()) {
|
2009-02-14 18:45:43 +03:00
|
|
|
hash = ary_make_hash_by(ary);
|
2013-10-08 11:11:15 +04:00
|
|
|
uniq = rb_hash_values(hash);
|
2009-02-14 18:45:43 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
hash = ary_make_hash(ary);
|
2013-12-03 08:55:51 +04:00
|
|
|
uniq = rb_hash_values(hash);
|
2009-02-05 06:24:20 +03:00
|
|
|
}
|
2013-10-08 10:35:29 +04:00
|
|
|
RBASIC_SET_CLASS(uniq, rb_obj_class(ary));
|
2019-07-16 00:03:28 +03:00
|
|
|
if (hash) {
|
|
|
|
ary_recycle_hash(hash);
|
|
|
|
}
|
2009-02-05 06:24:20 +03:00
|
|
|
|
|
|
|
return uniq;
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2004-07-13 20:21:23 +04:00
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary.compact! -> ary or nil
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2010-05-13 09:49:55 +04:00
|
|
|
* Removes +nil+ elements from the array.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2011-10-07 01:36:17 +04:00
|
|
|
* Returns +nil+ if no changes were made, otherwise returns the array.
|
2004-07-13 20:21:23 +04:00
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* [ "a", nil, "b", nil, "c" ].compact! #=> [ "a", "b", "c" ]
|
|
|
|
* [ "a", "b", "c" ].compact! #=> nil
|
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_compact_bang(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
VALUE *p, *t, *end;
|
2006-09-02 18:42:08 +04:00
|
|
|
long n;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_ary_modify(ary);
|
2018-10-31 00:53:56 +03:00
|
|
|
p = t = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(ary); /* WB: no new reference */
|
2006-09-02 18:42:08 +04:00
|
|
|
end = p + RARRAY_LEN(ary);
|
2009-02-22 17:23:33 +03:00
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
while (t < end) {
|
|
|
|
if (NIL_P(*t)) t++;
|
|
|
|
else *p++ = *t++;
|
|
|
|
}
|
2018-10-31 00:53:56 +03:00
|
|
|
n = p - RARRAY_CONST_PTR_TRANSIENT(ary);
|
2008-05-21 11:50:27 +04:00
|
|
|
if (RARRAY_LEN(ary) == n) {
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qnil;
|
|
|
|
}
|
2013-10-10 16:37:58 +04:00
|
|
|
ary_resize_smaller(ary, n);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2004-07-13 20:21:23 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary.compact -> new_ary
|
2003-12-16 23:28:44 +03:00
|
|
|
*
|
2010-05-13 09:49:55 +04:00
|
|
|
* Returns a copy of +self+ with all +nil+ elements removed.
|
2004-07-13 20:21:23 +04:00
|
|
|
*
|
|
|
|
* [ "a", nil, "b", nil, "c", nil ].compact
|
2003-12-16 23:28:44 +03:00
|
|
|
* #=> [ "a", "b", "c" ]
|
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2005-09-10 17:34:53 +04:00
|
|
|
rb_ary_compact(VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2002-08-27 12:31:08 +04:00
|
|
|
ary = rb_ary_dup(ary);
|
1999-10-20 11:10:23 +04:00
|
|
|
rb_ary_compact_bang(ary);
|
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2008-05-14 07:46:37 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.count -> int
|
|
|
|
* ary.count(obj) -> int
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.count {|item| block} -> int
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Returns the number of elements.
|
|
|
|
*
|
|
|
|
* If an argument is given, counts the number of elements which equal +obj+
|
2013-07-16 13:50:11 +04:00
|
|
|
* using <code>==</code>.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
|
|
|
* If a block is given, counts the number of elements for which the block
|
|
|
|
* returns a true value.
|
2008-05-14 07:46:37 +04:00
|
|
|
*
|
|
|
|
* ary = [1, 2, 4, 2]
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.count #=> 4
|
|
|
|
* ary.count(2) #=> 2
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.count {|x| x%2 == 0} #=> 3
|
2008-05-14 07:46:37 +04:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_count(int argc, VALUE *argv, VALUE ary)
|
|
|
|
{
|
2013-07-18 15:38:01 +04:00
|
|
|
long i, n = 0;
|
2008-05-14 07:46:37 +04:00
|
|
|
|
2018-12-05 04:09:44 +03:00
|
|
|
if (rb_check_arity(argc, 0, 1) == 0) {
|
2013-07-18 13:18:50 +04:00
|
|
|
VALUE v;
|
2008-05-14 07:46:37 +04:00
|
|
|
|
2008-05-29 23:18:54 +04:00
|
|
|
if (!rb_block_given_p())
|
|
|
|
return LONG2NUM(RARRAY_LEN(ary));
|
2008-05-14 07:46:37 +04:00
|
|
|
|
2013-07-18 13:18:50 +04:00
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
|
|
|
v = RARRAY_AREF(ary, i);
|
|
|
|
if (RTEST(rb_yield(v))) n++;
|
2008-05-14 07:46:37 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2018-12-05 04:09:44 +03:00
|
|
|
VALUE obj = argv[0];
|
2008-05-14 07:46:37 +04:00
|
|
|
|
|
|
|
if (rb_block_given_p()) {
|
|
|
|
rb_warn("given block not used");
|
|
|
|
}
|
2013-07-18 15:38:01 +04:00
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
|
|
|
if (rb_equal(RARRAY_AREF(ary, i), obj)) n++;
|
2008-05-14 07:46:37 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return LONG2NUM(n);
|
|
|
|
}
|
|
|
|
|
2007-12-07 06:27:20 +03:00
|
|
|
static VALUE
|
2019-09-27 19:24:25 +03:00
|
|
|
flatten(VALUE ary, int level)
|
2007-12-07 06:27:20 +03:00
|
|
|
{
|
2019-09-27 19:24:25 +03:00
|
|
|
long i;
|
2020-05-22 07:49:08 +03:00
|
|
|
VALUE stack, result, tmp = 0, elt, vmemo;
|
2007-12-07 06:27:20 +03:00
|
|
|
st_table *memo;
|
|
|
|
st_data_t id;
|
|
|
|
|
2019-09-27 19:24:25 +03:00
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
|
|
|
elt = RARRAY_AREF(ary, i);
|
|
|
|
tmp = rb_check_array_type(elt);
|
|
|
|
if (!NIL_P(tmp)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i == RARRAY_LEN(ary)) {
|
|
|
|
return ary;
|
|
|
|
} else if (tmp == ary) {
|
|
|
|
rb_raise(rb_eArgError, "tried to flatten recursive array");
|
|
|
|
}
|
|
|
|
|
2008-05-22 07:40:57 +04:00
|
|
|
result = ary_new(0, RARRAY_LEN(ary));
|
2019-09-27 19:24:25 +03:00
|
|
|
ary_memcpy(result, 0, i, RARRAY_CONST_PTR_TRANSIENT(ary));
|
|
|
|
ARY_SET_LEN(result, i);
|
|
|
|
|
|
|
|
stack = ary_new(0, ARY_DEFAULT_SIZE);
|
|
|
|
rb_ary_push(stack, ary);
|
|
|
|
rb_ary_push(stack, LONG2NUM(i + 1));
|
|
|
|
|
2019-09-20 04:29:24 +03:00
|
|
|
vmemo = rb_hash_new();
|
|
|
|
RBASIC_CLEAR_CLASS(vmemo);
|
2007-12-07 06:27:20 +03:00
|
|
|
memo = st_init_numtable();
|
2019-09-20 04:29:24 +03:00
|
|
|
rb_hash_st_table_set(vmemo, memo);
|
2007-12-07 06:27:20 +03:00
|
|
|
st_insert(memo, (st_data_t)ary, (st_data_t)Qtrue);
|
2019-09-27 19:24:25 +03:00
|
|
|
st_insert(memo, (st_data_t)tmp, (st_data_t)Qtrue);
|
|
|
|
|
|
|
|
ary = tmp;
|
|
|
|
i = 0;
|
2007-12-07 06:27:20 +03:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
while (i < RARRAY_LEN(ary)) {
|
2013-05-13 13:56:22 +04:00
|
|
|
elt = RARRAY_AREF(ary, i++);
|
2015-01-25 06:04:10 +03:00
|
|
|
if (level >= 0 && RARRAY_LEN(stack) / 2 >= level) {
|
|
|
|
rb_ary_push(result, elt);
|
|
|
|
continue;
|
|
|
|
}
|
2007-12-07 06:27:20 +03:00
|
|
|
tmp = rb_check_array_type(elt);
|
2008-05-22 07:40:57 +04:00
|
|
|
if (RBASIC(result)->klass) {
|
2019-09-20 04:29:24 +03:00
|
|
|
RB_GC_GUARD(vmemo);
|
|
|
|
st_clear(memo);
|
2008-05-22 07:40:57 +04:00
|
|
|
rb_raise(rb_eRuntimeError, "flatten reentered");
|
|
|
|
}
|
2015-01-25 06:04:10 +03:00
|
|
|
if (NIL_P(tmp)) {
|
2007-12-07 06:27:20 +03:00
|
|
|
rb_ary_push(result, elt);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
id = (st_data_t)tmp;
|
2017-05-19 01:59:38 +03:00
|
|
|
if (st_is_member(memo, id)) {
|
2019-09-20 04:29:24 +03:00
|
|
|
st_clear(memo);
|
2007-12-07 06:27:20 +03:00
|
|
|
rb_raise(rb_eArgError, "tried to flatten recursive array");
|
|
|
|
}
|
|
|
|
st_insert(memo, id, (st_data_t)Qtrue);
|
|
|
|
rb_ary_push(stack, ary);
|
|
|
|
rb_ary_push(stack, LONG2NUM(i));
|
|
|
|
ary = tmp;
|
|
|
|
i = 0;
|
|
|
|
}
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
2007-12-07 06:27:20 +03:00
|
|
|
if (RARRAY_LEN(stack) == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
id = (st_data_t)ary;
|
|
|
|
st_delete(memo, &id, 0);
|
|
|
|
tmp = rb_ary_pop(stack);
|
|
|
|
i = NUM2LONG(tmp);
|
|
|
|
ary = rb_ary_pop(stack);
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
|
|
|
|
2019-09-20 04:29:24 +03:00
|
|
|
st_clear(memo);
|
2008-05-22 01:41:09 +04:00
|
|
|
|
2016-09-08 11:56:30 +03:00
|
|
|
RBASIC_SET_CLASS(result, rb_obj_class(ary));
|
2007-12-07 06:27:20 +03:00
|
|
|
return result;
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2013-02-24 00:17:20 +04:00
|
|
|
* ary.flatten! -> ary or nil
|
|
|
|
* ary.flatten!(level) -> ary or nil
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2010-05-13 09:49:55 +04:00
|
|
|
* Flattens +self+ in place.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
|
|
|
* Returns +nil+ if no modifications were made (i.e., the array contains no
|
|
|
|
* subarrays.)
|
|
|
|
*
|
|
|
|
* The optional +level+ argument determines the level of recursion to flatten.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* a = [ 1, 2, [3, [4, 5] ] ]
|
2006-12-31 18:02:22 +03:00
|
|
|
* a.flatten! #=> [1, 2, 3, 4, 5]
|
|
|
|
* a.flatten! #=> nil
|
|
|
|
* a #=> [1, 2, 3, 4, 5]
|
* sprintf.c (rb_str_format): allow %c to print one character
string (e.g. ?x).
* lib/tempfile.rb (Tempfile::make_tmpname): put dot between
basename and pid. [ruby-talk:196272]
* parse.y (do_block): remove -> style block.
* parse.y (parser_yylex): remove tLAMBDA_ARG.
* eval.c (rb_call0): binding for the return event hook should have
consistent scope. [ruby-core:07928]
* eval.c (proc_invoke): return behavior should depend whether it
is surrounded by a lambda or a mere block.
* eval.c (formal_assign): handles post splat arguments.
* eval.c (rb_call0): ditto.
* st.c (strhash): use FNV-1a hash.
* parse.y (parser_yylex): removed experimental ';;' terminator.
* eval.c (rb_node_arity): should be aware of post splat arguments.
* eval.c (rb_proc_arity): ditto.
* parse.y (f_args): syntax rule enhanced to support arguments
after the splat.
* parse.y (block_param): ditto for block parameters.
* parse.y (f_post_arg): mandatory formal arguments after the splat
argument.
* parse.y (new_args_gen): generate nodes for mandatory formal
arguments after the splat argument.
* eval.c (rb_eval): dispatch mandatory formal arguments after the
splat argument.
* parse.y (args): allow more than one splat in the argument list.
* parse.y (method_call): allow aref [] to accept all kind of
method argument, including assocs, splat, and block argument.
* eval.c (SETUP_ARGS0): prepare block argument as well.
* lib/mathn.rb (Integer): remove Integer#gcd2. [ruby-core:07931]
* eval.c (error_line): print receivers true/false/nil specially.
* eval.c (rb_proc_yield): handles parameters in yield semantics.
* eval.c (nil_yield): gives LocalJumpError to denote no block
error.
* io.c (rb_io_getc): now takes one-character string.
* string.c (rb_str_hash): use FNV-1a hash from Fowler/Noll/Vo
hashing algorithm.
* string.c (rb_str_aref): str[0] now returns 1 character string,
instead of a fixnum. [Ruby2]
* parse.y (parser_yylex): ?c now returns 1 character string,
instead of a fixnum. [Ruby2]
* string.c (rb_str_aset): no longer support fixnum insertion.
* eval.c (umethod_bind): should not update original class.
[ruby-dev:28636]
* eval.c (ev_const_get): should support constant access from
within instance_eval(). [ruby-dev:28327]
* time.c (time_timeval): should round for usec floating
number. [ruby-core:07896]
* time.c (time_add): ditto.
* dir.c (sys_warning): should not call a vararg function
rb_sys_warning() indirectly. [ruby-core:07886]
* numeric.c (flo_divmod): the first element of Float#divmod should
be an integer. [ruby-dev:28589]
* test/ruby/test_float.rb: add tests for divmod, div, modulo and remainder.
* re.c (rb_reg_initialize): should not allow modifying literal
regexps. frozen check moved from rb_reg_initialize_m as well.
* re.c (rb_reg_initialize): should not modify untainted objects in
safe levels higher than 3.
* re.c (rb_memcmp): type change from char* to const void*.
* dir.c (dir_close): should not close untainted dir stream.
* dir.c (GetDIR): add tainted/frozen check for each dir operation.
* lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_symbol_arg):
typo fixed. a patch from Florian Gross <florg at florg.net>.
* eval.c (EXEC_EVENT_HOOK): trace_func may remove itself from
event_hooks. no guarantee for arbitrary hook deletion.
[ruby-dev:28632]
* util.c (ruby_strtod): differ addition to minimize error.
[ruby-dev:28619]
* util.c (ruby_strtod): should not raise ERANGE when the input
string does not have any digits. [ruby-dev:28629]
* eval.c (proc_invoke): should restore old ruby_frame->block.
thanks to ts <decoux at moulon.inra.fr>. [ruby-core:07833]
also fix [ruby-dev:28614] as well.
* signal.c (trap): sig should be less then NSIG. Coverity found
this bug. a patch from Kevin Tew <tewk at tewk.com>.
[ruby-core:07823]
* math.c (math_log2): add new method inspired by
[ruby-talk:191237].
* math.c (math_log): add optional base argument to Math::log().
[ruby-talk:191308]
* ext/syck/emitter.c (syck_scan_scalar): avoid accessing
uninitialized array element. a patch from Pat Eyler
<rubypate at gmail.com>. [ruby-core:07809]
* array.c (rb_ary_fill): initialize local variables first. a
patch from Pat Eyler <rubypate at gmail.com>. [ruby-core:07810]
* ext/syck/yaml2byte.c (syck_yaml2byte_handler): need to free
type_tag. a patch from Pat Eyler <rubypate at gmail.com>.
[ruby-core:07808]
* ext/socket/socket.c (make_hostent_internal): accept ai_family
check from Sam Roberts <sroberts at uniserve.com>.
[ruby-core:07691]
* util.c (ruby_strtod): should not cut off 18 digits for no
reason. [ruby-core:07796]
* array.c (rb_ary_fill): internalize local variable "beg" to
pacify Coverity. [ruby-core:07770]
* pack.c (pack_unpack): now supports CRLF newlines. a patch from
<tommy at tmtm.org>. [ruby-dev:28601]
* applied code clean-up patch from Stefan Huehner
<stefan at huehner.org>. [ruby-core:07764]
* lib/jcode.rb (String::tr_s): should have translated non
squeezing character sequence (i.e. a character) as well. thanks
to Hiroshi Ichikawa <gimite at gimite.ddo.jp> [ruby-list:42090]
* ext/socket/socket.c: document update patch from Sam Roberts
<sroberts at uniserve.com>. [ruby-core:07701]
* lib/mathn.rb (Integer): need not to remove gcd2. a patch from
NARUSE, Yui <naruse at airemix.com>. [ruby-dev:28570]
* parse.y (arg): too much NEW_LIST()
* eval.c (SETUP_ARGS0): remove unnecessary access to nd_alen.
* eval.c (rb_eval): use ARGSCAT for NODE_OP_ASGN1.
[ruby-dev:28585]
* parse.y (arg): use NODE_ARGSCAT for placeholder.
* lib/getoptlong.rb (GetoptLong::get): RDoc update patch from
mathew <meta at pobox.com>. [ruby-core:07738]
* variable.c (rb_const_set): raise error when no target klass is
supplied. [ruby-dev:28582]
* prec.c (prec_prec_f): documentation patch from
<gerardo.santana at gmail.com>. [ruby-core:07689]
* bignum.c (rb_big_pow): second operand may be too big even if
it's a Fixnum. [ruby-talk:187984]
* README.EXT: update symbol description. [ruby-talk:188104]
* COPYING: explicitly note GPLv2. [ruby-talk:187922]
* parse.y: remove some obsolete syntax rules (unparenthesized
method calls in argument list).
* eval.c (rb_call0): insecure calling should be checked for non
NODE_SCOPE method invocations too.
* eval.c (rb_alias): should preserve the current safe level as
well as method definition.
* process.c (rb_f_sleep): remove RDoc description about SIGALRM
which is not valid on the current implementation. [ruby-dev:28464]
Thu Mar 23 21:40:47 2006 K.Kosako <sndgk393 AT ybb.ne.jp>
* eval.c (method_missing): should support argument splat in
super. a bug in combination of super, splat and
method_missing. [ruby-talk:185438]
* configure.in: Solaris SunPro compiler -rapth patch from
<kuwa at labs.fujitsu.com>. [ruby-dev:28443]
* configure.in: remove enable_rpath=no for Solaris.
[ruby-dev:28440]
* ext/win32ole/win32ole.c (ole_val2olevariantdata): change behavior
of converting OLE Variant object with VT_ARRAY|VT_UI1 and Ruby
String object.
* ruby.1: a clarification patch from David Lutterkort
<dlutter at redhat.com>. [ruby-core:7508]
* lib/rdoc/ri/ri_paths.rb (RI::Paths): adding paths from rubygems
directories. a patch from Eric Hodel <drbrain at segment7.net>.
[ruby-core:07423]
* eval.c (rb_clear_cache_by_class): clearing wrong cache.
* ext/extmk.rb: use :remove_destination to install extension libraries
to avoid SEGV. [ruby-dev:28417]
* eval.c (rb_thread_fd_writable): should not re-schedule output
from KILLED thread (must be error printing).
* array.c (rb_ary_flatten_bang): allow specifying recursion
level. [ruby-talk:182170]
* array.c (rb_ary_flatten): ditto.
* gc.c (add_heap): a heap_slots may overflow. a patch from Stefan
Weil <weil at mail.berlios.de>.
* eval.c (rb_call): use separate cache for fcall/vcall
invocation.
* eval.c (rb_eval): NODE_FCALL, NODE_VCALL can call local
functions.
* eval.c (rb_mod_local): a new method to specify newly added
visibility "local".
* eval.c (search_method): search for local methods which are
visible only from the current class.
* class.c (rb_class_local_methods): a method to list local methods.
* object.c (Init_Object): add BasicObject class as a top level
BlankSlate class.
* ruby.h (SYM2ID): should not cast to signed long.
[ruby-core:07414]
* class.c (rb_include_module): allow module duplication.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10235 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2006-06-10 01:20:17 +04:00
|
|
|
* a = [ 1, 2, [3, [4, 5] ] ]
|
|
|
|
* a.flatten!(1) #=> [1, 2, 3, [4, 5]]
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
* sprintf.c (rb_str_format): allow %c to print one character
string (e.g. ?x).
* lib/tempfile.rb (Tempfile::make_tmpname): put dot between
basename and pid. [ruby-talk:196272]
* parse.y (do_block): remove -> style block.
* parse.y (parser_yylex): remove tLAMBDA_ARG.
* eval.c (rb_call0): binding for the return event hook should have
consistent scope. [ruby-core:07928]
* eval.c (proc_invoke): return behavior should depend whether it
is surrounded by a lambda or a mere block.
* eval.c (formal_assign): handles post splat arguments.
* eval.c (rb_call0): ditto.
* st.c (strhash): use FNV-1a hash.
* parse.y (parser_yylex): removed experimental ';;' terminator.
* eval.c (rb_node_arity): should be aware of post splat arguments.
* eval.c (rb_proc_arity): ditto.
* parse.y (f_args): syntax rule enhanced to support arguments
after the splat.
* parse.y (block_param): ditto for block parameters.
* parse.y (f_post_arg): mandatory formal arguments after the splat
argument.
* parse.y (new_args_gen): generate nodes for mandatory formal
arguments after the splat argument.
* eval.c (rb_eval): dispatch mandatory formal arguments after the
splat argument.
* parse.y (args): allow more than one splat in the argument list.
* parse.y (method_call): allow aref [] to accept all kind of
method argument, including assocs, splat, and block argument.
* eval.c (SETUP_ARGS0): prepare block argument as well.
* lib/mathn.rb (Integer): remove Integer#gcd2. [ruby-core:07931]
* eval.c (error_line): print receivers true/false/nil specially.
* eval.c (rb_proc_yield): handles parameters in yield semantics.
* eval.c (nil_yield): gives LocalJumpError to denote no block
error.
* io.c (rb_io_getc): now takes one-character string.
* string.c (rb_str_hash): use FNV-1a hash from Fowler/Noll/Vo
hashing algorithm.
* string.c (rb_str_aref): str[0] now returns 1 character string,
instead of a fixnum. [Ruby2]
* parse.y (parser_yylex): ?c now returns 1 character string,
instead of a fixnum. [Ruby2]
* string.c (rb_str_aset): no longer support fixnum insertion.
* eval.c (umethod_bind): should not update original class.
[ruby-dev:28636]
* eval.c (ev_const_get): should support constant access from
within instance_eval(). [ruby-dev:28327]
* time.c (time_timeval): should round for usec floating
number. [ruby-core:07896]
* time.c (time_add): ditto.
* dir.c (sys_warning): should not call a vararg function
rb_sys_warning() indirectly. [ruby-core:07886]
* numeric.c (flo_divmod): the first element of Float#divmod should
be an integer. [ruby-dev:28589]
* test/ruby/test_float.rb: add tests for divmod, div, modulo and remainder.
* re.c (rb_reg_initialize): should not allow modifying literal
regexps. frozen check moved from rb_reg_initialize_m as well.
* re.c (rb_reg_initialize): should not modify untainted objects in
safe levels higher than 3.
* re.c (rb_memcmp): type change from char* to const void*.
* dir.c (dir_close): should not close untainted dir stream.
* dir.c (GetDIR): add tainted/frozen check for each dir operation.
* lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_symbol_arg):
typo fixed. a patch from Florian Gross <florg at florg.net>.
* eval.c (EXEC_EVENT_HOOK): trace_func may remove itself from
event_hooks. no guarantee for arbitrary hook deletion.
[ruby-dev:28632]
* util.c (ruby_strtod): differ addition to minimize error.
[ruby-dev:28619]
* util.c (ruby_strtod): should not raise ERANGE when the input
string does not have any digits. [ruby-dev:28629]
* eval.c (proc_invoke): should restore old ruby_frame->block.
thanks to ts <decoux at moulon.inra.fr>. [ruby-core:07833]
also fix [ruby-dev:28614] as well.
* signal.c (trap): sig should be less then NSIG. Coverity found
this bug. a patch from Kevin Tew <tewk at tewk.com>.
[ruby-core:07823]
* math.c (math_log2): add new method inspired by
[ruby-talk:191237].
* math.c (math_log): add optional base argument to Math::log().
[ruby-talk:191308]
* ext/syck/emitter.c (syck_scan_scalar): avoid accessing
uninitialized array element. a patch from Pat Eyler
<rubypate at gmail.com>. [ruby-core:07809]
* array.c (rb_ary_fill): initialize local variables first. a
patch from Pat Eyler <rubypate at gmail.com>. [ruby-core:07810]
* ext/syck/yaml2byte.c (syck_yaml2byte_handler): need to free
type_tag. a patch from Pat Eyler <rubypate at gmail.com>.
[ruby-core:07808]
* ext/socket/socket.c (make_hostent_internal): accept ai_family
check from Sam Roberts <sroberts at uniserve.com>.
[ruby-core:07691]
* util.c (ruby_strtod): should not cut off 18 digits for no
reason. [ruby-core:07796]
* array.c (rb_ary_fill): internalize local variable "beg" to
pacify Coverity. [ruby-core:07770]
* pack.c (pack_unpack): now supports CRLF newlines. a patch from
<tommy at tmtm.org>. [ruby-dev:28601]
* applied code clean-up patch from Stefan Huehner
<stefan at huehner.org>. [ruby-core:07764]
* lib/jcode.rb (String::tr_s): should have translated non
squeezing character sequence (i.e. a character) as well. thanks
to Hiroshi Ichikawa <gimite at gimite.ddo.jp> [ruby-list:42090]
* ext/socket/socket.c: document update patch from Sam Roberts
<sroberts at uniserve.com>. [ruby-core:07701]
* lib/mathn.rb (Integer): need not to remove gcd2. a patch from
NARUSE, Yui <naruse at airemix.com>. [ruby-dev:28570]
* parse.y (arg): too much NEW_LIST()
* eval.c (SETUP_ARGS0): remove unnecessary access to nd_alen.
* eval.c (rb_eval): use ARGSCAT for NODE_OP_ASGN1.
[ruby-dev:28585]
* parse.y (arg): use NODE_ARGSCAT for placeholder.
* lib/getoptlong.rb (GetoptLong::get): RDoc update patch from
mathew <meta at pobox.com>. [ruby-core:07738]
* variable.c (rb_const_set): raise error when no target klass is
supplied. [ruby-dev:28582]
* prec.c (prec_prec_f): documentation patch from
<gerardo.santana at gmail.com>. [ruby-core:07689]
* bignum.c (rb_big_pow): second operand may be too big even if
it's a Fixnum. [ruby-talk:187984]
* README.EXT: update symbol description. [ruby-talk:188104]
* COPYING: explicitly note GPLv2. [ruby-talk:187922]
* parse.y: remove some obsolete syntax rules (unparenthesized
method calls in argument list).
* eval.c (rb_call0): insecure calling should be checked for non
NODE_SCOPE method invocations too.
* eval.c (rb_alias): should preserve the current safe level as
well as method definition.
* process.c (rb_f_sleep): remove RDoc description about SIGALRM
which is not valid on the current implementation. [ruby-dev:28464]
Thu Mar 23 21:40:47 2006 K.Kosako <sndgk393 AT ybb.ne.jp>
* eval.c (method_missing): should support argument splat in
super. a bug in combination of super, splat and
method_missing. [ruby-talk:185438]
* configure.in: Solaris SunPro compiler -rapth patch from
<kuwa at labs.fujitsu.com>. [ruby-dev:28443]
* configure.in: remove enable_rpath=no for Solaris.
[ruby-dev:28440]
* ext/win32ole/win32ole.c (ole_val2olevariantdata): change behavior
of converting OLE Variant object with VT_ARRAY|VT_UI1 and Ruby
String object.
* ruby.1: a clarification patch from David Lutterkort
<dlutter at redhat.com>. [ruby-core:7508]
* lib/rdoc/ri/ri_paths.rb (RI::Paths): adding paths from rubygems
directories. a patch from Eric Hodel <drbrain at segment7.net>.
[ruby-core:07423]
* eval.c (rb_clear_cache_by_class): clearing wrong cache.
* ext/extmk.rb: use :remove_destination to install extension libraries
to avoid SEGV. [ruby-dev:28417]
* eval.c (rb_thread_fd_writable): should not re-schedule output
from KILLED thread (must be error printing).
* array.c (rb_ary_flatten_bang): allow specifying recursion
level. [ruby-talk:182170]
* array.c (rb_ary_flatten): ditto.
* gc.c (add_heap): a heap_slots may overflow. a patch from Stefan
Weil <weil at mail.berlios.de>.
* eval.c (rb_call): use separate cache for fcall/vcall
invocation.
* eval.c (rb_eval): NODE_FCALL, NODE_VCALL can call local
functions.
* eval.c (rb_mod_local): a new method to specify newly added
visibility "local".
* eval.c (search_method): search for local methods which are
visible only from the current class.
* class.c (rb_class_local_methods): a method to list local methods.
* object.c (Init_Object): add BasicObject class as a top level
BlankSlate class.
* ruby.h (SYM2ID): should not cast to signed long.
[ruby-core:07414]
* class.c (rb_include_module): allow module duplication.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10235 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2006-06-10 01:20:17 +04:00
|
|
|
rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2007-12-07 06:27:20 +03:00
|
|
|
int mod = 0, level = -1;
|
|
|
|
VALUE result, lv;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2018-12-05 04:09:44 +03:00
|
|
|
lv = (rb_check_arity(argc, 0, 1) ? argv[0] : Qnil);
|
2010-02-10 10:31:06 +03:00
|
|
|
rb_ary_modify_check(ary);
|
2007-07-13 05:33:31 +04:00
|
|
|
if (!NIL_P(lv)) level = NUM2INT(lv);
|
2009-05-07 11:40:11 +04:00
|
|
|
if (level == 0) return Qnil;
|
2007-12-07 06:27:20 +03:00
|
|
|
|
2019-09-27 19:24:25 +03:00
|
|
|
result = flatten(ary, level);
|
|
|
|
if (result == ary) {
|
2009-05-08 05:07:03 +04:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
if (!(mod = ARY_EMBED_P(result))) rb_obj_freeze(result);
|
2007-12-07 06:27:20 +03:00
|
|
|
rb_ary_replace(ary, result);
|
2009-05-08 05:07:03 +04:00
|
|
|
if (mod) ARY_SET_EMBED_LEN(result, 0);
|
2007-12-07 06:27:20 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
return ary;
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2003-12-16 23:28:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary.flatten -> new_ary
|
|
|
|
* ary.flatten(level) -> new_ary
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Returns a new array that is a one-dimensional flattening of +self+
|
|
|
|
* (recursively).
|
|
|
|
*
|
|
|
|
* That is, for every element that is an array, extract its elements into
|
|
|
|
* the new array.
|
|
|
|
*
|
|
|
|
* The optional +level+ argument determines the level of recursion to
|
|
|
|
* flatten.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-16 23:28:44 +03:00
|
|
|
* s = [ 1, 2, 3 ] #=> [1, 2, 3]
|
|
|
|
* t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]]
|
|
|
|
* a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
|
2008-03-07 13:18:18 +03:00
|
|
|
* a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
* sprintf.c (rb_str_format): allow %c to print one character
string (e.g. ?x).
* lib/tempfile.rb (Tempfile::make_tmpname): put dot between
basename and pid. [ruby-talk:196272]
* parse.y (do_block): remove -> style block.
* parse.y (parser_yylex): remove tLAMBDA_ARG.
* eval.c (rb_call0): binding for the return event hook should have
consistent scope. [ruby-core:07928]
* eval.c (proc_invoke): return behavior should depend whether it
is surrounded by a lambda or a mere block.
* eval.c (formal_assign): handles post splat arguments.
* eval.c (rb_call0): ditto.
* st.c (strhash): use FNV-1a hash.
* parse.y (parser_yylex): removed experimental ';;' terminator.
* eval.c (rb_node_arity): should be aware of post splat arguments.
* eval.c (rb_proc_arity): ditto.
* parse.y (f_args): syntax rule enhanced to support arguments
after the splat.
* parse.y (block_param): ditto for block parameters.
* parse.y (f_post_arg): mandatory formal arguments after the splat
argument.
* parse.y (new_args_gen): generate nodes for mandatory formal
arguments after the splat argument.
* eval.c (rb_eval): dispatch mandatory formal arguments after the
splat argument.
* parse.y (args): allow more than one splat in the argument list.
* parse.y (method_call): allow aref [] to accept all kind of
method argument, including assocs, splat, and block argument.
* eval.c (SETUP_ARGS0): prepare block argument as well.
* lib/mathn.rb (Integer): remove Integer#gcd2. [ruby-core:07931]
* eval.c (error_line): print receivers true/false/nil specially.
* eval.c (rb_proc_yield): handles parameters in yield semantics.
* eval.c (nil_yield): gives LocalJumpError to denote no block
error.
* io.c (rb_io_getc): now takes one-character string.
* string.c (rb_str_hash): use FNV-1a hash from Fowler/Noll/Vo
hashing algorithm.
* string.c (rb_str_aref): str[0] now returns 1 character string,
instead of a fixnum. [Ruby2]
* parse.y (parser_yylex): ?c now returns 1 character string,
instead of a fixnum. [Ruby2]
* string.c (rb_str_aset): no longer support fixnum insertion.
* eval.c (umethod_bind): should not update original class.
[ruby-dev:28636]
* eval.c (ev_const_get): should support constant access from
within instance_eval(). [ruby-dev:28327]
* time.c (time_timeval): should round for usec floating
number. [ruby-core:07896]
* time.c (time_add): ditto.
* dir.c (sys_warning): should not call a vararg function
rb_sys_warning() indirectly. [ruby-core:07886]
* numeric.c (flo_divmod): the first element of Float#divmod should
be an integer. [ruby-dev:28589]
* test/ruby/test_float.rb: add tests for divmod, div, modulo and remainder.
* re.c (rb_reg_initialize): should not allow modifying literal
regexps. frozen check moved from rb_reg_initialize_m as well.
* re.c (rb_reg_initialize): should not modify untainted objects in
safe levels higher than 3.
* re.c (rb_memcmp): type change from char* to const void*.
* dir.c (dir_close): should not close untainted dir stream.
* dir.c (GetDIR): add tainted/frozen check for each dir operation.
* lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_symbol_arg):
typo fixed. a patch from Florian Gross <florg at florg.net>.
* eval.c (EXEC_EVENT_HOOK): trace_func may remove itself from
event_hooks. no guarantee for arbitrary hook deletion.
[ruby-dev:28632]
* util.c (ruby_strtod): differ addition to minimize error.
[ruby-dev:28619]
* util.c (ruby_strtod): should not raise ERANGE when the input
string does not have any digits. [ruby-dev:28629]
* eval.c (proc_invoke): should restore old ruby_frame->block.
thanks to ts <decoux at moulon.inra.fr>. [ruby-core:07833]
also fix [ruby-dev:28614] as well.
* signal.c (trap): sig should be less then NSIG. Coverity found
this bug. a patch from Kevin Tew <tewk at tewk.com>.
[ruby-core:07823]
* math.c (math_log2): add new method inspired by
[ruby-talk:191237].
* math.c (math_log): add optional base argument to Math::log().
[ruby-talk:191308]
* ext/syck/emitter.c (syck_scan_scalar): avoid accessing
uninitialized array element. a patch from Pat Eyler
<rubypate at gmail.com>. [ruby-core:07809]
* array.c (rb_ary_fill): initialize local variables first. a
patch from Pat Eyler <rubypate at gmail.com>. [ruby-core:07810]
* ext/syck/yaml2byte.c (syck_yaml2byte_handler): need to free
type_tag. a patch from Pat Eyler <rubypate at gmail.com>.
[ruby-core:07808]
* ext/socket/socket.c (make_hostent_internal): accept ai_family
check from Sam Roberts <sroberts at uniserve.com>.
[ruby-core:07691]
* util.c (ruby_strtod): should not cut off 18 digits for no
reason. [ruby-core:07796]
* array.c (rb_ary_fill): internalize local variable "beg" to
pacify Coverity. [ruby-core:07770]
* pack.c (pack_unpack): now supports CRLF newlines. a patch from
<tommy at tmtm.org>. [ruby-dev:28601]
* applied code clean-up patch from Stefan Huehner
<stefan at huehner.org>. [ruby-core:07764]
* lib/jcode.rb (String::tr_s): should have translated non
squeezing character sequence (i.e. a character) as well. thanks
to Hiroshi Ichikawa <gimite at gimite.ddo.jp> [ruby-list:42090]
* ext/socket/socket.c: document update patch from Sam Roberts
<sroberts at uniserve.com>. [ruby-core:07701]
* lib/mathn.rb (Integer): need not to remove gcd2. a patch from
NARUSE, Yui <naruse at airemix.com>. [ruby-dev:28570]
* parse.y (arg): too much NEW_LIST()
* eval.c (SETUP_ARGS0): remove unnecessary access to nd_alen.
* eval.c (rb_eval): use ARGSCAT for NODE_OP_ASGN1.
[ruby-dev:28585]
* parse.y (arg): use NODE_ARGSCAT for placeholder.
* lib/getoptlong.rb (GetoptLong::get): RDoc update patch from
mathew <meta at pobox.com>. [ruby-core:07738]
* variable.c (rb_const_set): raise error when no target klass is
supplied. [ruby-dev:28582]
* prec.c (prec_prec_f): documentation patch from
<gerardo.santana at gmail.com>. [ruby-core:07689]
* bignum.c (rb_big_pow): second operand may be too big even if
it's a Fixnum. [ruby-talk:187984]
* README.EXT: update symbol description. [ruby-talk:188104]
* COPYING: explicitly note GPLv2. [ruby-talk:187922]
* parse.y: remove some obsolete syntax rules (unparenthesized
method calls in argument list).
* eval.c (rb_call0): insecure calling should be checked for non
NODE_SCOPE method invocations too.
* eval.c (rb_alias): should preserve the current safe level as
well as method definition.
* process.c (rb_f_sleep): remove RDoc description about SIGALRM
which is not valid on the current implementation. [ruby-dev:28464]
Thu Mar 23 21:40:47 2006 K.Kosako <sndgk393 AT ybb.ne.jp>
* eval.c (method_missing): should support argument splat in
super. a bug in combination of super, splat and
method_missing. [ruby-talk:185438]
* configure.in: Solaris SunPro compiler -rapth patch from
<kuwa at labs.fujitsu.com>. [ruby-dev:28443]
* configure.in: remove enable_rpath=no for Solaris.
[ruby-dev:28440]
* ext/win32ole/win32ole.c (ole_val2olevariantdata): change behavior
of converting OLE Variant object with VT_ARRAY|VT_UI1 and Ruby
String object.
* ruby.1: a clarification patch from David Lutterkort
<dlutter at redhat.com>. [ruby-core:7508]
* lib/rdoc/ri/ri_paths.rb (RI::Paths): adding paths from rubygems
directories. a patch from Eric Hodel <drbrain at segment7.net>.
[ruby-core:07423]
* eval.c (rb_clear_cache_by_class): clearing wrong cache.
* ext/extmk.rb: use :remove_destination to install extension libraries
to avoid SEGV. [ruby-dev:28417]
* eval.c (rb_thread_fd_writable): should not re-schedule output
from KILLED thread (must be error printing).
* array.c (rb_ary_flatten_bang): allow specifying recursion
level. [ruby-talk:182170]
* array.c (rb_ary_flatten): ditto.
* gc.c (add_heap): a heap_slots may overflow. a patch from Stefan
Weil <weil at mail.berlios.de>.
* eval.c (rb_call): use separate cache for fcall/vcall
invocation.
* eval.c (rb_eval): NODE_FCALL, NODE_VCALL can call local
functions.
* eval.c (rb_mod_local): a new method to specify newly added
visibility "local".
* eval.c (search_method): search for local methods which are
visible only from the current class.
* class.c (rb_class_local_methods): a method to list local methods.
* object.c (Init_Object): add BasicObject class as a top level
BlankSlate class.
* ruby.h (SYM2ID): should not cast to signed long.
[ruby-core:07414]
* class.c (rb_include_module): allow module duplication.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10235 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2006-06-10 01:20:17 +04:00
|
|
|
* a = [ 1, 2, [3, [4, 5] ] ]
|
|
|
|
* a.flatten(1) #=> [1, 2, 3, [4, 5]]
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
* sprintf.c (rb_str_format): allow %c to print one character
string (e.g. ?x).
* lib/tempfile.rb (Tempfile::make_tmpname): put dot between
basename and pid. [ruby-talk:196272]
* parse.y (do_block): remove -> style block.
* parse.y (parser_yylex): remove tLAMBDA_ARG.
* eval.c (rb_call0): binding for the return event hook should have
consistent scope. [ruby-core:07928]
* eval.c (proc_invoke): return behavior should depend whether it
is surrounded by a lambda or a mere block.
* eval.c (formal_assign): handles post splat arguments.
* eval.c (rb_call0): ditto.
* st.c (strhash): use FNV-1a hash.
* parse.y (parser_yylex): removed experimental ';;' terminator.
* eval.c (rb_node_arity): should be aware of post splat arguments.
* eval.c (rb_proc_arity): ditto.
* parse.y (f_args): syntax rule enhanced to support arguments
after the splat.
* parse.y (block_param): ditto for block parameters.
* parse.y (f_post_arg): mandatory formal arguments after the splat
argument.
* parse.y (new_args_gen): generate nodes for mandatory formal
arguments after the splat argument.
* eval.c (rb_eval): dispatch mandatory formal arguments after the
splat argument.
* parse.y (args): allow more than one splat in the argument list.
* parse.y (method_call): allow aref [] to accept all kind of
method argument, including assocs, splat, and block argument.
* eval.c (SETUP_ARGS0): prepare block argument as well.
* lib/mathn.rb (Integer): remove Integer#gcd2. [ruby-core:07931]
* eval.c (error_line): print receivers true/false/nil specially.
* eval.c (rb_proc_yield): handles parameters in yield semantics.
* eval.c (nil_yield): gives LocalJumpError to denote no block
error.
* io.c (rb_io_getc): now takes one-character string.
* string.c (rb_str_hash): use FNV-1a hash from Fowler/Noll/Vo
hashing algorithm.
* string.c (rb_str_aref): str[0] now returns 1 character string,
instead of a fixnum. [Ruby2]
* parse.y (parser_yylex): ?c now returns 1 character string,
instead of a fixnum. [Ruby2]
* string.c (rb_str_aset): no longer support fixnum insertion.
* eval.c (umethod_bind): should not update original class.
[ruby-dev:28636]
* eval.c (ev_const_get): should support constant access from
within instance_eval(). [ruby-dev:28327]
* time.c (time_timeval): should round for usec floating
number. [ruby-core:07896]
* time.c (time_add): ditto.
* dir.c (sys_warning): should not call a vararg function
rb_sys_warning() indirectly. [ruby-core:07886]
* numeric.c (flo_divmod): the first element of Float#divmod should
be an integer. [ruby-dev:28589]
* test/ruby/test_float.rb: add tests for divmod, div, modulo and remainder.
* re.c (rb_reg_initialize): should not allow modifying literal
regexps. frozen check moved from rb_reg_initialize_m as well.
* re.c (rb_reg_initialize): should not modify untainted objects in
safe levels higher than 3.
* re.c (rb_memcmp): type change from char* to const void*.
* dir.c (dir_close): should not close untainted dir stream.
* dir.c (GetDIR): add tainted/frozen check for each dir operation.
* lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_symbol_arg):
typo fixed. a patch from Florian Gross <florg at florg.net>.
* eval.c (EXEC_EVENT_HOOK): trace_func may remove itself from
event_hooks. no guarantee for arbitrary hook deletion.
[ruby-dev:28632]
* util.c (ruby_strtod): differ addition to minimize error.
[ruby-dev:28619]
* util.c (ruby_strtod): should not raise ERANGE when the input
string does not have any digits. [ruby-dev:28629]
* eval.c (proc_invoke): should restore old ruby_frame->block.
thanks to ts <decoux at moulon.inra.fr>. [ruby-core:07833]
also fix [ruby-dev:28614] as well.
* signal.c (trap): sig should be less then NSIG. Coverity found
this bug. a patch from Kevin Tew <tewk at tewk.com>.
[ruby-core:07823]
* math.c (math_log2): add new method inspired by
[ruby-talk:191237].
* math.c (math_log): add optional base argument to Math::log().
[ruby-talk:191308]
* ext/syck/emitter.c (syck_scan_scalar): avoid accessing
uninitialized array element. a patch from Pat Eyler
<rubypate at gmail.com>. [ruby-core:07809]
* array.c (rb_ary_fill): initialize local variables first. a
patch from Pat Eyler <rubypate at gmail.com>. [ruby-core:07810]
* ext/syck/yaml2byte.c (syck_yaml2byte_handler): need to free
type_tag. a patch from Pat Eyler <rubypate at gmail.com>.
[ruby-core:07808]
* ext/socket/socket.c (make_hostent_internal): accept ai_family
check from Sam Roberts <sroberts at uniserve.com>.
[ruby-core:07691]
* util.c (ruby_strtod): should not cut off 18 digits for no
reason. [ruby-core:07796]
* array.c (rb_ary_fill): internalize local variable "beg" to
pacify Coverity. [ruby-core:07770]
* pack.c (pack_unpack): now supports CRLF newlines. a patch from
<tommy at tmtm.org>. [ruby-dev:28601]
* applied code clean-up patch from Stefan Huehner
<stefan at huehner.org>. [ruby-core:07764]
* lib/jcode.rb (String::tr_s): should have translated non
squeezing character sequence (i.e. a character) as well. thanks
to Hiroshi Ichikawa <gimite at gimite.ddo.jp> [ruby-list:42090]
* ext/socket/socket.c: document update patch from Sam Roberts
<sroberts at uniserve.com>. [ruby-core:07701]
* lib/mathn.rb (Integer): need not to remove gcd2. a patch from
NARUSE, Yui <naruse at airemix.com>. [ruby-dev:28570]
* parse.y (arg): too much NEW_LIST()
* eval.c (SETUP_ARGS0): remove unnecessary access to nd_alen.
* eval.c (rb_eval): use ARGSCAT for NODE_OP_ASGN1.
[ruby-dev:28585]
* parse.y (arg): use NODE_ARGSCAT for placeholder.
* lib/getoptlong.rb (GetoptLong::get): RDoc update patch from
mathew <meta at pobox.com>. [ruby-core:07738]
* variable.c (rb_const_set): raise error when no target klass is
supplied. [ruby-dev:28582]
* prec.c (prec_prec_f): documentation patch from
<gerardo.santana at gmail.com>. [ruby-core:07689]
* bignum.c (rb_big_pow): second operand may be too big even if
it's a Fixnum. [ruby-talk:187984]
* README.EXT: update symbol description. [ruby-talk:188104]
* COPYING: explicitly note GPLv2. [ruby-talk:187922]
* parse.y: remove some obsolete syntax rules (unparenthesized
method calls in argument list).
* eval.c (rb_call0): insecure calling should be checked for non
NODE_SCOPE method invocations too.
* eval.c (rb_alias): should preserve the current safe level as
well as method definition.
* process.c (rb_f_sleep): remove RDoc description about SIGALRM
which is not valid on the current implementation. [ruby-dev:28464]
Thu Mar 23 21:40:47 2006 K.Kosako <sndgk393 AT ybb.ne.jp>
* eval.c (method_missing): should support argument splat in
super. a bug in combination of super, splat and
method_missing. [ruby-talk:185438]
* configure.in: Solaris SunPro compiler -rapth patch from
<kuwa at labs.fujitsu.com>. [ruby-dev:28443]
* configure.in: remove enable_rpath=no for Solaris.
[ruby-dev:28440]
* ext/win32ole/win32ole.c (ole_val2olevariantdata): change behavior
of converting OLE Variant object with VT_ARRAY|VT_UI1 and Ruby
String object.
* ruby.1: a clarification patch from David Lutterkort
<dlutter at redhat.com>. [ruby-core:7508]
* lib/rdoc/ri/ri_paths.rb (RI::Paths): adding paths from rubygems
directories. a patch from Eric Hodel <drbrain at segment7.net>.
[ruby-core:07423]
* eval.c (rb_clear_cache_by_class): clearing wrong cache.
* ext/extmk.rb: use :remove_destination to install extension libraries
to avoid SEGV. [ruby-dev:28417]
* eval.c (rb_thread_fd_writable): should not re-schedule output
from KILLED thread (must be error printing).
* array.c (rb_ary_flatten_bang): allow specifying recursion
level. [ruby-talk:182170]
* array.c (rb_ary_flatten): ditto.
* gc.c (add_heap): a heap_slots may overflow. a patch from Stefan
Weil <weil at mail.berlios.de>.
* eval.c (rb_call): use separate cache for fcall/vcall
invocation.
* eval.c (rb_eval): NODE_FCALL, NODE_VCALL can call local
functions.
* eval.c (rb_mod_local): a new method to specify newly added
visibility "local".
* eval.c (search_method): search for local methods which are
visible only from the current class.
* class.c (rb_class_local_methods): a method to list local methods.
* object.c (Init_Object): add BasicObject class as a top level
BlankSlate class.
* ruby.h (SYM2ID): should not cast to signed long.
[ruby-core:07414]
* class.c (rb_include_module): allow module duplication.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10235 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2006-06-10 01:20:17 +04:00
|
|
|
rb_ary_flatten(int argc, VALUE *argv, VALUE ary)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2019-09-27 19:24:25 +03:00
|
|
|
int level = -1;
|
2018-12-05 04:09:44 +03:00
|
|
|
VALUE result;
|
2007-12-07 06:27:20 +03:00
|
|
|
|
2018-12-05 04:09:44 +03:00
|
|
|
if (rb_check_arity(argc, 0, 1) && !NIL_P(argv[0])) {
|
|
|
|
level = NUM2INT(argv[0]);
|
|
|
|
if (level == 0) return ary_make_shared_copy(ary);
|
|
|
|
}
|
2007-12-07 06:27:20 +03:00
|
|
|
|
2019-09-27 19:24:25 +03:00
|
|
|
result = flatten(ary, level);
|
|
|
|
if (result == ary) {
|
|
|
|
result = ary_make_shared_copy(ary);
|
|
|
|
}
|
2007-12-07 06:27:20 +03:00
|
|
|
|
|
|
|
return result;
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2012-10-09 13:01:40 +04:00
|
|
|
#define RAND_UPTO(max) (long)rb_random_ulong_limited((randgen), (max)-1)
|
2010-08-22 01:46:31 +04:00
|
|
|
|
2006-08-31 12:24:36 +04:00
|
|
|
static VALUE
|
2020-01-26 12:27:40 +03:00
|
|
|
rb_ary_shuffle_bang(rb_execution_context_t *ec, VALUE ary, VALUE randgen)
|
2006-08-31 12:24:36 +04:00
|
|
|
{
|
2013-11-07 06:08:36 +04:00
|
|
|
long i, len;
|
2006-08-31 12:24:36 +04:00
|
|
|
|
* array.c (ary_iter_check): should check modification (size
change) during iteration.
* array.c (rb_ary_initialize, rb_ary_shift, rb_ary_unshift,
rb_ary_splice, rb_ary_reverse, rb_ary_sort, rb_ary_delete,
rb_ary_delete_at, rb_ary_reject_bang, rb_ary_replace,
rb_ary_clear, rb_ary_fill, rb_ary_uniq_bang, rb_ary_compact,
rb_ary_shuffle): add iteration check.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11429 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2006-12-29 22:25:11 +03:00
|
|
|
rb_ary_modify(ary);
|
2013-11-07 06:08:36 +04:00
|
|
|
i = len = RARRAY_LEN(ary);
|
|
|
|
RARRAY_PTR_USE(ary, ptr, {
|
|
|
|
while (i) {
|
|
|
|
long j = RAND_UPTO(i);
|
|
|
|
VALUE tmp;
|
2018-10-31 00:54:13 +03:00
|
|
|
if (len != RARRAY_LEN(ary) || ptr != RARRAY_CONST_PTR_TRANSIENT(ary)) {
|
2018-10-31 00:02:12 +03:00
|
|
|
rb_raise(rb_eRuntimeError, "modified during shuffle");
|
2013-11-07 06:08:36 +04:00
|
|
|
}
|
|
|
|
tmp = ptr[--i];
|
|
|
|
ptr[i] = ptr[j];
|
|
|
|
ptr[j] = tmp;
|
2010-08-27 02:57:39 +04:00
|
|
|
}
|
2013-11-07 06:08:36 +04:00
|
|
|
}); /* WB: no new reference */
|
2006-08-31 12:24:36 +04:00
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2020-01-26 12:27:40 +03:00
|
|
|
rb_ary_shuffle(rb_execution_context_t *ec, VALUE ary, VALUE randgen)
|
2006-08-31 12:24:36 +04:00
|
|
|
{
|
|
|
|
ary = rb_ary_dup(ary);
|
2020-01-26 12:27:40 +03:00
|
|
|
rb_ary_shuffle_bang(ec, ary, randgen);
|
2006-08-31 12:24:36 +04:00
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2007-05-01 12:45:28 +04:00
|
|
|
static VALUE
|
2020-01-26 12:34:18 +03:00
|
|
|
rb_ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE to_array)
|
2007-05-01 12:45:28 +04:00
|
|
|
{
|
2020-01-26 12:34:18 +03:00
|
|
|
VALUE result;
|
2008-08-20 11:40:03 +04:00
|
|
|
long n, len, i, j, k, idx[10];
|
2012-10-09 13:01:40 +04:00
|
|
|
long rnds[numberof(idx)];
|
2017-01-20 05:39:27 +03:00
|
|
|
long memo_threshold;
|
2007-05-01 12:45:28 +04:00
|
|
|
|
2010-08-27 02:57:39 +04:00
|
|
|
len = RARRAY_LEN(ary);
|
2020-01-26 12:34:18 +03:00
|
|
|
if (!to_array) {
|
2013-11-06 06:50:28 +04:00
|
|
|
if (len < 2)
|
2010-08-27 02:57:39 +04:00
|
|
|
i = 0;
|
2013-11-06 06:50:28 +04:00
|
|
|
else
|
2012-10-09 13:01:40 +04:00
|
|
|
i = RAND_UPTO(len);
|
2013-11-06 06:50:28 +04:00
|
|
|
|
|
|
|
return rb_ary_elt(ary, i);
|
2008-08-11 14:00:47 +04:00
|
|
|
}
|
2008-08-20 11:40:03 +04:00
|
|
|
n = NUM2LONG(nv);
|
2009-05-07 09:26:16 +04:00
|
|
|
if (n < 0) rb_raise(rb_eArgError, "negative sample number");
|
2010-08-27 02:57:39 +04:00
|
|
|
if (n > len) n = len;
|
|
|
|
if (n <= numberof(idx)) {
|
|
|
|
for (i = 0; i < n; ++i) {
|
2012-10-09 13:01:40 +04:00
|
|
|
rnds[i] = RAND_UPTO(len - i);
|
2010-08-27 02:57:39 +04:00
|
|
|
}
|
|
|
|
}
|
2012-10-09 13:01:40 +04:00
|
|
|
k = len;
|
2009-02-22 17:23:33 +03:00
|
|
|
len = RARRAY_LEN(ary);
|
2013-11-06 06:50:28 +04:00
|
|
|
if (len < k && n <= numberof(idx)) {
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
|
|
if (rnds[i] >= len) return rb_ary_new_capa(0);
|
2012-10-09 13:01:40 +04:00
|
|
|
}
|
|
|
|
}
|
2008-08-20 07:28:34 +04:00
|
|
|
if (n > len) n = len;
|
2008-08-20 11:40:03 +04:00
|
|
|
switch (n) {
|
2010-08-27 02:57:39 +04:00
|
|
|
case 0:
|
2013-11-06 06:50:28 +04:00
|
|
|
return rb_ary_new_capa(0);
|
2008-08-20 11:40:03 +04:00
|
|
|
case 1:
|
2012-10-09 13:01:40 +04:00
|
|
|
i = rnds[0];
|
2013-11-06 06:50:28 +04:00
|
|
|
return rb_ary_new_from_values(1, &RARRAY_AREF(ary, i));
|
2008-08-20 11:40:03 +04:00
|
|
|
case 2:
|
2012-10-09 13:01:40 +04:00
|
|
|
i = rnds[0];
|
|
|
|
j = rnds[1];
|
2008-10-24 19:14:44 +04:00
|
|
|
if (j >= i) j++;
|
2013-11-06 06:50:28 +04:00
|
|
|
return rb_ary_new_from_args(2, RARRAY_AREF(ary, i), RARRAY_AREF(ary, j));
|
2008-08-20 11:40:03 +04:00
|
|
|
case 3:
|
2012-10-09 13:01:40 +04:00
|
|
|
i = rnds[0];
|
|
|
|
j = rnds[1];
|
|
|
|
k = rnds[2];
|
2008-10-24 19:14:44 +04:00
|
|
|
{
|
|
|
|
long l = j, g = i;
|
|
|
|
if (j >= i) l = i, g = ++j;
|
|
|
|
if (k >= l && (++k >= g)) ++k;
|
|
|
|
}
|
2013-11-06 06:50:28 +04:00
|
|
|
return rb_ary_new_from_args(3, RARRAY_AREF(ary, i), RARRAY_AREF(ary, j), RARRAY_AREF(ary, k));
|
2008-08-20 11:40:03 +04:00
|
|
|
}
|
2017-01-20 05:39:27 +03:00
|
|
|
memo_threshold =
|
|
|
|
len < 2560 ? len / 128 :
|
|
|
|
len < 5120 ? len / 64 :
|
|
|
|
len < 10240 ? len / 32 :
|
|
|
|
len / 16;
|
2010-08-27 02:57:39 +04:00
|
|
|
if (n <= numberof(idx)) {
|
|
|
|
long sorted[numberof(idx)];
|
2012-10-09 13:01:40 +04:00
|
|
|
sorted[0] = idx[0] = rnds[0];
|
2008-08-20 11:40:03 +04:00
|
|
|
for (i=1; i<n; i++) {
|
2012-10-09 13:01:40 +04:00
|
|
|
k = rnds[i];
|
2008-10-24 19:14:44 +04:00
|
|
|
for (j = 0; j < i; ++j) {
|
|
|
|
if (k < sorted[j]) break;
|
|
|
|
++k;
|
|
|
|
}
|
|
|
|
memmove(&sorted[j+1], &sorted[j], sizeof(sorted[0])*(i-j));
|
|
|
|
sorted[j] = idx[i] = k;
|
2008-08-20 11:40:03 +04:00
|
|
|
}
|
2013-11-06 06:50:28 +04:00
|
|
|
result = rb_ary_new_capa(n);
|
2018-12-03 15:36:39 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(result, ptr_result, {
|
2013-11-06 06:50:28 +04:00
|
|
|
for (i=0; i<n; i++) {
|
|
|
|
ptr_result[i] = RARRAY_AREF(ary, idx[i]);
|
|
|
|
}
|
|
|
|
});
|
2008-08-11 14:00:47 +04:00
|
|
|
}
|
2017-01-20 05:39:27 +03:00
|
|
|
else if (n <= memo_threshold / 2) {
|
|
|
|
long max_idx = 0;
|
|
|
|
#undef RUBY_UNTYPED_DATA_WARNING
|
|
|
|
#define RUBY_UNTYPED_DATA_WARNING 0
|
2018-01-02 09:41:57 +03:00
|
|
|
VALUE vmemo = Data_Wrap_Struct(0, 0, st_free_table, 0);
|
2017-01-20 05:39:27 +03:00
|
|
|
st_table *memo = st_init_numtable_with_size(n);
|
|
|
|
DATA_PTR(vmemo) = memo;
|
|
|
|
result = rb_ary_new_capa(n);
|
|
|
|
RARRAY_PTR_USE(result, ptr_result, {
|
|
|
|
for (i=0; i<n; i++) {
|
|
|
|
long r = RAND_UPTO(len-i) + i;
|
|
|
|
ptr_result[i] = r;
|
|
|
|
if (r > max_idx) max_idx = r;
|
|
|
|
}
|
|
|
|
len = RARRAY_LEN(ary);
|
|
|
|
if (len <= max_idx) n = 0;
|
|
|
|
else if (n > len) n = len;
|
2018-12-03 15:36:39 +03:00
|
|
|
RARRAY_PTR_USE_TRANSIENT(ary, ptr_ary, {
|
2017-01-20 05:39:27 +03:00
|
|
|
for (i=0; i<n; i++) {
|
|
|
|
long j2 = j = ptr_result[i];
|
|
|
|
long i2 = i;
|
|
|
|
st_data_t value;
|
|
|
|
if (st_lookup(memo, (st_data_t)i, &value)) i2 = (long)value;
|
|
|
|
if (st_lookup(memo, (st_data_t)j, &value)) j2 = (long)value;
|
|
|
|
st_insert(memo, (st_data_t)j, (st_data_t)i2);
|
|
|
|
ptr_result[i] = ptr_ary[j2];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
DATA_PTR(vmemo) = 0;
|
|
|
|
st_free_table(memo);
|
|
|
|
}
|
2008-08-20 11:40:03 +04:00
|
|
|
else {
|
2013-11-07 05:37:34 +04:00
|
|
|
result = rb_ary_dup(ary);
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_CLEAR_CLASS(result);
|
2010-08-25 16:14:38 +04:00
|
|
|
RB_GC_GUARD(ary);
|
2013-11-06 06:50:28 +04:00
|
|
|
RARRAY_PTR_USE(result, ptr_result, {
|
|
|
|
for (i=0; i<n; i++) {
|
|
|
|
j = RAND_UPTO(len-i) + i;
|
|
|
|
nv = ptr_result[j];
|
|
|
|
ptr_result[j] = ptr_result[i];
|
|
|
|
ptr_result[i] = nv;
|
|
|
|
}
|
|
|
|
});
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_SET_CLASS_RAW(result, rb_cArray);
|
2008-08-11 14:00:47 +04:00
|
|
|
}
|
2008-10-24 19:14:44 +04:00
|
|
|
ARY_SET_LEN(result, n);
|
2008-08-20 11:40:03 +04:00
|
|
|
|
2008-08-11 14:00:47 +04:00
|
|
|
return result;
|
2007-05-01 12:45:28 +04:00
|
|
|
}
|
|
|
|
|
2012-11-06 21:12:05 +04:00
|
|
|
static VALUE
|
2013-06-26 17:43:22 +04:00
|
|
|
rb_ary_cycle_size(VALUE self, VALUE args, VALUE eobj)
|
2012-11-06 21:12:05 +04:00
|
|
|
{
|
|
|
|
long mul;
|
|
|
|
VALUE n = Qnil;
|
|
|
|
if (args && (RARRAY_LEN(args) > 0)) {
|
2013-05-13 13:56:22 +04:00
|
|
|
n = RARRAY_AREF(args, 0);
|
2012-11-06 21:12:05 +04:00
|
|
|
}
|
|
|
|
if (RARRAY_LEN(self) == 0) return INT2FIX(0);
|
2018-01-19 04:45:36 +03:00
|
|
|
if (n == Qnil) return DBL2NUM(HUGE_VAL);
|
2012-11-06 21:12:05 +04:00
|
|
|
mul = NUM2LONG(n);
|
|
|
|
if (mul <= 0) return INT2FIX(0);
|
2013-09-29 18:51:03 +04:00
|
|
|
n = LONG2FIX(mul);
|
2017-08-30 08:36:59 +03:00
|
|
|
return rb_fix_mul_fix(rb_ary_length(self), n);
|
2012-11-06 21:12:05 +04:00
|
|
|
}
|
2007-05-01 12:45:28 +04:00
|
|
|
|
2007-08-06 20:26:17 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.cycle(n=nil) {|obj| block} -> nil
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.cycle(n=nil) -> Enumerator
|
|
|
|
*
|
|
|
|
* Calls the given block for each element +n+ times or forever if +nil+ is
|
|
|
|
* given.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Does nothing if a non-positive number is given or the array is empty.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Returns +nil+ if the loop has finished without getting interrupted.
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* If no block is given, an Enumerator is returned instead.
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2007-08-06 20:26:17 +04:00
|
|
|
* a = ["a", "b", "c"]
|
2018-07-11 12:56:49 +03:00
|
|
|
* a.cycle {|x| puts x} # print, a, b, c, a, b, c,.. forever.
|
|
|
|
* a.cycle(2) {|x| puts x} # print, a, b, c, a, b, c.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2007-08-06 20:26:17 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2008-04-13 18:59:55 +04:00
|
|
|
rb_ary_cycle(int argc, VALUE *argv, VALUE ary)
|
2007-08-06 20:26:17 +04:00
|
|
|
{
|
2008-04-13 18:59:55 +04:00
|
|
|
long n, i;
|
2007-08-06 20:26:17 +04:00
|
|
|
|
2018-12-05 04:09:44 +03:00
|
|
|
rb_check_arity(argc, 0, 1);
|
2008-04-13 18:59:55 +04:00
|
|
|
|
2012-11-06 21:12:05 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_cycle_size);
|
2018-12-05 04:09:44 +03:00
|
|
|
if (argc == 0 || NIL_P(argv[0])) {
|
2008-04-13 18:59:55 +04:00
|
|
|
n = -1;
|
|
|
|
}
|
|
|
|
else {
|
2018-12-05 04:09:44 +03:00
|
|
|
n = NUM2LONG(argv[0]);
|
2008-04-13 18:59:55 +04:00
|
|
|
if (n <= 0) return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (RARRAY_LEN(ary) > 0 && (n < 0 || 0 < n--)) {
|
|
|
|
for (i=0; i<RARRAY_LEN(ary); i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
rb_yield(RARRAY_AREF(ary, i));
|
2008-04-13 18:59:55 +04:00
|
|
|
}
|
2007-08-06 20:26:17 +04:00
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2009-08-03 10:48:46 +04:00
|
|
|
#define tmpary(n) rb_ary_tmp_new(n)
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
#define tmpary_discard(a) (ary_discard(a), RBASIC_SET_CLASS_RAW(a, rb_cArray))
|
2007-10-09 13:11:36 +04:00
|
|
|
|
2014-06-13 12:33:58 +04:00
|
|
|
/*
|
|
|
|
* Build a ruby array of the corresponding values and yield it to the
|
|
|
|
* associated block.
|
|
|
|
* Return the class of +values+ for reentry check.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
yield_indexed_values(const VALUE values, const long r, const long *const p)
|
|
|
|
{
|
|
|
|
const VALUE result = rb_ary_new2(r);
|
|
|
|
long i;
|
|
|
|
|
2019-05-21 08:58:39 +03:00
|
|
|
for (i = 0; i < r; i++) ARY_SET(result, i, RARRAY_AREF(values, p[i]));
|
2014-06-13 12:33:58 +04:00
|
|
|
ARY_SET_LEN(result, r);
|
|
|
|
rb_yield(result);
|
|
|
|
return !RBASIC(values)->klass;
|
|
|
|
}
|
|
|
|
|
2007-10-02 03:35:30 +04:00
|
|
|
/*
|
2014-06-14 05:54:45 +04:00
|
|
|
* Compute permutations of +r+ elements of the set <code>[0..n-1]</code>.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2016-01-26 13:37:12 +03:00
|
|
|
* When we have a complete permutation of array indices, copy the values
|
|
|
|
* at those indices into a new array and yield that array.
|
2007-10-02 03:35:30 +04:00
|
|
|
*
|
2009-02-22 17:23:33 +03:00
|
|
|
* n: the size of the set
|
2007-10-02 03:35:30 +04:00
|
|
|
* r: the number of elements in each permutation
|
|
|
|
* p: the array (of size r) that we're filling in
|
|
|
|
* used: an array of booleans: whether a given index is already used
|
|
|
|
* values: the Ruby array that holds the actual values to permute
|
|
|
|
*/
|
|
|
|
static void
|
2014-06-14 05:54:45 +04:00
|
|
|
permute0(const long n, const long r, long *const p, char *const used, const VALUE values)
|
2007-10-02 07:33:53 +04:00
|
|
|
{
|
2014-06-14 05:54:45 +04:00
|
|
|
long i = 0, index = 0;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
const char *const unused = memchr(&used[i], 0, n-i);
|
|
|
|
if (!unused) {
|
|
|
|
if (!index) break;
|
|
|
|
i = p[--index]; /* pop index */
|
|
|
|
used[i++] = 0; /* index unused */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
i = unused - used;
|
2007-10-02 03:35:30 +04:00
|
|
|
p[index] = i;
|
2014-06-14 05:54:45 +04:00
|
|
|
used[i] = 1; /* mark index used */
|
|
|
|
++index;
|
2007-10-02 03:35:30 +04:00
|
|
|
if (index < r-1) { /* if not done yet */
|
2014-06-14 05:54:45 +04:00
|
|
|
p[index] = i = 0;
|
|
|
|
continue;
|
2007-10-02 03:35:30 +04:00
|
|
|
}
|
2014-06-14 05:54:45 +04:00
|
|
|
for (i = 0; i < n; ++i) {
|
|
|
|
if (used[i]) continue;
|
|
|
|
p[index] = i;
|
2014-06-13 12:33:58 +04:00
|
|
|
if (!yield_indexed_values(values, r, p)) {
|
2009-08-03 10:48:46 +04:00
|
|
|
rb_raise(rb_eRuntimeError, "permute reentered");
|
|
|
|
}
|
2007-10-02 03:35:30 +04:00
|
|
|
}
|
2014-06-14 05:54:45 +04:00
|
|
|
i = p[--index]; /* pop index */
|
|
|
|
used[i] = 0; /* index unused */
|
|
|
|
p[index] = ++i;
|
2007-10-02 03:35:30 +04:00
|
|
|
}
|
2007-09-29 12:43:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-06 21:11:06 +04:00
|
|
|
/*
|
|
|
|
* Returns the product of from, from-1, ..., from - how_many + 1.
|
|
|
|
* http://en.wikipedia.org/wiki/Pochhammer_symbol
|
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
descending_factorial(long from, long how_many)
|
|
|
|
{
|
2017-08-30 10:55:19 +03:00
|
|
|
VALUE cnt;
|
|
|
|
if (how_many > 0) {
|
|
|
|
cnt = LONG2FIX(from);
|
|
|
|
while (--how_many > 0) {
|
|
|
|
long v = --from;
|
|
|
|
cnt = rb_int_mul(cnt, LONG2FIX(v));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cnt = LONG2FIX(how_many == 0);
|
2012-11-06 21:11:06 +04:00
|
|
|
}
|
|
|
|
return cnt;
|
|
|
|
}
|
|
|
|
|
2012-11-06 21:11:21 +04:00
|
|
|
static VALUE
|
|
|
|
binomial_coefficient(long comb, long size)
|
|
|
|
{
|
2017-08-30 11:26:16 +03:00
|
|
|
VALUE r;
|
|
|
|
long i;
|
2012-11-06 21:11:21 +04:00
|
|
|
if (comb > size-comb) {
|
|
|
|
comb = size-comb;
|
|
|
|
}
|
|
|
|
if (comb < 0) {
|
|
|
|
return LONG2FIX(0);
|
|
|
|
}
|
2017-08-30 11:26:16 +03:00
|
|
|
else if (comb == 0) {
|
|
|
|
return LONG2FIX(1);
|
|
|
|
}
|
|
|
|
r = LONG2FIX(size);
|
|
|
|
for (i = 1; i < comb; ++i) {
|
|
|
|
r = rb_int_mul(r, LONG2FIX(size - i));
|
|
|
|
r = rb_int_idiv(r, LONG2FIX(i + 1));
|
|
|
|
}
|
|
|
|
return r;
|
2012-11-06 21:11:21 +04:00
|
|
|
}
|
|
|
|
|
2012-11-06 21:11:06 +04:00
|
|
|
static VALUE
|
2013-06-26 17:43:22 +04:00
|
|
|
rb_ary_permutation_size(VALUE ary, VALUE args, VALUE eobj)
|
2012-11-06 21:11:06 +04:00
|
|
|
{
|
|
|
|
long n = RARRAY_LEN(ary);
|
2013-05-13 13:56:22 +04:00
|
|
|
long k = (args && (RARRAY_LEN(args) > 0)) ? NUM2LONG(RARRAY_AREF(args, 0)) : n;
|
2012-11-06 21:11:06 +04:00
|
|
|
|
|
|
|
return descending_factorial(n, k);
|
|
|
|
}
|
|
|
|
|
2007-09-29 12:43:59 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.permutation {|p| block} -> ary
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.permutation -> Enumerator
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.permutation(n) {|p| block} -> ary
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.permutation(n) -> Enumerator
|
|
|
|
*
|
|
|
|
* When invoked with a block, yield all permutations of length +n+ of the
|
|
|
|
* elements of the array, then return the array itself.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-10-07 01:36:17 +04:00
|
|
|
* If +n+ is not specified, yield all permutations of all elements.
|
2007-10-02 03:35:30 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* The implementation makes no guarantees about the order in which the
|
|
|
|
* permutations are yielded.
|
|
|
|
*
|
|
|
|
* If no block is given, an Enumerator is returned instead.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2007-10-02 03:35:30 +04:00
|
|
|
* Examples:
|
2008-03-09 04:04:46 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* a = [1, 2, 3]
|
|
|
|
* a.permutation.to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
|
|
|
|
* a.permutation(1).to_a #=> [[1],[2],[3]]
|
|
|
|
* a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]]
|
|
|
|
* a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
|
|
|
|
* a.permutation(0).to_a #=> [[]] # one permutation of length 0
|
|
|
|
* a.permutation(4).to_a #=> [] # no permutations of length 4
|
2007-09-29 12:43:59 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2007-11-19 10:06:03 +03:00
|
|
|
rb_ary_permutation(int argc, VALUE *argv, VALUE ary)
|
2007-09-29 12:43:59 +04:00
|
|
|
{
|
2007-10-04 10:51:17 +04:00
|
|
|
long r, n, i;
|
|
|
|
|
2007-11-19 10:06:03 +03:00
|
|
|
n = RARRAY_LEN(ary); /* Array length */
|
2012-11-06 21:11:06 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_permutation_size); /* Return enumerator if no block */
|
2018-12-05 04:09:44 +03:00
|
|
|
r = n;
|
|
|
|
if (rb_check_arity(argc, 0, 1) && !NIL_P(argv[0]))
|
|
|
|
r = NUM2LONG(argv[0]); /* Permutation size from argument */
|
2007-10-02 03:35:30 +04:00
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
if (r < 0 || n < r) {
|
2007-10-02 03:35:30 +04:00
|
|
|
/* no permutations: yield nothing */
|
|
|
|
}
|
|
|
|
else if (r == 0) { /* exactly one permutation: the zero-length array */
|
|
|
|
rb_yield(rb_ary_new2(0));
|
|
|
|
}
|
|
|
|
else if (r == 1) { /* this is a special, easy case */
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
|
2007-10-02 03:35:30 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else { /* this is the general case */
|
2014-06-14 05:54:45 +04:00
|
|
|
volatile VALUE t0;
|
2015-06-21 15:28:20 +03:00
|
|
|
long *p = ALLOCV_N(long, t0, r+roomof(n, sizeof(long)));
|
2014-06-14 05:54:45 +04:00
|
|
|
char *used = (char*)(p + r);
|
2010-08-19 07:10:15 +04:00
|
|
|
VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_CLEAR_CLASS(ary0);
|
2007-10-02 03:37:02 +04:00
|
|
|
|
2009-08-03 10:56:57 +04:00
|
|
|
MEMZERO(used, char, n); /* initialize array */
|
2007-10-02 03:35:30 +04:00
|
|
|
|
2014-06-14 05:54:45 +04:00
|
|
|
permute0(n, r, p, used, ary0); /* compute and yield permutations */
|
|
|
|
ALLOCV_END(t0);
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_SET_CLASS_RAW(ary0, rb_cArray);
|
2007-10-02 03:35:30 +04:00
|
|
|
}
|
|
|
|
return ary;
|
2007-09-29 12:43:59 +04:00
|
|
|
}
|
|
|
|
|
2014-06-14 05:54:33 +04:00
|
|
|
static void
|
|
|
|
combinate0(const long len, const long n, long *const stack, const VALUE values)
|
|
|
|
{
|
|
|
|
long lev = 0;
|
|
|
|
|
|
|
|
MEMZERO(stack+1, long, n);
|
|
|
|
stack[0] = -1;
|
|
|
|
for (;;) {
|
|
|
|
for (lev++; lev < n; lev++) {
|
|
|
|
stack[lev+1] = stack[lev]+1;
|
|
|
|
}
|
|
|
|
if (!yield_indexed_values(values, n, stack+1)) {
|
|
|
|
rb_raise(rb_eRuntimeError, "combination reentered");
|
|
|
|
}
|
|
|
|
do {
|
|
|
|
if (lev == 0) return;
|
|
|
|
stack[lev--]++;
|
|
|
|
} while (stack[lev+1]+n == len+lev+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-06 21:11:21 +04:00
|
|
|
static VALUE
|
2013-06-26 17:43:22 +04:00
|
|
|
rb_ary_combination_size(VALUE ary, VALUE args, VALUE eobj)
|
2012-11-06 21:11:21 +04:00
|
|
|
{
|
|
|
|
long n = RARRAY_LEN(ary);
|
2013-05-13 13:56:22 +04:00
|
|
|
long k = NUM2LONG(RARRAY_AREF(args, 0));
|
2012-11-06 21:11:21 +04:00
|
|
|
|
|
|
|
return binomial_coefficient(k, n);
|
|
|
|
}
|
|
|
|
|
2007-09-29 12:43:59 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.combination(n) {|c| block} -> ary
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.combination(n) -> Enumerator
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* When invoked with a block, yields all combinations of length +n+ of elements
|
|
|
|
* from the array and then returns the array itself.
|
2007-10-02 03:35:30 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* The implementation makes no guarantees about the order in which the
|
|
|
|
* combinations are yielded.
|
|
|
|
*
|
|
|
|
* If no block is given, an Enumerator is returned instead.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2007-10-02 03:35:30 +04:00
|
|
|
* Examples:
|
2008-03-09 04:04:46 +03:00
|
|
|
*
|
2007-09-29 12:43:59 +04:00
|
|
|
* a = [1, 2, 3, 4]
|
|
|
|
* a.combination(1).to_a #=> [[1],[2],[3],[4]]
|
|
|
|
* a.combination(2).to_a #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
|
|
|
|
* a.combination(3).to_a #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]]
|
|
|
|
* a.combination(4).to_a #=> [[1,2,3,4]]
|
2008-03-09 04:04:46 +03:00
|
|
|
* a.combination(0).to_a #=> [[]] # one combination of length 0
|
|
|
|
* a.combination(5).to_a #=> [] # no combinations of length 5
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2007-09-29 12:43:59 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_combination(VALUE ary, VALUE num)
|
|
|
|
{
|
2014-06-14 05:54:33 +04:00
|
|
|
long i, n, len;
|
2007-09-29 12:43:59 +04:00
|
|
|
|
|
|
|
n = NUM2LONG(num);
|
2012-11-06 21:11:21 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_combination_size);
|
2007-09-29 12:43:59 +04:00
|
|
|
len = RARRAY_LEN(ary);
|
2007-10-02 03:35:30 +04:00
|
|
|
if (n < 0 || len < n) {
|
2007-09-29 12:43:59 +04:00
|
|
|
/* yield nothing */
|
|
|
|
}
|
2007-10-02 03:35:30 +04:00
|
|
|
else if (n == 0) {
|
2007-10-01 18:46:07 +04:00
|
|
|
rb_yield(rb_ary_new2(0));
|
2007-09-29 12:43:59 +04:00
|
|
|
}
|
|
|
|
else if (n == 1) {
|
2016-12-20 08:26:08 +03:00
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
|
2007-09-29 12:43:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2014-06-13 12:34:17 +04:00
|
|
|
VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
|
|
|
|
volatile VALUE t0;
|
|
|
|
long *stack = ALLOCV_N(long, t0, n+1);
|
2007-09-29 12:43:59 +04:00
|
|
|
|
2014-06-13 12:34:17 +04:00
|
|
|
RBASIC_CLEAR_CLASS(ary0);
|
2014-06-14 05:54:33 +04:00
|
|
|
combinate0(len, n, stack, ary0);
|
2014-06-13 12:34:17 +04:00
|
|
|
ALLOCV_END(t0);
|
|
|
|
RBASIC_SET_CLASS_RAW(ary0, rb_cArray);
|
2007-09-29 12:43:59 +04:00
|
|
|
}
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2010-04-16 11:24:04 +04:00
|
|
|
/*
|
2014-06-14 05:55:07 +04:00
|
|
|
* Compute repeated permutations of +r+ elements of the set
|
2012-06-01 03:51:33 +04:00
|
|
|
* <code>[0..n-1]</code>.
|
|
|
|
*
|
2016-01-26 13:37:12 +03:00
|
|
|
* When we have a complete repeated permutation of array indices, copy the
|
|
|
|
* values at those indices into a new array and yield that array.
|
2010-04-16 11:24:04 +04:00
|
|
|
*
|
|
|
|
* n: the size of the set
|
|
|
|
* r: the number of elements in each permutation
|
|
|
|
* p: the array (of size r) that we're filling in
|
|
|
|
* values: the Ruby array that holds the actual values to permute
|
|
|
|
*/
|
|
|
|
static void
|
2014-06-14 05:55:07 +04:00
|
|
|
rpermute0(const long n, const long r, long *const p, const VALUE values)
|
2010-04-16 11:24:04 +04:00
|
|
|
{
|
2014-06-14 05:55:07 +04:00
|
|
|
long i = 0, index = 0;
|
|
|
|
|
|
|
|
p[index] = i;
|
|
|
|
for (;;) {
|
|
|
|
if (++index < r-1) {
|
|
|
|
p[index] = i = 0;
|
|
|
|
continue;
|
2010-04-16 11:24:04 +04:00
|
|
|
}
|
2014-06-14 05:55:07 +04:00
|
|
|
for (i = 0; i < n; ++i) {
|
|
|
|
p[index] = i;
|
2014-06-13 12:33:58 +04:00
|
|
|
if (!yield_indexed_values(values, r, p)) {
|
2010-04-16 11:24:04 +04:00
|
|
|
rb_raise(rb_eRuntimeError, "repeated permute reentered");
|
|
|
|
}
|
|
|
|
}
|
2014-06-14 05:55:07 +04:00
|
|
|
do {
|
|
|
|
if (index <= 0) return;
|
|
|
|
} while ((i = ++p[--index]) >= n);
|
2010-04-16 11:24:04 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-06 21:11:36 +04:00
|
|
|
static VALUE
|
2013-06-26 17:43:22 +04:00
|
|
|
rb_ary_repeated_permutation_size(VALUE ary, VALUE args, VALUE eobj)
|
2012-11-06 21:11:36 +04:00
|
|
|
{
|
|
|
|
long n = RARRAY_LEN(ary);
|
2013-05-13 13:56:22 +04:00
|
|
|
long k = NUM2LONG(RARRAY_AREF(args, 0));
|
2012-11-06 21:11:36 +04:00
|
|
|
|
|
|
|
if (k < 0) {
|
|
|
|
return LONG2FIX(0);
|
|
|
|
}
|
2017-08-30 08:36:59 +03:00
|
|
|
if (n <= 0) {
|
|
|
|
return LONG2FIX(!k);
|
|
|
|
}
|
|
|
|
return rb_int_positive_pow(n, (unsigned long)k);
|
2012-11-06 21:11:36 +04:00
|
|
|
}
|
|
|
|
|
2010-04-16 11:24:04 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.repeated_permutation(n) {|p| block} -> ary
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.repeated_permutation(n) -> Enumerator
|
|
|
|
*
|
|
|
|
* When invoked with a block, yield all repeated permutations of length +n+ of
|
|
|
|
* the elements of the array, then return the array itself.
|
2010-04-16 11:24:04 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* The implementation makes no guarantees about the order in which the repeated
|
|
|
|
* permutations are yielded.
|
2010-04-16 11:24:04 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* If no block is given, an Enumerator is returned instead.
|
2010-04-16 11:24:04 +04:00
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* a = [1, 2]
|
|
|
|
* a.repeated_permutation(1).to_a #=> [[1], [2]]
|
|
|
|
* a.repeated_permutation(2).to_a #=> [[1,1],[1,2],[2,1],[2,2]]
|
|
|
|
* a.repeated_permutation(3).to_a #=> [[1,1,1],[1,1,2],[1,2,1],[1,2,2],
|
|
|
|
* # [2,1,1],[2,1,2],[2,2,1],[2,2,2]]
|
|
|
|
* a.repeated_permutation(0).to_a #=> [[]] # one permutation of length 0
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_repeated_permutation(VALUE ary, VALUE num)
|
|
|
|
{
|
|
|
|
long r, n, i;
|
|
|
|
|
|
|
|
n = RARRAY_LEN(ary); /* Array length */
|
2012-11-06 21:11:36 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_permutation_size); /* Return Enumerator if no block */
|
2010-04-16 11:24:04 +04:00
|
|
|
r = NUM2LONG(num); /* Permutation size from argument */
|
|
|
|
|
|
|
|
if (r < 0) {
|
|
|
|
/* no permutations: yield nothing */
|
|
|
|
}
|
|
|
|
else if (r == 0) { /* exactly one permutation: the zero-length array */
|
|
|
|
rb_yield(rb_ary_new2(0));
|
|
|
|
}
|
|
|
|
else if (r == 1) { /* this is a special, easy case */
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
|
2010-04-16 11:24:04 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else { /* this is the general case */
|
2014-06-14 05:55:07 +04:00
|
|
|
volatile VALUE t0;
|
2015-08-11 08:57:11 +03:00
|
|
|
long *p = ALLOCV_N(long, t0, r);
|
2010-08-19 07:10:15 +04:00
|
|
|
VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_CLEAR_CLASS(ary0);
|
2010-04-16 11:24:04 +04:00
|
|
|
|
2014-06-14 05:55:07 +04:00
|
|
|
rpermute0(n, r, p, ary0); /* compute and yield repeated permutations */
|
|
|
|
ALLOCV_END(t0);
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_SET_CLASS_RAW(ary0, rb_cArray);
|
2010-04-16 11:24:04 +04:00
|
|
|
}
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-06-14 05:55:25 +04:00
|
|
|
rcombinate0(const long n, const long r, long *const p, const long rest, const VALUE values)
|
2010-04-16 11:24:04 +04:00
|
|
|
{
|
2014-06-14 05:55:25 +04:00
|
|
|
long i = 0, index = 0;
|
|
|
|
|
|
|
|
p[index] = i;
|
|
|
|
for (;;) {
|
|
|
|
if (++index < r-1) {
|
|
|
|
p[index] = i;
|
|
|
|
continue;
|
2010-04-16 11:24:04 +04:00
|
|
|
}
|
2014-06-14 05:55:25 +04:00
|
|
|
for (; i < n; ++i) {
|
|
|
|
p[index] = i;
|
|
|
|
if (!yield_indexed_values(values, r, p)) {
|
|
|
|
rb_raise(rb_eRuntimeError, "repeated combination reentered");
|
|
|
|
}
|
2010-04-16 11:24:04 +04:00
|
|
|
}
|
2014-06-14 05:55:25 +04:00
|
|
|
do {
|
|
|
|
if (index <= 0) return;
|
|
|
|
} while ((i = ++p[--index]) >= n);
|
2010-04-16 11:24:04 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-06 21:11:51 +04:00
|
|
|
static VALUE
|
2013-06-26 17:43:22 +04:00
|
|
|
rb_ary_repeated_combination_size(VALUE ary, VALUE args, VALUE eobj)
|
2012-11-06 21:11:51 +04:00
|
|
|
{
|
|
|
|
long n = RARRAY_LEN(ary);
|
2013-05-13 13:56:22 +04:00
|
|
|
long k = NUM2LONG(RARRAY_AREF(args, 0));
|
2012-11-06 21:11:51 +04:00
|
|
|
if (k == 0) {
|
|
|
|
return LONG2FIX(1);
|
|
|
|
}
|
|
|
|
return binomial_coefficient(k, n + k - 1);
|
|
|
|
}
|
|
|
|
|
2010-04-16 11:24:04 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.repeated_combination(n) {|c| block} -> ary
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.repeated_combination(n) -> Enumerator
|
2010-04-16 11:24:04 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* When invoked with a block, yields all repeated combinations of length +n+ of
|
|
|
|
* elements from the array and then returns the array itself.
|
2010-04-16 11:24:04 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* The implementation makes no guarantees about the order in which the repeated
|
|
|
|
* combinations are yielded.
|
|
|
|
*
|
|
|
|
* If no block is given, an Enumerator is returned instead.
|
2010-04-16 11:24:04 +04:00
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* a = [1, 2, 3]
|
|
|
|
* a.repeated_combination(1).to_a #=> [[1], [2], [3]]
|
|
|
|
* a.repeated_combination(2).to_a #=> [[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]]
|
|
|
|
* a.repeated_combination(3).to_a #=> [[1,1,1],[1,1,2],[1,1,3],[1,2,2],[1,2,3],
|
|
|
|
* # [1,3,3],[2,2,2],[2,2,3],[2,3,3],[3,3,3]]
|
|
|
|
* a.repeated_combination(4).to_a #=> [[1,1,1,1],[1,1,1,2],[1,1,1,3],[1,1,2,2],[1,1,2,3],
|
|
|
|
* # [1,1,3,3],[1,2,2,2],[1,2,2,3],[1,2,3,3],[1,3,3,3],
|
|
|
|
* # [2,2,2,2],[2,2,2,3],[2,2,3,3],[2,3,3,3],[3,3,3,3]]
|
|
|
|
* a.repeated_combination(0).to_a #=> [[]] # one combination of length 0
|
2010-04-16 11:24:04 +04:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_repeated_combination(VALUE ary, VALUE num)
|
|
|
|
{
|
|
|
|
long n, i, len;
|
|
|
|
|
|
|
|
n = NUM2LONG(num); /* Combination size from argument */
|
2012-11-06 21:11:51 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_combination_size); /* Return enumerator if no block */
|
2010-04-16 11:24:04 +04:00
|
|
|
len = RARRAY_LEN(ary);
|
|
|
|
if (n < 0) {
|
|
|
|
/* yield nothing */
|
|
|
|
}
|
|
|
|
else if (n == 0) {
|
|
|
|
rb_yield(rb_ary_new2(0));
|
|
|
|
}
|
|
|
|
else if (n == 1) {
|
2016-12-20 08:26:08 +03:00
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
|
2010-04-16 11:24:04 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (len == 0) {
|
|
|
|
/* yield nothing */
|
|
|
|
}
|
|
|
|
else {
|
2014-06-14 05:55:25 +04:00
|
|
|
volatile VALUE t0;
|
|
|
|
long *p = ALLOCV_N(long, t0, n);
|
2010-08-19 07:10:15 +04:00
|
|
|
VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_CLEAR_CLASS(ary0);
|
2010-04-16 11:24:04 +04:00
|
|
|
|
2014-06-14 05:55:25 +04:00
|
|
|
rcombinate0(len, n, p, n, ary0); /* compute and yield repeated combinations */
|
|
|
|
ALLOCV_END(t0);
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_SET_CLASS_RAW(ary0, rb_cArray);
|
2010-04-16 11:24:04 +04:00
|
|
|
}
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2007-09-29 12:43:59 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary.product(other_ary, ...) -> new_ary
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.product(other_ary, ...) {|p| block} -> ary
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-02-10 21:37:28 +04:00
|
|
|
* Returns an array of all combinations of elements from all arrays.
|
2010-04-03 01:56:34 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* The length of the returned array is the product of the length of +self+ and
|
|
|
|
* the argument arrays.
|
|
|
|
*
|
|
|
|
* If given a block, #product will yield all combinations and return +self+
|
|
|
|
* instead.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2010-05-18 01:07:33 +04:00
|
|
|
* [1,2,3].product([4,5]) #=> [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
|
|
|
|
* [1,2].product([1,2]) #=> [[1,1],[1,2],[2,1],[2,2]]
|
|
|
|
* [1,2].product([3,4],[5,6]) #=> [[1,3,5],[1,3,6],[1,4,5],[1,4,6],
|
2007-10-02 07:33:53 +04:00
|
|
|
* # [2,3,5],[2,3,6],[2,4,5],[2,4,6]]
|
2010-05-18 01:07:33 +04:00
|
|
|
* [1,2].product() #=> [[1],[2]]
|
|
|
|
* [1,2].product([]) #=> []
|
2007-09-29 12:43:59 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2007-10-02 07:33:53 +04:00
|
|
|
rb_ary_product(int argc, VALUE *argv, VALUE ary)
|
2007-09-29 12:43:59 +04:00
|
|
|
{
|
2007-10-02 07:33:53 +04:00
|
|
|
int n = argc+1; /* How many arrays we're operating on */
|
2010-05-28 12:51:41 +04:00
|
|
|
volatile VALUE t0 = tmpary(n);
|
2018-01-19 11:17:56 +03:00
|
|
|
volatile VALUE t1 = Qundef;
|
2010-05-28 12:51:41 +04:00
|
|
|
VALUE *arrays = RARRAY_PTR(t0); /* The arrays we're computing the product of */
|
2018-01-19 11:17:56 +03:00
|
|
|
int *counters = ALLOCV_N(int, t1, n); /* The current position in each one */
|
2010-04-03 01:56:34 +04:00
|
|
|
VALUE result = Qnil; /* The array we'll be returning, when no block given */
|
2007-10-02 07:33:53 +04:00
|
|
|
long i,j;
|
2007-10-04 15:18:14 +04:00
|
|
|
long resultlen = 1;
|
2007-09-29 12:43:59 +04:00
|
|
|
|
* include/ruby/ruby.h: constify RBasic::klass and add
RBASIC_CLASS(obj) macro which returns a class of `obj'.
This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
* object.c: add new function rb_obj_reveal().
This function reveal interal (hidden) object by rb_obj_hide().
Note that do not change class before and after hiding.
Only permitted example is:
klass = RBASIC_CLASS(obj);
rb_obj_hide(obj);
....
rb_obj_reveal(obj, klass);
TODO: API design. rb_obj_reveal() should be replaced with others.
TODO: modify constified variables using cast may be harmful for
compiler's analysis and optimizaton.
Any idea to prohibt inserting RBasic::klass directly?
If rename RBasic::klass and force to use RBASIC_CLASS(obj),
then all codes such as `RBASIC(obj)->klass' will be
compilation error. Is it acceptable? (We have similar
experience at Ruby 1.9,
for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
* internal.h: add some macros.
* RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
object.
* RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
* RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
without write barrier (planned).
* RCLASS_SET_SUPER(a, b) set super class of a.
* array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
Use above macros and functions to access RBasic::klass.
* ext/coverage/coverage.c, ext/readline/readline.c,
ext/socket/ancdata.c, ext/socket/init.c,
* ext/zlib/zlib.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:49:11 +04:00
|
|
|
RBASIC_CLEAR_CLASS(t0);
|
2007-10-09 11:33:35 +04:00
|
|
|
|
2007-10-02 07:33:53 +04:00
|
|
|
/* initialize the arrays of arrays */
|
2010-06-06 05:44:38 +04:00
|
|
|
ARY_SET_LEN(t0, n);
|
2007-10-02 07:33:53 +04:00
|
|
|
arrays[0] = ary;
|
2010-06-06 14:56:45 +04:00
|
|
|
for (i = 1; i < n; i++) arrays[i] = Qnil;
|
2007-11-06 21:54:02 +03:00
|
|
|
for (i = 1; i < n; i++) arrays[i] = to_ary(argv[i-1]);
|
2009-02-22 17:23:33 +03:00
|
|
|
|
2007-10-02 07:33:53 +04:00
|
|
|
/* initialize the counters for the arrays */
|
2007-10-09 16:29:21 +04:00
|
|
|
for (i = 0; i < n; i++) counters[i] = 0;
|
2007-10-02 07:33:53 +04:00
|
|
|
|
|
|
|
/* Otherwise, allocate and fill in an array of results */
|
2010-04-03 02:44:17 +04:00
|
|
|
if (rb_block_given_p()) {
|
2010-04-04 00:59:56 +04:00
|
|
|
/* Make defensive copies of arrays; exit if any is empty */
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
if (RARRAY_LEN(arrays[i]) == 0) goto done;
|
2010-08-19 07:10:15 +04:00
|
|
|
arrays[i] = ary_make_shared_copy(arrays[i]);
|
2010-04-04 00:59:56 +04:00
|
|
|
}
|
2010-04-03 02:44:17 +04:00
|
|
|
}
|
|
|
|
else {
|
2010-04-04 00:59:56 +04:00
|
|
|
/* Compute the length of the result array; return [] if any is empty */
|
|
|
|
for (i = 0; i < n; i++) {
|
2013-04-09 15:39:53 +04:00
|
|
|
long k = RARRAY_LEN(arrays[i]);
|
2010-04-04 00:59:56 +04:00
|
|
|
if (k == 0) {
|
|
|
|
result = rb_ary_new2(0);
|
|
|
|
goto done;
|
|
|
|
}
|
2013-04-09 15:39:53 +04:00
|
|
|
if (MUL_OVERFLOW_LONG_P(resultlen, k))
|
2010-04-04 00:59:56 +04:00
|
|
|
rb_raise(rb_eRangeError, "too big to product");
|
2013-04-09 15:39:53 +04:00
|
|
|
resultlen *= k;
|
2010-04-04 00:59:56 +04:00
|
|
|
}
|
2010-04-03 01:56:34 +04:00
|
|
|
result = rb_ary_new2(resultlen);
|
|
|
|
}
|
2010-04-04 00:59:56 +04:00
|
|
|
for (;;) {
|
2007-10-04 15:18:14 +04:00
|
|
|
int m;
|
2007-10-02 07:33:53 +04:00
|
|
|
/* fill in one subarray */
|
|
|
|
VALUE subarray = rb_ary_new2(n);
|
2007-10-09 16:29:21 +04:00
|
|
|
for (j = 0; j < n; j++) {
|
2007-10-02 07:33:53 +04:00
|
|
|
rb_ary_push(subarray, rb_ary_entry(arrays[j], counters[j]));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* put it on the result array */
|
2012-12-01 19:25:28 +04:00
|
|
|
if (NIL_P(result)) {
|
2010-05-28 06:43:34 +04:00
|
|
|
FL_SET(t0, FL_USER5);
|
2010-04-03 01:56:34 +04:00
|
|
|
rb_yield(subarray);
|
2010-05-28 06:43:34 +04:00
|
|
|
if (! FL_TEST(t0, FL_USER5)) {
|
2010-04-03 02:25:49 +04:00
|
|
|
rb_raise(rb_eRuntimeError, "product reentered");
|
|
|
|
}
|
2010-05-28 06:43:34 +04:00
|
|
|
else {
|
|
|
|
FL_UNSET(t0, FL_USER5);
|
|
|
|
}
|
2010-04-03 01:56:34 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_ary_push(result, subarray);
|
|
|
|
}
|
2007-10-02 07:33:53 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Increment the last counter. If it overflows, reset to 0
|
|
|
|
* and increment the one before it.
|
|
|
|
*/
|
2007-10-04 15:18:14 +04:00
|
|
|
m = n-1;
|
2007-10-02 07:33:53 +04:00
|
|
|
counters[m]++;
|
2010-04-04 00:59:56 +04:00
|
|
|
while (counters[m] == RARRAY_LEN(arrays[m])) {
|
2007-10-02 07:33:53 +04:00
|
|
|
counters[m] = 0;
|
2011-01-11 09:34:14 +03:00
|
|
|
/* If the first counter overflows, we are done */
|
2010-04-04 00:59:56 +04:00
|
|
|
if (--m < 0) goto done;
|
2007-10-02 07:33:53 +04:00
|
|
|
counters[m]++;
|
2007-09-29 12:43:59 +04:00
|
|
|
}
|
|
|
|
}
|
2010-04-04 00:59:56 +04:00
|
|
|
done:
|
2010-05-28 12:51:41 +04:00
|
|
|
tmpary_discard(t0);
|
2018-01-19 11:17:56 +03:00
|
|
|
ALLOCV_END(t1);
|
2007-10-02 07:33:53 +04:00
|
|
|
|
2010-04-03 01:56:34 +04:00
|
|
|
return NIL_P(result) ? ary : result;
|
2007-09-29 12:43:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-17 16:28:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary.take(n) -> new_ary
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-10-07 01:36:17 +04:00
|
|
|
* Returns first +n+ elements from the array.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-11-25 17:28:59 +04:00
|
|
|
* If a negative number is given, raises an ArgumentError.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
|
|
|
* See also Array#drop
|
|
|
|
*
|
2008-03-17 16:28:46 +03:00
|
|
|
* a = [1, 2, 3, 4, 5, 0]
|
2010-05-18 01:07:33 +04:00
|
|
|
* a.take(3) #=> [1, 2, 3]
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2008-03-17 16:28:46 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_take(VALUE obj, VALUE n)
|
|
|
|
{
|
2008-03-25 13:13:03 +03:00
|
|
|
long len = NUM2LONG(n);
|
|
|
|
if (len < 0) {
|
|
|
|
rb_raise(rb_eArgError, "attempt to take negative size");
|
|
|
|
}
|
|
|
|
return rb_ary_subseq(obj, 0, len);
|
2008-03-17 16:28:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.take_while {|obj| block} -> new_ary
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.take_while -> Enumerator
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Passes elements to the block until the block returns +nil+ or +false+, then
|
|
|
|
* stops iterating and returns an array of all prior elements.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* If no block is given, an Enumerator is returned instead.
|
|
|
|
*
|
|
|
|
* See also Array#drop_while
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2008-03-17 16:28:46 +03:00
|
|
|
* a = [1, 2, 3, 4, 5, 0]
|
2018-07-11 12:56:49 +03:00
|
|
|
* a.take_while {|i| i < 3} #=> [1, 2]
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2008-03-17 16:28:46 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_take_while(VALUE ary)
|
|
|
|
{
|
|
|
|
long i;
|
|
|
|
|
|
|
|
RETURN_ENUMERATOR(ary, 0, 0);
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
if (!RTEST(rb_yield(RARRAY_AREF(ary, i)))) break;
|
2008-03-17 16:28:46 +03:00
|
|
|
}
|
|
|
|
return rb_ary_take(ary, LONG2FIX(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-13 09:49:55 +04:00
|
|
|
* ary.drop(n) -> new_ary
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Drops first +n+ elements from +ary+ and returns the rest of the elements in
|
|
|
|
* an array.
|
|
|
|
*
|
2012-11-25 17:28:59 +04:00
|
|
|
* If a negative number is given, raises an ArgumentError.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
|
|
|
* See also Array#take
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2008-03-17 16:28:46 +03:00
|
|
|
* a = [1, 2, 3, 4, 5, 0]
|
2010-05-18 01:07:33 +04:00
|
|
|
* a.drop(3) #=> [4, 5, 0]
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2008-03-17 16:28:46 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_drop(VALUE ary, VALUE n)
|
|
|
|
{
|
|
|
|
VALUE result;
|
2008-03-25 13:13:03 +03:00
|
|
|
long pos = NUM2LONG(n);
|
|
|
|
if (pos < 0) {
|
|
|
|
rb_raise(rb_eArgError, "attempt to drop negative size");
|
|
|
|
}
|
2008-03-17 16:28:46 +03:00
|
|
|
|
2008-03-25 13:13:03 +03:00
|
|
|
result = rb_ary_subseq(ary, pos, RARRAY_LEN(ary));
|
2008-03-17 16:28:46 +03:00
|
|
|
if (result == Qnil) result = rb_ary_new();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.drop_while {|obj| block} -> new_ary
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary.drop_while -> Enumerator
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Drops elements up to, but not including, the first element for which the
|
|
|
|
* block returns +nil+ or +false+ and returns an array containing the
|
|
|
|
* remaining elements.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* If no block is given, an Enumerator is returned instead.
|
|
|
|
*
|
|
|
|
* See also Array#take_while
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2008-03-17 16:28:46 +03:00
|
|
|
* a = [1, 2, 3, 4, 5, 0]
|
2010-05-18 01:07:33 +04:00
|
|
|
* a.drop_while {|i| i < 3 } #=> [3, 4, 5, 0]
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2008-03-17 16:28:46 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_drop_while(VALUE ary)
|
|
|
|
{
|
|
|
|
long i;
|
|
|
|
|
|
|
|
RETURN_ENUMERATOR(ary, 0, 0);
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
2013-05-13 13:56:22 +04:00
|
|
|
if (!RTEST(rb_yield(RARRAY_AREF(ary, i)))) break;
|
2008-03-17 16:28:46 +03:00
|
|
|
}
|
|
|
|
return rb_ary_drop(ary, LONG2FIX(i));
|
|
|
|
}
|
|
|
|
|
2014-07-18 17:16:48 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-07-11 12:56:49 +03:00
|
|
|
* ary.any? [{|obj| block} ] -> true or false
|
2018-07-01 04:38:18 +03:00
|
|
|
* ary.any?(pattern) -> true or false
|
2014-07-18 17:16:48 +04:00
|
|
|
*
|
|
|
|
* See also Enumerable#any?
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2017-12-11 01:36:28 +03:00
|
|
|
rb_ary_any_p(int argc, VALUE *argv, VALUE ary)
|
2014-07-18 17:16:48 +04:00
|
|
|
{
|
|
|
|
long i, len = RARRAY_LEN(ary);
|
|
|
|
|
2017-12-11 01:36:28 +03:00
|
|
|
rb_check_arity(argc, 0, 1);
|
2014-07-18 17:16:48 +04:00
|
|
|
if (!len) return Qfalse;
|
2017-12-11 01:36:28 +03:00
|
|
|
if (argc) {
|
2018-09-13 14:10:24 +03:00
|
|
|
if (rb_block_given_p()) {
|
|
|
|
rb_warn("given block not used");
|
|
|
|
}
|
2017-12-11 01:36:28 +03:00
|
|
|
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
|
|
|
if (RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) return Qtrue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!rb_block_given_p()) {
|
2018-10-30 06:21:56 +03:00
|
|
|
for (i = 0; i < len; ++i) {
|
|
|
|
if (RTEST(RARRAY_AREF(ary, i))) return Qtrue;
|
|
|
|
}
|
2014-07-18 17:16:48 +04:00
|
|
|
}
|
|
|
|
else {
|
2014-07-18 18:24:48 +04:00
|
|
|
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
|
|
|
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qtrue;
|
|
|
|
}
|
2014-07-18 17:16:48 +04:00
|
|
|
}
|
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
|
2018-12-05 07:25:44 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* ary.all? [{|obj| block} ] -> true or false
|
|
|
|
* ary.all?(pattern) -> true or false
|
|
|
|
*
|
|
|
|
* See also Enumerable#all?
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_all_p(int argc, VALUE *argv, VALUE ary)
|
|
|
|
{
|
|
|
|
long i, len = RARRAY_LEN(ary);
|
|
|
|
|
|
|
|
rb_check_arity(argc, 0, 1);
|
|
|
|
if (!len) return Qtrue;
|
|
|
|
if (argc) {
|
|
|
|
if (rb_block_given_p()) {
|
|
|
|
rb_warn("given block not used");
|
|
|
|
}
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
|
|
|
if (!RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) return Qfalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!rb_block_given_p()) {
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
|
|
if (!RTEST(RARRAY_AREF(ary, i))) return Qfalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
|
|
|
if (!RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qfalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Qtrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* ary.none? [{|obj| block} ] -> true or false
|
|
|
|
* ary.none?(pattern) -> true or false
|
|
|
|
*
|
|
|
|
* See also Enumerable#none?
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_none_p(int argc, VALUE *argv, VALUE ary)
|
|
|
|
{
|
|
|
|
long i, len = RARRAY_LEN(ary);
|
|
|
|
|
|
|
|
rb_check_arity(argc, 0, 1);
|
|
|
|
if (!len) return Qtrue;
|
|
|
|
if (argc) {
|
|
|
|
if (rb_block_given_p()) {
|
|
|
|
rb_warn("given block not used");
|
|
|
|
}
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
|
|
|
if (RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) return Qfalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!rb_block_given_p()) {
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
|
|
if (RTEST(RARRAY_AREF(ary, i))) return Qfalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
|
|
|
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qfalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Qtrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* ary.one? [{|obj| block} ] -> true or false
|
|
|
|
* ary.one?(pattern) -> true or false
|
|
|
|
*
|
|
|
|
* See also Enumerable#one?
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_ary_one_p(int argc, VALUE *argv, VALUE ary)
|
|
|
|
{
|
|
|
|
long i, len = RARRAY_LEN(ary);
|
|
|
|
VALUE result = Qfalse;
|
|
|
|
|
|
|
|
rb_check_arity(argc, 0, 1);
|
|
|
|
if (!len) return Qfalse;
|
|
|
|
if (argc) {
|
|
|
|
if (rb_block_given_p()) {
|
|
|
|
rb_warn("given block not used");
|
|
|
|
}
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
|
|
|
if (RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) {
|
|
|
|
if (result) return Qfalse;
|
|
|
|
result = Qtrue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!rb_block_given_p()) {
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
|
|
if (RTEST(RARRAY_AREF(ary, i))) {
|
|
|
|
if (result) return Qfalse;
|
|
|
|
result = Qtrue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
|
|
|
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) {
|
|
|
|
if (result) return Qfalse;
|
|
|
|
result = Qtrue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-11-09 15:27:26 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* ary.dig(idx, ...) -> object
|
|
|
|
*
|
2015-12-08 08:21:11 +03:00
|
|
|
* Extracts the nested value specified by the sequence of <i>idx</i>
|
|
|
|
* objects by calling +dig+ at each step, returning +nil+ if any
|
|
|
|
* intermediate step is +nil+.
|
2015-11-09 15:27:26 +03:00
|
|
|
*
|
|
|
|
* a = [[1, [2, 3]]]
|
|
|
|
*
|
|
|
|
* a.dig(0, 1, 1) #=> 3
|
2015-12-08 08:21:11 +03:00
|
|
|
* a.dig(1, 2, 3) #=> nil
|
2016-10-04 06:59:46 +03:00
|
|
|
* a.dig(0, 0, 0) #=> TypeError: Integer does not have #dig method
|
2015-12-08 08:21:11 +03:00
|
|
|
* [42, {foo: :bar}].dig(1, :foo) #=> :bar
|
2015-11-09 15:27:26 +03:00
|
|
|
*/
|
|
|
|
|
2018-05-08 12:09:12 +03:00
|
|
|
static VALUE
|
2015-11-09 15:27:26 +03:00
|
|
|
rb_ary_dig(int argc, VALUE *argv, VALUE self)
|
|
|
|
{
|
|
|
|
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
|
|
|
|
self = rb_ary_at(self, *argv);
|
|
|
|
if (!--argc) return self;
|
|
|
|
++argv;
|
|
|
|
return rb_obj_dig(argc, argv, self, Qnil);
|
|
|
|
}
|
|
|
|
|
2017-02-18 06:42:35 +03:00
|
|
|
static inline VALUE
|
2017-02-18 07:23:20 +03:00
|
|
|
finish_exact_sum(long n, VALUE r, VALUE v, int z)
|
2017-02-18 06:42:35 +03:00
|
|
|
{
|
|
|
|
if (n != 0)
|
|
|
|
v = rb_fix_plus(LONG2FIX(n), v);
|
|
|
|
if (r != Qundef) {
|
|
|
|
/* r can be an Integer when mathn is loaded */
|
|
|
|
if (FIXNUM_P(r))
|
|
|
|
v = rb_fix_plus(r, v);
|
|
|
|
else if (RB_TYPE_P(r, T_BIGNUM))
|
|
|
|
v = rb_big_plus(r, v);
|
|
|
|
else
|
|
|
|
v = rb_rational_plus(r, v);
|
|
|
|
}
|
2017-02-18 07:23:20 +03:00
|
|
|
else if (!n && z) {
|
|
|
|
v = rb_fix_plus(LONG2FIX(0), v);
|
|
|
|
}
|
2017-02-18 06:42:35 +03:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2016-04-13 16:51:53 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2016-04-14 15:48:44 +03:00
|
|
|
* ary.sum(init=0) -> number
|
|
|
|
* ary.sum(init=0) {|e| expr } -> number
|
2016-04-13 16:51:53 +03:00
|
|
|
*
|
|
|
|
* Returns the sum of elements.
|
2016-04-14 15:48:44 +03:00
|
|
|
* For example, [e1, e2, e3].sum returns init + e1 + e2 + e3.
|
2016-04-13 16:51:53 +03:00
|
|
|
*
|
2016-04-14 15:48:44 +03:00
|
|
|
* If a block is given, the block is applied to each element
|
2016-04-17 14:34:52 +03:00
|
|
|
* before addition.
|
2016-04-13 16:51:53 +03:00
|
|
|
*
|
2016-04-14 15:48:44 +03:00
|
|
|
* If <i>ary</i> is empty, it returns <i>init</i>.
|
|
|
|
*
|
|
|
|
* [].sum #=> 0
|
|
|
|
* [].sum(0.0) #=> 0.0
|
|
|
|
* [1, 2, 3].sum #=> 6
|
|
|
|
* [3, 5.5].sum #=> 8.5
|
2016-04-14 15:56:38 +03:00
|
|
|
* [2.5, 3.0].sum(0.0) {|e| e * e } #=> 15.25
|
2016-04-14 15:48:44 +03:00
|
|
|
* [Object.new].sum #=> TypeError
|
2016-04-13 16:51:53 +03:00
|
|
|
*
|
2016-04-17 14:34:52 +03:00
|
|
|
* The (arithmetic) mean value of an array can be obtained as follows.
|
2016-04-14 15:56:38 +03:00
|
|
|
*
|
|
|
|
* mean = ary.sum(0.0) / ary.length
|
|
|
|
*
|
2016-04-22 14:44:34 +03:00
|
|
|
* This method can be used for non-numeric objects by
|
|
|
|
* explicit <i>init</i> argument.
|
|
|
|
*
|
|
|
|
* ["a", "b", "c"].sum("") #=> "abc"
|
|
|
|
* [[1], [[2]], [3]].sum([]) #=> [1, [2], 3]
|
|
|
|
*
|
2016-11-05 05:50:15 +03:00
|
|
|
* However, Array#join and Array#flatten is faster than Array#sum for
|
|
|
|
* array of strings and array of arrays.
|
2016-04-22 14:44:34 +03:00
|
|
|
*
|
|
|
|
* ["a", "b", "c"].join #=> "abc"
|
|
|
|
* [[1], [[2]], [3]].flatten(1) #=> [1, [2], 3]
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Array#sum method may not respect method redefinition of "+" methods
|
2016-10-09 17:05:57 +03:00
|
|
|
* such as Integer#+.
|
2016-04-13 16:51:53 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-04-14 15:48:44 +03:00
|
|
|
static VALUE
|
|
|
|
rb_ary_sum(int argc, VALUE *argv, VALUE ary)
|
2016-04-13 16:51:53 +03:00
|
|
|
{
|
2016-04-15 19:04:18 +03:00
|
|
|
VALUE e, v, r;
|
2016-04-13 16:51:53 +03:00
|
|
|
long i, n;
|
2016-04-14 15:48:44 +03:00
|
|
|
int block_given;
|
2016-04-13 16:51:53 +03:00
|
|
|
|
2018-12-05 04:09:44 +03:00
|
|
|
v = (rb_check_arity(argc, 0, 1) ? argv[0] : LONG2FIX(0));
|
2016-04-13 16:51:53 +03:00
|
|
|
|
2016-04-14 15:48:44 +03:00
|
|
|
block_given = rb_block_given_p();
|
|
|
|
|
|
|
|
if (RARRAY_LEN(ary) == 0)
|
|
|
|
return v;
|
2016-04-13 16:51:53 +03:00
|
|
|
|
|
|
|
n = 0;
|
2016-04-15 19:04:18 +03:00
|
|
|
r = Qundef;
|
2016-04-13 16:51:53 +03:00
|
|
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
|
|
|
e = RARRAY_AREF(ary, i);
|
2016-04-14 15:48:44 +03:00
|
|
|
if (block_given)
|
|
|
|
e = rb_yield(e);
|
2016-04-13 16:51:53 +03:00
|
|
|
if (FIXNUM_P(e)) {
|
|
|
|
n += FIX2LONG(e); /* should not overflow long type */
|
|
|
|
if (!FIXABLE(n)) {
|
|
|
|
v = rb_big_plus(LONG2NUM(n), v);
|
|
|
|
n = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(e, T_BIGNUM))
|
|
|
|
v = rb_big_plus(e, v);
|
2016-04-15 19:04:18 +03:00
|
|
|
else if (RB_TYPE_P(e, T_RATIONAL)) {
|
|
|
|
if (r == Qundef)
|
|
|
|
r = e;
|
|
|
|
else
|
|
|
|
r = rb_rational_plus(r, e);
|
|
|
|
}
|
2016-04-13 16:51:53 +03:00
|
|
|
else
|
2016-04-15 19:04:18 +03:00
|
|
|
goto not_exact;
|
2016-04-13 16:51:53 +03:00
|
|
|
}
|
2017-02-18 07:23:20 +03:00
|
|
|
v = finish_exact_sum(n, r, v, argc!=0);
|
2016-04-13 16:51:53 +03:00
|
|
|
return v;
|
|
|
|
|
2016-04-15 19:04:18 +03:00
|
|
|
not_exact:
|
2017-02-18 07:23:20 +03:00
|
|
|
v = finish_exact_sum(n, r, v, i!=0);
|
2016-04-13 16:51:53 +03:00
|
|
|
|
|
|
|
if (RB_FLOAT_TYPE_P(e)) {
|
2016-12-06 16:40:31 +03:00
|
|
|
/*
|
|
|
|
* Kahan-Babuska balancing compensated summation algorithm
|
|
|
|
* See http://link.springer.com/article/10.1007/s00607-005-0139-x
|
|
|
|
*/
|
2016-04-13 16:51:53 +03:00
|
|
|
double f, c;
|
2019-10-09 06:25:08 +03:00
|
|
|
double x, t;
|
2016-04-15 16:33:05 +03:00
|
|
|
|
2016-04-13 16:51:53 +03:00
|
|
|
f = NUM2DBL(v);
|
|
|
|
c = 0.0;
|
2016-04-15 19:26:38 +03:00
|
|
|
goto has_float_value;
|
2016-04-13 16:51:53 +03:00
|
|
|
for (; i < RARRAY_LEN(ary); i++) {
|
|
|
|
e = RARRAY_AREF(ary, i);
|
2016-04-14 15:48:44 +03:00
|
|
|
if (block_given)
|
|
|
|
e = rb_yield(e);
|
2016-04-13 16:51:53 +03:00
|
|
|
if (RB_FLOAT_TYPE_P(e))
|
2016-04-15 19:26:38 +03:00
|
|
|
has_float_value:
|
2016-04-13 16:51:53 +03:00
|
|
|
x = RFLOAT_VALUE(e);
|
|
|
|
else if (FIXNUM_P(e))
|
|
|
|
x = FIX2LONG(e);
|
|
|
|
else if (RB_TYPE_P(e, T_BIGNUM))
|
|
|
|
x = rb_big2dbl(e);
|
2016-04-15 16:33:05 +03:00
|
|
|
else if (RB_TYPE_P(e, T_RATIONAL))
|
|
|
|
x = rb_num2dbl(e);
|
2016-04-13 16:51:53 +03:00
|
|
|
else
|
|
|
|
goto not_float;
|
|
|
|
|
2018-07-22 13:47:33 +03:00
|
|
|
if (isnan(f)) continue;
|
|
|
|
if (isnan(x)) {
|
|
|
|
f = x;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (isinf(x)) {
|
|
|
|
if (isinf(f) && signbit(x) != signbit(f))
|
|
|
|
f = NAN;
|
|
|
|
else
|
|
|
|
f = x;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (isinf(f)) continue;
|
|
|
|
|
2016-12-06 16:40:31 +03:00
|
|
|
t = f + x;
|
|
|
|
if (fabs(f) >= fabs(x))
|
|
|
|
c += ((f - t) + x);
|
|
|
|
else
|
|
|
|
c += ((x - t) + f);
|
2016-04-13 16:51:53 +03:00
|
|
|
f = t;
|
|
|
|
}
|
2016-12-06 16:40:31 +03:00
|
|
|
f += c;
|
2016-04-13 16:51:53 +03:00
|
|
|
return DBL2NUM(f);
|
|
|
|
|
|
|
|
not_float:
|
|
|
|
v = DBL2NUM(f);
|
|
|
|
}
|
|
|
|
|
2016-04-15 19:26:38 +03:00
|
|
|
goto has_some_value;
|
2016-04-13 16:51:53 +03:00
|
|
|
for (; i < RARRAY_LEN(ary); i++) {
|
2016-04-14 15:48:44 +03:00
|
|
|
e = RARRAY_AREF(ary, i);
|
|
|
|
if (block_given)
|
|
|
|
e = rb_yield(e);
|
2016-04-15 19:26:38 +03:00
|
|
|
has_some_value:
|
2016-04-14 15:48:44 +03:00
|
|
|
v = rb_funcall(v, idPLUS, 1, e);
|
2016-04-13 16:51:53 +03:00
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2019-04-17 09:48:03 +03:00
|
|
|
static VALUE
|
|
|
|
rb_ary_deconstruct(VALUE ary)
|
|
|
|
{
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2011-10-11 02:55:54 +04:00
|
|
|
/*
|
2020-05-16 00:12:40 +03:00
|
|
|
* An \Array is an ordered, integer-indexed collection of objects,
|
|
|
|
* called _elements_. Any object may be an \Array element.
|
|
|
|
*
|
|
|
|
* == \Array Indexes
|
|
|
|
*
|
|
|
|
* \Array indexing starts at 0, as in C or Java.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
2020-05-16 00:12:40 +03:00
|
|
|
* A positive index is an offset from the first element:
|
|
|
|
* - Index 0 indicates the first element.
|
|
|
|
* - Index 1 indicates the second element.
|
|
|
|
* - ...
|
|
|
|
*
|
|
|
|
* A negative index is an offset, backwards, from the end of the array:
|
|
|
|
* - Index -1 indicates the last element.
|
|
|
|
* - Index -2 indicates the next-to-last element.
|
|
|
|
* - ...
|
|
|
|
*
|
|
|
|
* A non-negative index is <i>in range</i> if it is smaller than
|
|
|
|
* the size of the array. For a 3-element array:
|
|
|
|
* - Indexes 0 through 2 are in range.
|
|
|
|
* - Index 3 is out of range.
|
|
|
|
*
|
|
|
|
* A negative index is <i>in range</i> if its absolute value is
|
|
|
|
* not larger than the size of the array. For a 3-element array:
|
|
|
|
* - Indexes -1 through -3 are in range.
|
|
|
|
* - Index -4 is out of range.
|
2012-06-01 03:51:33 +04:00
|
|
|
*
|
|
|
|
* == Creating Arrays
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* A new array can be created by using the literal constructor
|
|
|
|
* <code>[]</code>. Arrays can contain different types of objects. For
|
|
|
|
* example, the array below contains an Integer, a String and a Float:
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary = [1, "two", 3.0] #=> [1, "two", 3.0]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* An array can also be created by explicitly calling Array.new with zero, one
|
|
|
|
* (the initial size of the Array) or two arguments (the initial size and a
|
|
|
|
* default object).
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* ary = Array.new #=> []
|
|
|
|
* Array.new(3) #=> [nil, nil, nil]
|
2013-03-17 05:34:20 +04:00
|
|
|
* Array.new(3, true) #=> [true, true, true]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-11-25 17:28:59 +04:00
|
|
|
* Note that the second argument populates the array with references to the
|
|
|
|
* same object. Therefore, it is only recommended in cases when you need to
|
|
|
|
* instantiate arrays with natively immutable objects such as Symbols,
|
|
|
|
* numbers, true or false.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* To create an array with separate objects a block can be passed instead.
|
|
|
|
* This method is safe to use with mutable objects such as hashes, strings or
|
|
|
|
* other arrays:
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2018-07-11 12:56:49 +03:00
|
|
|
* Array.new(4) {Hash.new} #=> [{}, {}, {}, {}]
|
2017-03-20 23:30:25 +03:00
|
|
|
* Array.new(4) {|i| i.to_s } #=> ["0", "1", "2", "3"]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* This is also a quick way to build up multi-dimensional arrays:
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2018-07-11 12:56:49 +03:00
|
|
|
* empty_table = Array.new(3) {Array.new(3)}
|
2012-06-01 03:51:33 +04:00
|
|
|
* #=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2013-02-19 07:32:11 +04:00
|
|
|
* An array can also be created by using the Array() method, provided by
|
2013-02-19 20:19:13 +04:00
|
|
|
* Kernel, which tries to call #to_ary, then #to_a on its argument.
|
2013-02-19 07:32:11 +04:00
|
|
|
*
|
|
|
|
* Array({:a => "a", :b => "b"}) #=> [[:a, "a"], [:b, "b"]]
|
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* == Example Usage
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* In addition to the methods it mixes in through the Enumerable module, the
|
|
|
|
* Array class has proprietary methods for accessing, searching and otherwise
|
|
|
|
* manipulating arrays.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Some of the more common ones are illustrated below.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* == Accessing Elements
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Elements in an array can be retrieved using the Array#[] method. It can
|
|
|
|
* take a single integer argument (a numeric index), a pair of arguments
|
2013-11-07 21:15:49 +04:00
|
|
|
* (start and length) or a range. Negative indices start counting from the end,
|
|
|
|
* with -1 being the last element.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr = [1, 2, 3, 4, 5, 6]
|
|
|
|
* arr[2] #=> 3
|
|
|
|
* arr[100] #=> nil
|
|
|
|
* arr[-3] #=> 4
|
|
|
|
* arr[2, 3] #=> [3, 4, 5]
|
|
|
|
* arr[1..4] #=> [2, 3, 4, 5]
|
2013-11-07 21:15:49 +04:00
|
|
|
* arr[1..-3] #=> [2, 3, 4]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Another way to access a particular array element is by using the #at method
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr.at(0) #=> 1
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* The #slice method works in an identical manner to Array#[].
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* To raise an error for indices outside of the array bounds or else to
|
|
|
|
* provide a default value when that happens, you can use #fetch.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr = ['a', 'b', 'c', 'd', 'e', 'f']
|
|
|
|
* arr.fetch(100) #=> IndexError: index 100 outside of array bounds: -6...6
|
|
|
|
* arr.fetch(100, "oops") #=> "oops"
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* The special methods #first and #last will return the first and last
|
|
|
|
* elements of an array, respectively.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr.first #=> 1
|
|
|
|
* arr.last #=> 6
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* To return the first +n+ elements of an array, use #take
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr.take(3) #=> [1, 2, 3]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* #drop does the opposite of #take, by returning the elements after +n+
|
|
|
|
* elements have been dropped:
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr.drop(3) #=> [4, 5, 6]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* == Obtaining Information about an Array
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Arrays keep track of their own length at all times. To query an array
|
|
|
|
* about the number of elements it contains, use #length, #count or #size.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* browsers = ['Chrome', 'Firefox', 'Safari', 'Opera', 'IE']
|
|
|
|
* browsers.length #=> 5
|
|
|
|
* browsers.count #=> 5
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* To check whether an array contains any elements at all
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* browsers.empty? #=> false
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* To check whether a particular item is included in the array
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* browsers.include?('Konqueror') #=> false
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* == Adding Items to Arrays
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Items can be added to the end of an array by using either #push or #<<
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr = [1, 2, 3, 4]
|
|
|
|
* arr.push(5) #=> [1, 2, 3, 4, 5]
|
|
|
|
* arr << 6 #=> [1, 2, 3, 4, 5, 6]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* #unshift will add a new item to the beginning of an array.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr.unshift(0) #=> [0, 1, 2, 3, 4, 5, 6]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* With #insert you can add a new element to an array at any position.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr.insert(3, 'apple') #=> [0, 1, 2, 'apple', 3, 4, 5, 6]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Using the #insert method, you can also insert multiple values at once:
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr.insert(3, 'orange', 'pear', 'grapefruit')
|
|
|
|
* #=> [0, 1, 2, "orange", "pear", "grapefruit", "apple", 3, 4, 5, 6]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* == Removing Items from an Array
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* The method #pop removes the last element in an array and returns it:
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr = [1, 2, 3, 4, 5, 6]
|
|
|
|
* arr.pop #=> 6
|
|
|
|
* arr #=> [1, 2, 3, 4, 5]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* To retrieve and at the same time remove the first item, use #shift:
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr.shift #=> 1
|
|
|
|
* arr #=> [2, 3, 4, 5]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* To delete an element at a particular index:
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr.delete_at(2) #=> 4
|
|
|
|
* arr #=> [2, 3, 5]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* To delete a particular element anywhere in an array, use #delete:
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr = [1, 2, 2, 3]
|
2013-03-17 22:19:56 +04:00
|
|
|
* arr.delete(2) #=> 2
|
|
|
|
* arr #=> [1,3]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* A useful method if you need to remove +nil+ values from an array is
|
|
|
|
* #compact:
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr = ['foo', 0, nil, 'bar', 7, 'baz', nil]
|
|
|
|
* arr.compact #=> ['foo', 0, 'bar', 7, 'baz']
|
|
|
|
* arr #=> ['foo', 0, nil, 'bar', 7, 'baz', nil]
|
|
|
|
* arr.compact! #=> ['foo', 0, 'bar', 7, 'baz']
|
|
|
|
* arr #=> ['foo', 0, 'bar', 7, 'baz']
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Another common need is to remove duplicate elements from an array.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* It has the non-destructive #uniq, and destructive method #uniq!
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr = [2, 5, 6, 556, 6, 6, 8, 9, 0, 123, 556]
|
|
|
|
* arr.uniq #=> [2, 5, 6, 556, 8, 9, 0, 123]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* == Iterating over Arrays
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Like all classes that include the Enumerable module, Array has an each
|
|
|
|
* method, which defines what elements should be iterated over and how. In
|
|
|
|
* case of Array's #each, all elements in the Array instance are yielded to
|
|
|
|
* the supplied block in sequence.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Note that this operation leaves the array unchanged.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr = [1, 2, 3, 4, 5]
|
2018-07-11 12:56:49 +03:00
|
|
|
* arr.each {|a| print a -= 10, " "}
|
2012-06-01 03:51:33 +04:00
|
|
|
* # prints: -9 -8 -7 -6 -5
|
|
|
|
* #=> [1, 2, 3, 4, 5]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Another sometimes useful iterator is #reverse_each which will iterate over
|
|
|
|
* the elements in the array in reverse order.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2013-07-11 09:51:19 +04:00
|
|
|
* words = %w[first second third fourth fifth sixth]
|
2012-06-01 03:51:33 +04:00
|
|
|
* str = ""
|
2018-07-11 12:56:49 +03:00
|
|
|
* words.reverse_each {|word| str += "#{word} "}
|
2013-07-11 09:51:19 +04:00
|
|
|
* p str #=> "sixth fifth fourth third second first "
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* The #map method can be used to create a new array based on the original
|
|
|
|
* array, but with the values modified by the supplied block:
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2018-07-11 12:56:49 +03:00
|
|
|
* arr.map {|a| 2*a} #=> [2, 4, 6, 8, 10]
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr #=> [1, 2, 3, 4, 5]
|
2018-07-11 12:56:49 +03:00
|
|
|
* arr.map! {|a| a**2} #=> [1, 4, 9, 16, 25]
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr #=> [1, 4, 9, 16, 25]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* == Selecting Items from an Array
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Elements can be selected from an array according to criteria defined in a
|
|
|
|
* block. The selection can happen in a destructive or a non-destructive
|
|
|
|
* manner. While the destructive operations will modify the array they were
|
|
|
|
* called on, the non-destructive methods usually return a new array with the
|
|
|
|
* selected elements, but leave the original array unchanged.
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* === Non-destructive Selection
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr = [1, 2, 3, 4, 5, 6]
|
2018-07-11 12:56:49 +03:00
|
|
|
* arr.select {|a| a > 3} #=> [4, 5, 6]
|
|
|
|
* arr.reject {|a| a < 3} #=> [3, 4, 5, 6]
|
|
|
|
* arr.drop_while {|a| a < 4} #=> [4, 5, 6]
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr #=> [1, 2, 3, 4, 5, 6]
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* === Destructive Selection
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* #select! and #reject! are the corresponding destructive methods to #select
|
|
|
|
* and #reject
|
2011-10-11 02:55:54 +04:00
|
|
|
*
|
2012-06-01 03:51:33 +04:00
|
|
|
* Similar to #select vs. #reject, #delete_if and #keep_if have the exact
|
|
|
|
* opposite result when supplied with the same block:
|
|
|
|
*
|
2018-07-11 12:56:49 +03:00
|
|
|
* arr.delete_if {|a| a < 4} #=> [4, 5, 6]
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr #=> [4, 5, 6]
|
|
|
|
*
|
|
|
|
* arr = [1, 2, 3, 4, 5, 6]
|
2018-07-11 12:56:49 +03:00
|
|
|
* arr.keep_if {|a| a < 4} #=> [1, 2, 3]
|
2012-06-01 03:51:33 +04:00
|
|
|
* arr #=> [1, 2, 3]
|
2003-12-16 23:28:44 +03:00
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
void
|
2005-09-10 17:34:53 +04:00
|
|
|
Init_Array(void)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2008-06-09 13:25:32 +04:00
|
|
|
#undef rb_intern
|
2008-08-16 04:20:31 +04:00
|
|
|
#define rb_intern(str) rb_intern_const(str)
|
2008-06-09 13:25:32 +04:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_cArray = rb_define_class("Array", rb_cObject);
|
|
|
|
rb_include_module(rb_cArray, rb_mEnumerable);
|
|
|
|
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
|
|
|
rb_define_alloc_func(rb_cArray, empty_ary_alloc);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_singleton_method(rb_cArray, "[]", rb_ary_s_create, -1);
|
2007-08-24 21:47:09 +04:00
|
|
|
rb_define_singleton_method(rb_cArray, "try_convert", rb_ary_s_try_convert, 1);
|
2000-02-29 11:05:32 +03:00
|
|
|
rb_define_method(rb_cArray, "initialize", rb_ary_initialize, -1);
|
2003-05-19 09:41:08 +04:00
|
|
|
rb_define_method(rb_cArray, "initialize_copy", rb_ary_replace, 1);
|
2003-04-03 09:25:00 +04:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cArray, "inspect", rb_ary_inspect, 0);
|
2009-05-02 04:19:41 +04:00
|
|
|
rb_define_alias(rb_cArray, "to_s", "inspect");
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cArray, "to_a", rb_ary_to_a, 0);
|
2013-10-23 19:10:48 +04:00
|
|
|
rb_define_method(rb_cArray, "to_h", rb_ary_to_h, 0);
|
2003-02-10 12:40:13 +03:00
|
|
|
rb_define_method(rb_cArray, "to_ary", rb_ary_to_ary_m, 0);
|
1999-01-20 07:59:39 +03:00
|
|
|
|
|
|
|
rb_define_method(rb_cArray, "==", rb_ary_equal, 1);
|
|
|
|
rb_define_method(rb_cArray, "eql?", rb_ary_eql, 1);
|
|
|
|
rb_define_method(rb_cArray, "hash", rb_ary_hash, 0);
|
|
|
|
|
|
|
|
rb_define_method(rb_cArray, "[]", rb_ary_aref, -1);
|
|
|
|
rb_define_method(rb_cArray, "[]=", rb_ary_aset, -1);
|
1999-10-13 10:44:42 +04:00
|
|
|
rb_define_method(rb_cArray, "at", rb_ary_at, 1);
|
2001-02-02 14:38:20 +03:00
|
|
|
rb_define_method(rb_cArray, "fetch", rb_ary_fetch, -1);
|
2003-06-06 13:24:59 +04:00
|
|
|
rb_define_method(rb_cArray, "first", rb_ary_first, -1);
|
|
|
|
rb_define_method(rb_cArray, "last", rb_ary_last, -1);
|
2016-08-27 04:26:17 +03:00
|
|
|
rb_define_method(rb_cArray, "concat", rb_ary_concat_multi, -1);
|
2018-09-20 06:18:52 +03:00
|
|
|
rb_define_method(rb_cArray, "union", rb_ary_union_multi, -1);
|
2018-10-05 09:23:34 +03:00
|
|
|
rb_define_method(rb_cArray, "difference", rb_ary_difference_multi, -1);
|
2019-10-07 08:12:29 +03:00
|
|
|
rb_define_method(rb_cArray, "intersection", rb_ary_intersection_multi, -1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cArray, "<<", rb_ary_push, 1);
|
2000-01-05 07:41:21 +03:00
|
|
|
rb_define_method(rb_cArray, "push", rb_ary_push_m, -1);
|
2017-04-01 10:38:12 +03:00
|
|
|
rb_define_alias(rb_cArray, "append", "push");
|
2004-06-16 11:05:24 +04:00
|
|
|
rb_define_method(rb_cArray, "pop", rb_ary_pop_m, -1);
|
|
|
|
rb_define_method(rb_cArray, "shift", rb_ary_shift_m, -1);
|
2000-05-01 13:42:38 +04:00
|
|
|
rb_define_method(rb_cArray, "unshift", rb_ary_unshift_m, -1);
|
2017-04-01 10:38:12 +03:00
|
|
|
rb_define_alias(rb_cArray, "prepend", "unshift");
|
2001-05-02 08:22:21 +04:00
|
|
|
rb_define_method(rb_cArray, "insert", rb_ary_insert, -1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cArray, "each", rb_ary_each, 0);
|
|
|
|
rb_define_method(rb_cArray, "each_index", rb_ary_each_index, 0);
|
|
|
|
rb_define_method(rb_cArray, "reverse_each", rb_ary_reverse_each, 0);
|
|
|
|
rb_define_method(rb_cArray, "length", rb_ary_length, 0);
|
|
|
|
rb_define_alias(rb_cArray, "size", "length");
|
|
|
|
rb_define_method(rb_cArray, "empty?", rb_ary_empty_p, 0);
|
2008-04-11 11:58:06 +04:00
|
|
|
rb_define_method(rb_cArray, "find_index", rb_ary_index, -1);
|
2004-10-05 05:37:46 +04:00
|
|
|
rb_define_method(rb_cArray, "index", rb_ary_index, -1);
|
|
|
|
rb_define_method(rb_cArray, "rindex", rb_ary_rindex, -1);
|
2000-01-05 07:41:21 +03:00
|
|
|
rb_define_method(rb_cArray, "join", rb_ary_join_m, -1);
|
|
|
|
rb_define_method(rb_cArray, "reverse", rb_ary_reverse_m, 0);
|
2000-08-24 10:21:43 +04:00
|
|
|
rb_define_method(rb_cArray, "reverse!", rb_ary_reverse_bang, 0);
|
2010-01-21 05:15:48 +03:00
|
|
|
rb_define_method(rb_cArray, "rotate", rb_ary_rotate_m, -1);
|
|
|
|
rb_define_method(rb_cArray, "rotate!", rb_ary_rotate_bang, -1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cArray, "sort", rb_ary_sort, 0);
|
|
|
|
rb_define_method(rb_cArray, "sort!", rb_ary_sort_bang, 0);
|
2009-02-02 13:43:27 +03:00
|
|
|
rb_define_method(rb_cArray, "sort_by!", rb_ary_sort_by_bang, 0);
|
1999-10-29 13:25:48 +04:00
|
|
|
rb_define_method(rb_cArray, "collect", rb_ary_collect, 0);
|
2000-05-01 13:42:38 +04:00
|
|
|
rb_define_method(rb_cArray, "collect!", rb_ary_collect_bang, 0);
|
2001-07-14 19:17:19 +04:00
|
|
|
rb_define_method(rb_cArray, "map", rb_ary_collect, 0);
|
2000-05-01 13:42:38 +04:00
|
|
|
rb_define_method(rb_cArray, "map!", rb_ary_collect_bang, 0);
|
2004-06-16 11:05:24 +04:00
|
|
|
rb_define_method(rb_cArray, "select", rb_ary_select, 0);
|
2010-03-03 08:35:08 +03:00
|
|
|
rb_define_method(rb_cArray, "select!", rb_ary_select_bang, 0);
|
2018-02-25 16:52:07 +03:00
|
|
|
rb_define_method(rb_cArray, "filter", rb_ary_select, 0);
|
|
|
|
rb_define_method(rb_cArray, "filter!", rb_ary_select_bang, 0);
|
2010-03-03 08:35:08 +03:00
|
|
|
rb_define_method(rb_cArray, "keep_if", rb_ary_keep_if, 0);
|
2003-05-04 20:03:24 +04:00
|
|
|
rb_define_method(rb_cArray, "values_at", rb_ary_values_at, -1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cArray, "delete", rb_ary_delete, 1);
|
2000-05-30 08:24:17 +04:00
|
|
|
rb_define_method(rb_cArray, "delete_at", rb_ary_delete_at_m, 1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cArray, "delete_if", rb_ary_delete_if, 0);
|
2001-10-16 07:27:23 +04:00
|
|
|
rb_define_method(rb_cArray, "reject", rb_ary_reject, 0);
|
2000-08-07 09:05:04 +04:00
|
|
|
rb_define_method(rb_cArray, "reject!", rb_ary_reject_bang, 0);
|
2008-01-08 12:50:01 +03:00
|
|
|
rb_define_method(rb_cArray, "zip", rb_ary_zip, -1);
|
2002-11-19 11:07:51 +03:00
|
|
|
rb_define_method(rb_cArray, "transpose", rb_ary_transpose, 0);
|
2001-05-06 19:06:00 +04:00
|
|
|
rb_define_method(rb_cArray, "replace", rb_ary_replace, 1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cArray, "clear", rb_ary_clear, 0);
|
|
|
|
rb_define_method(rb_cArray, "fill", rb_ary_fill, -1);
|
|
|
|
rb_define_method(rb_cArray, "include?", rb_ary_includes, 1);
|
|
|
|
rb_define_method(rb_cArray, "<=>", rb_ary_cmp, 1);
|
|
|
|
|
2000-02-01 06:12:21 +03:00
|
|
|
rb_define_method(rb_cArray, "slice", rb_ary_aref, -1);
|
2000-05-24 08:34:26 +04:00
|
|
|
rb_define_method(rb_cArray, "slice!", rb_ary_slice_bang, -1);
|
2000-02-01 06:12:21 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cArray, "assoc", rb_ary_assoc, 1);
|
|
|
|
rb_define_method(rb_cArray, "rassoc", rb_ary_rassoc, 1);
|
|
|
|
|
|
|
|
rb_define_method(rb_cArray, "+", rb_ary_plus, 1);
|
|
|
|
rb_define_method(rb_cArray, "*", rb_ary_times, 1);
|
|
|
|
|
|
|
|
rb_define_method(rb_cArray, "-", rb_ary_diff, 1);
|
|
|
|
rb_define_method(rb_cArray, "&", rb_ary_and, 1);
|
|
|
|
rb_define_method(rb_cArray, "|", rb_ary_or, 1);
|
|
|
|
|
2016-03-17 15:14:21 +03:00
|
|
|
rb_define_method(rb_cArray, "max", rb_ary_max, -1);
|
|
|
|
rb_define_method(rb_cArray, "min", rb_ary_min, -1);
|
2019-06-17 21:33:44 +03:00
|
|
|
rb_define_method(rb_cArray, "minmax", rb_ary_minmax, 0);
|
2016-03-17 15:14:21 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cArray, "uniq", rb_ary_uniq, 0);
|
|
|
|
rb_define_method(rb_cArray, "uniq!", rb_ary_uniq_bang, 0);
|
|
|
|
rb_define_method(rb_cArray, "compact", rb_ary_compact, 0);
|
|
|
|
rb_define_method(rb_cArray, "compact!", rb_ary_compact_bang, 0);
|
* sprintf.c (rb_str_format): allow %c to print one character
string (e.g. ?x).
* lib/tempfile.rb (Tempfile::make_tmpname): put dot between
basename and pid. [ruby-talk:196272]
* parse.y (do_block): remove -> style block.
* parse.y (parser_yylex): remove tLAMBDA_ARG.
* eval.c (rb_call0): binding for the return event hook should have
consistent scope. [ruby-core:07928]
* eval.c (proc_invoke): return behavior should depend whether it
is surrounded by a lambda or a mere block.
* eval.c (formal_assign): handles post splat arguments.
* eval.c (rb_call0): ditto.
* st.c (strhash): use FNV-1a hash.
* parse.y (parser_yylex): removed experimental ';;' terminator.
* eval.c (rb_node_arity): should be aware of post splat arguments.
* eval.c (rb_proc_arity): ditto.
* parse.y (f_args): syntax rule enhanced to support arguments
after the splat.
* parse.y (block_param): ditto for block parameters.
* parse.y (f_post_arg): mandatory formal arguments after the splat
argument.
* parse.y (new_args_gen): generate nodes for mandatory formal
arguments after the splat argument.
* eval.c (rb_eval): dispatch mandatory formal arguments after the
splat argument.
* parse.y (args): allow more than one splat in the argument list.
* parse.y (method_call): allow aref [] to accept all kind of
method argument, including assocs, splat, and block argument.
* eval.c (SETUP_ARGS0): prepare block argument as well.
* lib/mathn.rb (Integer): remove Integer#gcd2. [ruby-core:07931]
* eval.c (error_line): print receivers true/false/nil specially.
* eval.c (rb_proc_yield): handles parameters in yield semantics.
* eval.c (nil_yield): gives LocalJumpError to denote no block
error.
* io.c (rb_io_getc): now takes one-character string.
* string.c (rb_str_hash): use FNV-1a hash from Fowler/Noll/Vo
hashing algorithm.
* string.c (rb_str_aref): str[0] now returns 1 character string,
instead of a fixnum. [Ruby2]
* parse.y (parser_yylex): ?c now returns 1 character string,
instead of a fixnum. [Ruby2]
* string.c (rb_str_aset): no longer support fixnum insertion.
* eval.c (umethod_bind): should not update original class.
[ruby-dev:28636]
* eval.c (ev_const_get): should support constant access from
within instance_eval(). [ruby-dev:28327]
* time.c (time_timeval): should round for usec floating
number. [ruby-core:07896]
* time.c (time_add): ditto.
* dir.c (sys_warning): should not call a vararg function
rb_sys_warning() indirectly. [ruby-core:07886]
* numeric.c (flo_divmod): the first element of Float#divmod should
be an integer. [ruby-dev:28589]
* test/ruby/test_float.rb: add tests for divmod, div, modulo and remainder.
* re.c (rb_reg_initialize): should not allow modifying literal
regexps. frozen check moved from rb_reg_initialize_m as well.
* re.c (rb_reg_initialize): should not modify untainted objects in
safe levels higher than 3.
* re.c (rb_memcmp): type change from char* to const void*.
* dir.c (dir_close): should not close untainted dir stream.
* dir.c (GetDIR): add tainted/frozen check for each dir operation.
* lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_symbol_arg):
typo fixed. a patch from Florian Gross <florg at florg.net>.
* eval.c (EXEC_EVENT_HOOK): trace_func may remove itself from
event_hooks. no guarantee for arbitrary hook deletion.
[ruby-dev:28632]
* util.c (ruby_strtod): differ addition to minimize error.
[ruby-dev:28619]
* util.c (ruby_strtod): should not raise ERANGE when the input
string does not have any digits. [ruby-dev:28629]
* eval.c (proc_invoke): should restore old ruby_frame->block.
thanks to ts <decoux at moulon.inra.fr>. [ruby-core:07833]
also fix [ruby-dev:28614] as well.
* signal.c (trap): sig should be less then NSIG. Coverity found
this bug. a patch from Kevin Tew <tewk at tewk.com>.
[ruby-core:07823]
* math.c (math_log2): add new method inspired by
[ruby-talk:191237].
* math.c (math_log): add optional base argument to Math::log().
[ruby-talk:191308]
* ext/syck/emitter.c (syck_scan_scalar): avoid accessing
uninitialized array element. a patch from Pat Eyler
<rubypate at gmail.com>. [ruby-core:07809]
* array.c (rb_ary_fill): initialize local variables first. a
patch from Pat Eyler <rubypate at gmail.com>. [ruby-core:07810]
* ext/syck/yaml2byte.c (syck_yaml2byte_handler): need to free
type_tag. a patch from Pat Eyler <rubypate at gmail.com>.
[ruby-core:07808]
* ext/socket/socket.c (make_hostent_internal): accept ai_family
check from Sam Roberts <sroberts at uniserve.com>.
[ruby-core:07691]
* util.c (ruby_strtod): should not cut off 18 digits for no
reason. [ruby-core:07796]
* array.c (rb_ary_fill): internalize local variable "beg" to
pacify Coverity. [ruby-core:07770]
* pack.c (pack_unpack): now supports CRLF newlines. a patch from
<tommy at tmtm.org>. [ruby-dev:28601]
* applied code clean-up patch from Stefan Huehner
<stefan at huehner.org>. [ruby-core:07764]
* lib/jcode.rb (String::tr_s): should have translated non
squeezing character sequence (i.e. a character) as well. thanks
to Hiroshi Ichikawa <gimite at gimite.ddo.jp> [ruby-list:42090]
* ext/socket/socket.c: document update patch from Sam Roberts
<sroberts at uniserve.com>. [ruby-core:07701]
* lib/mathn.rb (Integer): need not to remove gcd2. a patch from
NARUSE, Yui <naruse at airemix.com>. [ruby-dev:28570]
* parse.y (arg): too much NEW_LIST()
* eval.c (SETUP_ARGS0): remove unnecessary access to nd_alen.
* eval.c (rb_eval): use ARGSCAT for NODE_OP_ASGN1.
[ruby-dev:28585]
* parse.y (arg): use NODE_ARGSCAT for placeholder.
* lib/getoptlong.rb (GetoptLong::get): RDoc update patch from
mathew <meta at pobox.com>. [ruby-core:07738]
* variable.c (rb_const_set): raise error when no target klass is
supplied. [ruby-dev:28582]
* prec.c (prec_prec_f): documentation patch from
<gerardo.santana at gmail.com>. [ruby-core:07689]
* bignum.c (rb_big_pow): second operand may be too big even if
it's a Fixnum. [ruby-talk:187984]
* README.EXT: update symbol description. [ruby-talk:188104]
* COPYING: explicitly note GPLv2. [ruby-talk:187922]
* parse.y: remove some obsolete syntax rules (unparenthesized
method calls in argument list).
* eval.c (rb_call0): insecure calling should be checked for non
NODE_SCOPE method invocations too.
* eval.c (rb_alias): should preserve the current safe level as
well as method definition.
* process.c (rb_f_sleep): remove RDoc description about SIGALRM
which is not valid on the current implementation. [ruby-dev:28464]
Thu Mar 23 21:40:47 2006 K.Kosako <sndgk393 AT ybb.ne.jp>
* eval.c (method_missing): should support argument splat in
super. a bug in combination of super, splat and
method_missing. [ruby-talk:185438]
* configure.in: Solaris SunPro compiler -rapth patch from
<kuwa at labs.fujitsu.com>. [ruby-dev:28443]
* configure.in: remove enable_rpath=no for Solaris.
[ruby-dev:28440]
* ext/win32ole/win32ole.c (ole_val2olevariantdata): change behavior
of converting OLE Variant object with VT_ARRAY|VT_UI1 and Ruby
String object.
* ruby.1: a clarification patch from David Lutterkort
<dlutter at redhat.com>. [ruby-core:7508]
* lib/rdoc/ri/ri_paths.rb (RI::Paths): adding paths from rubygems
directories. a patch from Eric Hodel <drbrain at segment7.net>.
[ruby-core:07423]
* eval.c (rb_clear_cache_by_class): clearing wrong cache.
* ext/extmk.rb: use :remove_destination to install extension libraries
to avoid SEGV. [ruby-dev:28417]
* eval.c (rb_thread_fd_writable): should not re-schedule output
from KILLED thread (must be error printing).
* array.c (rb_ary_flatten_bang): allow specifying recursion
level. [ruby-talk:182170]
* array.c (rb_ary_flatten): ditto.
* gc.c (add_heap): a heap_slots may overflow. a patch from Stefan
Weil <weil at mail.berlios.de>.
* eval.c (rb_call): use separate cache for fcall/vcall
invocation.
* eval.c (rb_eval): NODE_FCALL, NODE_VCALL can call local
functions.
* eval.c (rb_mod_local): a new method to specify newly added
visibility "local".
* eval.c (search_method): search for local methods which are
visible only from the current class.
* class.c (rb_class_local_methods): a method to list local methods.
* object.c (Init_Object): add BasicObject class as a top level
BlankSlate class.
* ruby.h (SYM2ID): should not cast to signed long.
[ruby-core:07414]
* class.c (rb_include_module): allow module duplication.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10235 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2006-06-10 01:20:17 +04:00
|
|
|
rb_define_method(rb_cArray, "flatten", rb_ary_flatten, -1);
|
|
|
|
rb_define_method(rb_cArray, "flatten!", rb_ary_flatten_bang, -1);
|
2008-05-14 07:46:37 +04:00
|
|
|
rb_define_method(rb_cArray, "count", rb_ary_count, -1);
|
2008-04-13 18:59:55 +04:00
|
|
|
rb_define_method(rb_cArray, "cycle", rb_ary_cycle, -1);
|
2007-11-19 10:06:03 +03:00
|
|
|
rb_define_method(rb_cArray, "permutation", rb_ary_permutation, -1);
|
2007-09-29 12:43:59 +04:00
|
|
|
rb_define_method(rb_cArray, "combination", rb_ary_combination, 1);
|
2010-04-16 11:24:04 +04:00
|
|
|
rb_define_method(rb_cArray, "repeated_permutation", rb_ary_repeated_permutation, 1);
|
|
|
|
rb_define_method(rb_cArray, "repeated_combination", rb_ary_repeated_combination, 1);
|
2007-10-02 07:33:53 +04:00
|
|
|
rb_define_method(rb_cArray, "product", rb_ary_product, -1);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2008-03-17 16:28:46 +03:00
|
|
|
rb_define_method(rb_cArray, "take", rb_ary_take, 1);
|
|
|
|
rb_define_method(rb_cArray, "take_while", rb_ary_take_while, 0);
|
|
|
|
rb_define_method(rb_cArray, "drop", rb_ary_drop, 1);
|
|
|
|
rb_define_method(rb_cArray, "drop_while", rb_ary_drop_while, 0);
|
2012-11-14 19:53:50 +04:00
|
|
|
rb_define_method(rb_cArray, "bsearch", rb_ary_bsearch, 0);
|
2015-06-12 10:28:21 +03:00
|
|
|
rb_define_method(rb_cArray, "bsearch_index", rb_ary_bsearch_index, 0);
|
2017-12-11 01:36:28 +03:00
|
|
|
rb_define_method(rb_cArray, "any?", rb_ary_any_p, -1);
|
2018-12-05 07:25:44 +03:00
|
|
|
rb_define_method(rb_cArray, "all?", rb_ary_all_p, -1);
|
|
|
|
rb_define_method(rb_cArray, "none?", rb_ary_none_p, -1);
|
|
|
|
rb_define_method(rb_cArray, "one?", rb_ary_one_p, -1);
|
2015-11-09 15:27:26 +03:00
|
|
|
rb_define_method(rb_cArray, "dig", rb_ary_dig, -1);
|
2016-04-14 15:48:44 +03:00
|
|
|
rb_define_method(rb_cArray, "sum", rb_ary_sum, -1);
|
2008-03-17 16:28:46 +03:00
|
|
|
|
2019-04-17 09:48:03 +03:00
|
|
|
rb_define_method(rb_cArray, "deconstruct", rb_ary_deconstruct, 0);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2020-01-26 12:27:40 +03:00
|
|
|
|
|
|
|
#include "array.rbinc"
|