"Fossies" - the Fresh Open Source Software Archive

Member "mlr-5.9.1/c/lib/mvfuncs.c" (3 Sep 2020, 88107 Bytes) of package /linux/misc/mlr-5.9.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mvfuncs.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.9.0_vs_5.9.1.

    1 #include <stdio.h>
    2 #include <stdlib.h>
    3 #include <string.h>
    4 #include <math.h>
    5 #include "lib/mlr_globals.h"
    6 #include "lib/mlrutil.h"
    7 #include "lib/mlrdatetime.h"
    8 #include "lib/mlrregex.h"
    9 #include "lib/mvfuncs.h"
   10 #include "lib/utf8.h"
   11 #include "lib/string_builder.h"
   12 
   13 // ================================================================
   14 // See important notes at the top of mlrval.h.
   15 // ================================================================
   16 
   17 typedef int mv_i_nn_comparator_func_t(mv_t* pa, mv_t* pb);
   18 typedef int mv_i_xx_comparator_func_t(const mv_t* pa, const mv_t* pb);
   19 
   20 // ----------------------------------------------------------------
   21 // Keystroke-savers for disposition matrices:
   22 
   23 static mv_t _a(mv_t* pa, mv_t* pb) {
   24     return mv_absent();
   25 }
   26 static mv_t _emt(mv_t* pa, mv_t* pb) {
   27     return mv_empty();
   28 }
   29 static mv_t _err(mv_t* pa, mv_t* pb) {
   30     return mv_error();
   31 }
   32 static mv_t _0(mv_t* pa) {
   33     return *pa;
   34 }
   35 static mv_t _1(mv_t* pa, mv_t* pb) {
   36     return *pa;
   37 }
   38 static mv_t _2(mv_t* pa, mv_t* pb) {
   39     return *pb;
   40 }
   41 static mv_t _1f(mv_t* pa, mv_t* pb) {
   42     mv_free(pb);
   43     return *pa;
   44 }
   45 static mv_t _2f(mv_t* pa, mv_t* pb) {
   46     mv_free(pa);
   47     return *pb;
   48 }
   49 static mv_t _s1(mv_t* pa, mv_t* pb) {
   50     return s_x_string_func(pa);
   51 }
   52 static mv_t _s2(mv_t* pa, mv_t* pb) {
   53     return s_x_string_func(pb);
   54 }
   55 static mv_t _f0(mv_t* pa, mv_t* pb) {
   56     return mv_from_float(0.0);
   57 }
   58 static mv_t _i0(mv_t* pa, mv_t* pb) {
   59     return mv_from_int(0LL);
   60 }
   61 static mv_t _a1(mv_t* pa) {
   62     return mv_absent();
   63 }
   64 static mv_t _emt1(mv_t* pa) {
   65     return mv_empty();
   66 }
   67 static mv_t _err1(mv_t* pa) {
   68     return mv_error();
   69 }
   70 
   71 // ----------------------------------------------------------------
   72 static mv_t dot_strings(char* string1, char* string2) {
   73     int len1 = strlen(string1);
   74     int len2 = strlen(string2);
   75     int len3 = len1 + len2 + 1; // for the null-terminator byte
   76     char* string3 = mlr_malloc_or_die(len3);
   77     strcpy(&string3[0], string1);
   78     strcpy(&string3[len1], string2);
   79     return mv_from_string_with_free(string3);
   80 }
   81 
   82 mv_t dot_s_ss(mv_t* pval1, mv_t* pval2) {
   83     mv_t rv = dot_strings(pval1->u.strv, pval2->u.strv);
   84     mv_free(pval1);
   85     mv_free(pval2);
   86     return rv;
   87 }
   88 
   89 mv_t dot_s_xs(mv_t* pval1, mv_t* pval2) {
   90     mv_t sval1 = s_x_string_func(pval1);
   91     mv_free(pval1);
   92     mv_t rv = dot_strings(sval1.u.strv, pval2->u.strv);
   93     mv_free(&sval1);
   94     mv_free(pval2);
   95     return rv;
   96 }
   97 
   98 mv_t dot_s_sx(mv_t* pval1, mv_t* pval2) {
   99     mv_t sval2 = s_x_string_func(pval2);
  100     mv_free(pval2);
  101     mv_t rv = dot_strings(pval1->u.strv, sval2.u.strv);
  102     mv_free(pval1);
  103     mv_free(&sval2);
  104     return rv;
  105 }
  106 
  107 mv_t dot_s_xx(mv_t* pval1, mv_t* pval2) {
  108     mv_t sval1 = s_x_string_func(pval1);
  109     mv_t sval2 = s_x_string_func(pval2);
  110     mv_t rv = dot_strings(sval1.u.strv, sval2.u.strv);
  111     mv_free(&sval1);
  112     mv_free(&sval2);
  113     return rv;
  114 }
  115 
  116 static mv_binary_func_t* dot_dispositions[MT_DIM][MT_DIM] = {
  117     //         ERROR  ABSENT EMPTY STRING     INT        FLOAT      BOOL
  118     /*ERROR*/  {_err, _err,  _err, _err,      _err,      _err,      _err},
  119     /*ABSENT*/ {_err, _a,    _emt, _2,        _s2,       _s2,       _s2},
  120     /*EMPTY*/  {_err, _emt,  _emt, _2,        _s2,       _s2,       _s2},
  121     /*STRING*/ {_err, _1,    _1,   dot_s_ss,  dot_s_sx,  dot_s_sx,  dot_s_sx},
  122     /*INT*/    {_err, _s1,   _s1,  dot_s_xs,  dot_s_xx,  dot_s_xx,  dot_s_xx},
  123     /*FLOAT*/  {_err, _s1,   _s1,  dot_s_xs,  dot_s_xx,  dot_s_xx,  dot_s_xx},
  124     /*BOOL*/   {_err, _s1,   _s1,  dot_s_xs,  dot_s_xx,  dot_s_xx,  dot_s_xx},
  125 };
  126 
  127 mv_t s_xx_dot_func(mv_t* pval1, mv_t* pval2) { return (dot_dispositions[pval1->type][pval2->type])(pval1,pval2); }
  128 
  129 // ----------------------------------------------------------------
  130 mv_t sub_no_precomp_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
  131     regex_t regex;
  132     string_builder_t *psb = sb_alloc(MV_SB_ALLOC_LENGTH);
  133     mv_t rv = sub_precomp_func(pval1, regcomp_or_die(&regex, pval2->u.strv, 0), psb, pval3);
  134     sb_free(psb);
  135     regfree(&regex);
  136     mv_free(pval2);
  137     return rv;
  138 }
  139 
  140 // ----------------------------------------------------------------
  141 // Example:
  142 // * pval1->u.strv = "hello"
  143 // * regex = "l+"
  144 // * pval3->u.strv = "yyy"
  145 //
  146 // *  len1 = 2 = length of "he"
  147 // * olen2 = 2 = length of "ll"
  148 // * nlen2 = 3 = length of "yyy"
  149 // *  len3 = 1 = length of "o"
  150 // *  len4 = 6 = 2+3+1
  151 
  152 mv_t sub_precomp_func(mv_t* pval1, regex_t* pregex, string_builder_t* psb, mv_t* pval3) {
  153     int matched      = FALSE;
  154     int all_captured = FALSE;
  155     char* input      = pval1->u.strv;
  156     char* output     = regex_sub(input, pregex, psb, pval3->u.strv, &matched, &all_captured);
  157 
  158     mv_free(pval1);
  159     mv_free(pval3);
  160     return mv_from_string_with_free(output);
  161 }
  162 
  163 // ----------------------------------------------------------------
  164 // Example:
  165 // * pval1->u.strv = "hello"
  166 // * regex = "l+"
  167 // * pval3->u.strv = "yyy"
  168 //
  169 // *  len1 = 2 = length of "he"
  170 // * olen2 = 2 = length of "ll"
  171 // * nlen2 = 3 = length of "yyy"
  172 // *  len3 = 1 = length of "o"
  173 // *  len4 = 6 = 2+3+1
  174 
  175 mv_t gsub_no_precomp_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
  176     regex_t regex;
  177     string_builder_t *psb = sb_alloc(MV_SB_ALLOC_LENGTH);
  178     mv_t rv = gsub_precomp_func(pval1, regcomp_or_die(&regex, pval2->u.strv, 0), psb, pval3);
  179     sb_free(psb);
  180     regfree(&regex);
  181     mv_free(pval2);
  182     return rv;
  183 }
  184 
  185 mv_t gsub_precomp_func(mv_t* pval1, regex_t* pregex, string_builder_t* psb, mv_t* pval3) {
  186     int matched      = FALSE;
  187     int all_captured = FALSE;
  188     char* input      = pval1->u.strv;
  189     char free_flags  = NO_FREE;
  190     char* output     = regex_gsub(input, pregex, psb, pval3->u.strv, &matched, &all_captured, &free_flags);
  191 
  192     mv_free(pval1);
  193     mv_free(pval3);
  194     return mv_from_string(output, free_flags);
  195 }
  196 
  197 // ----------------------------------------------------------------
  198 mv_t regextract_no_precomp_func(mv_t* pval1, mv_t* pval2) {
  199     regex_t regex;
  200     mv_t rv = regextract_precomp_func(pval1, regcomp_or_die(&regex, pval2->u.strv, 0));
  201     regfree(&regex);
  202     mv_free(pval2);
  203     return rv;
  204 }
  205 
  206 // ----------------------------------------------------------------
  207 mv_t regextract_precomp_func(mv_t* pval1, regex_t* pregex) {
  208     char* input  = pval1->u.strv;
  209     char* output = regextract(input, pregex);
  210 
  211     mv_free(pval1);
  212     if (output == NULL) {
  213         return mv_absent();
  214     } else {
  215         return mv_from_string_with_free(output);
  216     }
  217 }
  218 
  219 // ----------------------------------------------------------------
  220 mv_t regextract_or_else_no_precomp_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
  221     regex_t regex;
  222     mv_t rv = regextract_or_else_precomp_func(pval1, regcomp_or_die(&regex, pval2->u.strv, 0), pval3);
  223     regfree(&regex);
  224     mv_free(pval2);
  225     return rv;
  226 }
  227 
  228 // ----------------------------------------------------------------
  229 mv_t regextract_or_else_precomp_func(mv_t* pval1, regex_t* pregex, mv_t* pval3) {
  230     char* input  = pval1->u.strv;
  231     char* default_value  = pval3->u.strv;
  232     char* output = regextract_or_else(input, pregex, default_value);
  233 
  234     mv_free(pval1);
  235     mv_free(pval3);
  236     return mv_from_string_with_free(output);
  237 }
  238 
  239 // ----------------------------------------------------------------
  240 // String-substitution with no regexes or special characters.
  241 // It is assumed that all inputs have already been checked to be strings.
  242 mv_t s_sss_ssub_func(mv_t* pmvinput, mv_t* pmvold, mv_t* pmvnew) {
  243     char* pinput = pmvinput->u.strv;
  244     char* pold = pmvold->u.strv;
  245     char* pnew = pmvnew->u.strv;
  246 
  247     char* pmatch = strstr(pinput, pold);
  248 
  249     if (pmatch == NULL) {
  250         mv_free(pmvold);
  251         mv_free(pmvnew);
  252         return *pmvinput;
  253     } else {
  254         // Example:
  255         // input: aaaaOOObbbbb
  256         // old:   OOO
  257         // new:   NNNNN
  258         // Output length: strlen(aaaa) + strlen(NNNNN) + strlen(bbbbb)
  259 
  260         // Compute lengths
  261         int input_length = strlen(pinput);
  262         int old_length = strlen(pold);
  263         int new_length = strlen(pnew);
  264         int output_length = input_length - old_length + new_length + 1;
  265         int pre_length = pmatch - pinput; // the "aaaa" part
  266         int post_length = input_length - pre_length - old_length; // the "bbbbb" part
  267 
  268         // Allocate output
  269         char* poutput = mlr_malloc_or_die(output_length);
  270         char* p = poutput;
  271 
  272         // Populate output
  273         strncpy(p, pinput, pre_length);
  274         p += pre_length;
  275 
  276         strcpy(p, pnew);
  277         p += new_length;
  278 
  279         strcpy(p, &pinput[pre_length + old_length]);
  280         p += post_length;
  281 
  282         *p = 0;
  283 
  284         mv_free(pmvinput);
  285         mv_free(pmvold);
  286         mv_free(pmvnew);
  287         return mv_from_string(poutput, FREE_ENTRY_VALUE);
  288     }
  289 }
  290 
  291 // ----------------------------------------------------------------
  292 // https://en.wikipedia.org/wiki/Hamming_weight
  293 
  294 static const unsigned long long _m1  = 0x5555555555555555;
  295 static const unsigned long long _m2  = 0x3333333333333333;
  296 static const unsigned long long _m4  = 0x0f0f0f0f0f0f0f0f;
  297 static const unsigned long long _m8  = 0x00ff00ff00ff00ff;
  298 static const unsigned long long _m16 = 0x0000ffff0000ffff;
  299 static const unsigned long long _m32 = 0x00000000ffffffff;
  300 
  301 mv_t i_i_bitcount_func(mv_t* pval1) {
  302     unsigned long long a = pval1->u.intv;
  303     a = (a & _m1 ) + ((a >>  1) & _m1 );
  304     a = (a & _m2 ) + ((a >>  2) & _m2 );
  305     a = (a & _m4 ) + ((a >>  4) & _m4 );
  306     a = (a & _m8 ) + ((a >>  8) & _m8 );
  307     a = (a & _m16) + ((a >> 16) & _m16);
  308     a = (a & _m32) + ((a >> 32) & _m32);
  309     return mv_from_int((long long)a);
  310 }
  311 
  312 // ----------------------------------------------------------------
  313 mv_t i_iii_modadd_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
  314     long long m = pval3->u.intv;
  315     if (m <= 0LL)
  316         return mv_error();
  317     long long a = pval1->u.intv % m;
  318     if (a < 0LL)
  319         a += m; // crazy C-language mod operator
  320     long long b = pval2->u.intv % m;
  321     if (b < 0LL)
  322         b += m;
  323     long long c = (a + b) % m;
  324     return mv_from_int(c);
  325 }
  326 
  327 mv_t i_iii_modsub_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
  328     long long m = pval3->u.intv;
  329     if (m <= 0LL)
  330         return mv_error();
  331     long long a = pval1->u.intv % m;
  332     if (a < 0LL)
  333         a += m; // crazy C-language mod operator
  334     long long b = pval2->u.intv % m;
  335     if (b < 0LL)
  336         b += m;
  337     long long c = (a - b) % m;
  338     if (c < 0LL)
  339         c += m;
  340     return mv_from_int(c);
  341 }
  342 
  343 mv_t i_iii_modmul_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
  344     long long m = pval3->u.intv;
  345     if (m <= 0LL)
  346         return mv_error();
  347     long long a = pval1->u.intv % m;
  348     if (a < 0LL)
  349         a += m; // crazy C-language mod operator
  350     long long b = pval2->u.intv % m;
  351     if (b < 0LL)
  352         b += m;
  353     long long c = (a * b) % m;
  354     return mv_from_int(c);
  355 }
  356 
  357 mv_t i_iii_modexp_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
  358     long long m = pval3->u.intv;
  359     if (m <= 0LL)
  360         return mv_error();
  361     long long a = pval1->u.intv % m;
  362     if (a < 0LL)
  363         a += m; // crazy C-language mod operator
  364 
  365     long long e = pval2->u.intv;
  366 
  367     long long c = 1LL;
  368     if (e == 1LL) {
  369         c = a;
  370     } else if (e == 0LL) {
  371         c = 1LL;
  372     } else if (e > 0) {
  373         long long ap = a;
  374         c = 1LL;
  375         unsigned long long u = (unsigned long long)e;
  376 
  377         // repeated-squaring algorithm
  378         while (u != 0) {
  379             if ((u & 1LL) == 1LL) {
  380                 c = (c * ap) % m;
  381             }
  382             u >>= 1;
  383             ap = (ap * ap) % m;
  384         }
  385     } else {
  386         return mv_error();
  387     }
  388 
  389     return mv_from_int(c);
  390 }
  391 
  392 // ----------------------------------------------------------------
  393 mv_t i_s_strlen_func(mv_t* pval1) {
  394     mv_t rv = mv_from_int(strlen_for_utf8_display(pval1->u.strv));
  395     mv_free(pval1);
  396     return rv;
  397 }
  398 
  399 mv_t s_x_typeof_func(mv_t* pval1) {
  400     mv_t rv = mv_from_string(mt_describe_type(pval1->type), NO_FREE);
  401     mv_free(pval1);
  402     return rv;
  403 }
  404 
  405 // ----------------------------------------------------------------
  406 mv_t s_s_tolower_func(mv_t* pval1) {
  407     char* string = mlr_strdup_or_die(pval1->u.strv);
  408 #if 0
  409     // ASCII only
  410     for (char* c = string; *c; c++)
  411         *c = tolower((unsigned char)*c);
  412 #else
  413     // UTF-8
  414     utf8lwr(string);
  415 #endif
  416     mv_free(pval1);
  417     pval1->u.strv = NULL;
  418 
  419     return mv_from_string_with_free(string);
  420 }
  421 
  422 mv_t s_s_toupper_func(mv_t* pval1) {
  423     char* string = mlr_strdup_or_die(pval1->u.strv);
  424 #if 0
  425     // ASCII only
  426     for (char* c = string; *c; c++)
  427         *c = toupper((unsigned char)*c);
  428 #else
  429     // UTF-8
  430     utf8upr(string);
  431 #endif
  432     mv_free(pval1);
  433     pval1->u.strv = NULL;
  434 
  435     return mv_from_string_with_free(string);
  436 }
  437 
  438 mv_t s_s_capitalize_func(mv_t* pval1) {
  439     char* string = mlr_strdup_or_die(pval1->u.strv);
  440 
  441     if (*string) {
  442 #if 0
  443         // ASCII
  444         *string = toupper((unsigned char)*string);
  445 #else
  446         // UTF-8
  447         utf8upr1(string);
  448 #endif
  449     }
  450 
  451     mv_free(pval1);
  452     pval1->u.strv = NULL;
  453 
  454     return mv_from_string_with_free(string);
  455 }
  456 
  457 mv_t s_s_system_func(mv_t* pval1) {
  458     char* cmd = pval1->u.strv;
  459 
  460     mv_t retval = mv_from_string_no_free("error-running-system-command");
  461     string_builder_t* psb = sb_alloc(100);
  462     char buffer[128];
  463     FILE* pipe = popen(cmd, "r");
  464     if (pipe != NULL) {
  465         while (fgets(buffer, sizeof buffer, pipe) != NULL) {
  466             sb_append_string(psb, buffer);
  467         }
  468         pclose(pipe);
  469         char* output_string = sb_finish(psb);
  470 
  471         // xxx make a windows-friendly lib func for chomp
  472         int len = strlen(output_string);
  473         if (len > 0) {
  474             if (output_string[len-1] == '\n') {
  475                 output_string[len-1] = 0;
  476             }
  477         }
  478 
  479         retval = mv_from_string_with_free(output_string);
  480     }
  481     sb_free(psb);
  482 
  483     mv_free(pval1);
  484     pval1->u.strv = NULL;
  485 
  486     return retval;
  487 }
  488 
  489 // ----------------------------------------------------------------
  490 mv_t s_s_lstrip_func(mv_t* pval1) {
  491     if (!isspace(pval1->u.strv[0])) {
  492         return *pval1;
  493     } else {
  494         char* p = pval1->u.strv;
  495         while (isspace(*p)) {
  496             p++;
  497         }
  498         char* retval = mlr_strdup_or_die(p);
  499         mv_free(pval1);
  500         return mv_from_string(retval, FREE_ENTRY_VALUE);
  501     }
  502 }
  503 
  504 mv_t s_s_rstrip_func(mv_t* pval1) {
  505     char* start = pval1->u.strv;
  506     int oldlen = strlen(start);
  507     char* last_non_space = &start[oldlen-1];
  508     while ((start <= last_non_space) && isspace(*last_non_space))
  509         last_non_space--;
  510     if (last_non_space < start) {
  511         mv_free(pval1);
  512         return mv_empty();
  513     } else {
  514         int newlen = (last_non_space - start) + 1;
  515         char* retval = mlr_malloc_or_die(newlen + 1);
  516         memcpy(retval, start, newlen);
  517         retval[newlen] = 0;
  518         mv_free(pval1);
  519         return mv_from_string(retval, FREE_ENTRY_VALUE);
  520     }
  521 }
  522 
  523 mv_t s_s_strip_func(mv_t* pval1) {
  524     mv_t temp = s_s_rstrip_func(pval1);
  525     return s_s_lstrip_func(&temp);
  526 }
  527 
  528 mv_t s_s_collapse_whitespace_func(mv_t* pval1) {
  529     int len = strlen(pval1->u.strv);
  530     char* retval = mlr_malloc_or_die(len+1);
  531     char* pdst = retval;
  532     int last_was_space = FALSE;
  533     for (char* psrc = pval1->u.strv; *psrc; psrc++) {
  534         int current_is_space = isspace(*psrc);
  535         if (last_was_space && current_is_space) {
  536         } else {
  537             *pdst = *psrc;
  538             pdst++;
  539         }
  540         last_was_space = current_is_space;
  541     }
  542     *pdst = 0;
  543     mv_free(pval1);
  544     return mv_from_string(retval, FREE_ENTRY_VALUE);
  545 }
  546 
  547 mv_t s_s_clean_whitespace_func(mv_t* pval1) {
  548     mv_t temp = s_s_collapse_whitespace_func(pval1);
  549     return s_s_strip_func(&temp);
  550 }
  551 
  552 // ----------------------------------------------------------------
  553 // Precondition: psec is either int or float.
  554 mv_t time_string_from_seconds(mv_t* psec, char* format,
  555     timezone_handling_t timezone_handling)
  556 {
  557     double seconds_since_the_epoch = 0.0;
  558     if (psec->type == MT_FLOAT) {
  559         if (isinf(psec->u.fltv) || isnan(psec->u.fltv)) {
  560             return mv_error();
  561         }
  562         seconds_since_the_epoch = psec->u.fltv;
  563     } else {
  564         seconds_since_the_epoch = psec->u.intv;
  565     }
  566 
  567     char* string = mlr_alloc_time_string_from_seconds(seconds_since_the_epoch, format,
  568         timezone_handling);
  569 
  570     return mv_from_string_with_free(string);
  571 }
  572 
  573 // ----------------------------------------------------------------
  574 static mv_t sec2gmt_s_n(mv_t* pa) {
  575     return time_string_from_seconds(pa, ISO8601_TIME_FORMAT, TIMEZONE_HANDLING_GMT);
  576 }
  577 
  578 static mv_unary_func_t* sec2gmt_dispositions[MT_DIM] = {
  579     /*ERROR*/  _err1,
  580     /*ABSENT*/ _a1,
  581     /*EMPTY*/  _emt1,
  582     /*STRING*/ _0,
  583     /*INT*/    sec2gmt_s_n,
  584     /*FLOAT*/  sec2gmt_s_n,
  585     /*BOOL*/   _0,
  586 };
  587 mv_t s_x_sec2gmt_func(mv_t* pval1) { return (sec2gmt_dispositions[pval1->type])(pval1); }
  588 
  589 // Precondition: val2 is already asserted int
  590 static mv_t sec2gmt_s_ni(mv_t* pa, mv_t* pb) {
  591     switch (pb->u.intv) {
  592     case 1: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_1, TIMEZONE_HANDLING_GMT); break;
  593     case 2: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_2, TIMEZONE_HANDLING_GMT); break;
  594     case 3: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_3, TIMEZONE_HANDLING_GMT); break;
  595     case 4: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_4, TIMEZONE_HANDLING_GMT); break;
  596     case 5: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_5, TIMEZONE_HANDLING_GMT); break;
  597     case 6: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_6, TIMEZONE_HANDLING_GMT); break;
  598     case 7: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_7, TIMEZONE_HANDLING_GMT); break;
  599     case 8: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_8, TIMEZONE_HANDLING_GMT); break;
  600     case 9: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_9, TIMEZONE_HANDLING_GMT); break;
  601     default: return mv_error();
  602     }
  603 }
  604 
  605 static mv_binary_func_t* sec2gmtn_dispositions[MT_DIM] = {
  606     /*ERROR*/  _err,
  607     /*ABSENT*/ _a,
  608     /*EMPTY*/  _emt,
  609     /*STRING*/ _1,
  610     /*INT*/    sec2gmt_s_ni,
  611     /*FLOAT*/  sec2gmt_s_ni,
  612     /*BOOL*/   _1,
  613 };
  614 mv_t s_xi_sec2gmt_func(mv_t* pval1, mv_t* pval2) { return (sec2gmtn_dispositions[pval1->type])(pval1, pval2); }
  615 
  616 // ----------------------------------------------------------------
  617 static mv_t sec2gmtdate_s_n(mv_t* pa) {
  618     return time_string_from_seconds(pa, ISO8601_DATE_FORMAT, TIMEZONE_HANDLING_GMT);
  619 }
  620 
  621 static mv_unary_func_t* sec2gmtdate_dispositions[MT_DIM] = {
  622     /*ERROR*/  _err1,
  623     /*ABSENT*/ _a1,
  624     /*EMPTY*/  _emt1,
  625     /*STRING*/ _0,
  626     /*INT*/    sec2gmtdate_s_n,
  627     /*FLOAT*/  sec2gmtdate_s_n,
  628     /*BOOL*/   _0,
  629 };
  630 
  631 mv_t s_x_sec2gmtdate_func(mv_t* pval1) { return (sec2gmtdate_dispositions[pval1->type])(pval1); }
  632 
  633 // ----------------------------------------------------------------
  634 static mv_t sec2localtime_s_n(mv_t* pa) {
  635     return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT, TIMEZONE_HANDLING_LOCAL);
  636 }
  637 
  638 static mv_unary_func_t* sec2localtime_dispositions[MT_DIM] = {
  639     /*ERROR*/  _err1,
  640     /*ABSENT*/ _a1,
  641     /*EMPTY*/  _emt1,
  642     /*STRING*/ _0,
  643     /*INT*/    sec2localtime_s_n,
  644     /*FLOAT*/  sec2localtime_s_n,
  645     /*BOOL*/   _0,
  646 };
  647 mv_t s_x_sec2localtime_func(mv_t* pval1) { return (sec2localtime_dispositions[pval1->type])(pval1); }
  648 
  649 // Precondition: val2 is already asserted int
  650 static mv_t sec2localtime_s_ni(mv_t* pa, mv_t* pb) {
  651     switch (pb->u.intv) {
  652     case 1: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_1, TIMEZONE_HANDLING_LOCAL); break;
  653     case 2: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_2, TIMEZONE_HANDLING_LOCAL); break;
  654     case 3: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_3, TIMEZONE_HANDLING_LOCAL); break;
  655     case 4: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_4, TIMEZONE_HANDLING_LOCAL); break;
  656     case 5: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_5, TIMEZONE_HANDLING_LOCAL); break;
  657     case 6: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_6, TIMEZONE_HANDLING_LOCAL); break;
  658     case 7: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_7, TIMEZONE_HANDLING_LOCAL); break;
  659     case 8: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_8, TIMEZONE_HANDLING_LOCAL); break;
  660     case 9: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_9, TIMEZONE_HANDLING_LOCAL); break;
  661     default: return mv_error();
  662     }
  663 }
  664 
  665 static mv_binary_func_t* sec2localn_dispositions[MT_DIM] = {
  666     /*ERROR*/  _err,
  667     /*ABSENT*/ _a,
  668     /*EMPTY*/  _emt,
  669     /*STRING*/ _1,
  670     /*INT*/    sec2localtime_s_ni,
  671     /*FLOAT*/  sec2localtime_s_ni,
  672     /*BOOL*/   _1,
  673 };
  674 mv_t s_xi_sec2localtime_func(mv_t* pval1, mv_t* pval2) { return (sec2localn_dispositions[pval1->type])(pval1, pval2); }
  675 
  676 // ----------------------------------------------------------------
  677 static mv_t sec2localdate_s_n(mv_t* pa) {
  678     return time_string_from_seconds(pa, ISO8601_DATE_FORMAT, TIMEZONE_HANDLING_LOCAL);
  679 }
  680 
  681 static mv_unary_func_t* sec2localdate_dispositions[MT_DIM] = {
  682     /*ERROR*/  _err1,
  683     /*ABSENT*/ _a1,
  684     /*EMPTY*/  _emt1,
  685     /*STRING*/ _0,
  686     /*INT*/    sec2localdate_s_n,
  687     /*FLOAT*/  sec2localdate_s_n,
  688     /*BOOL*/   _0,
  689 };
  690 
  691 mv_t s_x_sec2localdate_func(mv_t* pval1) { return (sec2localdate_dispositions[pval1->type])(pval1); }
  692 
  693 
  694 // ----------------------------------------------------------------
  695 mv_t s_ns_strftime_func(mv_t* pval1, mv_t* pval2) {
  696     mv_t rv = time_string_from_seconds(pval1, pval2->u.strv, TIMEZONE_HANDLING_GMT);
  697     mv_free(pval2);
  698     return rv;
  699 }
  700 
  701 // ----------------------------------------------------------------
  702 mv_t s_ns_strftime_local_func(mv_t* pval1, mv_t* pval2) {
  703     mv_t rv = time_string_from_seconds(pval1, pval2->u.strv, TIMEZONE_HANDLING_LOCAL);
  704     mv_free(pval2);
  705     return rv;
  706 }
  707 
  708 // ----------------------------------------------------------------
  709 static mv_t seconds_from_time_string(char* string, char* format,
  710     timezone_handling_t timezone_handling)
  711 {
  712     if (*string == '\0') {
  713         return mv_empty();
  714     } else {
  715         return mv_from_float(mlr_seconds_from_time_string(string, format, timezone_handling));
  716     }
  717 }
  718 
  719 mv_t i_s_gmt2sec_func(mv_t* pval1) {
  720     mv_t rv = seconds_from_time_string(pval1->u.strv, ISO8601_TIME_FORMAT, TIMEZONE_HANDLING_GMT);
  721     mv_free(pval1);
  722     return rv;
  723 }
  724 
  725 mv_t i_s_localtime2sec_func(mv_t* pval1) {
  726     mv_t rv = seconds_from_time_string(pval1->u.strv, ISO8601_LOCAL_TIME_FORMAT, TIMEZONE_HANDLING_LOCAL);
  727     mv_free(pval1);
  728     return rv;
  729 }
  730 
  731 mv_t i_ss_strptime_func(mv_t* pval1, mv_t* pval2) {
  732     mv_t rv = seconds_from_time_string(pval1->u.strv, pval2->u.strv, TIMEZONE_HANDLING_GMT);
  733     mv_free(pval1);
  734     mv_free(pval2);
  735     return rv;
  736 }
  737 
  738 mv_t i_ss_strptime_local_func(mv_t* pval1, mv_t* pval2) {
  739     mv_t rv = seconds_from_time_string(pval1->u.strv, pval2->u.strv, TIMEZONE_HANDLING_LOCAL);
  740     mv_free(pval1);
  741     mv_free(pval2);
  742     return rv;
  743 }
  744 
  745 // ----------------------------------------------------------------
  746 static void split_ull_to_hms(long long u, long long* ph, long long* pm, long long* ps) {
  747     long long h = 0LL, m = 0LL, s = 0LL;
  748     long long sign = 1LL;
  749     if (u < 0LL) {
  750         u = -u;
  751         sign = -1LL;
  752     }
  753     s = u % 60LL;
  754     u = u / 60LL;
  755     if (u == 0LL) {
  756         s = s * sign;
  757     } else {
  758         m = u % 60LL;
  759         u = u / 60LL;
  760         if (u == 0LL) {
  761             m = m * sign;
  762         } else {
  763             h = u * sign;
  764         }
  765     }
  766     *ph = h;
  767     *pm = m;
  768     *ps = s;
  769 }
  770 
  771 static void split_ull_to_dhms(long long u, long long* pd, long long* ph, long long* pm, long long* ps) {
  772     long long d = 0LL, h = 0LL, m = 0LL, s = 0LL;
  773     long long sign = 1LL;
  774     if (u < 0LL) {
  775         u = -u;
  776         sign = -1LL;
  777     }
  778     s = u % 60LL;
  779     u = u / 60LL;
  780     if (u == 0LL) {
  781         s = s * sign;
  782     } else {
  783         m = u % 60LL;
  784         u = u / 60LL;
  785         if (u == 0LL) {
  786             m = m * sign;
  787         } else {
  788             h = u % 24LL;
  789             u = u / 24LL;
  790             if (u == 0LL) {
  791                 h = h * sign;
  792             } else {
  793                 d = u * sign;
  794             }
  795         }
  796     }
  797     *pd = d;
  798     *ph = h;
  799     *pm = m;
  800     *ps = s;
  801 }
  802 
  803 mv_t s_i_sec2hms_func(mv_t* pval1) {
  804     long long u = pval1->u.intv;
  805     long long h, m, s;
  806     char* fmt = "%02lld:%02lld:%02lld";
  807     if (u < 0) {
  808         u = -u;
  809         fmt = "-%02lld:%02lld:%02lld";
  810     }
  811     split_ull_to_hms(u, &h, &m, &s);
  812     int n = snprintf(NULL, 0, fmt, h, m, s);
  813     char* string = mlr_malloc_or_die(n+1);
  814     sprintf(string, fmt, h, m, s);
  815     return mv_from_string_with_free(string);
  816 }
  817 
  818 mv_t s_f_fsec2hms_func(mv_t* pval1) {
  819     double v = fabs(pval1->u.fltv);
  820     long long h, m, s;
  821     char* fmt = "%lld:%02lld:%09.6lf";
  822     long long u = (long long)trunc(v);
  823     double f = v - u;
  824     if (pval1->u.fltv < 0.0) {
  825         fmt = "-%02lld:%02lld:%09.6lf";
  826     }
  827     split_ull_to_hms(u, &h, &m, &s);
  828     int n = snprintf(NULL, 0, fmt, h, m, s+f);
  829     char* string = mlr_malloc_or_die(n+1);
  830     sprintf(string, fmt, h, m, s+f);
  831     return mv_from_string_with_free(string);
  832 }
  833 
  834 mv_t s_i_sec2dhms_func(mv_t* pval1) {
  835     long long u = pval1->u.intv;
  836     long long d, h, m, s;
  837     split_ull_to_dhms(u, &d, &h, &m, &s);
  838     if (d != 0.0) {
  839         char* fmt = "%lldd%02lldh%02lldm%02llds";
  840         int n = snprintf(NULL, 0, fmt, d, h, m, s);
  841         char* string = mlr_malloc_or_die(n+1);
  842         sprintf(string, fmt, d, h, m, s);
  843         return mv_from_string_with_free(string);
  844     } else if (h != 0.0) {
  845         char* fmt = "%lldh%02lldm%02llds";
  846         int n = snprintf(NULL, 0, fmt, h, m, s);
  847         char* string = mlr_malloc_or_die(n+1);
  848         sprintf(string, fmt, h, m, s);
  849         return mv_from_string_with_free(string);
  850     } else if (m != 0.0) {
  851         char* fmt = "%lldm%02llds";
  852         int n = snprintf(NULL, 0, fmt, m, s);
  853         char* string = mlr_malloc_or_die(n+1);
  854         sprintf(string, fmt, m, s);
  855         return mv_from_string_with_free(string);
  856     } else {
  857         char* fmt = "%llds";
  858         int n = snprintf(NULL, 0, fmt, s);
  859         char* string = mlr_malloc_or_die(n+1);
  860         sprintf(string, fmt, s);
  861         return mv_from_string_with_free(string);
  862     }
  863 }
  864 
  865 mv_t s_f_fsec2dhms_func(mv_t* pval1) {
  866     double v = fabs(pval1->u.fltv);
  867     long long sign = pval1->u.fltv < 0.0 ? -1LL : 1LL;
  868     long long d, h, m, s;
  869     long long u = (long long)trunc(v);
  870     double f = v - u;
  871     split_ull_to_dhms(u, &d, &h, &m, &s);
  872     if (d != 0.0) {
  873         d = sign * d;
  874         char* fmt = "%lldd%02lldh%02lldm%09.6lfs";
  875         int n = snprintf(NULL, 0, fmt, d, h, m, s+f);
  876         char* string = mlr_malloc_or_die(n+1);
  877         sprintf(string, fmt, d, h, m, s+f);
  878         return mv_from_string_with_free(string);
  879     } else if (h != 0.0) {
  880         h = sign * h;
  881         char* fmt = "%lldh%02lldm%09.6lfs";
  882         int n = snprintf(NULL, 0, fmt, h, m, s+f);
  883         char* string = mlr_malloc_or_die(n+1);
  884         sprintf(string, fmt, h, m, s+f);
  885         return mv_from_string_with_free(string);
  886     } else if (m != 0.0) {
  887         m = sign * m;
  888         char* fmt = "%lldm%09.6lfs";
  889         int n = snprintf(NULL, 0, fmt, m, s+f);
  890         char* string = mlr_malloc_or_die(n+1);
  891         sprintf(string, fmt, m, s+f);
  892         return mv_from_string_with_free(string);
  893     } else {
  894         s = sign * s;
  895         f = sign * f;
  896         char* fmt = "%.6lfs";
  897         int n = snprintf(NULL, 0, fmt, s+f);
  898         char* string = mlr_malloc_or_die(n+1);
  899         sprintf(string, fmt, s+f);
  900         return mv_from_string_with_free(string);
  901     }
  902 }
  903 
  904 // ----------------------------------------------------------------
  905 mv_t i_s_hms2sec_func(mv_t* pval1) {
  906     long long h = 0LL, m = 0LL, s = 0LL;
  907     long long sec = 0LL;
  908     char* p = pval1->u.strv;
  909     long long sign = 1LL;
  910     if (*p == '-') {
  911         p++;
  912         sign = -1LL;
  913     }
  914     if (sscanf(p, "%lld:%lld:%lld", &h, &m, &s) == 3) {
  915         if (h >= 0LL)
  916             sec = 3600LL*h + 60LL*m + s;
  917         else
  918             sec = -(-3600LL*h + 60LL*m + s);
  919     } else if (sscanf(p, "%lld:%lld", &m, &s) == 2) {
  920         if (m >= 0LL)
  921             sec = 60LL*m + s;
  922         else
  923             sec = -(-60LL*m + s);
  924     } else if (sscanf(p, "%lld", &s) == 1) {
  925         sec = s;
  926     } else {
  927         mv_free(pval1);
  928         return mv_error();
  929     }
  930     mv_free(pval1);
  931     return mv_from_int(sec * sign);
  932 }
  933 
  934 mv_t f_s_hms2fsec_func(mv_t* pval1) {
  935     long long h = 0LL, m = 0LL;
  936     double s = 0.0;
  937     double sec = 0.0;
  938     char* p = pval1->u.strv;
  939     double sign = 1.0;
  940     if (*p == '-') {
  941         p++;
  942         sign = -1.0;
  943     }
  944     if (sscanf(p, "%lld:%lld:%lf", &h, &m, &s) == 3) {
  945         sec = 3600*h + 60*m + s;
  946     } else if (sscanf(p, "%lld:%lf", &m, &s) == 2) {
  947         sec = 60*m + s;
  948     } else if (sscanf(p, "%lf", &s) == 2) {
  949         sec = s;
  950     } else {
  951         mv_free(pval1);
  952         return mv_error();
  953     }
  954     mv_free(pval1);
  955     return mv_from_float(sec * sign);
  956 }
  957 
  958 mv_t i_s_dhms2sec_func(mv_t* pval1) {
  959     long long d = 0LL, h = 0LL, m = 0LL, s = 0LL;
  960     long long sec = 0LL;
  961     char* p = pval1->u.strv;
  962     long long sign = 1LL;
  963     if (*p == '-') {
  964         p++;
  965         sign = -1LL;
  966     }
  967     if (sscanf(p, "%lldd%lldh%lldm%llds", &d, &h, &m, &s) == 4) {
  968         sec = 86400*d + 3600*h + 60*m + s;
  969     } else if (sscanf(p, "%lldh%lldm%llds", &h, &m, &s) == 3) {
  970         sec = 3600*h + 60*m + s;
  971     } else if (sscanf(p, "%lldm%llds", &m, &s) == 2) {
  972         sec = 60*m + s;
  973     } else if (sscanf(p, "%llds", &s) == 1) {
  974         sec = s;
  975     } else {
  976         mv_free(pval1);
  977         return mv_error();
  978     }
  979     mv_free(pval1);
  980     return mv_from_int(sec * sign);
  981 }
  982 
  983 mv_t f_s_dhms2fsec_func(mv_t* pval1) {
  984     long long d = 0LL, h = 0LL, m = 0LL;
  985     double s = 0.0;
  986     double sec = 0.0;
  987     char* p = pval1->u.strv;
  988     long long sign = 1.0;
  989     if (*p == '-') {
  990         p++;
  991         sign = -1.0;
  992     }
  993     if (sscanf(p, "%lldd%lldh%lldm%lfs", &d, &h, &m, &s) == 4) {
  994         sec = 86400*d + 3600*h + 60*m + s;
  995     } else if (sscanf(p, "%lldh%lldm%lfs", &h, &m, &s) == 3) {
  996         sec = 3600*h + 60*m + s;
  997     } else if (sscanf(p, "%lldm%lfs", &m, &s) == 2) {
  998         sec = 60*m + s;
  999     } else if (sscanf(p, "%lfs", &s) == 1) {
 1000         sec = s;
 1001     } else {
 1002         mv_free(pval1);
 1003         return mv_error();
 1004     }
 1005     mv_free(pval1);
 1006     return mv_from_float(sec * sign);
 1007 }
 1008 
 1009 // ================================================================
 1010 static mv_t plus_f_ff(mv_t* pa, mv_t* pb) {
 1011     double a = pa->u.fltv;
 1012     double b = pb->u.fltv;
 1013     return mv_from_float(a + b);
 1014 }
 1015 static mv_t plus_f_fi(mv_t* pa, mv_t* pb) {
 1016     double a = pa->u.fltv;
 1017     double b = (double)pb->u.intv;
 1018     return mv_from_float(a + b);
 1019 }
 1020 static mv_t plus_f_if(mv_t* pa, mv_t* pb) {
 1021     double a = (double)pa->u.intv;
 1022     double b = pb->u.fltv;
 1023     return mv_from_float(a + b);
 1024 }
 1025 // Adds & subtracts overflow by at most one bit so it suffices to check
 1026 // sign-changes.
 1027 static mv_t plus_n_ii(mv_t* pa, mv_t* pb) {
 1028     long long a = pa->u.intv;
 1029     long long b = pb->u.intv;
 1030     long long c = a + b;
 1031 
 1032     int overflowed = FALSE;
 1033     if (a > 0LL) {
 1034         if (b > 0LL && c < 0LL)
 1035             overflowed = TRUE;
 1036     } else if (a < 0LL) {
 1037         if (b < 0LL && c > 0LL)
 1038             overflowed = TRUE;
 1039     }
 1040 
 1041     if (overflowed) {
 1042         return mv_from_float((double)a + (double)b);
 1043     } else {
 1044         return mv_from_int(c);
 1045     }
 1046 }
 1047 
 1048 static mv_binary_func_t* plus_dispositions[MT_DIM][MT_DIM] = {
 1049     //         ERROR  ABSENT EMPTY STRING INT        FLOAT      BOOL
 1050     /*ERROR*/  {_err, _err,  _err, _err,  _err,      _err,      _err},
 1051     /*ABSENT*/ {_err, _a,    _a,   _err,  _2,        _2,        _err},
 1052     /*EMPTY*/  {_err, _a,    _emt, _err,  _emt,      _emt,      _err},
 1053     /*STRING*/ {_err, _err,  _err, _err,  _err,      _err,      _err},
 1054     /*INT*/    {_err, _1,    _emt, _err,  plus_n_ii, plus_f_if, _err},
 1055     /*FLOAT*/  {_err, _1,    _emt, _err,  plus_f_fi, plus_f_ff, _err},
 1056     /*BOOL*/   {_err, _err,  _err, _err,  _err,      _err,      _err},
 1057 };
 1058 
 1059 mv_t x_xx_plus_func(mv_t* pval1, mv_t* pval2) { return (plus_dispositions[pval1->type][pval2->type])(pval1,pval2); }
 1060 
 1061 // ----------------------------------------------------------------
 1062 static mv_t minus_f_ff(mv_t* pa, mv_t* pb) {
 1063     double a = pa->u.fltv;
 1064     double b = pb->u.fltv;
 1065     return mv_from_float(a - b);
 1066 }
 1067 static mv_t minus_f_fi(mv_t* pa, mv_t* pb) {
 1068     double a = pa->u.fltv;
 1069     double b = (double)pb->u.intv;
 1070     return mv_from_float(a - b);
 1071 }
 1072 static mv_t minus_f_if(mv_t* pa, mv_t* pb) {
 1073     double a = (double)pa->u.intv;
 1074     double b = pb->u.fltv;
 1075     return mv_from_float(a - b);
 1076 }
 1077 // Adds & subtracts overflow by at most one bit so it suffices to check
 1078 // sign-changes.
 1079 static mv_t minus_n_ii(mv_t* pa, mv_t* pb) {
 1080     long long a = pa->u.intv;
 1081     long long b = pb->u.intv;
 1082     long long c = a - b;
 1083 
 1084     int overflowed = FALSE;
 1085     if (a > 0LL) {
 1086         if (b < 0LL && c < 0LL)
 1087             overflowed = TRUE;
 1088     } else if (a < 0LL) {
 1089         if (b > 0LL && c > 0LL)
 1090             overflowed = TRUE;
 1091     }
 1092 
 1093     if (overflowed) {
 1094         return mv_from_float((double)a - (double)b);
 1095     } else {
 1096         return mv_from_int(c);
 1097     }
 1098 }
 1099 
 1100 static mv_binary_func_t* minus_dispositions[MT_DIM][MT_DIM] = {
 1101     //         ERROR  ABSENT EMPTY STRING INT         FLOAT       BOOL
 1102     /*ERROR*/  {_err, _err,  _err, _err,  _err,       _err,       _err},
 1103     /*ABSENT*/ {_err, _a,    _a,   _err,  _2,         _2,         _err},
 1104     /*EMPTY*/  {_err, _a,    _emt, _err,  _emt,       _emt,       _err},
 1105     /*STRING*/ {_err, _err,  _err, _err,  _err,       _err,       _err},
 1106     /*INT*/    {_err, _1,    _emt, _err,  minus_n_ii, minus_f_if, _err},
 1107     /*FLOAT*/  {_err, _1,    _emt, _err,  minus_f_fi, minus_f_ff, _err},
 1108     /*BOOL*/   {_err, _err,  _err, _err,  _err,       _err,       _err},
 1109 };
 1110 
 1111 mv_t x_xx_minus_func(mv_t* pval1, mv_t* pval2) { return (minus_dispositions[pval1->type][pval2->type])(pval1,pval2); }
 1112 
 1113 // ----------------------------------------------------------------
 1114 static mv_t times_f_ff(mv_t* pa, mv_t* pb) {
 1115     double a = pa->u.fltv;
 1116     double b = pb->u.fltv;
 1117     return mv_from_float(a * b);
 1118 }
 1119 static mv_t times_f_fi(mv_t* pa, mv_t* pb) {
 1120     double a = pa->u.fltv;
 1121     double b = (double)pb->u.intv;
 1122     return mv_from_float(a * b);
 1123 }
 1124 static mv_t times_f_if(mv_t* pa, mv_t* pb) {
 1125     double a = (double)pa->u.intv;
 1126     double b = pb->u.fltv;
 1127     return mv_from_float(a * b);
 1128 }
 1129 // Unlike adds & subtracts which overflow by at most one bit, multiplies can
 1130 // overflow by a word size. Thus detecting sign-changes does not suffice to
 1131 // detect overflow. Instead we test whether the floating-point product exceeds
 1132 // the representable integer range. Now 64-bit integers have 64-bit precision
 1133 // while IEEE-doubles have only 52-bit mantissas -- so, 53 bits including
 1134 // implicit leading one.
 1135 //
 1136 // The following experiment explicitly demonstrates the resolution at this range:
 1137 //
 1138 //    64-bit integer     64-bit integer     Casted to double           Back to 64-bit
 1139 //        in hex           in decimal                                    integer
 1140 // 0x7ffffffffffff9ff 9223372036854774271 9223372036854773760.000000 0x7ffffffffffff800
 1141 // 0x7ffffffffffffa00 9223372036854774272 9223372036854773760.000000 0x7ffffffffffff800
 1142 // 0x7ffffffffffffbff 9223372036854774783 9223372036854774784.000000 0x7ffffffffffffc00
 1143 // 0x7ffffffffffffc00 9223372036854774784 9223372036854774784.000000 0x7ffffffffffffc00
 1144 // 0x7ffffffffffffdff 9223372036854775295 9223372036854774784.000000 0x7ffffffffffffc00
 1145 // 0x7ffffffffffffe00 9223372036854775296 9223372036854775808.000000 0x8000000000000000
 1146 // 0x7ffffffffffffffe 9223372036854775806 9223372036854775808.000000 0x8000000000000000
 1147 // 0x7fffffffffffffff 9223372036854775807 9223372036854775808.000000 0x8000000000000000
 1148 //
 1149 // That is, we cannot check an integer product to see if it is greater than
 1150 // 2**63-1 (or is less than -2**63) using integer arithmetic (it may have
 1151 // already overflowed) *or* using double-precision (granularity). Instead we
 1152 // check if the absolute value of the product exceeds the largest representable
 1153 // double less than 2**63. (An alterative would be to do all integer multiplies
 1154 // using handcrafted multi-word 128-bit arithmetic).
 1155 static mv_t times_n_ii(mv_t* pa, mv_t* pb) {
 1156     long long a = pa->u.intv;
 1157     long long b = pb->u.intv;
 1158 
 1159     double d = (double)a * (double)b;
 1160     if (fabs(d) > 9223372036854774784.0) {
 1161         return mv_from_float(d);
 1162     } else {
 1163         return mv_from_int(a * b);
 1164     }
 1165 }
 1166 
 1167 static mv_binary_func_t* times_dispositions[MT_DIM][MT_DIM] = {
 1168     //         ERROR  ABSENT EMPTY STRING INT         FLOAT       BOOL
 1169     /*ERROR*/  {_err, _err,  _err, _err,  _err,       _err,       _err},
 1170     /*ABSENT*/ {_err, _a,    _a,   _err,  _2,         _2,         _err},
 1171     /*EMPTY*/  {_err, _a,    _emt, _err,  _emt,       _emt,       _err},
 1172     /*STRING*/ {_err, _err,  _err, _err,  _err,       _err,       _err},
 1173     /*INT*/    {_err, _1,    _emt, _err,  times_n_ii, times_f_if, _err},
 1174     /*FLOAT*/  {_err, _1,    _emt, _err,  times_f_fi, times_f_ff, _err},
 1175     /*BOOL*/   {_err, _err,  _err, _err,  _err,       _err,       _err},
 1176 };
 1177 
 1178 mv_t x_xx_times_func(mv_t* pval1, mv_t* pval2) { return (times_dispositions[pval1->type][pval2->type])(pval1,pval2); }
 1179 
 1180 // ----------------------------------------------------------------
 1181 static mv_t divide_f_ff(mv_t* pa, mv_t* pb) {
 1182     double a = pa->u.fltv;
 1183     double b = pb->u.fltv;
 1184     return mv_from_float(a / b);
 1185 }
 1186 static mv_t divide_f_fi(mv_t* pa, mv_t* pb) {
 1187     double a = pa->u.fltv;
 1188     double b = (double)pb->u.intv;
 1189     return mv_from_float(a / b);
 1190 }
 1191 static mv_t divide_f_if(mv_t* pa, mv_t* pb) {
 1192     double a = (double)pa->u.intv;
 1193     double b = pb->u.fltv;
 1194     return mv_from_float(a / b);
 1195 }
 1196 static mv_t divide_n_ii(mv_t* pa, mv_t* pb) {
 1197     long long a = pa->u.intv;
 1198     long long b = pb->u.intv;
 1199     if (b == 0LL) { // Compute inf/nan as with floats rather than fatal runtime FPE on integer divide by zero
 1200         return mv_from_float((double)a / (double)b);
 1201     }
 1202     long long r = a % b;
 1203     // Pythonic division, not C division.
 1204     if (r == 0LL) {
 1205         return mv_from_int(a / b);
 1206     } else {
 1207         return mv_from_float((double)a / (double)b);
 1208     }
 1209 }
 1210 
 1211 static mv_binary_func_t* divide_dispositions[MT_DIM][MT_DIM] = {
 1212     //         ERROR  ABSENT EMPTY STRING INT          FLOAT        BOOL
 1213     /*ERROR*/  {_err, _err,  _err, _err,  _err,        _err,        _err},
 1214     /*ABSENT*/ {_err, _a,    _a,   _err,  _i0,         _f0,         _err},
 1215     /*EMPTY*/  {_err, _a,    _emt, _err,  _emt,        _emt,        _err},
 1216     /*STRING*/ {_err, _err,  _err, _err,  _err,        _err,        _err},
 1217     /*INT*/    {_err, _1,    _emt, _err,  divide_n_ii, divide_f_if, _err},
 1218     /*FLOAT*/  {_err, _1,    _emt, _err,  divide_f_fi, divide_f_ff, _err},
 1219     /*BOOL*/   {_err, _err,  _err, _err,  _err,        _err,        _err},
 1220 };
 1221 
 1222 mv_t x_xx_divide_func(mv_t* pval1, mv_t* pval2) { return (divide_dispositions[pval1->type][pval2->type])(pval1,pval2); }
 1223 
 1224 // ----------------------------------------------------------------
 1225 static mv_t idiv_f_ff(mv_t* pa, mv_t* pb) {
 1226     double a = pa->u.fltv;
 1227     double b = pb->u.fltv;
 1228     return mv_from_float(floor(a / b));
 1229 }
 1230 static mv_t idiv_f_fi(mv_t* pa, mv_t* pb) {
 1231     double a = pa->u.fltv;
 1232     double b = (double)pb->u.intv;
 1233     return mv_from_float(floor(a / b));
 1234 }
 1235 static mv_t idiv_f_if(mv_t* pa, mv_t* pb) {
 1236     double a = (double)pa->u.intv;
 1237     double b = pb->u.fltv;
 1238     return mv_from_float(floor(a / b));
 1239 }
 1240 static mv_t idiv_i_ii(mv_t* pa, mv_t* pb) {
 1241     long long a = pa->u.intv;
 1242     long long b = pb->u.intv;
 1243     if (b == 0LL) { // Compute inf/nan as with floats rather than fatal runtime FPE on integer divide by zero
 1244         return mv_from_float((double)a / (double)b);
 1245     }
 1246     // Pythonic division, not C division.
 1247     long long q = a / b;
 1248     long long r = a % b;
 1249     if (a < 0) {
 1250         if (b > 0) {
 1251             if (r != 0)
 1252                 q--;
 1253         }
 1254     } else {
 1255         if (b < 0) {
 1256             if (r != 0)
 1257                 q--;
 1258         }
 1259     }
 1260     return mv_from_int(q);
 1261 }
 1262 
 1263 static mv_binary_func_t* idiv_dispositions[MT_DIM][MT_DIM] = {
 1264     //         ERROR  ABSENT EMPTY STRING INT        FLOAT      BOOL
 1265     /*ERROR*/  {_err, _err,  _err, _err,  _err,      _err,      _err},
 1266     /*ABSENT*/ {_err, _a,    _a,   _err,  _i0,       _f0,       _err},
 1267     /*EMPTY*/  {_err, _a,    _emt, _err,  _emt,      _emt,      _err},
 1268     /*STRING*/ {_err, _err,  _err, _err,  _err,      _err,      _err},
 1269     /*INT*/    {_err, _1,    _emt, _err,  idiv_i_ii, idiv_f_if, _err},
 1270     /*FLOAT*/  {_err, _1,    _emt, _err,  idiv_f_fi, idiv_f_ff, _err},
 1271     /*BOOL*/   {_err, _err,  _err, _err,  _err,      _err,      _err},
 1272 };
 1273 
 1274 mv_t x_xx_int_divide_func(mv_t* pval1, mv_t* pval2) {
 1275     return (idiv_dispositions[pval1->type][pval2->type])(pval1,pval2);
 1276 }
 1277 
 1278 // ================================================================
 1279 static mv_t oplus_f_ff(mv_t* pa, mv_t* pb) {
 1280     double a = pa->u.fltv;
 1281     double b = pb->u.fltv;
 1282     return mv_from_float(a + b);
 1283 }
 1284 static mv_t oplus_f_fi(mv_t* pa, mv_t* pb) {
 1285     double a = pa->u.fltv;
 1286     double b = (double)pb->u.intv;
 1287     return mv_from_float(a + b);
 1288 }
 1289 static mv_t oplus_f_if(mv_t* pa, mv_t* pb) {
 1290     double a = (double)pa->u.intv;
 1291     double b = pb->u.fltv;
 1292     return mv_from_float(a + b);
 1293 }
 1294 static mv_t oplus_i_ii(mv_t* pa, mv_t* pb) {
 1295     long long a = pa->u.intv;
 1296     long long b = pb->u.intv;
 1297     long long c = a + b;
 1298     return mv_from_int(c);
 1299 }
 1300 
 1301 static mv_binary_func_t* oplus_dispositions[MT_DIM][MT_DIM] = {
 1302     //         ERROR  ABSENT EMPTY STRING INT         FLOAT       BOOL
 1303     /*ERROR*/  {_err, _err,  _err, _err,  _err,       _err,       _err},
 1304     /*ABSENT*/ {_err, _a,    _a,   _err,  _2,         _2,         _err},
 1305     /*EMPTY*/  {_err, _a,    _emt, _err,  _emt,       _emt,       _err},
 1306     /*STRING*/ {_err, _err,  _err, _err,  _err,       _err,       _err},
 1307     /*INT*/    {_err, _1,    _emt, _err,  oplus_i_ii, oplus_f_if, _err},
 1308     /*FLOAT*/  {_err, _1,    _emt, _err,  oplus_f_fi, oplus_f_ff, _err},
 1309     /*BOOL*/   {_err, _err,  _err, _err,  _err,       _err,       _err},
 1310 };
 1311 
 1312 mv_t x_xx_oplus_func(mv_t* pval1, mv_t* pval2) { return (oplus_dispositions[pval1->type][pval2->type])(pval1,pval2); }
 1313 
 1314 // ----------------------------------------------------------------
 1315 static mv_t ominus_f_ff(mv_t* pa, mv_t* pb) {
 1316     double a = pa->u.fltv;
 1317     double b = pb->u.fltv;
 1318     return mv_from_float(a - b);
 1319 }
 1320 static mv_t ominus_f_fi(mv_t* pa, mv_t* pb) {
 1321     double a = pa->u.fltv;
 1322     double b = (double)pb->u.intv;
 1323     return mv_from_float(a - b);
 1324 }
 1325 static mv_t ominus_f_if(mv_t* pa, mv_t* pb) {
 1326     double a = (double)pa->u.intv;
 1327     double b = pb->u.fltv;
 1328     return mv_from_float(a - b);
 1329 }
 1330 static mv_t ominus_n_ii(mv_t* pa, mv_t* pb) {
 1331     long long a = pa->u.intv;
 1332     long long b = pb->u.intv;
 1333     long long c = a - b;
 1334     return mv_from_int(c);
 1335 }
 1336 
 1337 static mv_binary_func_t* ominus_dispositions[MT_DIM][MT_DIM] = {
 1338     //         ERROR  ABSENT EMPTY STRING INT          FLOAT        BOOL
 1339     /*ERROR*/  {_err, _err,  _err, _err,  _err,        _err,        _err},
 1340     /*ABSENT*/ {_err, _a,    _a,   _err,  _2,          _2,          _err},
 1341     /*EMPTY*/  {_err, _a,    _emt, _err,  _emt,        _emt,        _err},
 1342     /*STRING*/ {_err, _err,  _err, _err,  _err,        _err,        _err},
 1343     /*INT*/    {_err, _1,    _emt, _err,  ominus_n_ii, ominus_f_if, _err},
 1344     /*FLOAT*/  {_err, _1,    _emt, _err,  ominus_f_fi, ominus_f_ff, _err},
 1345     /*BOOL*/   {_err, _err,  _err, _err,  _err,        _err,        _err},
 1346 };
 1347 
 1348 mv_t x_xx_ominus_func(mv_t* pval1, mv_t* pval2) { return (ominus_dispositions[pval1->type][pval2->type])(pval1,pval2); }
 1349 
 1350 // ----------------------------------------------------------------
 1351 static mv_t otimes_f_ff(mv_t* pa, mv_t* pb) {
 1352     double a = pa->u.fltv;
 1353     double b = pb->u.fltv;
 1354     return mv_from_float(a * b);
 1355 }
 1356 static mv_t otimes_f_fi(mv_t* pa, mv_t* pb) {
 1357     double a = pa->u.fltv;
 1358     double b = (double)pb->u.intv;
 1359     return mv_from_float(a * b);
 1360 }
 1361 static mv_t otimes_f_if(mv_t* pa, mv_t* pb) {
 1362     double a = (double)pa->u.intv;
 1363     double b = pb->u.fltv;
 1364     return mv_from_float(a * b);
 1365 }
 1366 static mv_t otimes_n_ii(mv_t* pa, mv_t* pb) {
 1367     long long a = pa->u.intv;
 1368     long long b = pb->u.intv;
 1369     return mv_from_int(a * b);
 1370 }
 1371 
 1372 static mv_binary_func_t* otimes_dispositions[MT_DIM][MT_DIM] = {
 1373     //         ERROR  ABSENT EMPTY STRING INT          FLOAT       BOOL
 1374     /*ERROR*/  {_err, _err,  _err, _err,  _err,        _err,       _err},
 1375     /*ABSENT*/ {_err, _a,    _a,   _err,  _2,          _2,         _err},
 1376     /*EMPTY*/  {_err, _a,    _emt, _err,  _emt,        _emt,       _err},
 1377     /*STRING*/ {_err, _err,  _err, _err,  _err,        _err,       _err},
 1378     /*INT*/    {_err, _1,    _emt, _err,  otimes_n_ii, otimes_f_if, _err},
 1379     /*FLOAT*/  {_err, _1,    _emt, _err,  otimes_f_fi, otimes_f_ff, _err},
 1380     /*BOOL*/   {_err, _err,  _err, _err,  _err,        _err,       _err},
 1381 };
 1382 
 1383 mv_t x_xx_otimes_func(mv_t* pval1, mv_t* pval2) { return (otimes_dispositions[pval1->type][pval2->type])(pval1,pval2); }
 1384 
 1385 // ----------------------------------------------------------------
 1386 static mv_t odivide_f_ff(mv_t* pa, mv_t* pb) {
 1387     double a = pa->u.fltv;
 1388     double b = pb->u.fltv;
 1389     return mv_from_float(a / b);
 1390 }
 1391 static mv_t odivide_f_fi(mv_t* pa, mv_t* pb) {
 1392     double a = pa->u.fltv;
 1393     double b = (double)pb->u.intv;
 1394     return mv_from_float(a / b);
 1395 }
 1396 static mv_t odivide_f_if(mv_t* pa, mv_t* pb) {
 1397     double a = (double)pa->u.intv;
 1398     double b = pb->u.fltv;
 1399     return mv_from_float(a / b);
 1400 }
 1401 static mv_t odivide_i_ii(mv_t* pa, mv_t* pb) {
 1402     long long a = pa->u.intv;
 1403     long long b = pb->u.intv;
 1404     return mv_from_int(a / b);
 1405 }
 1406 
 1407 static mv_binary_func_t* odivide_dispositions[MT_DIM][MT_DIM] = {
 1408     //         ERROR  ABSENT EMPTY STRING INT           FLOAT         BOOL
 1409     /*ERROR*/  {_err, _err,  _err, _err,  _err,         _err,         _err},
 1410     /*ABSENT*/ {_err, _a,    _a,   _err,  _i0,          _f0,          _err},
 1411     /*EMPTY*/  {_err, _a,    _emt, _err,  _emt,         _emt,         _err},
 1412     /*STRING*/ {_err, _err,  _err, _err,  _err,         _err,         _err},
 1413     /*INT*/    {_err, _1,    _emt, _err,  odivide_i_ii, odivide_f_if, _err},
 1414     /*FLOAT*/  {_err, _1,    _emt, _err,  odivide_f_fi, odivide_f_ff, _err},
 1415     /*BOOL*/   {_err, _err,  _err, _err,  _err,         _err,         _err},
 1416 };
 1417 
 1418 mv_t x_xx_odivide_func(mv_t* pval1, mv_t* pval2) { return (odivide_dispositions[pval1->type][pval2->type])(pval1,pval2); }
 1419 
 1420 // ----------------------------------------------------------------
 1421 static mv_t oidiv_f_ff(mv_t* pa, mv_t* pb) {
 1422     double a = pa->u.fltv;
 1423     double b = pb->u.fltv;
 1424     return mv_from_float(floor(a / b));
 1425 }
 1426 static mv_t oidiv_f_fi(mv_t* pa, mv_t* pb) {
 1427     double a = pa->u.fltv;
 1428     double b = (double)pb->u.intv;
 1429     return mv_from_float(floor(a / b));
 1430 }
 1431 static mv_t oidiv_f_if(mv_t* pa, mv_t* pb) {
 1432     double a = (double)pa->u.intv;
 1433     double b = pb->u.fltv;
 1434     return mv_from_float(floor(a / b));
 1435 }
 1436 static mv_t oidiv_i_ii(mv_t* pa, mv_t* pb) {
 1437     long long a = pa->u.intv;
 1438     long long b = pb->u.intv;
 1439 
 1440     // Pythonic division, not C division.
 1441     long long q = a / b;
 1442     long long r = a % b;
 1443     if (a < 0) {
 1444         if (b > 0) {
 1445             if (r != 0)
 1446                 q--;
 1447         }
 1448     } else {
 1449         if (b < 0) {
 1450             if (r != 0)
 1451                 q--;
 1452         }
 1453     }
 1454     return mv_from_int(q);
 1455 }
 1456 
 1457 static mv_binary_func_t* oidiv_dispositions[MT_DIM][MT_DIM] = {
 1458     //         ERROR  ABSENT EMPTY STRING INT         FLOAT       BOOL
 1459     /*ERROR*/  {_err, _err,  _err, _err,  _err,       _err,       _err},
 1460     /*ABSENT*/ {_err, _a,    _a,   _err,  _i0,        _f0,        _err},
 1461     /*EMPTY*/  {_err, _a,    _emt, _err,  _emt,       _emt,       _err},
 1462     /*STRING*/ {_err, _err,  _err, _err,  _err,       _err,       _err},
 1463     /*INT*/    {_err, _1,    _emt, _err,  oidiv_i_ii, oidiv_f_if, _err},
 1464     /*FLOAT*/  {_err, _1,    _emt, _err,  oidiv_f_fi, oidiv_f_ff, _err},
 1465     /*BOOL*/   {_err, _err,  _err, _err,  _err,       _err,       _err},
 1466 };
 1467 
 1468 mv_t x_xx_int_odivide_func(mv_t* pval1, mv_t* pval2) {
 1469     return (oidiv_dispositions[pval1->type][pval2->type])(pval1,pval2);
 1470 }
 1471 
 1472 // ================================================================
 1473 static mv_t mod_f_ff(mv_t* pa, mv_t* pb) {
 1474     double a = pa->u.fltv;
 1475     double b = pb->u.fltv;
 1476     return mv_from_float(a - b * floor(a / b));
 1477 }
 1478 static mv_t mod_f_fi(mv_t* pa, mv_t* pb) {
 1479     double a = pa->u.fltv;
 1480     double b = (double)pb->u.intv;
 1481     return mv_from_float(a - b * floor(a / b));
 1482 }
 1483 static mv_t mod_f_if(mv_t* pa, mv_t* pb) {
 1484     double a = (double)pa->u.intv;
 1485     double b = pb->u.fltv;
 1486     return mv_from_float(a - b * floor(a / b));
 1487 }
 1488 static mv_t mod_i_ii(mv_t* pa, mv_t* pb) {
 1489     long long a = pa->u.intv;
 1490     long long b = pb->u.intv;
 1491     if (b == 0LL) { // Compute inf/nan as with floats rather than fatal runtime FPE on integer divide by zero
 1492         return mv_from_float((double)a / (double)b);
 1493     }
 1494     long long u = a % b;
 1495     // Pythonic division, not C division.
 1496     if (a >= 0LL) {
 1497         if (b < 0LL) {
 1498             u += b;
 1499         }
 1500     } else {
 1501         if (b >= 0LL) {
 1502             u += b;
 1503         }
 1504     }
 1505     return mv_from_int(u);
 1506 }
 1507 
 1508 static mv_binary_func_t* mod_dispositions[MT_DIM][MT_DIM] = {
 1509     //         ERROR  ABSENT EMPTY STRING INT       FLOAT     BOOL
 1510     /*ERROR*/  {_err, _err,  _err, _err,  _err,     _err,     _err},
 1511     /*ABSENT*/ {_err, _a,    _a,   _err,  _i0,      _f0,      _err},
 1512     /*EMPTY*/  {_err, _a,    _emt, _err,  _emt,     _emt,     _err},
 1513     /*STRING*/ {_err, _err,  _err, _err,  _err,     _err,     _err},
 1514     /*INT*/    {_err, _1,    _emt, _err,  mod_i_ii, mod_f_if, _err},
 1515     /*FLOAT*/  {_err, _1,    _emt, _err,  mod_f_fi, mod_f_ff, _err},
 1516     /*BOOL*/   {_err, _err,  _err, _err,  _err,     _err,     _err},
 1517 };
 1518 
 1519 mv_t x_xx_mod_func(mv_t* pval1, mv_t* pval2) {
 1520     return (mod_dispositions[pval1->type][pval2->type])(pval1,pval2);
 1521 }
 1522 
 1523 // ----------------------------------------------------------------
 1524 static mv_t upos_i_i(mv_t* pa) {
 1525     return *pa;
 1526 }
 1527 static mv_t upos_f_f(mv_t* pa) {
 1528     return *pa;
 1529 }
 1530 
 1531 static mv_unary_func_t* upos_dispositions[MT_DIM] = {
 1532     /*ERROR*/  _err1,
 1533     /*ABSENT*/ _a1,
 1534     /*EMPTY*/  _emt1,
 1535     /*STRING*/ _err1,
 1536     /*INT*/    upos_i_i,
 1537     /*FLOAT*/  upos_f_f,
 1538     /*BOOL*/   _err1,
 1539 };
 1540 
 1541 mv_t x_x_upos_func(mv_t* pval1) { return (upos_dispositions[pval1->type])(pval1); }
 1542 
 1543 // ----------------------------------------------------------------
 1544 static mv_t uneg_i_i(mv_t* pa) {
 1545     return mv_from_int(-pa->u.intv);
 1546 }
 1547 static mv_t uneg_f_f(mv_t* pa) {
 1548     return mv_from_float(-pa->u.fltv);
 1549 }
 1550 
 1551 static mv_unary_func_t* uneg_disnegitions[MT_DIM] = {
 1552     /*ERROR*/  _err1,
 1553     /*ABSENT*/ _a1,
 1554     /*EMPTY*/  _emt1,
 1555     /*STRING*/ _err1,
 1556     /*INT*/    uneg_i_i,
 1557     /*FLOAT*/  uneg_f_f,
 1558     /*BOOL*/   _err1,
 1559 };
 1560 
 1561 mv_t x_x_uneg_func(mv_t* pval1) { return (uneg_disnegitions[pval1->type])(pval1); }
 1562 
 1563 // ----------------------------------------------------------------
 1564 static mv_t abs_n_f(mv_t* pa) {
 1565     return mv_from_float(fabs(pa->u.fltv));
 1566 }
 1567 static mv_t abs_n_i(mv_t* pa) {
 1568     return mv_from_int(pa->u.intv < 0LL ? -pa->u.intv : pa->u.intv);
 1569 }
 1570 
 1571 static mv_unary_func_t* abs_dispositions[MT_DIM] = {
 1572     /*ERROR*/  _err1,
 1573     /*ABSENT*/ _a1,
 1574     /*EMPTY*/  _emt1,
 1575     /*STRING*/ _err1,
 1576     /*INT*/    abs_n_i,
 1577     /*FLOAT*/  abs_n_f,
 1578     /*BOOL*/   _err1,
 1579 };
 1580 
 1581 mv_t x_x_abs_func(mv_t* pval1) { return (abs_dispositions[pval1->type])(pval1); }
 1582 
 1583 // ----------------------------------------------------------------
 1584 static mv_t sgn_n_f(mv_t* pa) {
 1585     if (pa->u.fltv > 0.0)
 1586         return mv_from_float(1.0);
 1587     if (pa->u.fltv < 0.0)
 1588         return mv_from_float(-1.0);
 1589     return mv_from_float(0.0);
 1590 }
 1591 static mv_t sgn_n_i(mv_t* pa) {
 1592     if (pa->u.intv > 0LL)
 1593         return mv_from_int(1LL);
 1594     if (pa->u.intv < 0LL)
 1595         return mv_from_int(-1LL);
 1596     return mv_from_int(0LL);
 1597 }
 1598 
 1599 static mv_unary_func_t* sgn_dispositions[MT_DIM] = {
 1600     /*ERROR*/  _err1,
 1601     /*ABSENT*/ _a1,
 1602     /*EMPTY*/  _emt1,
 1603     /*STRING*/ _err1,
 1604     /*INT*/    sgn_n_i,
 1605     /*FLOAT*/  sgn_n_f,
 1606     /*BOOL*/   _err1,
 1607 };
 1608 
 1609 mv_t x_x_sgn_func(mv_t* pval1) { return (sgn_dispositions[pval1->type])(pval1); }
 1610 
 1611 // ----------------------------------------------------------------
 1612 static mv_t ceil_n_f(mv_t* pa) {
 1613     return mv_from_float(ceil(pa->u.fltv));
 1614 }
 1615 static mv_t ceil_n_i(mv_t* pa) {
 1616     return mv_from_int(pa->u.intv);
 1617 }
 1618 
 1619 static mv_unary_func_t* ceil_dispositions[MT_DIM] = {
 1620     /*ERROR*/  _err1,
 1621     /*ABSENT*/ _a1,
 1622     /*EMPTY*/  _emt1,
 1623     /*STRING*/ _err1,
 1624     /*INT*/    ceil_n_i,
 1625     /*FLOAT*/  ceil_n_f,
 1626     /*BOOL*/   _err1,
 1627 };
 1628 
 1629 mv_t x_x_ceil_func(mv_t* pval1) { return (ceil_dispositions[pval1->type])(pval1); }
 1630 
 1631 // ----------------------------------------------------------------
 1632 static mv_t floor_n_f(mv_t* pa) {
 1633     return mv_from_float(floor(pa->u.fltv));
 1634 }
 1635 static mv_t floor_n_i(mv_t* pa) {
 1636     return mv_from_int(pa->u.intv);
 1637 }
 1638 
 1639 static mv_unary_func_t* floor_dispositions[MT_DIM] = {
 1640     /*ERROR*/  _err1,
 1641     /*ABSENT*/ _a1,
 1642     /*EMPTY*/  _emt1,
 1643     /*STRING*/ _err1,
 1644     /*INT*/    floor_n_i,
 1645     /*FLOAT*/  floor_n_f,
 1646     /*BOOL*/   _err1,
 1647 };
 1648 
 1649 mv_t x_x_floor_func(mv_t* pval1) { return (floor_dispositions[pval1->type])(pval1); }
 1650 
 1651 // ----------------------------------------------------------------
 1652 static mv_t round_n_f(mv_t* pa) {
 1653     return mv_from_float(round(pa->u.fltv));
 1654 }
 1655 static mv_t round_n_i(mv_t* pa) {
 1656     return mv_from_int(pa->u.intv);
 1657 }
 1658 
 1659 static mv_unary_func_t* round_dispositions[MT_DIM] = {
 1660     /*ERROR*/  _err1,
 1661     /*ABSENT*/ _a1,
 1662     /*EMPTY*/  _emt1,
 1663     /*STRING*/ _err1,
 1664     /*INT*/    round_n_i,
 1665     /*FLOAT*/  round_n_f,
 1666     /*BOOL*/   _err1,
 1667 };
 1668 
 1669 mv_t x_x_round_func(mv_t* pval1) { return (round_dispositions[pval1->type])(pval1); }
 1670 
 1671 // ----------------------------------------------------------------
 1672 static mv_t roundm_f_ff(mv_t* pa, mv_t* pb) {
 1673     double x = pa->u.fltv;
 1674     double m = pb->u.fltv;
 1675     return mv_from_float(round(x / m) * m);
 1676 }
 1677 static mv_t roundm_f_fi(mv_t* pa, mv_t* pb) {
 1678     double x = pa->u.fltv;
 1679     double m = (double)pb->u.intv;
 1680     return mv_from_float(round(x / m) * m);
 1681 }
 1682 static mv_t roundm_f_if(mv_t* pa, mv_t* pb) {
 1683     double x = (double)pa->u.intv;
 1684     double m = pb->u.fltv;
 1685     return mv_from_float(round(x / m) * m);
 1686 }
 1687 static mv_t roundm_i_ii(mv_t* pa, mv_t* pb) {
 1688     long long x = pa->u.intv;
 1689     long long m = pb->u.intv;
 1690     return mv_from_int((x / m) * m);
 1691 }
 1692 
 1693 static mv_binary_func_t* roundm_dispositions[MT_DIM][MT_DIM] = {
 1694     //         ERROR  ABSENT EMPTY STRING INT          FLOAT        BOOL
 1695     /*ERROR*/  {_err, _err,  _err, _err,  _err,        _err,        _err},
 1696     /*ABSENT*/ {_err, _a,    _a,   _err,  _a,          _err,        _err},
 1697     /*EMPTY*/  {_err, _a,    _emt, _err,  _err,        _err,        _err},
 1698     /*STRING*/ {_err, _err,  _err, _err,  _err,        _err,        _err},
 1699     /*INT*/    {_err, _a,    _err, _err,  roundm_i_ii, roundm_f_if, _err},
 1700     /*FLOAT*/  {_err, _err,  _err, _err,  roundm_f_fi, roundm_f_ff, _err},
 1701     /*BOOL*/   {_err, _err,  _err, _err,  _err,        _err,        _err},
 1702 };
 1703 
 1704 mv_t x_xx_roundm_func(mv_t* pval1, mv_t* pval2) { return (roundm_dispositions[pval1->type][pval2->type])(pval1,pval2); }
 1705 
 1706 // ----------------------------------------------------------------
 1707 static mv_t min_f_ff(mv_t* pa, mv_t* pb) {
 1708     double a = pa->u.fltv;
 1709     double b = pb->u.fltv;
 1710     return mv_from_float(fmin(a, b));
 1711 }
 1712 
 1713 static mv_t min_f_fi(mv_t* pa, mv_t* pb) {
 1714     double a = pa->u.fltv;
 1715     double b = (double)pb->u.intv;
 1716     return mv_from_float(fmin(a, b));
 1717 }
 1718 
 1719 static mv_t min_f_if(mv_t* pa, mv_t* pb) {
 1720     double a = (double)pa->u.intv;
 1721     double b = pb->u.fltv;
 1722     return mv_from_float(fmin(a, b));
 1723 }
 1724 
 1725 static mv_t min_i_ii(mv_t* pa, mv_t* pb) {
 1726     long long a = pa->u.intv;
 1727     long long b = pb->u.intv;
 1728     return mv_from_int(a < b ? a : b);
 1729 }
 1730 
 1731 static mv_t min_b_bb(mv_t* pa, mv_t* pb) {
 1732     int a = pa->u.boolv;
 1733     int b = pb->u.boolv;
 1734     return mv_from_bool(a < b ? a : b);
 1735 }
 1736 
 1737 static mv_t min_s_ss(mv_t* pa, mv_t* pb) {
 1738     char* a = pa->u.strv;
 1739     char* b = pb->u.strv;
 1740     int   c = strcmp(a, b);
 1741     if (c <= 0) {
 1742         mv_free(pb);
 1743         return *pa;
 1744     } else {
 1745         mv_free(pa);
 1746         return *pb;
 1747     }
 1748 }
 1749 
 1750 // Sort rules (same for min, max, and comparator):
 1751 // * NUMERICS < BOOL < STRINGS < ERROR < ABSENT
 1752 // * error == error (singleton type)
 1753 // * absent == absent (singleton type)
 1754 // * string compares on strings
 1755 // * numeric compares on numbers
 1756 // * false < true
 1757 // Exceptions for min & max:
 1758 // * absent-null always loses
 1759 // * empty-null always loses against numbers
 1760 static mv_binary_func_t* min_dispositions[MT_DIM][MT_DIM] = {
 1761     //         ERROR  ABSENT EMPTY STRING    INT       FLOAT     BOOL
 1762     /*ERROR*/  {_err, _err,  _err, _err,     _err,     _err,     _err},
 1763     /*ABSENT*/ {_err, _a,    _2,   _2f,      _2,       _2,       _2},
 1764     /*EMPTY*/  {_err, _1,    _emt, _emt,     _2,       _2,       _2},
 1765     /*STRING*/ {_err, _1f,   _emt, min_s_ss, _2f,      _2f,      _2f},
 1766     /*INT*/    {_err, _1,    _1,   _1f,      min_i_ii, min_f_if, _1},
 1767     /*FLOAT*/  {_err, _1,    _1,   _1f,      min_f_fi, min_f_ff, _1},
 1768     /*BOOL*/   {_err, _1,    _1,   _1f,      _2,       _2,       min_b_bb},
 1769 };
 1770 
 1771 mv_t x_xx_min_func(mv_t* pval1, mv_t* pval2) {
 1772     return (min_dispositions[pval1->type][pval2->type])(pval1,pval2);
 1773 }
 1774 
 1775 mv_t variadic_min_func(mv_t* pvals, int nvals) {
 1776     if (nvals == 0) {
 1777         return mv_empty();
 1778     } else {
 1779         mv_t rv = pvals[0];
 1780         for (int i = 1; i < nvals; i++) {
 1781             rv = x_xx_min_func(&rv, &pvals[i]);
 1782             // Disposition-matrix entries for min all free their non-return arguments
 1783         }
 1784         return rv;
 1785     }
 1786 }
 1787 
 1788 // ----------------------------------------------------------------
 1789 static mv_t max_f_ff(mv_t* pa, mv_t* pb) {
 1790     double a = pa->u.fltv;
 1791     double b = pb->u.fltv;
 1792     return mv_from_float(fmax(a, b));
 1793 }
 1794 
 1795 static mv_t max_f_fi(mv_t* pa, mv_t* pb) {
 1796     double a = pa->u.fltv;
 1797     double b = (double)pb->u.intv;
 1798     return mv_from_float(fmax(a, b));
 1799 }
 1800 
 1801 static mv_t max_f_if(mv_t* pa, mv_t* pb) {
 1802     double a = (double)pa->u.intv;
 1803     double b = pb->u.fltv;
 1804     return mv_from_float(fmax(a, b));
 1805 }
 1806 
 1807 static mv_t max_i_ii(mv_t* pa, mv_t* pb) {
 1808     long long a = pa->u.intv;
 1809     long long b = pb->u.intv;
 1810     return mv_from_int(a > b ? a : b);
 1811 }
 1812 
 1813 static mv_t max_b_bb(mv_t* pa, mv_t* pb) {
 1814     int a = pa->u.boolv;
 1815     int b = pb->u.boolv;
 1816     return mv_from_bool(a > b ? a : b);
 1817 }
 1818 
 1819 static mv_t max_s_ss(mv_t* pa, mv_t* pb) {
 1820     char* a = pa->u.strv;
 1821     char* b = pb->u.strv;
 1822     int   c = strcmp(a, b);
 1823     if (c >= 0) {
 1824         mv_free(pb);
 1825         return *pa;
 1826     } else {
 1827         mv_free(pa);
 1828         return *pb;
 1829     }
 1830 }
 1831 
 1832 // Sort rules (same for min, max, and comparator):
 1833 // * NUMERICS < BOOL < STRINGS < ERROR < ABSENT
 1834 // * error == error (singleton type)
 1835 // * absent == absent (singleton type)
 1836 // * string compares on strings
 1837 // * numeric compares on numbers
 1838 // * false < true
 1839 // Exceptions for min & max:
 1840 // * absent-null always loses
 1841 // * empty-null always loses against numbers
 1842 static mv_binary_func_t* max_dispositions[MT_DIM][MT_DIM] = {
 1843     //         ERROR  ABSENT EMPTY STRING    INT       FLOAT     BOOL
 1844     /*ERROR*/  {_err, _err,  _err, _err,     _err,     _err,     _err},
 1845     /*ABSENT*/ {_err, _a,    _2,   _2f,      _2,       _2,       _2},
 1846     /*EMPTY*/  {_err, _1,    _emt, _2f,      _2,       _2,       _2},
 1847     /*STRING*/ {_err, _1f,   _1f,  max_s_ss, _1f,      _1f,      _1f},
 1848     /*INT*/    {_err, _1,    _1,   _2f,      max_i_ii, max_f_if, _2},
 1849     /*FLOAT*/  {_err, _1,    _1,   _2f,      max_f_fi, max_f_ff, _2},
 1850     /*BOOL*/   {_err, _1,    _1,   _2f,      _1,       _1,       max_b_bb},
 1851     };
 1852 
 1853 mv_t x_xx_max_func(mv_t* pval1, mv_t* pval2) {
 1854     return (max_dispositions[pval1->type][pval2->type])(pval1,pval2);
 1855 }
 1856 
 1857 mv_t variadic_max_func(mv_t* pvals, int nvals) {
 1858     if (nvals == 0) {
 1859         return mv_empty();
 1860     } else {
 1861         mv_t rv = pvals[0];
 1862         for (int i = 1; i < nvals; i++) {
 1863             rv = x_xx_max_func(&rv, &pvals[i]);
 1864             // Disposition-matrix entries for max all free their non-return arguments
 1865         }
 1866         return rv;
 1867     }
 1868 }
 1869 
 1870 // ----------------------------------------------------------------
 1871 static mv_t int_i_b(mv_t* pa) { return mv_from_int(pa->u.boolv ? 1 : 0); }
 1872 static mv_t int_i_f(mv_t* pa) { return mv_from_int((long long)round(pa->u.fltv)); }
 1873 static mv_t int_i_i(mv_t* pa) { return mv_from_int(pa->u.intv); }
 1874 static mv_t int_i_s(mv_t* pa) {
 1875     if (*pa->u.strv == '\0') {
 1876         mv_free(pa);
 1877         return mv_empty();
 1878     }
 1879     mv_t retval = mv_from_int(0LL);
 1880     if (!mlr_try_int_from_string(pa->u.strv, &retval.u.intv)) {
 1881         mv_free(pa);
 1882         return mv_error();
 1883     }
 1884     mv_free(pa);
 1885     return retval;
 1886 }
 1887 
 1888 static mv_unary_func_t* int_dispositions[MT_DIM] = {
 1889     /*ERROR*/  _err1,
 1890     /*ABSENT*/ _a1,
 1891     /*EMPTY*/  _emt1,
 1892     /*STRING*/ int_i_s,
 1893     /*INT*/    int_i_i,
 1894     /*FLOAT*/  int_i_f,
 1895     /*BOOL*/   int_i_b,
 1896 };
 1897 
 1898 mv_t i_x_int_func(mv_t* pval1) { return (int_dispositions[pval1->type])(pval1); }
 1899 
 1900 // ----------------------------------------------------------------
 1901 static mv_t float_f_b(mv_t* pa) { return mv_from_float(pa->u.boolv ? 1.0 : 0.0); }
 1902 static mv_t float_f_f(mv_t* pa) { return mv_from_float(pa->u.fltv); }
 1903 static mv_t float_f_i(mv_t* pa) { return mv_from_float((double)pa->u.intv); }
 1904 static mv_t float_f_s(mv_t* pa) {
 1905     if (*pa->u.strv == '\0') {
 1906         mv_free(pa);
 1907         return mv_empty();
 1908     }
 1909     mv_t retval = mv_from_float(0.0);
 1910     if (!mlr_try_float_from_string(pa->u.strv, &retval.u.fltv)) {
 1911         mv_free(pa);
 1912         return mv_error();
 1913     }
 1914     mv_free(pa);
 1915     return retval;
 1916 }
 1917 
 1918 static mv_unary_func_t* float_dispositions[MT_DIM] = {
 1919     /*ERROR*/  _err1,
 1920     /*ABSENT*/ _a1,
 1921     /*EMPTY*/  _emt1,
 1922     /*STRING*/ float_f_s,
 1923     /*INT*/    float_f_i,
 1924     /*FLOAT*/  float_f_f,
 1925     /*BOOL*/   float_f_b,
 1926 };
 1927 
 1928 mv_t f_x_float_func(mv_t* pval1) { return (float_dispositions[pval1->type])(pval1); }
 1929 
 1930 // ----------------------------------------------------------------
 1931 static mv_t band_i_ii(mv_t* pa, mv_t* pb) {
 1932     return mv_from_int(pa->u.intv & pb->u.intv);
 1933 }
 1934 
 1935 static mv_binary_func_t* band_dispositions[MT_DIM][MT_DIM] = {
 1936     //         ERROR  ABSENT EMPTY STRING INT        FLOAT BOOL
 1937     /*ERROR*/  {_err, _err,  _err, _err,  _err,      _err, _err},
 1938     /*ABSENT*/ {_err, _a,    _a,   _err,  _2,        _err, _err},
 1939     /*EMPTY*/  {_err, _a,    _emt, _err,  _emt,      _emt, _err},
 1940     /*STRING*/ {_err, _err,  _err, _err,  _err,      _err, _err},
 1941     /*INT*/    {_err, _1,    _emt, _err,  band_i_ii, _err, _err},
 1942     /*FLOAT*/  {_err, _err,  _emt, _err,  _err,      _err, _err},
 1943     /*BOOL*/   {_err, _err,  _err, _err,  _err,      _err, _err},
 1944 };
 1945 
 1946 mv_t x_xx_band_func(mv_t* pval1, mv_t* pval2) { return (band_dispositions[pval1->type][pval2->type])(pval1,pval2); }
 1947 
 1948 // ----------------------------------------------------------------
 1949 static mv_t bor_i_ii(mv_t* pa, mv_t* pb) {
 1950     return mv_from_int(pa->u.intv | pb->u.intv);
 1951 }
 1952 
 1953 static mv_binary_func_t* bor_dispositions[MT_DIM][MT_DIM] = {
 1954     //         ERROR  ABSENT EMPTY STRING INT       FLOAT BOOL
 1955     /*ERROR*/  {_err, _err,  _err, _err,  _err,     _err, _err},
 1956     /*ABSENT*/ {_err, _a,    _a,   _err,  _2,       _err, _err},
 1957     /*EMPTY*/  {_err, _a,    _emt, _err,  _emt,     _emt, _err},
 1958     /*STRING*/ {_err, _err,  _err, _err,  _err,     _err, _err},
 1959     /*INT*/    {_err, _1,    _emt, _err,  bor_i_ii, _err, _err},
 1960     /*FLOAT*/  {_err, _err,  _emt, _err,  _err,     _err, _err},
 1961     /*BOOL*/   {_err, _err,  _err, _err,  _err,     _err, _err},
 1962 };
 1963 
 1964 mv_t x_xx_bor_func(mv_t* pval1, mv_t* pval2) { return (bor_dispositions[pval1->type][pval2->type])(pval1,pval2); }
 1965 
 1966 // ----------------------------------------------------------------
 1967 static mv_t bxor_i_ii(mv_t* pa, mv_t* pb) {
 1968     return mv_from_int(pa->u.intv ^ pb->u.intv);
 1969 }
 1970 
 1971 static mv_binary_func_t* bxor_dispositions[MT_DIM][MT_DIM] = {
 1972     //         ERROR  ABSENT EMPTY STRING INT        FLOAT BOOL
 1973     /*ERROR*/  {_err, _err,  _err, _err,  _err,      _err, _err},
 1974     /*ABSENT*/ {_err, _a,    _a,   _err,  _2,        _err, _err},
 1975     /*EMPTY*/  {_err, _a,    _emt, _err,  _emt,      _emt, _err},
 1976     /*STRING*/ {_err, _err,  _err, _err,  _err,      _err, _err},
 1977     /*INT*/    {_err, _1,    _emt, _err,  bxor_i_ii, _err, _err},
 1978     /*FLOAT*/  {_err, _err,  _emt, _err,  _err,      _err, _err},
 1979     /*BOOL*/   {_err, _err,  _err, _err,  _err,      _err, _err},
 1980 };
 1981 
 1982 mv_t x_xx_bxor_func(mv_t* pval1, mv_t* pval2) { return (bxor_dispositions[pval1->type][pval2->type])(pval1,pval2); }
 1983 
 1984 // ----------------------------------------------------------------
 1985 static mv_t boolean_b_b(mv_t* pa) { return mv_from_bool(pa->u.boolv); }
 1986 static mv_t boolean_b_f(mv_t* pa) { return mv_from_bool((pa->u.fltv == 0.0) ? FALSE : TRUE); }
 1987 static mv_t boolean_b_i(mv_t* pa) { return mv_from_bool((pa->u.intv == 0LL) ? FALSE : TRUE); }
 1988 static mv_t boolean_b_s(mv_t* pa) { return mv_from_bool((streq(pa->u.strv, "true") || streq(pa->u.strv, "TRUE")) ? TRUE : FALSE);}
 1989 
 1990 static mv_unary_func_t* boolean_dispositions[MT_DIM] = {
 1991     /*ERROR*/  _err1,
 1992     /*ABSENT*/ _a1,
 1993     /*EMPTY*/  _emt1,
 1994     /*STRING*/ boolean_b_s,
 1995     /*INT*/    boolean_b_i,
 1996     /*FLOAT*/  boolean_b_f,
 1997     /*BOOL*/   boolean_b_b,
 1998 };
 1999 
 2000 mv_t b_x_boolean_func(mv_t* pval1) { return (boolean_dispositions[pval1->type])(pval1); }
 2001 
 2002 // ----------------------------------------------------------------
 2003 static mv_t string_s_b(mv_t* pa) { return mv_from_string_no_free(pa->u.boolv?"true":"false"); }
 2004 static mv_t string_s_f(mv_t* pa) { return mv_from_string_with_free(mlr_alloc_string_from_double(pa->u.fltv, MLR_GLOBALS.ofmt)); }
 2005 static mv_t string_s_i(mv_t* pa) { return mv_from_string_with_free(mlr_alloc_string_from_ll(pa->u.intv)); }
 2006 static mv_t string_s_s(mv_t* pa) {
 2007     char free_flags = pa->free_flags;
 2008     pa->free_flags = NO_FREE;
 2009     return mv_from_string(pa->u.strv, free_flags);
 2010 }
 2011 
 2012 static mv_unary_func_t* string_dispositions[MT_DIM] = {
 2013     /*ERROR*/  _err1,
 2014     /*ABSENT*/ _a1,
 2015     /*EMPTY*/  _emt1,
 2016     /*STRING*/ string_s_s,
 2017     /*INT*/    string_s_i,
 2018     /*FLOAT*/  string_s_f,
 2019     /*BOOL*/   string_s_b,
 2020 };
 2021 
 2022 mv_t s_x_string_func(mv_t* pval1) { return (string_dispositions[pval1->type])(pval1); }
 2023 
 2024 // ----------------------------------------------------------------
 2025 mv_t s_sii_substr_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
 2026     int m = pval2->u.intv; // inclusive lower; -len..-1 alias to 0..len-1
 2027     int n = pval3->u.intv; // inclusive upper; -len..-1 alias to 0..len-1
 2028     int len = strlen(pval1->u.strv);
 2029     mv_t rv;
 2030 
 2031     if (m < 0)
 2032         m = len + m;
 2033     if (n < 0)
 2034         n = len + n;
 2035 
 2036     if (m < 0 || m >= len || n < 0 || n >= len || n < m) {
 2037         rv = mv_from_string("", 0);
 2038     } else {
 2039         int olen = n - m + 1;
 2040         char* p = mlr_malloc_or_die(olen + 1);
 2041         strncpy(p, &pval1->u.strv[m], olen);
 2042         p[olen] = 0;
 2043         rv = mv_from_string(p, FREE_ENTRY_VALUE);
 2044     }
 2045     mv_free(pval1);
 2046     mv_free(pval2);
 2047     mv_free(pval3);
 2048     return rv;
 2049 }
 2050 
 2051 // ----------------------------------------------------------------
 2052 static mv_t hexfmt_s_b(mv_t* pa) { return mv_from_string_no_free(pa->u.boolv?"0x1":"0x0"); }
 2053 static mv_t hexfmt_s_f(mv_t* pa) { return mv_from_string_with_free(mlr_alloc_hexfmt_from_ll((long long)pa->u.fltv)); }
 2054 static mv_t hexfmt_s_i(mv_t* pa) { return mv_from_string_with_free(mlr_alloc_hexfmt_from_ll(pa->u.intv)); }
 2055 static mv_t hexfmt_s_s(mv_t* pa) {
 2056     char free_flags = pa->free_flags;
 2057     pa->free_flags = NO_FREE;
 2058     return mv_from_string(pa->u.strv, free_flags);
 2059 }
 2060 
 2061 static mv_unary_func_t* hexfmt_dispositions[MT_DIM] = {
 2062     /*ERROR*/  _err1,
 2063     /*ABSENT*/ _a1,
 2064     /*EMPTY*/  _emt1,
 2065     /*STRING*/ hexfmt_s_s,
 2066     /*INT*/    hexfmt_s_i,
 2067     /*FLOAT*/  hexfmt_s_f,
 2068     /*BOOL*/   hexfmt_s_b,
 2069 };
 2070 
 2071 mv_t s_x_hexfmt_func(mv_t* pval1) { return (hexfmt_dispositions[pval1->type])(pval1); }
 2072 
 2073 // ----------------------------------------------------------------
 2074 static mv_t fmtnum_s_bs(mv_t* pa, mv_t* pfmt) { return mv_from_string_no_free(pa->u.boolv?"0x1":"0x0"); }
 2075 static mv_t fmtnum_s_ds(mv_t* pa, mv_t* pfmt) {
 2076     mv_t rv = mv_from_string_with_free(mlr_alloc_string_from_double(pa->u.fltv, pfmt->u.strv));
 2077     mv_free(pfmt);
 2078     return rv;
 2079 }
 2080 static mv_t fmtnum_s_is(mv_t* pa, mv_t* pfmt) {
 2081     mv_t rv = mv_from_string_with_free(mlr_alloc_string_from_ll_and_format(pa->u.intv, pfmt->u.strv));
 2082     mv_free(pfmt);
 2083     return rv;
 2084 }
 2085 static mv_binary_func_t* fmtnum_dispositions[MT_DIM] = {
 2086     /*ERROR*/  _err,
 2087     /*ABSENT*/ _a,
 2088     /*EMPTY*/  _emt,
 2089     /*STRING*/ _err,
 2090     /*INT*/    fmtnum_s_is,
 2091     /*FLOAT*/  fmtnum_s_ds,
 2092     /*BOOL*/   fmtnum_s_bs,
 2093 };
 2094 
 2095 mv_t s_xs_fmtnum_func(mv_t* pval1, mv_t* pval2) { return (fmtnum_dispositions[pval1->type])(pval1, pval2); }
 2096 
 2097 // ----------------------------------------------------------------
 2098 static mv_t eq_b_ii(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv == pb->u.intv); }
 2099 static mv_t ne_b_ii(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv != pb->u.intv); }
 2100 static mv_t gt_b_ii(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv >  pb->u.intv); }
 2101 static mv_t ge_b_ii(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv >= pb->u.intv); }
 2102 static mv_t lt_b_ii(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv <  pb->u.intv); }
 2103 static mv_t le_b_ii(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv <= pb->u.intv); }
 2104 
 2105 static mv_t eq_b_ff(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv == pb->u.fltv); }
 2106 static mv_t ne_b_ff(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv != pb->u.fltv); }
 2107 static mv_t gt_b_ff(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv >  pb->u.fltv); }
 2108 static mv_t ge_b_ff(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv >= pb->u.fltv); }
 2109 static mv_t lt_b_ff(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv <  pb->u.fltv); }
 2110 static mv_t le_b_ff(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv <= pb->u.fltv); }
 2111 
 2112 static mv_t eq_b_fi(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv == pb->u.intv); }
 2113 static mv_t ne_b_fi(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv != pb->u.intv); }
 2114 static mv_t gt_b_fi(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv >  pb->u.intv); }
 2115 static mv_t ge_b_fi(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv >= pb->u.intv); }
 2116 static mv_t lt_b_fi(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv <  pb->u.intv); }
 2117 static mv_t le_b_fi(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv <= pb->u.intv); }
 2118 
 2119 static mv_t eq_b_if(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv == pb->u.fltv); }
 2120 static mv_t ne_b_if(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv != pb->u.fltv); }
 2121 static mv_t gt_b_if(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv >  pb->u.fltv); }
 2122 static mv_t ge_b_if(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv >= pb->u.fltv); }
 2123 static mv_t lt_b_if(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv <  pb->u.fltv); }
 2124 static mv_t le_b_if(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv <= pb->u.fltv); }
 2125 
 2126 static mv_t eq_b_xs(mv_t* pa, mv_t* pb) {
 2127     char free_flags;
 2128     char* sa = mv_format_val(pa, &free_flags);
 2129     mv_t rv = mv_from_bool(strcmp(sa, pb->u.strv) == 0);
 2130     if (free_flags & FREE_ENTRY_VALUE)
 2131         free(sa);
 2132     mv_free(pa);
 2133     mv_free(pb);
 2134     return rv;
 2135 }
 2136 static mv_t ne_b_xs(mv_t* pa, mv_t* pb) {
 2137     char free_flags;
 2138     char* sa = mv_format_val(pa, &free_flags);
 2139     mv_t rv = mv_from_bool(strcmp(sa, pb->u.strv) != 0);
 2140     if (free_flags & FREE_ENTRY_VALUE)
 2141         free(sa);
 2142     mv_free(pa);
 2143     mv_free(pb);
 2144     return rv;
 2145 }
 2146 static mv_t gt_b_xs(mv_t* pa, mv_t* pb) {
 2147     char free_flags;
 2148     char* sa = mv_format_val(pa, &free_flags);
 2149     mv_t rv = mv_from_bool(strcmp(sa, pb->u.strv) > 0);
 2150     if (free_flags & FREE_ENTRY_VALUE)
 2151         free(sa);
 2152     mv_free(pa);
 2153     mv_free(pb);
 2154     return rv;
 2155 }
 2156 static mv_t ge_b_xs(mv_t* pa, mv_t* pb) {
 2157     char free_flags;
 2158     char* sa = mv_format_val(pa, &free_flags);
 2159     mv_t rv = mv_from_bool(strcmp(sa, pb->u.strv) >= 0);
 2160     if (free_flags & FREE_ENTRY_VALUE)
 2161         free(sa);
 2162     mv_free(pa);
 2163     mv_free(pb);
 2164     return rv;
 2165 }
 2166 static mv_t lt_b_xs(mv_t* pa, mv_t* pb) {
 2167     char free_flags;
 2168     char* sa = mv_format_val(pa, &free_flags);
 2169     mv_t rv = mv_from_bool(strcmp(sa, pb->u.strv) < 0);
 2170     if (free_flags & FREE_ENTRY_VALUE)
 2171         free(sa);
 2172     mv_free(pa);
 2173     mv_free(pb);
 2174     return rv;
 2175 }
 2176 static mv_t le_b_xs(mv_t* pa, mv_t* pb) {
 2177     char free_flags;
 2178     char* sa = mv_format_val(pa, &free_flags);
 2179     mv_t rv = mv_from_bool(strcmp(sa, pb->u.strv) <= 0);
 2180     if (free_flags & FREE_ENTRY_VALUE)
 2181         free(sa);
 2182     mv_free(pa);
 2183     mv_free(pb);
 2184     return rv;
 2185 }
 2186 
 2187 static mv_t eq_b_sx(mv_t* pa, mv_t* pb) {
 2188     char free_flags;
 2189     char* sb = mv_format_val(pb, &free_flags);
 2190     mv_t rv = mv_from_bool(strcmp(pa->u.strv, sb) == 0);
 2191     if (free_flags & FREE_ENTRY_VALUE)
 2192         free(sb);
 2193     mv_free(pa);
 2194     mv_free(pb);
 2195     return rv;
 2196 }
 2197 static mv_t ne_b_sx(mv_t* pa, mv_t* pb) {
 2198     char free_flags;
 2199     char* sb = mv_format_val(pb, &free_flags);
 2200     mv_t rv = mv_from_bool(strcmp(pa->u.strv, sb) != 0);
 2201     if (free_flags & FREE_ENTRY_VALUE)
 2202         free(sb);
 2203     mv_free(pa);
 2204     mv_free(pb);
 2205     return rv;
 2206 }
 2207 static mv_t gt_b_sx(mv_t* pa, mv_t* pb) {
 2208     char free_flags;
 2209     char* sb = mv_format_val(pb, &free_flags);
 2210     mv_t rv = mv_from_bool(strcmp(pa->u.strv, sb) > 0);
 2211     if (free_flags & FREE_ENTRY_VALUE)
 2212         free(sb);
 2213     mv_free(pa);
 2214     mv_free(pb);
 2215     return rv;
 2216 }
 2217 static mv_t ge_b_sx(mv_t* pa, mv_t* pb) {
 2218     char free_flags;
 2219     char* sb = mv_format_val(pb, &free_flags);
 2220     mv_t rv = mv_from_bool(strcmp(pa->u.strv, sb) >= 0);
 2221     if (free_flags & FREE_ENTRY_VALUE)
 2222         free(sb);
 2223     mv_free(pa);
 2224     mv_free(pb);
 2225     return rv;
 2226 }
 2227 static mv_t lt_b_sx(mv_t* pa, mv_t* pb) {
 2228     char free_flags;
 2229     char* sb = mv_format_val(pb, &free_flags);
 2230     mv_t rv = mv_from_bool(strcmp(pa->u.strv, sb) < 0);
 2231     if (free_flags & FREE_ENTRY_VALUE)
 2232         free(sb);
 2233     mv_free(pa);
 2234     mv_free(pb);
 2235     return rv;
 2236 }
 2237 static mv_t le_b_sx(mv_t* pa, mv_t* pb) {
 2238     char free_flags;
 2239     char* sb = mv_format_val(pb, &free_flags);
 2240     mv_t rv = mv_from_bool(strcmp(pa->u.strv, sb) <= 0);
 2241     if (free_flags & FREE_ENTRY_VALUE)
 2242         free(sb);
 2243     mv_free(pa);
 2244     mv_free(pb);
 2245     return rv;
 2246 }
 2247 
 2248 static mv_t eq_b_ss(mv_t*pa, mv_t*pb) {
 2249     mv_t rv = mv_from_bool(strcmp(pa->u.strv, pb->u.strv) == 0);
 2250     mv_free(pa);
 2251     mv_free(pb);
 2252     return rv;
 2253 }
 2254 static mv_t ne_b_ss(mv_t*pa, mv_t*pb) {
 2255     mv_t rv = mv_from_bool(strcmp(pa->u.strv, pb->u.strv) != 0);
 2256     mv_free(pa);
 2257     mv_free(pb);
 2258     return rv;
 2259 }
 2260 static mv_t gt_b_ss(mv_t*pa, mv_t*pb) {
 2261     mv_t rv = mv_from_bool(strcmp(pa->u.strv, pb->u.strv) >  0);
 2262     mv_free(pa);
 2263     mv_free(pb);
 2264     return rv;
 2265 }
 2266 static mv_t ge_b_ss(mv_t*pa, mv_t*pb) {
 2267     mv_t rv = mv_from_bool(strcmp(pa->u.strv, pb->u.strv) >= 0);
 2268     mv_free(pa);
 2269     mv_free(pb);
 2270     return rv;
 2271 }
 2272 static mv_t lt_b_ss(mv_t*pa, mv_t*pb) {
 2273     mv_t rv = mv_from_bool(strcmp(pa->u.strv, pb->u.strv) <  0);
 2274     mv_free(pa);
 2275     mv_free(pb);
 2276     return rv;
 2277 }
 2278 static mv_t le_b_ss(mv_t*pa, mv_t*pb) {
 2279     mv_t rv = mv_from_bool(strcmp(pa->u.strv, pb->u.strv) <= 0);
 2280     mv_free(pa);
 2281     mv_free(pb);
 2282     return rv;
 2283 }
 2284 
 2285 static mv_binary_func_t* eq_dispositions[MT_DIM][MT_DIM] = {
 2286     //         ERROR  ABSENT EMPTY    STRING   INT      FLOAT    BOOL
 2287     /*ERROR*/  {_err, _err,  _err,    _err,    _err,    _err,    _err},
 2288     /*ABSENT*/ {_err, _a,    _a,      _a,      _a,      _a,      _a},
 2289     /*EMPTY*/  {_err, _a,    eq_b_ss, eq_b_ss, eq_b_sx, eq_b_sx, _err},
 2290     /*STRING*/ {_err, _a,    eq_b_ss, eq_b_ss, eq_b_sx, eq_b_sx, _err},
 2291     /*INT*/    {_err, _a,    eq_b_xs, eq_b_xs, eq_b_ii, eq_b_if, _err},
 2292     /*FLOAT*/  {_err, _a,    eq_b_xs, eq_b_xs, eq_b_fi, eq_b_ff, _err},
 2293     /*BOOL*/   {_err, _err,  _a,      _err,    _err,    _err,    _err},
 2294 };
 2295 
 2296 static mv_binary_func_t* ne_dispositions[MT_DIM][MT_DIM] = {
 2297     //         ERROR  ABSENT EMPTY    STRING   INT      FLOAT    BOOL
 2298     /*ERROR*/  {_err, _err,  _err,    _err,    _err,    _err,    _err},
 2299     /*ABSENT*/ {_err, _a,    _a,      _a,      _a,      _a,      _a},
 2300     /*EMPTY*/  {_err, _a,    ne_b_ss, ne_b_ss, ne_b_sx, ne_b_sx, _err},
 2301     /*STRING*/ {_err, _a,    ne_b_ss, ne_b_ss, ne_b_sx, ne_b_sx, _err},
 2302     /*INT*/    {_err, _a,    ne_b_xs, ne_b_xs, ne_b_ii, ne_b_if, _err},
 2303     /*FLOAT*/  {_err, _a,    ne_b_xs, ne_b_xs, ne_b_fi, ne_b_ff, _err},
 2304     /*BOOL*/   {_err, _err,  _a,      _err,    _err,    _err,    _err},
 2305 };
 2306 
 2307 static mv_binary_func_t* gt_dispositions[MT_DIM][MT_DIM] = {
 2308     //         ERROR  ABSENT EMPTY    STRING   INT      FLOAT    BOOL
 2309     /*ERROR*/  {_err, _err,  _err,    _err,    _err,    _err,    _err},
 2310     /*ABSENT*/ {_err, _a,    _a,      _a,      _a,      _a,      _a},
 2311     /*EMPTY*/  {_err, _a,    gt_b_ss, gt_b_ss, gt_b_sx, gt_b_sx, _err},
 2312     /*STRING*/ {_err, _a,    gt_b_ss, gt_b_ss, gt_b_sx, gt_b_sx, _err},
 2313     /*INT*/    {_err, _a,    gt_b_xs, gt_b_xs, gt_b_ii, gt_b_if, _err},
 2314     /*FLOAT*/  {_err, _a,    gt_b_xs, gt_b_xs, gt_b_fi, gt_b_ff, _err},
 2315     /*BOOL*/   {_err, _err,  _a,      _err,    _err,    _err,    _err},
 2316 };
 2317 
 2318 static mv_binary_func_t* ge_dispositions[MT_DIM][MT_DIM] = {
 2319     //         ERROR  ABSENT EMPTY    STRING   INT      FLOAT    BOOL
 2320     /*ERROR*/  {_err, _err,  _err,    _err,    _err,    _err,    _err},
 2321     /*ABSENT*/ {_err, _a,    _a,      _a,      _a,      _a,      _a},
 2322     /*EMPTY*/  {_err, _a,    ge_b_ss, ge_b_ss, ge_b_sx, ge_b_sx, _err},
 2323     /*STRING*/ {_err, _a,    ge_b_ss, ge_b_ss, ge_b_sx, ge_b_sx, _err},
 2324     /*INT*/    {_err, _a,    ge_b_xs, ge_b_xs, ge_b_ii, ge_b_if, _err},
 2325     /*FLOAT*/  {_err, _a,    ge_b_xs, ge_b_xs, ge_b_fi, ge_b_ff, _err},
 2326     /*BOOL*/   {_err, _err,  _a,      _err,    _err,    _err,    _err},
 2327 };
 2328 
 2329 static mv_binary_func_t* lt_dispositions[MT_DIM][MT_DIM] = {
 2330     //         ERROR  ABSENT EMPTY    STRING   INT      FLOAT    BOOL
 2331     /*ERROR*/  {_err, _err,  _err,    _err,    _err,    _err,    _err},
 2332     /*ABSENT*/ {_err, _a,    _a,      _a,      _a,      _a,      _a},
 2333     /*EMPTY*/  {_err, _a,    lt_b_ss, lt_b_ss, lt_b_sx, lt_b_sx, _err},
 2334     /*STRING*/ {_err, _a,    lt_b_ss, lt_b_ss, lt_b_sx, lt_b_sx, _err},
 2335     /*INT*/    {_err, _a,    lt_b_xs, lt_b_xs, lt_b_ii, lt_b_if, _err},
 2336     /*FLOAT*/  {_err, _a,    lt_b_xs, lt_b_xs, lt_b_fi, lt_b_ff, _err},
 2337     /*BOOL*/   {_err, _err,  _a,      _err,    _err,    _err,    _err},
 2338 };
 2339 
 2340 static mv_binary_func_t* le_dispositions[MT_DIM][MT_DIM] = {
 2341     //         ERROR  ABSENT EMPTY    STRING   INT      FLOAT    BOOL
 2342     /*ERROR*/  {_err, _err,  _err,    _err,    _err,    _err,    _err},
 2343     /*ABSENT*/ {_err, _a,    _a,      _a,      _a,      _a,      _a},
 2344     /*EMPTY*/  {_err, _a,    le_b_ss, le_b_ss, le_b_sx, le_b_sx, _err},
 2345     /*STRING*/ {_err, _a,    le_b_ss, le_b_ss, le_b_sx, le_b_sx, _err},
 2346     /*INT*/    {_err, _a,    le_b_xs, le_b_xs, le_b_ii, le_b_if, _err},
 2347     /*FLOAT*/  {_err, _a,    le_b_xs, le_b_xs, le_b_fi, le_b_ff, _err},
 2348     /*BOOL*/   {_err, _err,  _a,      _err,    _err,    _err,    _err},
 2349 };
 2350 
 2351 mv_t eq_op_func(mv_t* pval1, mv_t* pval2) { return (eq_dispositions[pval1->type][pval2->type])(pval1, pval2); }
 2352 mv_t ne_op_func(mv_t* pval1, mv_t* pval2) { return (ne_dispositions[pval1->type][pval2->type])(pval1, pval2); }
 2353 mv_t gt_op_func(mv_t* pval1, mv_t* pval2) { return (gt_dispositions[pval1->type][pval2->type])(pval1, pval2); }
 2354 mv_t ge_op_func(mv_t* pval1, mv_t* pval2) { return (ge_dispositions[pval1->type][pval2->type])(pval1, pval2); }
 2355 mv_t lt_op_func(mv_t* pval1, mv_t* pval2) { return (lt_dispositions[pval1->type][pval2->type])(pval1, pval2); }
 2356 mv_t le_op_func(mv_t* pval1, mv_t* pval2) { return (le_dispositions[pval1->type][pval2->type])(pval1, pval2); }
 2357 
 2358 // ----------------------------------------------------------------
 2359 int mv_equals_si(mv_t* pa, mv_t* pb) {
 2360     if (pa->type == MT_INT) {
 2361         return (pb->type == MT_INT) ? pa->u.intv == pb->u.intv : FALSE;
 2362     } else {
 2363         return (pb->type == MT_STRING) ? streq(pa->u.strv, pb->u.strv) : FALSE;
 2364     }
 2365 }
 2366 
 2367 // ----------------------------------------------------------------
 2368 static int eq_i_ii(mv_t* pa, mv_t* pb) { return  pa->u.intv == pb->u.intv; }
 2369 static int ne_i_ii(mv_t* pa, mv_t* pb) { return  pa->u.intv != pb->u.intv; }
 2370 static int gt_i_ii(mv_t* pa, mv_t* pb) { return  pa->u.intv >  pb->u.intv; }
 2371 static int ge_i_ii(mv_t* pa, mv_t* pb) { return  pa->u.intv >= pb->u.intv; }
 2372 static int lt_i_ii(mv_t* pa, mv_t* pb) { return  pa->u.intv <  pb->u.intv; }
 2373 static int le_i_ii(mv_t* pa, mv_t* pb) { return  pa->u.intv <= pb->u.intv; }
 2374 
 2375 static int eq_i_ff(mv_t* pa, mv_t* pb) { return  pa->u.fltv == pb->u.fltv; }
 2376 static int ne_i_ff(mv_t* pa, mv_t* pb) { return  pa->u.fltv != pb->u.fltv; }
 2377 static int gt_i_ff(mv_t* pa, mv_t* pb) { return  pa->u.fltv >  pb->u.fltv; }
 2378 static int ge_i_ff(mv_t* pa, mv_t* pb) { return  pa->u.fltv >= pb->u.fltv; }
 2379 static int lt_i_ff(mv_t* pa, mv_t* pb) { return  pa->u.fltv <  pb->u.fltv; }
 2380 static int le_i_ff(mv_t* pa, mv_t* pb) { return  pa->u.fltv <= pb->u.fltv; }
 2381 
 2382 static int eq_i_fi(mv_t* pa, mv_t* pb) { return  pa->u.fltv == pb->u.intv; }
 2383 static int ne_i_fi(mv_t* pa, mv_t* pb) { return  pa->u.fltv != pb->u.intv; }
 2384 static int gt_i_fi(mv_t* pa, mv_t* pb) { return  pa->u.fltv >  pb->u.intv; }
 2385 static int ge_i_fi(mv_t* pa, mv_t* pb) { return  pa->u.fltv >= pb->u.intv; }
 2386 static int lt_i_fi(mv_t* pa, mv_t* pb) { return  pa->u.fltv <  pb->u.intv; }
 2387 static int le_i_fi(mv_t* pa, mv_t* pb) { return  pa->u.fltv <= pb->u.intv; }
 2388 
 2389 static int eq_i_if(mv_t* pa, mv_t* pb) { return  pa->u.intv == pb->u.fltv; }
 2390 static int ne_i_if(mv_t* pa, mv_t* pb) { return  pa->u.intv != pb->u.fltv; }
 2391 static int gt_i_if(mv_t* pa, mv_t* pb) { return  pa->u.intv >  pb->u.fltv; }
 2392 static int ge_i_if(mv_t* pa, mv_t* pb) { return  pa->u.intv >= pb->u.fltv; }
 2393 static int lt_i_if(mv_t* pa, mv_t* pb) { return  pa->u.intv <  pb->u.fltv; }
 2394 static int le_i_if(mv_t* pa, mv_t* pb) { return  pa->u.intv <= pb->u.fltv; }
 2395 
 2396 static mv_i_nn_comparator_func_t* ieq_dispositions[MT_DIM][MT_DIM] = {
 2397     //         ERROR  ABSENT EMPTY STRING INT      FLOAT    BOOL
 2398     /*ERROR*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2399     /*ABSENT*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2400     /*EMPTY*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2401     /*STRING*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2402     /*INT*/    {NULL, NULL,  NULL, NULL,  eq_i_ii, eq_i_if, NULL},
 2403     /*FLOAT*/  {NULL, NULL,  NULL, NULL,  eq_i_fi, eq_i_ff, NULL},
 2404     /*BOOL*/   {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2405 };
 2406 
 2407 static mv_i_nn_comparator_func_t* ine_dispositions[MT_DIM][MT_DIM] = {
 2408     //         ERROR  ABSENT EMPTY STRING INT      FLOAT    BOOL
 2409     /*ERROR*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2410     /*ABSENT*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2411     /*EMPTY*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2412     /*STRING*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2413     /*INT*/    {NULL, NULL,  NULL, NULL,  ne_i_ii, ne_i_if, NULL},
 2414     /*FLOAT*/  {NULL, NULL,  NULL, NULL,  ne_i_fi, ne_i_ff, NULL},
 2415     /*BOOL*/   {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2416 };
 2417 
 2418 static mv_i_nn_comparator_func_t* igt_dispositions[MT_DIM][MT_DIM] = {
 2419     //         ERROR  ABSENT EMPTY STRING INT      FLOAT    BOOL
 2420     /*ERROR*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2421     /*ABSENT*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2422     /*EMPTY*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2423     /*STRING*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2424     /*INT*/    {NULL, NULL,  NULL, NULL,  gt_i_ii, gt_i_if, NULL},
 2425     /*FLOAT*/  {NULL, NULL,  NULL, NULL,  gt_i_fi, gt_i_ff, NULL},
 2426     /*BOOL*/   {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2427 };
 2428 
 2429 static mv_i_nn_comparator_func_t* ige_dispositions[MT_DIM][MT_DIM] = {
 2430     //         ERROR  ABSENT EMPTY STRING INT      FLOAT    BOOL
 2431     /*ERROR*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2432     /*ABSENT*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2433     /*EMPTY*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2434     /*STRING*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2435     /*INT*/    {NULL, NULL,  NULL, NULL,  ge_i_ii, ge_i_if, NULL},
 2436     /*FLOAT*/  {NULL, NULL,  NULL, NULL,  ge_i_fi, ge_i_ff, NULL},
 2437     /*BOOL*/   {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2438 };
 2439 
 2440 static mv_i_nn_comparator_func_t* ilt_dispositions[MT_DIM][MT_DIM] = {
 2441     //         ERROR  ABSENT EMPTY STRING INT      FLOAT    BOOL
 2442     /*ERROR*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2443     /*ABSENT*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2444     /*EMPTY*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2445     /*STRING*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2446     /*INT*/    {NULL, NULL,  NULL, NULL,  lt_i_ii, lt_i_if, NULL},
 2447     /*FLOAT*/  {NULL, NULL,  NULL, NULL,  lt_i_fi, lt_i_ff, NULL},
 2448     /*BOOL*/   {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2449 };
 2450 
 2451 static mv_i_nn_comparator_func_t* ile_dispositions[MT_DIM][MT_DIM] = {
 2452     //         ERROR  ABSENT EMPTY STRING INT      FLOAT    BOOL
 2453     /*ERROR*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2454     /*ABSENT*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2455     /*EMPTY*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2456     /*STRING*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2457     /*INT*/    {NULL, NULL,  NULL, NULL,  le_i_ii, le_i_if, NULL},
 2458     /*FLOAT*/  {NULL, NULL,  NULL, NULL,  le_i_fi, le_i_ff, NULL},
 2459     /*BOOL*/   {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
 2460 };
 2461 
 2462 int mv_i_nn_eq(mv_t* pval1, mv_t* pval2) { return (ieq_dispositions[pval1->type][pval2->type])(pval1, pval2); }
 2463 int mv_i_nn_ne(mv_t* pval1, mv_t* pval2) { return (ine_dispositions[pval1->type][pval2->type])(pval1, pval2); }
 2464 int mv_i_nn_gt(mv_t* pval1, mv_t* pval2) { return (igt_dispositions[pval1->type][pval2->type])(pval1, pval2); }
 2465 int mv_i_nn_ge(mv_t* pval1, mv_t* pval2) { return (ige_dispositions[pval1->type][pval2->type])(pval1, pval2); }
 2466 int mv_i_nn_lt(mv_t* pval1, mv_t* pval2) { return (ilt_dispositions[pval1->type][pval2->type])(pval1, pval2); }
 2467 int mv_i_nn_le(mv_t* pval1, mv_t* pval2) { return (ile_dispositions[pval1->type][pval2->type])(pval1, pval2); }
 2468 
 2469 // ----------------------------------------------------------------
 2470 // For unit-test keystroke-saving
 2471 
 2472 int mveq(mv_t* pval1, mv_t* pval2) {
 2473     mv_t cmp = eq_op_func(pval1, pval2);
 2474     MLR_INTERNAL_CODING_ERROR_UNLESS(cmp.type == MT_BOOLEAN);
 2475     return cmp.u.boolv;
 2476 }
 2477 
 2478 int mvne(mv_t* pval1, mv_t* pval2) {
 2479     return !mveq(pval1, pval2);
 2480 }
 2481 
 2482 int mveqcopy(mv_t* pval1, mv_t* pval2) {
 2483     mv_t c1 = mv_copy(pval1);
 2484     mv_t c2 = mv_copy(pval2);
 2485     return mveq(&c1, &c2);
 2486 }
 2487 
 2488 int mvnecopy(mv_t* pval1, mv_t* pval2) {
 2489     mv_t c1 = mv_copy(pval1);
 2490     mv_t c2 = mv_copy(pval2);
 2491     return mvne(&c1, &c2);
 2492 }
 2493 
 2494 // ----------------------------------------------------------------
 2495 // arg2 evaluates to string via compound expression; regexes compiled on each call.
 2496 mv_t matches_no_precomp_func(mv_t* pval1, mv_t* pval2, string_array_t** ppregex_captures) {
 2497     char* s1 = pval1->u.strv;
 2498     char* s2 = pval2->u.strv;
 2499 
 2500     regex_t regex;
 2501     char* sstr   = s1;
 2502     char* sregex = s2;
 2503 
 2504     regcomp_or_die(&regex, sregex, REG_NOSUB);
 2505 
 2506     const size_t nmatchmax = 10; // Capture-groups \1 through \9 supported, along with entire-string match
 2507     regmatch_t matches[nmatchmax];
 2508     if (regmatch_or_die(&regex, sstr, nmatchmax, matches)) {
 2509         if (ppregex_captures != NULL && *ppregex_captures != NULL)
 2510             save_regex_captures(ppregex_captures, pval1->u.strv, matches, nmatchmax);
 2511         regfree(&regex);
 2512         mv_free(pval1);
 2513         mv_free(pval2);
 2514         return mv_from_true();
 2515     } else {
 2516         regfree(&regex);
 2517         mv_free(pval1);
 2518         mv_free(pval2);
 2519         return mv_from_false();
 2520     }
 2521 }
 2522 
 2523 mv_t does_not_match_no_precomp_func(mv_t* pval1, mv_t* pval2, string_array_t** ppregex_captures) {
 2524     mv_t rv = matches_no_precomp_func(pval1, pval2, ppregex_captures);
 2525     rv.u.boolv = !rv.u.boolv;
 2526     return rv;
 2527 }
 2528 
 2529 // ----------------------------------------------------------------
 2530 // arg2 is a string, compiled to regex only once at alloc time
 2531 mv_t matches_precomp_func(mv_t* pval1, regex_t* pregex, string_builder_t* psb, string_array_t** ppregex_captures) {
 2532     const size_t nmatchmax = 10; // Capture-groups \1 through \9 supported, along with entire-string match
 2533     regmatch_t matches[nmatchmax];
 2534     if (regmatch_or_die(pregex, pval1->u.strv, nmatchmax, matches)) {
 2535         if (ppregex_captures != NULL)
 2536             save_regex_captures(ppregex_captures, pval1->u.strv, matches, nmatchmax);
 2537         mv_free(pval1);
 2538         return mv_from_true();
 2539     } else {
 2540         // See comments in mapper_put.c. Setting this array to length 0 (i.e. zero matches) signals to the
 2541         // lrec-evaluator's from-literal function that we *are* in a regex-match context but there are *no* matches to
 2542         // be interpolated.
 2543         if (ppregex_captures != NULL) {
 2544             if (*ppregex_captures != NULL)
 2545                 string_array_realloc(*ppregex_captures, 0);
 2546             else
 2547                 *ppregex_captures = string_array_alloc(0);
 2548         }
 2549         mv_free(pval1);
 2550         return mv_from_false();
 2551     }
 2552 }
 2553 
 2554 mv_t does_not_match_precomp_func(mv_t* pval1, regex_t* pregex, string_builder_t* psb, string_array_t** ppregex_captures) {
 2555     mv_t rv = matches_precomp_func(pval1, pregex, psb, ppregex_captures);
 2556     rv.u.boolv = !rv.u.boolv;
 2557     return rv;
 2558 }
 2559 
 2560 // ----------------------------------------------------------------
 2561 static int mv_ff_cmp(const mv_t* pa, const mv_t* pb) {
 2562     double d = pa->u.fltv - pb->u.fltv;
 2563     return (d < 0) ? -1 : (d > 0) ? 1 : 0;
 2564 }
 2565 static int mv_fi_cmp(const mv_t* pa, const mv_t* pb) {
 2566     double d = pa->u.fltv - pb->u.intv;
 2567     return (d < 0) ? -1 : (d > 0) ? 1 : 0;
 2568 }
 2569 static int mv_if_cmp(const mv_t* pa, const mv_t* pb) {
 2570     double d = pa->u.intv - pb->u.fltv;
 2571     return (d < 0) ? -1 : (d > 0) ? 1 : 0;
 2572 }
 2573 static int mv_ii_cmp(const mv_t* pa, const mv_t* pb) {
 2574     long long d = pa->u.intv - pb->u.intv;
 2575     return (d < 0) ? -1 : (d > 0) ? 1 : 0;
 2576 }
 2577 // We assume mv_t's coming into percentile keeper are int or double -- in particular, non-null.
 2578 static mv_i_xx_comparator_func_t* mv_nn_comparator_dispositions[MT_DIM][MT_DIM] = {
 2579     //         ERROR  ABSENT EMPTY STRING INT        FLOAT      BOOL
 2580     /*ERROR*/  {NULL, NULL,  NULL, NULL,  NULL,      NULL,      NULL},
 2581     /*ABSENT*/ {NULL, NULL,  NULL, NULL,  NULL,      NULL,      NULL},
 2582     /*EMPTY*/  {NULL, NULL,  NULL, NULL,  NULL,      NULL,      NULL},
 2583     /*STRING*/ {NULL, NULL,  NULL, NULL,  NULL,      NULL,      NULL},
 2584     /*INT*/    {NULL, NULL,  NULL, NULL,  mv_ii_cmp, mv_if_cmp, NULL},
 2585     /*FLOAT*/  {NULL, NULL,  NULL, NULL,  mv_fi_cmp, mv_ff_cmp, NULL},
 2586     /*BOOL*/   {NULL, NULL,  NULL, NULL,  NULL,      NULL,      NULL},
 2587 };
 2588 
 2589 int mv_nn_comparator(const void* pva, const void* pvb) {
 2590     const mv_t* pa = pva;
 2591     const mv_t* pb = pvb;
 2592     return mv_nn_comparator_dispositions[pa->type][pb->type](pa, pb);
 2593 }
 2594 
 2595 // ----------------------------------------------------------------
 2596 // For general qsorting of mv_t's
 2597 
 2598 static int mv_cmp_eq(const mv_t* pa, const mv_t* pb) { return  0; }
 2599 static int mv_cmp_lt(const mv_t* pa, const mv_t* pb) { return -1; }
 2600 static int mv_cmp_gt(const mv_t* pa, const mv_t* pb) { return  1; }
 2601 
 2602 static int mv_bb_comparator(const mv_t* pa, const mv_t* pb) {
 2603     int d = pa->u.boolv - pb->u.boolv;
 2604     return (d < 0) ? -1 : (d > 0) ? 1 : 0;
 2605 }
 2606 static int mv_ss_cmp(const mv_t* pa, const mv_t* pb) {
 2607     return strcmp(pa->u.strv, pb->u.strv);
 2608 }
 2609 
 2610 // Sort rules (same for min, max, and comparator):
 2611 // * NUMERICS < BOOL < STRINGS < ERROR < ABSENT
 2612 // * error == error (singleton type)
 2613 // * absent == absent (singleton type)
 2614 // * string compares on strings
 2615 // * numeric compares on numbers
 2616 // * false < true
 2617 static mv_i_xx_comparator_func_t* mv_xx_comparator_dispositions[MT_DIM][MT_DIM] = {
 2618     //         ERROR       ABSENT     EMPTY      STRING     INT        FLOAT      BOOL
 2619     /*ERROR*/  {mv_cmp_eq, mv_cmp_lt, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt},
 2620     /*ABSENT*/ {mv_cmp_gt, mv_cmp_eq, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt},
 2621     /*EMPTY*/  {mv_cmp_lt, mv_cmp_lt, mv_cmp_eq, mv_ss_cmp, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt},
 2622     /*STRING*/ {mv_cmp_lt, mv_cmp_lt, mv_ss_cmp, mv_ss_cmp, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt},
 2623     /*INT*/    {mv_cmp_lt, mv_cmp_lt, mv_cmp_lt, mv_cmp_lt, mv_ii_cmp, mv_if_cmp, mv_cmp_lt},
 2624     /*FLOAT*/  {mv_cmp_lt, mv_cmp_lt, mv_cmp_lt, mv_cmp_lt, mv_fi_cmp, mv_ff_cmp, mv_cmp_lt},
 2625     /*BOOL*/   {mv_cmp_lt, mv_cmp_lt, mv_cmp_lt, mv_cmp_lt, mv_cmp_gt, mv_cmp_gt, mv_bb_comparator},
 2626 };
 2627 
 2628 int mv_xx_comparator(const void* pva, const void* pvb) {
 2629     const mv_t* pa = pva;
 2630     const mv_t* pb = pvb;
 2631     return mv_xx_comparator_dispositions[pa->type][pb->type](pa, pb);
 2632 }
 2633 
 2634 // ----------------------------------------------------------------
 2635 int mlr_bsearch_mv_n_for_insert(mv_t* array, int size, mv_t* pvalue) {
 2636     int lo = 0;
 2637     int hi = size-1;
 2638     int mid = (hi+lo)/2;
 2639     int newmid;
 2640 
 2641     if (size == 0)
 2642         return 0;
 2643     if (mv_i_nn_gt(pvalue, &array[0]))
 2644         return 0;
 2645     if (mv_i_nn_lt(pvalue, &array[hi]))
 2646         return size;
 2647 
 2648     while (lo < hi) {
 2649         mv_t* pa = &array[mid];
 2650         if (mv_i_nn_eq(pvalue, pa)) {
 2651             return mid;
 2652         }
 2653         else if (mv_i_nn_gt(pvalue, pa)) {
 2654             hi = mid;
 2655             newmid = (hi+lo)/2;
 2656         }
 2657         else {
 2658             lo = mid;
 2659             newmid = (hi+lo)/2;
 2660         }
 2661         if (mid == newmid) {
 2662             if (mv_i_nn_ge(pvalue, &array[lo]))
 2663                 return lo;
 2664             else if (mv_i_nn_ge(pvalue, &array[hi]))
 2665                 return hi;
 2666             else
 2667                 return hi+1;
 2668         }
 2669         mid = newmid;
 2670     }
 2671 
 2672     return lo;
 2673 }