enum.c


DEFINITIONS

This source file includes following functions.
  1. rb_each
  2. grep_i
  3. grep_iter_i
  4. enum_grep
  5. find_i
  6. enum_find
  7. find_all_i
  8. enum_find_all
  9. reject_i
  10. enum_reject
  11. collect_i
  12. collect_all
  13. enum_to_a
  14. enum_collect
  15. inject_i
  16. enum_inject
  17. partition_i
  18. enum_partition
  19. enum_sort
  20. sort_by_i
  21. sort_by_cmp
  22. enum_sort_by
  23. all_i
  24. enum_all
  25. any_i
  26. enum_any
  27. min_i
  28. min_ii
  29. enum_min
  30. max_i
  31. max_ii
  32. enum_max
  33. member_i
  34. enum_member
  35. each_with_index_i
  36. enum_each_with_index
  37. Init_Enumerable


   1  /**********************************************************************
   2  
   3    enum.c -
   4  
   5    $Author: matz $
   6    $Date: 2002/08/01 09:42:36 $
   7    created at: Fri Oct  1 15:15:19 JST 1993
   8  
   9    Copyright (C) 1993-2002 Yukihiro Matsumoto
  10  
  11  **********************************************************************/
  12  
  13  #include "ruby.h"
  14  #include "node.h"
  15  #include "util.h"
  16  
  17  VALUE rb_mEnumerable;
  18  static ID id_each, id_eqq, id_cmp;
  19  
  20  VALUE
  21  rb_each(obj)
  22      VALUE obj;
  23  {
  24      return rb_funcall(obj, id_each, 0, 0);
  25  }
  26  
  27  static VALUE
  28  grep_i(i, arg)
  29      VALUE i, *arg;
  30  {
  31      if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
  32          rb_ary_push(arg[1], i);
  33      }
  34      return Qnil;
  35  }
  36  
  37  static VALUE
  38  grep_iter_i(i, arg)
  39      VALUE i, *arg;
  40  {
  41      if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
  42          rb_ary_push(arg[1], rb_yield(i));
  43      }
  44      return Qnil;
  45  }
  46  
  47  static VALUE
  48  enum_grep(obj, pat)
  49      VALUE obj, pat;
  50  {
  51      VALUE ary = rb_ary_new();
  52      VALUE arg[2];
  53  
  54      arg[0] = pat;
  55      arg[1] = ary;
  56  
  57      rb_iterate(rb_each, obj, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)arg);
  58      
  59      return ary;
  60  }
  61  
  62  static VALUE
  63  find_i(i, memo)
  64      VALUE i;
  65      NODE *memo;
  66  {
  67      if (RTEST(rb_yield(i))) {
  68          memo->u2.value = Qtrue;
  69          memo->u1.value = i;
  70          rb_iter_break();
  71      }
  72      return Qnil;
  73  }
  74  
  75  static VALUE
  76  enum_find(argc, argv, obj)
  77      int argc;
  78      VALUE* argv;
  79      VALUE obj;
  80  {
  81      NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, Qfalse, 0);
  82      VALUE if_none;
  83  
  84      rb_scan_args(argc, argv, "01", &if_none);
  85      rb_iterate(rb_each, obj, find_i, (VALUE)memo);
  86      if (memo->u2.value) {
  87          VALUE result = memo->u1.value;
  88          rb_gc_force_recycle((VALUE)memo);
  89          return result;
  90      }
  91      rb_gc_force_recycle((VALUE)memo);
  92      if (!NIL_P(if_none)) {
  93          return rb_funcall(if_none, rb_intern("call"), 0, 0);
  94      }
  95      return Qnil;
  96  }
  97  
  98  static VALUE
  99  find_all_i(i, ary)
 100      VALUE i, ary;
 101  {
 102      if (RTEST(rb_yield(i))) {
 103          rb_ary_push(ary, i);
 104      }
 105      return Qnil;
 106  }
 107  
 108  static VALUE
 109  enum_find_all(obj)
 110      VALUE obj;
 111  {
 112      VALUE ary = rb_ary_new();
 113      
 114      rb_iterate(rb_each, obj, find_all_i, ary);
 115  
 116      return ary;
 117  }
 118  
 119  static VALUE
 120  reject_i(i, ary)
 121      VALUE i, ary;
 122  {
 123      if (!RTEST(rb_yield(i))) {
 124          rb_ary_push(ary, i);
 125      }
 126      return Qnil;
 127  }
 128  
 129  static VALUE
 130  enum_reject(obj)
 131      VALUE obj;
 132  {
 133      VALUE ary = rb_ary_new();
 134      
 135      rb_iterate(rb_each, obj, reject_i, ary);
 136  
 137      return ary;
 138  }
 139  
 140  static VALUE
 141  collect_i(i, ary)
 142      VALUE i, ary;
 143  {
 144      rb_ary_push(ary, rb_yield(i));
 145      
 146      return Qnil;
 147  }
 148  
 149  static VALUE
 150  collect_all(i, ary)
 151      VALUE i, ary;
 152  {
 153      rb_ary_push(ary, i);
 154      
 155      return Qnil;
 156  }
 157  
 158  static VALUE
 159  enum_to_a(obj)
 160      VALUE obj;
 161  {
 162      VALUE ary = rb_ary_new();
 163      
 164      rb_iterate(rb_each, obj, collect_all, ary);
 165  
 166      return ary;
 167  }
 168  
 169  static VALUE
 170  enum_collect(obj)
 171      VALUE obj;
 172  {
 173      VALUE ary = rb_ary_new();
 174      
 175      rb_iterate(rb_each, obj, rb_block_given_p() ? collect_i : collect_all, ary);
 176  
 177      return ary;
 178  }
 179  
 180  static VALUE
 181  inject_i(i, memo)
 182      VALUE i;
 183      NODE *memo;
 184  {
 185      if (memo->u2.value) {
 186          memo->u2.value = Qfalse;
 187          memo->u1.value = i;
 188      }
 189      else {
 190          memo->u1.value = rb_yield(rb_assoc_new(memo->u1.value, i));
 191      }
 192      return Qnil;
 193  }
 194  
 195  static VALUE
 196  enum_inject(argc, argv, obj)
 197      int argc;
 198      VALUE *argv, obj;
 199  {
 200      NODE *memo;
 201      VALUE n;
 202  
 203      if (rb_scan_args(argc, argv, "01", &n) == 1) {
 204          memo = rb_node_newnode(NODE_MEMO, n, Qfalse, 0);
 205      }
 206      else {
 207          memo = rb_node_newnode(NODE_MEMO, Qnil, Qtrue, 0);
 208      }
 209      rb_iterate(rb_each, obj, inject_i, (VALUE)memo);
 210      n = memo->u1.value;
 211      rb_gc_force_recycle((VALUE)memo);
 212      return n;
 213  }
 214  
 215  static VALUE
 216  partition_i(i, ary)
 217      VALUE i, *ary;
 218  {
 219      if (RTEST(rb_yield(i))) {
 220          rb_ary_push(ary[0], i);
 221      }
 222      else {
 223          rb_ary_push(ary[1], i);
 224      }
 225      return Qnil;
 226  }
 227  
 228  static VALUE
 229  enum_partition(obj)
 230      VALUE obj;
 231  {
 232      VALUE ary[2];
 233  
 234      ary[0] = rb_ary_new();
 235      ary[1] = rb_ary_new();
 236      rb_iterate(rb_each, obj, partition_i, (VALUE)ary);
 237  
 238      return rb_assoc_new(ary[0], ary[1]);
 239  }
 240  
 241  static VALUE
 242  enum_sort(obj)
 243      VALUE obj;
 244  {
 245      return rb_ary_sort(enum_to_a(obj));
 246  }
 247  
 248  static VALUE
 249  sort_by_i(i, ary)
 250      VALUE i, ary;
 251  {
 252      VALUE v, e;
 253  
 254      v = rb_yield(i);
 255      e = rb_assoc_new(v, i);
 256      rb_ary_push(ary, e);
 257      return Qnil;
 258  }
 259  
 260  static int
 261  sort_by_cmp(a, b)
 262      VALUE *a, *b;
 263  {
 264      VALUE retval;
 265  
 266      retval = rb_funcall(RARRAY(*a)->ptr[0], id_cmp, 1, RARRAY(*b)->ptr[0]);
 267      return rb_cmpint(retval);
 268  }
 269  
 270  static VALUE
 271  enum_sort_by(obj)
 272      VALUE obj;
 273  {
 274      VALUE ary;
 275      long i;
 276  
 277      ary  = rb_ary_new2((TYPE(obj) == T_ARRAY) ? RARRAY(obj)->len : 2000);
 278      rb_iterate(rb_each, obj, sort_by_i, ary);
 279      if (RARRAY(ary)->len > 1) {
 280          qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), sort_by_cmp);
 281      }
 282      for (i=0; i<RARRAY(ary)->len; i++) {
 283          VALUE e = RARRAY(ary)->ptr[i];
 284          RARRAY(ary)->ptr[i] = RARRAY(e)->ptr[1];
 285      }
 286      return ary;
 287  }
 288  
 289  static VALUE
 290  all_i(i, memo)
 291      VALUE i;
 292      NODE *memo;
 293  {
 294      if (!RTEST(rb_yield(i))) {
 295          memo->u1.value = Qfalse;
 296          rb_iter_break();
 297      }
 298      return Qnil;
 299  }
 300  
 301  static VALUE
 302  enum_all(obj)
 303      VALUE obj;
 304  {
 305      VALUE result;
 306      NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0);
 307  
 308      memo->u1.value = Qtrue;
 309      rb_iterate(rb_each, obj, all_i, (VALUE)memo);
 310      result = memo->u1.value;
 311      rb_gc_force_recycle((VALUE)memo);
 312      return result;
 313  }
 314  
 315  static VALUE
 316  any_i(i, memo)
 317      VALUE i;
 318      NODE *memo;
 319  {
 320      if (RTEST(rb_yield(i))) {
 321          memo->u1.value = Qtrue;
 322          rb_iter_break();
 323      }
 324      return Qnil;
 325  }
 326  
 327  static VALUE
 328  enum_any(obj)
 329      VALUE obj;
 330  {
 331      VALUE result;
 332      NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0);
 333  
 334      memo->u1.value = Qfalse;
 335      rb_iterate(rb_each, obj, any_i, (VALUE)memo);
 336      result = memo->u1.value;
 337      rb_gc_force_recycle((VALUE)memo);
 338      return result;
 339  }
 340  
 341  static VALUE
 342  min_i(i, memo)
 343      VALUE i;
 344      NODE *memo;
 345  {
 346      VALUE cmp;
 347  
 348      if (NIL_P(memo->u1.value)) {
 349          memo->u1.value = i;
 350      }
 351      else {
 352          cmp = rb_funcall(i, id_cmp, 1, memo->u1.value);
 353          if (rb_cmpint(cmp) < 0) {
 354              memo->u1.value = i;
 355          }
 356      }
 357      return Qnil;
 358  }
 359  
 360  static VALUE
 361  min_ii(i, memo)
 362      VALUE i;
 363      NODE *memo;
 364  {
 365      VALUE cmp;
 366  
 367      if (NIL_P(memo->u1.value)) {
 368          memo->u1.value = i;
 369      }
 370      else {
 371          cmp = rb_yield(rb_assoc_new(i, memo->u1.value));
 372          if (rb_cmpint(cmp) < 0) {
 373              memo->u1.value = i;
 374          }
 375      }
 376      return Qnil;
 377  }
 378  
 379  static VALUE
 380  enum_min(obj)
 381      VALUE obj;
 382  {
 383      VALUE result;
 384      NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0);
 385  
 386      rb_iterate(rb_each, obj, rb_block_given_p() ? min_ii : min_i, (VALUE)memo);
 387      result = memo->u1.value;
 388      rb_gc_force_recycle((VALUE)memo);
 389      return result;
 390  }
 391  
 392  static VALUE
 393  max_i(i, memo)
 394      VALUE i;
 395      NODE *memo;
 396  {
 397      VALUE cmp;
 398  
 399      if (NIL_P(memo->u1.value)) {
 400          memo->u1.value = i;
 401      }
 402      else {
 403          cmp = rb_funcall(i, id_cmp, 1, memo->u1.value);
 404          if (rb_cmpint(cmp) > 0) {
 405              memo->u1.value = i;
 406          }
 407      }
 408      return Qnil;
 409  }
 410  
 411  static VALUE
 412  max_ii(i, memo)
 413      VALUE i;
 414      NODE *memo;
 415  {
 416      VALUE cmp;
 417  
 418      if (NIL_P(memo->u1.value)) {
 419          memo->u1.value = i;
 420      }
 421      else {
 422          cmp = rb_yield(rb_assoc_new(i, memo->u1.value));
 423          if (rb_cmpint(cmp) > 0) {
 424              memo->u1.value = i;
 425          }
 426      }
 427      return Qnil;
 428  }
 429  
 430  static VALUE
 431  enum_max(obj)
 432      VALUE obj;
 433  {
 434      VALUE result;
 435      NODE *memo = rb_node_newnode(NODE_MEMO, Qnil, 0, 0);
 436  
 437      rb_iterate(rb_each, obj, rb_block_given_p() ? max_ii : max_i, (VALUE)memo);
 438      result = memo->u1.value;
 439      rb_gc_force_recycle((VALUE)memo);
 440      return result;
 441  }
 442  
 443  static VALUE
 444  member_i(item, memo)
 445      VALUE item;
 446      NODE *memo;
 447  {
 448      if (rb_equal(item, memo->u1.value)) {
 449          memo->u2.value = Qtrue;
 450          rb_iter_break();
 451      }
 452      return Qnil;
 453  }
 454  
 455  static VALUE
 456  enum_member(obj, val)
 457      VALUE obj, val;
 458  {
 459      VALUE result;
 460      NODE *memo = rb_node_newnode(NODE_MEMO, val, Qfalse, 0);
 461  
 462      rb_iterate(rb_each, obj, member_i, (VALUE)memo);
 463      result = memo->u2.value;
 464      rb_gc_force_recycle((VALUE)memo);
 465      return result;
 466  }
 467  
 468  static VALUE
 469  each_with_index_i(val, memo)
 470      VALUE val;
 471      NODE *memo;
 472  {
 473      rb_yield(rb_assoc_new(val, INT2FIX(memo->u3.cnt)));
 474      memo->u3.cnt++;
 475      return Qnil;
 476  }
 477  
 478  static VALUE
 479  enum_each_with_index(obj)
 480      VALUE obj;
 481  {
 482      NODE *memo = rb_node_newnode(NODE_MEMO, 0, 0, 0);
 483  
 484      rb_iterate(rb_each, obj, each_with_index_i, (VALUE)memo);
 485      rb_gc_force_recycle((VALUE)memo);
 486      return obj;
 487  }
 488  
 489  void
 490  Init_Enumerable()
 491  {
 492      rb_mEnumerable = rb_define_module("Enumerable");
 493  
 494      rb_define_method(rb_mEnumerable,"to_a", enum_to_a, 0);
 495      rb_define_method(rb_mEnumerable,"entries", enum_to_a, 0);
 496  
 497      rb_define_method(rb_mEnumerable,"sort", enum_sort, 0);
 498      rb_define_method(rb_mEnumerable,"sort_by", enum_sort_by, 0);
 499      rb_define_method(rb_mEnumerable,"grep", enum_grep, 1);
 500      rb_define_method(rb_mEnumerable,"find", enum_find, -1);
 501      rb_define_method(rb_mEnumerable,"detect", enum_find, -1);
 502      rb_define_method(rb_mEnumerable,"find_all", enum_find_all, 0);
 503      rb_define_method(rb_mEnumerable,"select", enum_find_all, 0);
 504      rb_define_method(rb_mEnumerable,"reject", enum_reject, 0);
 505      rb_define_method(rb_mEnumerable,"collect", enum_collect, 0);
 506      rb_define_method(rb_mEnumerable,"map", enum_collect, 0);
 507      rb_define_method(rb_mEnumerable,"inject", enum_inject, -1);
 508      rb_define_method(rb_mEnumerable,"partition", enum_partition, 0);
 509      rb_define_method(rb_mEnumerable,"all?", enum_all, 0);
 510      rb_define_method(rb_mEnumerable,"any?", enum_any, 0);
 511      rb_define_method(rb_mEnumerable,"min", enum_min, 0);
 512      rb_define_method(rb_mEnumerable,"max", enum_max, 0);
 513      rb_define_method(rb_mEnumerable,"member?", enum_member, 1);
 514      rb_define_method(rb_mEnumerable,"include?", enum_member, 1);
 515      rb_define_method(rb_mEnumerable,"each_with_index", enum_each_with_index, 0);
 516  
 517      id_eqq  = rb_intern("===");
 518      id_each = rb_intern("each");
 519      id_cmp  = rb_intern("<=>");
 520  }
 521