nullable min/max

This commit is contained in:
John Kerl 2015-07-27 09:23:26 -04:00
parent 94697cdb31
commit fbf92524bb
7 changed files with 138 additions and 6 deletions

View file

@ -167,6 +167,38 @@ lrec_evaluator_t* lrec_evaluator_alloc_from_f_ff_func(mv_binary_func_t* pfunc,
return pevaluator;
}
mv_t lrec_evaluator_f_ff_nullable_func(lrec_t* prec, context_t* pctx, void* pvstate) {
lrec_evaluator_f_ff_state_t* pstate = pvstate;
mv_t val1 = pstate->parg1->pevaluator_func(prec, pctx, pstate->parg1->pvstate);
ERROR_OUT(val1);
mt_get_double_nullable(&val1);
if (val1.type != MT_DOUBLE && val1.type != MT_NULL)
return MV_ERROR;
mv_t val2 = pstate->parg2->pevaluator_func(prec, pctx, pstate->parg2->pvstate);
ERROR_OUT(val2);
mt_get_double_nullable(&val2);
if (val2.type != MT_DOUBLE && val2.type != MT_NULL)
return MV_ERROR;
return pstate->pfunc(&val1, &val2);
}
lrec_evaluator_t* lrec_evaluator_alloc_from_f_ff_nullable_func(mv_binary_func_t* pfunc,
lrec_evaluator_t* parg1, lrec_evaluator_t* parg2)
{
lrec_evaluator_f_ff_state_t* pstate = mlr_malloc_or_die(sizeof(lrec_evaluator_f_ff_state_t));
pstate->pfunc = pfunc;
pstate->parg1 = parg1;
pstate->parg2 = parg2;
lrec_evaluator_t* pevaluator = mlr_malloc_or_die(sizeof(lrec_evaluator_t));
pevaluator->pvstate = pstate;
pevaluator->pevaluator_func = lrec_evaluator_f_ff_nullable_func;
return pevaluator;
}
// ----------------------------------------------------------------
typedef struct _lrec_evaluator_s_s_state_t {
mv_unary_func_t* pfunc;
@ -889,8 +921,8 @@ lrec_evaluator_t* lrec_evaluator_alloc_from_binary_func_name(char* fnnm,
} else if (streq(fnnm, "<")) { return lrec_evaluator_alloc_from_b_xx_func(lt_op_func, parg1, parg2);
} else if (streq(fnnm, "<=")) { return lrec_evaluator_alloc_from_b_xx_func(le_op_func, parg1, parg2);
} else if (streq(fnnm, ".")) { return lrec_evaluator_alloc_from_s_ss_func(s_ss_dot_func, parg1, parg2);
} else if (streq(fnnm, "max")) { return lrec_evaluator_alloc_from_f_ff_func(f_ff_max_func, parg1, parg2);
} else if (streq(fnnm, "min")) { return lrec_evaluator_alloc_from_f_ff_func(f_ff_min_func, parg1, parg2);
} else if (streq(fnnm, "max")) { return lrec_evaluator_alloc_from_f_ff_nullable_func(f_ff_max_func, parg1, parg2);
} else if (streq(fnnm, "min")) { return lrec_evaluator_alloc_from_f_ff_nullable_func(f_ff_min_func, parg1, parg2);
} else if (streq(fnnm, "pow")) { return lrec_evaluator_alloc_from_f_ff_func(f_ff_pow_func, parg1, parg2);
} else if (streq(fnnm, "+")) { return lrec_evaluator_alloc_from_f_ff_func(f_ff_plus_func, parg1, parg2);
} else if (streq(fnnm, "-")) { return lrec_evaluator_alloc_from_f_ff_func(f_ff_minus_func, parg1, parg2);

View file

@ -115,6 +115,37 @@ void mt_get_double_strict(mv_t* pval) {
// xxx else panic
}
// ----------------------------------------------------------------
// xxx merge with mt_get_double_string w/ a nullable parameter
void mt_get_double_nullable(mv_t* pval) {
if (pval->type == MT_NULL)
return;
if (pval->type == MT_ERROR)
return;
if (pval->type == MT_DOUBLE)
return;
if (pval->type == MT_STRING) {
double dblv;
if (*pval->u.strv == '\0') {
pval->type = MT_NULL;
pval->u.intv = 0;
} else if (!mlr_try_double_from_string(pval->u.strv, &dblv)) {
pval->type = MT_ERROR;
pval->u.intv = 0;
} else {
pval->type = MT_DOUBLE;
pval->u.dblv = dblv;
}
} else if (pval->type == MT_INT) {
pval ->type = MT_DOUBLE;
pval->u.dblv = (double)pval->u.intv;
} else if (pval->type == MT_BOOL) {
pval->type = MT_ERROR;
pval->u.intv = 0;
}
// xxx else panic
}
// ----------------------------------------------------------------
mv_t s_ss_dot_func(mv_t* pval1, mv_t* pval2) {
int len1 = strlen(pval1->u.strv);

View file

@ -44,6 +44,11 @@ extern mv_t MV_ERROR;
return MV_NULL; \
}
#define ERROR_OUT(val) { \
if ((val).type == MT_ERROR) \
return MV_ERROR; \
}
// ----------------------------------------------------------------
char* mt_describe_type(int type);
@ -53,6 +58,7 @@ char* mt_describe_val(mv_t val);
// xxx explain why one is void & the other isn't
int mt_get_boolean_strict(mv_t* pval);
void mt_get_double_strict(mv_t* pval);
void mt_get_double_nullable(mv_t* pval);
// ----------------------------------------------------------------
typedef mv_t mv_zary_func_t();
@ -137,12 +143,24 @@ static inline mv_t f_ff_divide_func(mv_t* pval1, mv_t* pval2) {
return rv;
}
static inline mv_t f_ff_max_func(mv_t* pval1, mv_t* pval2) {
mv_t rv = {.type = MT_DOUBLE, .u.dblv = fmax(pval1->u.dblv, pval2->u.dblv)}; // xxx impl: null loses ...
return rv;
if (pval1->type == MT_NULL) {
return *pval2;
} else if (pval2->type == MT_NULL) {
return *pval1;
} else {
mv_t rv = {.type = MT_DOUBLE, .u.dblv = fmax(pval1->u.dblv, pval2->u.dblv)};
return rv;
}
}
static inline mv_t f_ff_min_func(mv_t* pval1, mv_t* pval2) {
mv_t rv = {.type = MT_DOUBLE, .u.dblv = fmin(pval1->u.dblv, pval2->u.dblv)}; // xxx impl: null loses ...
return rv;
if (pval1->type == MT_NULL) {
return *pval2;
} else if (pval2->type == MT_NULL) {
return *pval1;
} else {
mv_t rv = {.type = MT_DOUBLE, .u.dblv = fmin(pval1->u.dblv, pval2->u.dblv)};
return rv;
}
}
static inline mv_t f_ff_pow_func(mv_t* pval1, mv_t* pval2) {
mv_t rv = {.type = MT_DOUBLE, .u.dblv = pow(pval1->u.dblv, pval2->u.dblv)};

View file

@ -1517,6 +1517,26 @@ gmt,sec
2017-07-14T02:40:00Z,1500000000
2033-05-18T03:33:20Z,2000000000
./test/../mlr put $z=min($x, $y) ./test/input/minmax.dkvp
x=1,y=2,z=1.000000
x=1,y=,z=1.000000
x=,y=,z=
x=,y=2,z=2.000000
x=3,y=2,z=2.000000
x=3,y=,z=3.000000
x=,y=,z=
x=,y=2,z=2.000000
./test/../mlr put $z=max($x, $y) ./test/input/minmax.dkvp
x=1,y=2,z=2.000000
x=1,y=,z=1.000000
x=,y=,z=
x=,y=2,z=2.000000
x=3,y=2,z=3.000000
x=3,y=,z=3.000000
x=,y=,z=
x=,y=2,z=2.000000
================================================================
CHAINING

8
c/test/input/minmax.dkvp Normal file
View file

@ -0,0 +1,8 @@
x=1,y=2
x=1,y=
x=,y=
x=,y=2
x=3,y=2
x=3,y=
x=,y=
x=,y=2

View file

@ -1517,6 +1517,26 @@ gmt,sec
2017-07-14T02:40:00Z,1500000000
2033-05-18T03:33:20Z,2000000000
./test/../mlr put $z=min($x, $y) ./test/input/minmax.dkvp
x=1,y=2,z=1.000000
x=1,y=,z=1.000000
x=,y=,z=
x=,y=2,z=2.000000
x=3,y=2,z=2.000000
x=3,y=,z=3.000000
x=,y=,z=
x=,y=2,z=2.000000
./test/../mlr put $z=max($x, $y) ./test/input/minmax.dkvp
x=1,y=2,z=2.000000
x=1,y=,z=1.000000
x=,y=,z=
x=,y=2,z=2.000000
x=3,y=2,z=3.000000
x=3,y=,z=3.000000
x=,y=,z=
x=,y=2,z=2.000000
================================================================
CHAINING

View file

@ -269,6 +269,9 @@ run_command $mlr filter -v '$x<$a*$b+-$c' /dev/null
run_command $mlr --csv put '$gmt=sec2gmt($sec)' $indir/sec2gmt
run_command $mlr --csv put '$sec=gmt2sec($gmt)' $indir/gmt2sec
run_command $mlr put '$z=min($x, $y)' $indir/minmax.dkvp
run_command $mlr put '$z=max($x, $y)' $indir/minmax.dkvp
# ----------------------------------------------------------------
announce CHAINING