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
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
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)
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);
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
);
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
;
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
;
77 static inline uint_default_t
index_get_value_(array_index_t idx
)
79 #ifndef SCALAR_ARRAY_INDEX_T
86 static inline void index_set_value_(array_index_t
*idx
, uint_default_t val
)
88 #ifndef SCALAR_ARRAY_INDEX_T
90 idx
->mp
= NULL
; /* against warning */
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
103 return pointer_decompress((uint_default_t
)(idx
<< 1));
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;
114 pointer_compress_test(mp
, false);
115 *idx
= (uint_default_t
)(pointer_compress(mp
) >> 1) | sign_bit(uint_default_t
);
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
);
127 #ifdef SCALAR_ARRAY_INDEX_T
128 #define index_invalid() (sign_bit(uint_default_t))
129 #define index_is_invalid(idx) ((idx) == index_invalid())
131 static inline array_index_t
index_invalid(void)
134 idx
.val
= (uint_default_t
)-1;
136 #ifdef DEBUG_ARRAY_INDICES
137 idx
.test_leak
= BAD_POINTER_2
;
141 static inline bool index_is_invalid(array_index_t idx
)
143 return (int_default_t
)idx
.val
< 0 && !idx
.mp
;
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
);
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
);
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
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
);
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
);
197 /* poison the pointer */
198 #ifndef SCALAR_ARRAY_INDEX_T
199 index_set_mp_(idx
, (mpint_t
*)BAD_POINTER_1 pass_position
);
201 *idx
= 1 | sign_bit(uint_default_t
);
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
)
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
);
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
);
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
;
264 array_index_t val_idx
;
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
);
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
;
283 array_index_t val_idx
;
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
);
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
);
306 index_alloc_leak_(idx1 pass_position
);
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
);
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
);
336 index_set_value_(idx1
, result
);
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
);
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
)
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
);
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
)
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
);
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
))) {
382 #ifdef UNUSUAL_MPINT_ARRAY_INDICES
384 if (index_export_to_int(index_get_mp_(idx pass_position
), &val
))
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
)
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
));
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"));
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
));
416 mpint_alloc_copy_mayfail(mp
, index_get_mp_(idx pass_position
), NULL
);