Branch data Line data Source code
1 : : // Copyright 2019-2026 David Robillard <d@drobilla.net>
2 : : // SPDX-License-Identifier: ISC
3 : :
4 : : #include "big_decimal.h"
5 : :
6 : : #include <exess/exess.h>
7 : :
8 : : #include <stdbool.h>
9 : : #include <stdint.h>
10 : : #include <string.h>
11 : :
12 : : static EXESS_NONBLOCKING ExessOrder
13 : 8 : compare_datatypes(const ExessDatatype lhs_datatype,
14 : : const ExessDatatype rhs_datatype)
15 : : {
16 : 8 : const char* const lhs_name = exess_datatype_name(lhs_datatype);
17 : 8 : const char* const rhs_name = exess_datatype_name(rhs_datatype);
18 : : return !lhs_name ? EXESS_ORDER_MAYBE_LESS
19 [ + + + + ]: 12 : : !rhs_name ? EXESS_ORDER_MAYBE_GREATER
20 [ + + ]: 4 : : (strcmp(lhs_name, rhs_name) < 0) ? EXESS_ORDER_MAYBE_LESS
21 : : : EXESS_ORDER_MAYBE_GREATER;
22 : : }
23 : :
24 : : static EXESS_NONBLOCKING ExessOrder
25 : 56 : compare_decimal(const void* const lhs_value, const void* const rhs_value)
26 : : {
27 : 56 : EXESS_CONSTEXPR int8_t kind_orders[7][7] = {
28 : : // -I +I -0 +0 -N +N
29 : : {+0, -1, -1, -1, -1, -1, -1}, // NaN
30 : : {+1, +0, -2, -2, -2, -2, -2}, // -I
31 : : {+1, +2, +0, +2, +2, +2, +2}, // +I
32 : : {+1, +2, -2, +0, +0, +2, -2}, // -0
33 : : {+1, +2, -2, +0, +0, +2, -2}, // +0
34 : : {+1, +2, -2, -2, -2, +0, -2}, // -N
35 : : {+1, +2, -2, +2, +2, +2, +0}}; // +N
36 : :
37 : 56 : const BigDecimal lhs = *(const BigDecimal*)lhs_value;
38 : 56 : const BigDecimal rhs = *(const BigDecimal*)rhs_value;
39 [ + + ]: 56 : if (lhs.kind != rhs.kind) {
40 : 18 : return (ExessOrder)kind_orders[lhs.kind][rhs.kind];
41 : : }
42 : :
43 : : // The internal representation has digits without leading zeros
44 : 38 : const char* const lhs_digits = (const char*)lhs_value + sizeof(lhs);
45 : 38 : const char* const rhs_digits = (const char*)rhs_value + sizeof(rhs);
46 : 38 : const bool negative = lhs.kind == EXESS_NEGATIVE;
47 [ + + ]: 38 : const int factor = negative ? -1 : 1;
48 : :
49 [ + + ]: 38 : if (lhs.expt != rhs.expt) {
50 : 8 : return (ExessOrder)(factor * ((lhs.expt < rhs.expt)
51 : : ? EXESS_ORDER_STRICTLY_LESS
52 [ + + ]: 8 : : EXESS_ORDER_STRICTLY_GREATER));
53 : : }
54 : :
55 : 30 : const int cmp = strncmp(lhs_digits, rhs_digits, lhs.n_digits);
56 : 30 : return (ExessOrder)(factor * (cmp < 0 ? EXESS_ORDER_STRICTLY_LESS
57 [ + + ]: 54 : : cmp > 0 ? EXESS_ORDER_STRICTLY_GREATER
58 [ + + ]: 24 : : EXESS_ORDER_EQUAL));
59 : : }
60 : :
61 : : static ExessOrder
62 : 44 : compare_blob(const size_t lhs_size,
63 : : const void* const lhs_value,
64 : : const size_t rhs_size,
65 : : const void* const rhs_value)
66 : : {
67 : 44 : const bool shorter_lhs = lhs_size < rhs_size;
68 [ + + ]: 44 : const size_t cmp_size = shorter_lhs ? lhs_size : rhs_size;
69 : 44 : const int cmp = memcmp(lhs_value, rhs_value, cmp_size);
70 : :
71 : : return cmp < 0 ? EXESS_ORDER_MAYBE_LESS
72 [ + + + + : 65 : : cmp > 0 ? EXESS_ORDER_MAYBE_GREATER
+ + ]
73 : : : shorter_lhs ? EXESS_ORDER_MAYBE_LESS
74 : : : (lhs_size == rhs_size) ? EXESS_ORDER_EQUAL
75 : 21 : : EXESS_ORDER_MAYBE_GREATER;
76 : : }
77 : :
78 : : EXESS_NONBLOCKING ExessOrder
79 : 590 : exess_compare_value(const ExessDatatype lhs_datatype,
80 : : const size_t lhs_size,
81 : : const void* const lhs_value,
82 : : const ExessDatatype rhs_datatype,
83 : : const size_t rhs_size,
84 : : const void* const rhs_value)
85 : : {
86 [ + + ]: 590 : if (lhs_datatype != rhs_datatype) {
87 : 8 : return compare_datatypes(lhs_datatype, rhs_datatype);
88 : : }
89 : :
90 : : #define COMPARE(lhs, rhs) \
91 : : ((lhs) < (rhs)) ? EXESS_ORDER_STRICTLY_LESS \
92 : : : ((rhs) < (lhs)) ? EXESS_ORDER_STRICTLY_GREATER \
93 : : : EXESS_ORDER_EQUAL
94 : :
95 [ + + + + : 582 : switch (lhs_datatype) {
+ + + + +
+ + + + +
+ + + +
- ]
96 : 2 : case EXESS_NOTHING:
97 : 2 : break;
98 : 30 : case EXESS_BOOLEAN:
99 [ + + + + ]: 30 : return COMPARE(*(const bool*)lhs_value, *(const bool*)rhs_value);
100 : 6 : case EXESS_DOUBLE:
101 [ + + + + ]: 6 : return COMPARE(*(const double*)lhs_value, *(const double*)rhs_value);
102 : 6 : case EXESS_FLOAT:
103 [ + + + + ]: 6 : return COMPARE(*(const float*)lhs_value, *(const float*)rhs_value);
104 : 6 : case EXESS_LONG:
105 [ + + + + ]: 6 : return COMPARE(*(const int64_t*)lhs_value, *(const int64_t*)rhs_value);
106 : 6 : case EXESS_INT:
107 [ + + + + ]: 6 : return COMPARE(*(const int32_t*)lhs_value, *(const int32_t*)rhs_value);
108 : 6 : case EXESS_SHORT:
109 [ + + + + ]: 6 : return COMPARE(*(const int16_t*)lhs_value, *(const int16_t*)rhs_value);
110 : 6 : case EXESS_BYTE:
111 [ + + + + ]: 6 : return COMPARE(*(const int8_t*)lhs_value, *(const int8_t*)rhs_value);
112 : 6 : case EXESS_ULONG:
113 [ + + + + ]: 6 : return COMPARE(*(const uint64_t*)lhs_value, *(const uint64_t*)rhs_value);
114 : 6 : case EXESS_UINT:
115 [ + + + + ]: 6 : return COMPARE(*(const uint32_t*)lhs_value, *(const uint32_t*)rhs_value);
116 : 6 : case EXESS_USHORT:
117 [ + + + + ]: 6 : return COMPARE(*(const uint16_t*)lhs_value, *(const uint16_t*)rhs_value);
118 : 6 : case EXESS_UBYTE:
119 [ + + + + ]: 6 : return COMPARE(*(const uint8_t*)lhs_value, *(const uint8_t*)rhs_value);
120 : 56 : case EXESS_DECIMAL:
121 : : case EXESS_INTEGER:
122 : : case EXESS_NON_POSITIVE_INTEGER:
123 : : case EXESS_NEGATIVE_INTEGER:
124 : : case EXESS_NON_NEGATIVE_INTEGER:
125 : : case EXESS_POSITIVE_INTEGER:
126 : 56 : return compare_decimal(lhs_value, rhs_value);
127 : 104 : case EXESS_DURATION:
128 : : case EXESS_YEAR_MONTH_DURATION:
129 : : case EXESS_DAY_TIME_DURATION:
130 : 104 : return exess_compare_duration(*(const ExessDuration*)lhs_value,
131 : : *(const ExessDuration*)rhs_value);
132 : :
133 : 122 : case EXESS_DATE_TIME:
134 : : case EXESS_DATE_TIME_STAMP:
135 : 122 : return exess_compare_date_time(*(const ExessDateTime*)lhs_value,
136 : : *(const ExessDateTime*)rhs_value);
137 : :
138 : 96 : case EXESS_TIME:
139 : 96 : return exess_compare_time(*(const ExessTime*)lhs_value,
140 : : *(const ExessTime*)rhs_value);
141 : :
142 : 68 : case EXESS_DATE:
143 : 68 : return exess_compare_date(*(const ExessDate*)lhs_value,
144 : : *(const ExessDate*)rhs_value);
145 : :
146 : 44 : case EXESS_HEX:
147 : : case EXESS_BASE64:
148 : 44 : return compare_blob(lhs_size, lhs_value, rhs_size, rhs_value);
149 : : }
150 : :
151 : : #undef COMPARE
152 : :
153 : 2 : return EXESS_ORDER_EQUAL;
154 : : }
|