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 : : #include "date.h"
6 : : #include "date_time.h"
7 : : #include "duration.h"
8 : : #include "time.h"
9 : :
10 : : #include <exess/exess.h>
11 : :
12 : : #include <stdbool.h>
13 : : #include <stdint.h>
14 : : #include <string.h>
15 : :
16 : : static EXESS_NONBLOCKING ExessOrder
17 : 8 : compare_datatypes(const ExessDatatype lhs_datatype,
18 : : const ExessDatatype rhs_datatype)
19 : : {
20 : 8 : const char* const lhs_name = exess_datatype_name(lhs_datatype);
21 : 8 : const char* const rhs_name = exess_datatype_name(rhs_datatype);
22 : : return !lhs_name ? EXESS_ORDER_MAYBE_LESS
23 [ + + + + ]: 12 : : !rhs_name ? EXESS_ORDER_MAYBE_GREATER
24 [ + + ]: 4 : : (strcmp(lhs_name, rhs_name) < 0) ? EXESS_ORDER_MAYBE_LESS
25 : : : EXESS_ORDER_MAYBE_GREATER;
26 : : }
27 : :
28 : : static EXESS_NONBLOCKING ExessOrder
29 : 56 : compare_decimal(const void* const lhs_value, const void* const rhs_value)
30 : : {
31 : 56 : EXESS_CONSTEXPR int8_t kind_orders[7][7] = {
32 : : // -I +I -0 +0 -N +N
33 : : {+0, -1, -1, -1, -1, -1, -1}, // NaN
34 : : {+1, +0, -2, -2, -2, -2, -2}, // -I
35 : : {+1, +2, +0, +2, +2, +2, +2}, // +I
36 : : {+1, +2, -2, +0, +0, +2, -2}, // -0
37 : : {+1, +2, -2, +0, +0, +2, -2}, // +0
38 : : {+1, +2, -2, -2, -2, +0, -2}, // -N
39 : : {+1, +2, -2, +2, +2, +2, +0}}; // +N
40 : :
41 : 56 : const BigDecimal lhs = *(const BigDecimal*)lhs_value;
42 : 56 : const BigDecimal rhs = *(const BigDecimal*)rhs_value;
43 [ + + ]: 56 : if (lhs.kind != rhs.kind) {
44 : 18 : return (ExessOrder)kind_orders[lhs.kind][rhs.kind];
45 : : }
46 : :
47 : : // The internal representation has digits without leading zeros
48 : 38 : const char* const lhs_digits = (const char*)lhs_value + sizeof(lhs);
49 : 38 : const char* const rhs_digits = (const char*)rhs_value + sizeof(rhs);
50 : 38 : const bool negative = lhs.kind == EXESS_NEGATIVE;
51 [ + + ]: 38 : const int factor = negative ? -1 : 1;
52 : :
53 [ + + ]: 38 : if (lhs.expt != rhs.expt) {
54 : 8 : return (ExessOrder)(factor * ((lhs.expt < rhs.expt)
55 : : ? EXESS_ORDER_STRICTLY_LESS
56 [ + + ]: 8 : : EXESS_ORDER_STRICTLY_GREATER));
57 : : }
58 : :
59 : 30 : const int cmp = strncmp(lhs_digits, rhs_digits, lhs.n_digits);
60 : 30 : return (ExessOrder)(factor * (cmp < 0 ? EXESS_ORDER_STRICTLY_LESS
61 [ + + ]: 54 : : cmp > 0 ? EXESS_ORDER_STRICTLY_GREATER
62 [ + + ]: 24 : : EXESS_ORDER_EQUAL));
63 : : }
64 : :
65 : : static ExessOrder
66 : 44 : compare_blob(const size_t lhs_size,
67 : : const void* const lhs_value,
68 : : const size_t rhs_size,
69 : : const void* const rhs_value)
70 : : {
71 : 44 : const bool shorter_lhs = lhs_size < rhs_size;
72 [ + + ]: 44 : const size_t cmp_size = shorter_lhs ? lhs_size : rhs_size;
73 : 44 : const int cmp = memcmp(lhs_value, rhs_value, cmp_size);
74 : :
75 : : return cmp < 0 ? EXESS_ORDER_MAYBE_LESS
76 [ + + + + : 65 : : cmp > 0 ? EXESS_ORDER_MAYBE_GREATER
+ + ]
77 : : : shorter_lhs ? EXESS_ORDER_MAYBE_LESS
78 : : : (lhs_size == rhs_size) ? EXESS_ORDER_EQUAL
79 : 21 : : EXESS_ORDER_MAYBE_GREATER;
80 : : }
81 : :
82 : : EXESS_NONBLOCKING ExessOrder
83 : 680 : exess_compare_value(const ExessDatatype lhs_datatype,
84 : : const size_t lhs_size,
85 : : const void* const lhs_value,
86 : : const ExessDatatype rhs_datatype,
87 : : const size_t rhs_size,
88 : : const void* const rhs_value)
89 : : {
90 [ + + ]: 680 : if (lhs_datatype != rhs_datatype) {
91 : 8 : return compare_datatypes(lhs_datatype, rhs_datatype);
92 : : }
93 : :
94 : : #ifdef __cplusplus
95 : : # define DATE(y, m, d, z) (ExessDate{y, m, d, z})
96 : : #else
97 : : # define DATE(y, m, d, z) ((ExessDate){y, m, d, z})
98 : : #endif
99 : :
100 : : #define COMPARE(lhs, rhs) \
101 : : ((lhs) < (rhs)) ? EXESS_ORDER_STRICTLY_LESS \
102 : : : ((rhs) < (lhs)) ? EXESS_ORDER_STRICTLY_GREATER \
103 : : : EXESS_ORDER_EQUAL
104 : :
105 [ + + + + : 672 : switch (lhs_datatype) {
+ + + + +
+ + + + +
+ + + + +
+ + + +
- ]
106 : 2 : case EXESS_NOTHING:
107 : 2 : break;
108 : 30 : case EXESS_BOOLEAN:
109 [ + + + + ]: 670 : return COMPARE(*(const bool*)lhs_value, *(const bool*)rhs_value);
110 : 6 : case EXESS_DOUBLE:
111 [ + + + + ]: 6 : return COMPARE(*(const double*)lhs_value, *(const double*)rhs_value);
112 : 6 : case EXESS_FLOAT:
113 [ + + + + ]: 6 : return COMPARE(*(const float*)lhs_value, *(const float*)rhs_value);
114 : 6 : case EXESS_LONG:
115 [ + + + + ]: 6 : return COMPARE(*(const int64_t*)lhs_value, *(const int64_t*)rhs_value);
116 : 6 : case EXESS_INT:
117 [ + + + + ]: 6 : return COMPARE(*(const int32_t*)lhs_value, *(const int32_t*)rhs_value);
118 : 6 : case EXESS_SHORT:
119 [ + + + + ]: 6 : return COMPARE(*(const int16_t*)lhs_value, *(const int16_t*)rhs_value);
120 : 6 : case EXESS_BYTE:
121 [ + + + + ]: 6 : return COMPARE(*(const int8_t*)lhs_value, *(const int8_t*)rhs_value);
122 : 6 : case EXESS_ULONG:
123 [ + + + + ]: 6 : return COMPARE(*(const uint64_t*)lhs_value, *(const uint64_t*)rhs_value);
124 : 6 : case EXESS_UINT:
125 [ + + + + ]: 6 : return COMPARE(*(const uint32_t*)lhs_value, *(const uint32_t*)rhs_value);
126 : 6 : case EXESS_USHORT:
127 [ + + + + ]: 6 : return COMPARE(*(const uint16_t*)lhs_value, *(const uint16_t*)rhs_value);
128 : 6 : case EXESS_UBYTE:
129 [ + + + + ]: 6 : return COMPARE(*(const uint8_t*)lhs_value, *(const uint8_t*)rhs_value);
130 : 56 : case EXESS_DECIMAL:
131 : : case EXESS_INTEGER:
132 : : case EXESS_NON_POSITIVE_INTEGER:
133 : : case EXESS_NEGATIVE_INTEGER:
134 : : case EXESS_NON_NEGATIVE_INTEGER:
135 : : case EXESS_POSITIVE_INTEGER:
136 : 56 : return compare_decimal(lhs_value, rhs_value);
137 : 104 : case EXESS_DURATION:
138 : : case EXESS_YEAR_MONTH_DURATION:
139 : : case EXESS_DAY_TIME_DURATION:
140 : 104 : return exess_compare_duration(*(const ExessDuration*)lhs_value,
141 : : *(const ExessDuration*)rhs_value);
142 : :
143 : 122 : case EXESS_DATE_TIME:
144 : : case EXESS_DATE_TIME_STAMP:
145 : 122 : return exess_compare_date_time(*(const ExessDateTime*)lhs_value,
146 : : *(const ExessDateTime*)rhs_value);
147 : :
148 : 96 : case EXESS_TIME:
149 : 96 : return exess_compare_time(*(const ExessTime*)lhs_value,
150 : : *(const ExessTime*)rhs_value);
151 : :
152 : 68 : case EXESS_DATE:
153 : 68 : return exess_compare_date(*(const ExessDate*)lhs_value,
154 : : *(const ExessDate*)rhs_value);
155 : :
156 : 18 : case EXESS_YEAR_MONTH:
157 : 18 : return exess_compare_date(DATE(((const ExessYearMonth*)lhs_value)->year,
158 : : ((const ExessYearMonth*)lhs_value)->month,
159 : : 1U,
160 : : ((const ExessYearMonth*)lhs_value)->zone),
161 : 18 : DATE(((const ExessYearMonth*)rhs_value)->year,
162 : : ((const ExessYearMonth*)rhs_value)->month,
163 : : 1U,
164 : : ((const ExessYearMonth*)rhs_value)->zone));
165 : :
166 : 18 : case EXESS_YEAR:
167 : 18 : return exess_compare_date(DATE(((const ExessYear*)lhs_value)->year,
168 : : 1U,
169 : : 1U,
170 : : ((const ExessYear*)lhs_value)->zone),
171 : 18 : DATE(((const ExessYear*)rhs_value)->year,
172 : : 1U,
173 : : 1U,
174 : : ((const ExessYear*)rhs_value)->zone));
175 : :
176 : 18 : case EXESS_MONTH_DAY:
177 : 18 : return exess_compare_date(DATE(0U,
178 : : ((const ExessMonthDay*)lhs_value)->month,
179 : : ((const ExessMonthDay*)lhs_value)->day,
180 : : ((const ExessMonthDay*)lhs_value)->zone),
181 : 18 : DATE(0U,
182 : : ((const ExessMonthDay*)rhs_value)->month,
183 : : ((const ExessMonthDay*)rhs_value)->day,
184 : : ((const ExessMonthDay*)rhs_value)->zone));
185 : :
186 : 18 : case EXESS_DAY:
187 : 18 : return exess_compare_date(DATE(0U,
188 : : 1U,
189 : : ((const ExessDay*)lhs_value)->day,
190 : : ((const ExessDay*)lhs_value)->zone),
191 : 18 : DATE(0U,
192 : : 1U,
193 : : ((const ExessDay*)rhs_value)->day,
194 : : ((const ExessDay*)rhs_value)->zone));
195 : :
196 : 18 : case EXESS_MONTH:
197 : 18 : return exess_compare_date(DATE(0U,
198 : : ((const ExessMonth*)lhs_value)->month,
199 : : 1U,
200 : : ((const ExessMonth*)lhs_value)->zone),
201 : 18 : DATE(0U,
202 : : ((const ExessMonth*)rhs_value)->month,
203 : : 1U,
204 : : ((const ExessMonth*)rhs_value)->zone));
205 : :
206 : 44 : case EXESS_HEX:
207 : : case EXESS_BASE64:
208 : 44 : return compare_blob(lhs_size, lhs_value, rhs_size, rhs_value);
209 : : }
210 : :
211 : : #undef COMPARE
212 : : #undef DATE
213 : :
214 : 2 : return EXESS_ORDER_EQUAL;
215 : : }
|