summaryrefslogtreecommitdiff
path: root/enum.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-10-14 22:24:34 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-10-14 22:24:34 +0000
commit5a601ec59173ba8f0be5df6b0db5f86b6f3f6ec5 (patch)
treea08e68317b7f46b78ac7643c2b2f5a29497030d3 /enum.c
parentd63a88c0b5015cb9d99901437b031316e1fc1155 (diff)
* enum.c: min(n) drops elements bigger than the n-th maximum element.
(struct nmin_data): New field to record the n-th maximumelement, limit (nmin_filter): Update limit field. (nmin_i): Drop too big eleents. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47923 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'enum.c')
-rw-r--r--enum.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/enum.c b/enum.c
index b6bcd5c..205664f 100644
--- a/enum.c
+++ b/enum.c
@@ -1110,6 +1110,7 @@ struct nmin_data {
long bufmax;
long curlen;
VALUE buf;
+ VALUE limit;
int (*cmpfunc)(const void *, const void *, void *);
int rev; /* max if 1 */
int by; /* min_by if 1 */
@@ -1221,17 +1222,32 @@ nmin_filter(struct nmin_data *data)
data->curlen = data->n;
rb_ary_resize(data->buf, data->n * eltsize);
+ data->limit = RARRAY_PTR(data->buf)[(data->n-1)*eltsize];
}
static VALUE
nmin_i(VALUE i, VALUE *_data, int argc, VALUE *argv)
{
struct nmin_data *data = (struct nmin_data *)_data;
+ VALUE cmpv;
ENUM_WANT_SVALUE();
if (data->by)
- rb_ary_push(data->buf, rb_yield(i));
+ cmpv = rb_yield(i);
+ else
+ cmpv = i;
+
+ if (data->limit != Qundef) {
+ int c = data->cmpfunc(&cmpv, &data->limit, data);
+ if (data->rev)
+ c = -c;
+ if (c > 0)
+ return Qnil;
+ }
+
+ if (data->by)
+ rb_ary_push(data->buf, cmpv);
rb_ary_push(data->buf, i);
data->curlen++;
@@ -1259,6 +1275,7 @@ nmin_run(VALUE obj, VALUE num, int by, int rev)
data.bufmax = data.n * 4;
data.curlen = 0;
data.buf = rb_ary_tmp_new(data.bufmax * (by ? 2 : 1));
+ data.limit = Qundef;
data.cmpfunc = by ? nmin_cmp :
rb_block_given_p() ? nmin_block_cmp :
nmin_cmp;