1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/enum.c
matz 2f8d3bdc21 * array.c (rb_ary_modify): should copy the internal buffer if the
modifying buffer is shared.

* array.c (ary_make_shared): make an internal buffer of an array
  to be shared.

* array.c (rb_ary_shift): avoid sliding an internal buffer by
  using shared buffer.

* array.c (rb_ary_subseq): avoid copying the buffer.

* parse.y (gettable): should freeze __LINE__ string.

* io.c (rb_io_puts): old behavoir restored.  rationale: a) if you
  want to call to_s for arrays, you can just call print a, "\n".
  b) to_s wastes memory if array (and sum of its contents) is
  huge.  c) now any object that has to_ary is treated as an array,
  using rb_check_convert_type().

* hash.c (rb_hash_initialize): now accepts a block to calculate
  the default value. [new]

* hash.c (rb_hash_aref): call "default" method to get the value
  corrensponding to the non existing key.

* hash.c (rb_hash_default): get the default value based on the
  block given to 'new'.  Now it takes an optinal "key" argument.
  "default" became the method to get the value for non existing
  key.  Users may override "default" method to change the hash
  behavior.

* hash.c (rb_hash_set_default): clear the flag if a block is given
  to 'new'

* object.c (Init_Object): undef Data.allocate, left Data.new.

* ext/curses/curses.c (window_scrollok): use RTEST().

* ext/curses/curses.c (window_idlok): ditto.

* ext/curses/curses.c (window_keypad): ditto.

* ext/curses/curses.c (window_idlok): idlok() may return void on
  some platforms; so don't use return value.

* ext/curses/curses.c (window_scrollok): ditto for consistency.

* ext/curses/curses.c: replace FIX2INT() by typechecking NUM2INT().

* parse.y (str_extend): should not process immature #$x and
  #@x interpolation, e.g #@#@ etc.

* enum.c (enum_sort_by): sort_by does not have to be stable always.

* enum.c (enum_sort_by): call qsort directly to gain performance.

* util.c (ruby_qsort): ruby_qsort(qs6) is now native thread safe.

* error.c (rb_sys_fail): it must be a bug if it's called when
  errno == 0.

* regex.c (WC2MBC1ST): should not pass through > 0x80 number in UTF-8.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1896 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2001-12-10 07:18:16 +00:00

463 lines
8.4 KiB
C

/**********************************************************************
enum.c -
$Author$
$Date$
created at: Fri Oct 1 15:15:19 JST 1993
Copyright (C) 1993-2001 Yukihiro Matsumoto
**********************************************************************/
#include "ruby.h"
#include "node.h"
#include "util.h"
VALUE rb_mEnumerable;
static ID id_each, id_eqq, id_cmp;
VALUE
rb_each(obj)
VALUE obj;
{
return rb_funcall(obj, id_each, 0, 0);
}
static VALUE
grep_i(i, arg)
VALUE i, *arg;
{
if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
rb_ary_push(arg[1], i);
}
return Qnil;
}
static VALUE
grep_iter_i(i, arg)
VALUE i, *arg;
{
if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
rb_ary_push(arg[1], rb_yield(i));
}
return Qnil;
}
static VALUE
enum_grep(obj, pat)
VALUE obj, pat;
{
VALUE tmp, arg[2];
arg[0] = pat; arg[1] = tmp = rb_ary_new();
if (rb_block_given_p()) {
rb_iterate(rb_each, obj, grep_iter_i, (VALUE)arg);
}
else {
rb_iterate(rb_each, obj, grep_i, (VALUE)arg);
}
return tmp;
}
static VALUE
find_i(i, memo)
VALUE i;
NODE *memo;
{
if (RTEST(rb_yield(i))) {
memo->u2.value = Qtrue;
memo->u1.value = i;
rb_iter_break();
}
return Qnil;
}
static VALUE
enum_find(argc, argv, obj)
int argc;
VALUE* argv;
VALUE obj;
{
NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, Qfalse, 0);
VALUE if_none;
rb_scan_args(argc, argv, "01", &if_none);
rb_iterate(rb_each, obj, find_i, (VALUE)memo);
if (memo->u2.value) {
rb_gc_force_recycle((VALUE)memo);
return memo->u1.value;
}
rb_gc_force_recycle((VALUE)memo);
if (!NIL_P(if_none)) {
rb_eval_cmd(if_none, rb_ary_new2(0), 0);
}
return Qnil;
}
static VALUE
find_all_i(i, tmp)
VALUE i, tmp;
{
if (RTEST(rb_yield(i))) {
rb_ary_push(tmp, i);
}
return Qnil;
}
static VALUE
enum_find_all(obj)
VALUE obj;
{
VALUE tmp;
tmp = rb_ary_new();
rb_iterate(rb_each, obj, find_all_i, tmp);
return tmp;
}
static VALUE
reject_i(i, tmp)
VALUE i, tmp;
{
if (!RTEST(rb_yield(i))) {
rb_ary_push(tmp, i);
}
return Qnil;
}
static VALUE
enum_reject(obj)
VALUE obj;
{
VALUE tmp;
tmp = rb_ary_new();
rb_iterate(rb_each, obj, reject_i, tmp);
return tmp;
}
static VALUE
collect_i(i, tmp)
VALUE i, tmp;
{
rb_ary_push(tmp, rb_yield(i));
return Qnil;
}
static VALUE
collect_all(i, ary)
VALUE i, ary;
{
rb_ary_push(ary, i);
return Qnil;
}
static VALUE
enum_to_a(obj)
VALUE obj;
{
VALUE ary;
ary = rb_ary_new();
rb_iterate(rb_each, obj, collect_all, ary);
return ary;
}
static VALUE
enum_collect(obj)
VALUE obj;
{
VALUE tmp;
tmp = rb_ary_new();
rb_iterate(rb_each, obj, rb_block_given_p() ? collect_i : collect_all, tmp);
return tmp;
}
static VALUE
inject_i(i, np)
VALUE i;
VALUE *np;
{
*np = rb_yield(rb_assoc_new(*np, i));
return Qnil;
}
static VALUE
enum_inject(obj, n)
VALUE obj, n;
{
rb_iterate(rb_each, obj, inject_i, (VALUE)&n);
return n;
}
static VALUE
enum_sort(obj)
VALUE obj;
{
return rb_ary_sort(enum_to_a(obj));
}
static VALUE
sort_by_i(i, ary)
VALUE i, ary;
{
VALUE v, e;
v = rb_yield(i);
e = rb_assoc_new(v, i);
rb_ary_push(ary, e);
return Qnil;
}
static int
sort_by_cmp(a, b)
VALUE *a, *b;
{
VALUE retval;
retval = rb_funcall(RARRAY(*a)->ptr[0], id_cmp, 1, RARRAY(*b)->ptr[0]);
return rb_cmpint(retval);
}
static VALUE
enum_sort_by(obj)
VALUE obj;
{
VALUE ary;
long i;
ary = rb_ary_new2((TYPE(obj) == T_ARRAY) ? RARRAY(obj)->len : 2000);
rb_iterate(rb_each, obj, sort_by_i, ary);
if (RARRAY(ary)->len <= 1) return ary;
qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), sort_by_cmp);
for (i=0; i<RARRAY(ary)->len; i++) {
VALUE e = RARRAY(ary)->ptr[i];
RARRAY(ary)->ptr[i] = RARRAY(e)->ptr[1];
}
return ary;
}
static VALUE
all_i(i, memo)
VALUE i;
NODE *memo;
{
if (!RTEST(rb_yield(i))) {
memo->u1.value = Qfalse;
rb_iter_break();
}
return Qnil;
}
static VALUE
enum_all(obj)
VALUE obj;
{
NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0);
memo->u1.value = Qtrue;
rb_iterate(rb_each, obj, all_i, (VALUE)memo);
rb_gc_force_recycle((VALUE)memo);
return memo->u1.value;
}
static VALUE
any_i(i, memo)
VALUE i;
NODE *memo;
{
if (RTEST(rb_yield(i))) {
memo->u1.value = Qtrue;
rb_iter_break();
}
return Qnil;
}
static VALUE
enum_any(obj)
VALUE obj;
{
NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0);
memo->u1.value = Qfalse;
rb_iterate(rb_each, obj, any_i, (VALUE)memo);
rb_gc_force_recycle((VALUE)memo);
return memo->u1.value;
}
static VALUE
min_i(i, memo)
VALUE i;
NODE *memo;
{
VALUE cmp;
if (NIL_P(memo->u1.value))
memo->u1.value = i;
else {
cmp = rb_funcall(i, id_cmp, 1, memo->u1.value);
if (rb_cmpint(cmp) < 0)
memo->u1.value = i;
}
return Qnil;
}
static VALUE
min_ii(i, memo)
VALUE i;
NODE *memo;
{
VALUE cmp;
if (NIL_P(memo->u1.value))
memo->u1.value = i;
else {
cmp = rb_yield(rb_assoc_new(i, memo->u1.value));
if (rb_cmpint(cmp) < 0)
memo->u1.value = i;
}
return Qnil;
}
static VALUE
enum_min(obj)
VALUE obj;
{
NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0);
rb_iterate(rb_each, obj, rb_block_given_p()?min_ii:min_i, (VALUE)memo);
rb_gc_force_recycle((VALUE)memo);
return memo->u1.value;
}
static VALUE
max_i(i, memo)
VALUE i;
NODE *memo;
{
VALUE cmp;
if (NIL_P(memo->u1.value))
memo->u1.value = i;
else {
cmp = rb_funcall(i, id_cmp, 1, memo->u1.value);
if (rb_cmpint(cmp) > 0)
memo->u1.value = i;
}
return Qnil;
}
static VALUE
max_ii(i, memo)
VALUE i;
NODE *memo;
{
VALUE cmp;
if (NIL_P(memo->u1.value))
memo->u1.value = i;
else {
cmp = rb_yield(rb_assoc_new(i, memo->u1.value));
if (rb_cmpint(cmp) > 0)
memo->u1.value = i;
}
return Qnil;
}
static VALUE
enum_max(obj)
VALUE obj;
{
NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0);
rb_iterate(rb_each, obj, rb_block_given_p()?max_ii:max_i, (VALUE)memo);
rb_gc_force_recycle((VALUE)memo);
return memo->u1.value;
}
static VALUE
member_i(item, memo)
VALUE item;
NODE *memo;
{
if (rb_equal(item, memo->u1.value)) {
memo->u2.value = Qtrue;
rb_iter_break();
}
return Qnil;
}
static VALUE
enum_member(obj, val)
VALUE obj, val;
{
VALUE result;
NODE *memo = rb_node_newnode(NODE_MEMO, val, Qfalse, 0);
rb_iterate(rb_each, obj, member_i, (VALUE)memo);
result = memo->u2.value;
rb_gc_force_recycle((VALUE)memo);
return result;
}
static VALUE
each_with_index_i(val, memo)
VALUE val;
NODE *memo;
{
rb_yield(rb_assoc_new(val, INT2FIX(memo->u3.cnt)));
memo->u3.cnt++;
return Qnil;
}
static VALUE
enum_each_with_index(obj)
VALUE obj;
{
NODE *memo = rb_node_newnode(NODE_MEMO, 0, 0, 0);
rb_iterate(rb_each, obj, each_with_index_i, (VALUE)memo);
rb_gc_force_recycle((VALUE)memo);
return Qnil;
}
void
Init_Enumerable()
{
rb_mEnumerable = rb_define_module("Enumerable");
rb_define_method(rb_mEnumerable,"to_a", enum_to_a, 0);
rb_define_method(rb_mEnumerable,"entries", enum_to_a, 0);
rb_define_method(rb_mEnumerable,"sort", enum_sort, 0);
rb_define_method(rb_mEnumerable,"sort_by", enum_sort_by, 0);
rb_define_method(rb_mEnumerable,"grep", enum_grep, 1);
rb_define_method(rb_mEnumerable,"find", enum_find, -1);
rb_define_method(rb_mEnumerable,"detect", enum_find, -1);
rb_define_method(rb_mEnumerable,"find_all", enum_find_all, 0);
rb_define_method(rb_mEnumerable,"select", enum_find_all, 0);
rb_define_method(rb_mEnumerable,"reject", enum_reject, 0);
rb_define_method(rb_mEnumerable,"collect", enum_collect, 0);
rb_define_method(rb_mEnumerable,"map", enum_collect, 0);
rb_define_method(rb_mEnumerable,"inject", enum_inject, 1);
rb_define_method(rb_mEnumerable,"all?", enum_all, 0);
rb_define_method(rb_mEnumerable,"any?", enum_any, 0);
rb_define_method(rb_mEnumerable,"min", enum_min, 0);
rb_define_method(rb_mEnumerable,"max", enum_max, 0);
rb_define_method(rb_mEnumerable,"member?", enum_member, 1);
rb_define_method(rb_mEnumerable,"include?", enum_member, 1);
rb_define_method(rb_mEnumerable,"each_with_index", enum_each_with_index, 0);
id_eqq = rb_intern("===");
id_each = rb_intern("each");
id_cmp = rb_intern("<=>");
}