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