x86: fix a crash on 386
[ajla.git] / arindex.h
blob98dc5a63b3ce8a4f4c37356ca30aaedccf9c09e0
1 /*
2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
9 * version.
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
19 #ifndef AJLA_ARINDEX_H
20 #define AJLA_ARINDEX_H
22 #include "data.h"
24 #define index_export_to_int name(index_export_to_int)
25 #define index_free_mp_ name(index_free_mp_)
26 #define index_copy_mp_ name(index_copy_mp_)
27 #define index_ge_index_mp_ name(index_ge_index_mp_)
28 #define index_eq_index_mp_ name(index_eq_index_mp_)
29 #define index_op_mp_ name(index_op_mp_)
32 static inline void index_init_from_int(mpint_t *t, int_default_t val)
34 cat(mpint_init_from_,int_default_t)(t, val, NULL);
37 bool index_export_to_int(const mpint_t *t, int_default_t *result);
39 #if !defined(DEBUG) || defined(DEBUG_ARRAY_INDICES) || defined(UNUSUAL_MPINT_ARRAY_INDICES)
40 #define index_increment_count() do { } while (0)
41 #define index_decrement_count() do { } while (0)
42 #else
43 #define ARRAY_INDEX_T_COUNT_INDICES
44 #define index_increment_count name(index_increment_count)
45 #define index_decrement_count name(index_decrement_count)
46 void index_increment_count(void);
47 void index_decrement_count(void);
48 #endif
50 static inline void index_alloc_leak_(array_index_t attr_unused *idx argument_position)
52 #ifdef DEBUG_ARRAY_INDICES
53 idx->test_leak = mem_alloc_position(0, NULL pass_position);
54 #endif
55 index_increment_count();
58 static inline void index_free_leak_(array_index_t attr_unused *idx argument_position)
60 index_decrement_count();
61 #ifdef DEBUG_ARRAY_INDICES
62 if (likely(idx->test_leak != BAD_POINTER_3))
63 mem_free_position(idx->test_leak pass_position);
64 idx->test_leak = BAD_POINTER_1;
65 #endif
68 static inline void index_detach_leak(array_index_t attr_unused *idx)
70 #ifdef DEBUG_ARRAY_INDICES
71 if (idx->test_leak != BAD_POINTER_3)
72 mem_free_position(idx->test_leak pass_file_line);
73 idx->test_leak = BAD_POINTER_3;
74 #endif
77 static inline uint_default_t index_get_value_(array_index_t idx)
79 #ifndef SCALAR_ARRAY_INDEX_T
80 return idx.val;
81 #else
82 return idx;
83 #endif
86 static inline void index_set_value_(array_index_t *idx, uint_default_t val)
88 #ifndef SCALAR_ARRAY_INDEX_T
89 idx->val = val;
90 idx->mp = NULL; /* against warning */
91 #else
92 *idx = val;
93 #endif
96 #define index_get_mp(idx) index_get_mp_(idx pass_file_line)
97 static inline mpint_t *index_get_mp_(array_index_t idx argument_position)
99 ajla_assert((int_default_t)index_get_value_(idx) < 0, (caller_file_line, "index_get_mp_: invalid value %"PRIdMAX"", (intmax_t)index_get_value_(idx)));
100 #ifndef SCALAR_ARRAY_INDEX_T
101 return idx.mp;
102 #else
103 return pointer_decompress((uint_default_t)(idx << 1));
104 #endif
107 #define index_set_mp(idx, mp) index_set_mp_(idx, mp pass_file_line)
108 static inline void index_set_mp_(array_index_t *idx, mpint_t *mp argument_position)
110 #ifndef SCALAR_ARRAY_INDEX_T
111 idx->val = (uint_default_t)-1;
112 idx->mp = mp;
113 #else
114 pointer_compress_test(mp, false);
115 *idx = (uint_default_t)(pointer_compress(mp) >> 1) | sign_bit(uint_default_t);
116 #endif
119 static inline void index_validate(array_index_t attr_unused idx argument_position)
121 #ifdef DEBUG_ARRAY_INDICES
122 if (likely(idx.test_leak != BAD_POINTER_3))
123 mem_verify_position(idx.test_leak pass_position);
124 #endif
127 #ifdef SCALAR_ARRAY_INDEX_T
128 #define index_invalid() (sign_bit(uint_default_t))
129 #define index_is_invalid(idx) ((idx) == index_invalid())
130 #else
131 static inline array_index_t index_invalid(void)
133 array_index_t idx;
134 idx.val = (uint_default_t)-1;
135 idx.mp = NULL;
136 #ifdef DEBUG_ARRAY_INDICES
137 idx.test_leak = BAD_POINTER_2;
138 #endif
139 return idx;
141 static inline bool index_is_invalid(array_index_t idx)
143 return (int_default_t)idx.val < 0 && !idx.mp;
145 #endif
147 #define index_is_mp(idx) index_is_mp_(idx pass_file_line)
148 static inline bool index_is_mp_(array_index_t idx argument_position)
150 index_validate(idx pass_position);
151 return (int_default_t)index_get_value_(idx) < 0;
154 #define index_from_int(idx, val) index_from_int_(idx, val pass_file_line)
155 static inline void index_from_int_(array_index_t *idx, int_default_t val argument_position)
157 ajla_assert(val >= 0, (caller_file_line, "index_from_int: negative value %"PRIdMAX"", (intmax_t)val));
158 index_alloc_leak_(idx pass_position);
159 #ifndef UNUSUAL_MPINT_ARRAY_INDICES
160 index_set_value_(idx, (uint_default_t)val);
161 #else
163 mpint_t *result;
164 result = mem_alloc_compressed_mayfail(mpint_t *, sizeof(mpint_t), NULL);
165 index_init_from_int(result, val);
166 index_set_mp_(idx, result pass_file_line);
168 #endif
171 #define index_from_mp(idx, mp) index_from_mp_(idx, mp pass_file_line)
172 static inline void index_from_mp_(array_index_t *idx, const mpint_t *mp argument_position)
174 #ifndef UNUSUAL_MPINT_ARRAY_INDICES
175 int_default_t id;
176 if (index_export_to_int(mp, &id)) {
177 ajla_assert_lo(id >= 0, (caller_file_line, "index_from_mp: the result is negative: %"PRIdMAX"", (intmax_t)id));
178 index_set_value_(idx, (uint_default_t)id);
179 } else
180 #endif
182 mpint_t *result;
183 result = mem_alloc_compressed_mayfail(mpint_t *, sizeof(mpint_t), NULL);
184 mpint_alloc_copy_mayfail(result, mp, NULL);
185 index_set_mp_(idx, result pass_file_line);
187 index_alloc_leak_(idx pass_position);
190 void index_free_mp_(array_index_t idx argument_position);
191 #define index_free(idx) index_free_(idx pass_file_line)
192 static inline void index_free_(array_index_t *idx argument_position)
194 if (unlikely(index_is_mp_(*idx pass_position)))
195 index_free_mp_(*idx pass_position);
196 #ifdef DEBUG
197 /* poison the pointer */
198 #ifndef SCALAR_ARRAY_INDEX_T
199 index_set_mp_(idx, (mpint_t *)BAD_POINTER_1 pass_position);
200 #else
201 *idx = 1 | sign_bit(uint_default_t);
202 #endif
203 #endif
204 index_free_leak_(idx pass_position);
207 #define index_free_get_mp(idx, mp) index_free_get_mp_(idx, mp pass_file_line)
208 static inline void index_free_get_mp_(array_index_t *idx, mpint_t *mp argument_position)
210 mpint_t *mp_ptr;
211 ajla_assert(index_is_mp_(*idx pass_position), (caller_file_line, "index_free_get_mp: positive value %"PRIdMAX"", (intmax_t)index_get_value_(*idx)));
212 mp_ptr = index_get_mp_(*idx pass_position);
213 *mp = *mp_ptr;
214 mem_free_compressed(mp_ptr);
215 index_set_value_(idx, 0);
216 index_free_(idx pass_position);
219 array_index_t index_copy_mp_(array_index_t idx argument_position);
220 #define index_copy(idx1, idx2) index_copy_(idx1, idx2 pass_file_line)
221 static inline void index_copy_(array_index_t *idx1, array_index_t idx2 argument_position)
223 if (unlikely(index_is_mp_(idx2 pass_position))) {
224 *idx1 = index_copy_mp_(idx2 pass_position);
225 } else {
226 *idx1 = idx2;
228 index_alloc_leak_(idx1 pass_position);
231 bool index_ge_index_mp_(array_index_t idx1, array_index_t idx2 argument_position);
232 #define index_ge_index(idx1, idx2) index_ge_index_(idx1, idx2 pass_file_line)
233 static inline bool index_ge_index_(array_index_t idx1, array_index_t idx2 argument_position)
235 index_validate(idx1 pass_position);
236 index_validate(idx2 pass_position);
237 if (unlikely((int_default_t)(index_get_value_(idx1) & index_get_value_(idx2)) < 0)) {
238 return index_ge_index_mp_(idx1, idx2 pass_position);
240 return index_get_value_(idx1) >= index_get_value_(idx2);
243 bool index_eq_index_mp_(array_index_t idx1, array_index_t idx2 argument_position);
244 #define index_eq_index(idx1, idx2) index_eq_index_(idx1, idx2 pass_file_line)
245 static inline bool index_eq_index_(array_index_t idx1, array_index_t idx2 argument_position)
247 index_validate(idx1 pass_position);
248 index_validate(idx2 pass_position);
249 if (unlikely((int_default_t)(index_get_value_(idx1) & index_get_value_(idx2)) < 0)) {
250 return index_eq_index_mp_(idx1, idx2 pass_position);
252 return index_get_value_(idx1) == index_get_value_(idx2);
255 #define index_ge_int(idx, val) index_ge_int_(idx, val pass_file_line)
256 static inline bool index_ge_int_(array_index_t idx, int_default_t val argument_position)
258 index_validate(idx pass_position);
259 ajla_assert(val >= 0, (caller_file_line, "index_ge_int: negative value %"PRIdMAX"", (intmax_t)val));
260 #ifndef UNUSUAL_MPINT_ARRAY_INDICES
261 return index_get_value_(idx) >= (uint_default_t)val;
262 #else
264 array_index_t val_idx;
265 bool ret;
266 index_from_int_(&val_idx, val pass_position);
267 ret = index_ge_index_(idx, val_idx pass_position);
268 index_free_(&val_idx pass_position);
269 return ret;
271 #endif
274 #define index_eq_int(idx, val) index_eq_int_(idx, val pass_file_line)
275 static inline bool index_eq_int_(array_index_t idx, int_default_t val argument_position)
277 index_validate(idx pass_position);
278 ajla_assert(val >= 0, (caller_file_line, "index_eq_int: negative value %"PRIdMAX"", (intmax_t)val));
279 #ifndef UNUSUAL_MPINT_ARRAY_INDICES
280 return index_get_value_(idx) == (uint_default_t)val;
281 #else
283 array_index_t val_idx;
284 bool ret;
285 index_from_int_(&val_idx, val pass_position);
286 ret = index_eq_index_(idx, val_idx pass_position);
287 index_free_(&val_idx pass_position);
288 return ret;
290 #endif
293 #define INDEX_OP_MP_ARG3_ 0x1
294 #define INDEX_OP_MP_SUB_ 0x2
295 array_index_t index_op_mp_(array_index_t idx2, array_index_t idx3, unsigned flags, ajla_error_t *err argument_position);
296 #define index_add3(idx1, idx2, idx3) index_add3_(idx1, idx2, idx3, NULL pass_file_line)
297 static inline bool index_add3_(array_index_t *idx1, array_index_t idx2, array_index_t idx3, ajla_error_t *err argument_position)
299 index_validate(idx2 pass_position);
300 index_validate(idx3 pass_position);
301 index_set_value_(idx1, index_get_value_(idx2) + index_get_value_(idx3));
302 if (unlikely((int_default_t)(index_get_value_(*idx1) | index_get_value_(idx2) | index_get_value_(idx3)) < 0)) {
303 *idx1 = index_op_mp_(idx2, idx3, INDEX_OP_MP_ARG3_, err pass_position);
304 return !index_is_invalid(*idx1);
305 } else {
306 index_alloc_leak_(idx1 pass_position);
307 return true;
311 #define index_sub3(idx1, idx2, idx3) index_sub3_(idx1, idx2, idx3 pass_file_line)
312 static inline void index_sub3_(array_index_t *idx1, array_index_t idx2, array_index_t idx3 argument_position)
314 index_validate(idx2 pass_position);
315 index_validate(idx3 pass_position);
316 ajla_assert(index_ge_index_(idx2, idx3 pass_position), (caller_file_line, "index_sub3: invalid parameters %"PRIdMAX", %"PRIdMAX"", (intmax_t)index_get_value_(idx2), (intmax_t)index_get_value_(idx3)));
317 if (unlikely(index_is_mp_(idx2 pass_position))) {
318 *idx1 = index_op_mp_(idx2, idx3, INDEX_OP_MP_ARG3_ | INDEX_OP_MP_SUB_, NULL pass_position);
319 } else {
320 index_set_value_(idx1, index_get_value_(idx2) - index_get_value_(idx3));
321 index_alloc_leak_(idx1 pass_position);
325 #define index_add(idx1, idx2) index_add_(idx1, idx2, NULL pass_file_line)
326 static inline bool index_add_(array_index_t *idx1, array_index_t idx2, ajla_error_t *err argument_position)
328 uint_default_t result;
329 index_validate(*idx1 pass_position);
330 index_validate(idx2 pass_position);
331 result = index_get_value_(*idx1) + index_get_value_(idx2);
332 if (unlikely((int_default_t)(result | index_get_value_(*idx1) | index_get_value_(idx2)) < 0)) {
333 *idx1 = index_op_mp_(*idx1, idx2, 0, err pass_position);
334 return !index_is_invalid(*idx1);
335 } else {
336 index_set_value_(idx1, result);
337 return true;
341 #define index_sub(idx1, idx2) index_sub_(idx1, idx2 pass_file_line)
342 static inline void index_sub_(array_index_t *idx1, array_index_t idx2 argument_position)
344 index_validate(*idx1 pass_position);
345 index_validate(idx2 pass_position);
346 ajla_assert(index_ge_index_(*idx1, idx2 pass_position), (caller_file_line, "index_sub: invalid parameters %"PRIdMAX", %"PRIdMAX"", (intmax_t)index_get_value_(*idx1), (intmax_t)index_get_value_(idx2)));
347 if (unlikely(index_is_mp_(*idx1 pass_position))) {
348 *idx1 = index_op_mp_(*idx1, idx2, INDEX_OP_MP_SUB_, NULL pass_position);
349 } else {
350 index_set_value_(idx1, index_get_value_(*idx1) - index_get_value_(idx2));
354 #define index_add_int(idx1, val) index_add_int_(idx1, val pass_file_line)
355 static inline void index_add_int_(array_index_t *idx1, int_default_t val argument_position)
357 array_index_t idx2;
358 index_from_int_(&idx2, val pass_position);
359 index_add_(idx1, idx2, NULL pass_position);
360 #if defined(ARRAY_INDEX_T_COUNT_INDICES) || defined(DEBUG_ARRAY_INDICES) || defined(UNUSUAL_MPINT_ARRAY_INDICES)
361 index_free_(&idx2 pass_position);
362 #endif
365 #define index_sub_int(idx1, val) index_sub_int_(idx1, val pass_file_line)
366 static inline void index_sub_int_(array_index_t *idx1, int_default_t val argument_position)
368 array_index_t idx2;
369 index_from_int_(&idx2, val pass_position);
370 index_sub_(idx1, idx2 pass_position);
371 #if defined(ARRAY_INDEX_T_COUNT_INDICES) || defined(DEBUG_ARRAY_INDICES) || defined(UNUSUAL_MPINT_ARRAY_INDICES)
372 index_free_(&idx2 pass_position);
373 #endif
376 #define index_is_int(idx) index_is_int_(idx pass_file_line)
377 static inline bool index_is_int_(array_index_t idx argument_position)
379 if (likely(!index_is_mp_(idx pass_position))) {
380 return true;
381 } else {
382 #ifdef UNUSUAL_MPINT_ARRAY_INDICES
383 int_default_t val;
384 if (index_export_to_int(index_get_mp_(idx pass_position), &val))
385 return true;
386 #endif
387 return false;
391 #define index_to_int(idx) index_to_int_(idx pass_file_line)
392 static inline int_default_t index_to_int_(array_index_t idx argument_position)
394 int_default_t val;
395 index_validate(idx pass_position);
396 #ifndef UNUSUAL_MPINT_ARRAY_INDICES
397 val = (int_default_t)index_get_value_(idx);
398 #if !(defined(__IBMC__) && INT_DEFAULT_BITS > 32)
399 /* compiler bug - causes internal error */
400 ajla_assert(val >= 0, (caller_file_line, "index_to_int: negative number %"PRIdMAX"", (intmax_t)val));
401 #endif
402 #else
403 val = 0; /* against warning */
404 if (unlikely(!index_export_to_int(index_get_mp_(idx pass_position), &val)))
405 internal(caller_file_line, ("index_to_int: index_export_to_int failed"));
406 #endif
407 return val;
410 #define index_to_mpint(idx, mp) index_to_mpint_(idx, mp pass_file_line)
411 static inline void index_to_mpint_(array_index_t idx, mpint_t *mp argument_position)
413 if (!index_is_mp_(idx pass_position)) {
414 index_init_from_int(mp, (int_default_t)index_get_value_(idx));
415 } else {
416 mpint_alloc_copy_mayfail(mp, index_get_mp_(idx pass_position), NULL);
420 #endif