aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--enum.c19
2 files changed, 26 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 1b23847c34..2979d66fb0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Wed Oct 15 07:21:09 2014 Tanaka Akira <akr@fsij.org>
+
+ * 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.
+ (nmin_run): Initialize limit field.
+
Wed Oct 15 07:00:14 2014 Eric Wong <e@80x24.org>
* test/ruby/test_optimization.rb (test_string_size): new test
diff --git a/enum.c b/enum.c
index b6bcd5cc71..205664f88a 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;