From 5c36e045ff6fe6623c6322fee43e59d5fb43bb70 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 27 Apr 2024 08:55:51 +0200 Subject: [PATCH] Add proper support for exception for DEQUE --- m-deque.h | 41 ++++++++-------- tests/except-deque.c | 100 ++++++++++++++++++++++++++++++++++++++++ tests/test-obj-except.h | 8 +++- 3 files changed, 125 insertions(+), 24 deletions(-) create mode 100644 tests/except-deque.c diff --git a/m-deque.h b/m-deque.h index f5850c83..c81d9561 100644 --- a/m-deque.h +++ b/m-deque.h @@ -177,6 +177,7 @@ /* Test for overflow of the size computation */ \ if (M_UNLIKELY_NOMEM (def > SIZE_MAX / sizeof (type) - sizeof(node_t))) { \ M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \ + abort(); \ return NULL; \ } \ /* Alloc a new node with dynamic size */ \ @@ -185,6 +186,7 @@ sizeof(node_t) + def * sizeof(type) ); \ if (M_UNLIKELY_NOMEM (n==NULL)) { \ M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \ + abort(); \ return NULL; \ } \ /* Initialize the node */ \ @@ -205,7 +207,6 @@ d->default_size = M_USE_DEQUE_DEFAULT_SIZE; \ d->count = 0; \ node_t *n = M_C3(m_d3qu3_,name,_new_node)(d); \ - if (n == NULL) return; \ M_F(name, _node_list_push_back)(d->list, n); \ d->front->node = n; \ d->front->index = M_USE_DEQUE_DEFAULT_SIZE/2; \ @@ -264,7 +265,6 @@ if (n == NULL) { \ /* No node exists, allocate a new one */ \ n = M_C3(m_d3qu3_,name,_new_node)(d); \ - if (M_UNLIKELY (n == NULL)) return NULL; \ M_F(name, _node_list_push_back)(d->list, n); \ } \ d->back->node = n; \ @@ -289,7 +289,7 @@ M_F(name, _push_back)(deque_t d, type const x) \ { \ type *p = M_F(name, _push_back_raw)(d); \ - if (M_LIKELY(p != NULL)) { \ + M_ON_EXCEPTION(d->back->index --, d->count--) { \ M_CALL_INIT_SET(oplist, *p, x); \ } \ } \ @@ -299,7 +299,7 @@ M_F(name, _push_back_new)(deque_t d) \ { \ type *p = M_F(name, _push_back_raw)(d); \ - if (M_LIKELY(p != NULL)) { \ + M_ON_EXCEPTION(d->back->index --, d->count--) { \ M_CALL_INIT(oplist, *p); \ } \ return p; \ @@ -311,8 +311,6 @@ { \ M_ASSERT (x != NULL); \ type *p = M_F(name, _push_back_raw)(d); \ - if (M_UNLIKELY(p == NULL)) \ - return; \ M_DO_INIT_MOVE (oplist, *p, *x); \ } \ \ @@ -328,7 +326,6 @@ n = M_F(name, _node_list_previous_obj)(d->list, n); \ if (n == NULL) { \ n = M_C3(m_d3qu3_,name,_new_node)(d); \ - if (M_UNLIKELY (n == NULL)) return NULL; \ M_F(name, _node_list_push_front)(d->list, n); \ } \ d->front->node = n; \ @@ -345,7 +342,7 @@ M_F(name, _push_front)(deque_t d, type const x) \ { \ type *p = M_F(name, _push_front_raw)(d); \ - if (M_LIKELY(p != NULL)) { \ + M_ON_EXCEPTION(d->front->index ++, d->count--) { \ M_CALL_INIT_SET(oplist, *p, x); \ } \ } \ @@ -355,7 +352,7 @@ M_F(name, _push_front_new)(deque_t d) \ { \ type *p = M_F(name, _push_front_raw)(d); \ - if (M_LIKELY(p != NULL)) { \ + M_ON_EXCEPTION(d->front->index ++, d->count--) { \ M_CALL_INIT(oplist, *p); \ } \ return p; \ @@ -367,8 +364,6 @@ { \ M_ASSERT (x != NULL); \ type *p = M_F(name, _push_front_raw)(d); \ - if (M_UNLIKELY(p == NULL)) \ - return; \ M_DO_INIT_MOVE (oplist, *p, *x); \ } \ \ @@ -738,9 +733,8 @@ M_ASSERT (d != NULL); \ M_F(name, _node_list_init)(d->list); \ d->default_size = M_USE_DEQUE_DEFAULT_SIZE + src->count; \ - d->count = src->count; \ node_t *n = M_C3(m_d3qu3_,name,_new_node)(d); \ - if (n == NULL) return; \ + d->count = src->count; \ d->default_size /= 2; \ M_F(name, _node_list_push_back)(d->list, n); \ d->front->node = n; \ @@ -748,7 +742,8 @@ d->back->node = n; \ d->back->index = M_USE_DEQUE_DEFAULT_SIZE/2 + src->count; \ it_t it; \ - size_t i = M_USE_DEQUE_DEFAULT_SIZE/2; \ + size_t m_volatile i = M_USE_DEQUE_DEFAULT_SIZE/2; \ + M_ON_EXCEPTION(d->count = i - M_USE_DEQUE_DEFAULT_SIZE/2, d->back->index = i, M_F(name, _clear)(d) ) \ for(M_F(name, _it)(it, src); !M_F(name, _end_p)(it) ; M_F(name, _next)(it)) { \ type const *obj = M_F(name, _cref)(it); \ M_CALL_INIT_SET(oplist, n->data[i], *obj); \ @@ -764,8 +759,10 @@ if (M_UNLIKELY (src == d)) \ return; \ /* TODO: Reuse memory of d! */ \ - M_F(name, _clear)(d); \ - M_F(name, _init_set)(d, src); \ + M_ON_EXCEPTION( M_F(name, _init)(d) ) {\ + M_F(name, _clear)(d); \ + M_F(name, _init_set)(d, src); \ + }\ } \ \ M_INLINE void \ @@ -1045,9 +1042,9 @@ M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ M_F(name, _subtype_ct) *data = M_F(name, _push_back_raw)(v); \ - if (M_UNLIKELY (data == NULL) ) \ - return; \ - M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \ + M_ON_EXCEPTION(v->back->index --, v->count--) { \ + M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \ + } \ } @@ -1058,9 +1055,9 @@ M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ M_F(name, _subtype_ct) *data = M_F(name, _push_front_raw)(v); \ - if (M_UNLIKELY (data == NULL) ) \ - return; \ - M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \ + M_ON_EXCEPTION(v->front->index ++, v->count--) { \ + M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \ + } \ } diff --git a/tests/except-deque.c b/tests/except-deque.c new file mode 100644 index 00000000..0b934003 --- /dev/null +++ b/tests/except-deque.c @@ -0,0 +1,100 @@ +/* + * Test that the deque module properly support exceptions + * + * Copyright (c) 2017-2024, Patrick Pelissier + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include "test-obj-except.h" +#include "m-deque.h" +#include "m-string.h" + +M_TRY_DEF_ONCE() + +DEQUE_DEF(list_obj, test_obj_except__t, TEST_OBJ_EXCEPT_OPLIST) +#define M_OPL_list_obj_t() LIST_OPLIST(list_obj, TEST_OBJ_EXCEPT_OPLIST) + +static void test1(unsigned n) +{ + FILE *f = m_core_fopen ("a-edeque.dat", "wt"); + assert(f != NULL); + M_TRY(test1) { + M_LET(obj, test_obj_except__t) + M_LET(list, tmp, list_obj_t) { + for(unsigned i = 0; i < n; i++) { + test_obj_except__set_ui(obj, i); + list_obj_push_back(list, obj); + } + list_obj_set(tmp, list); + M_LET( (tmp2, tmp), list_obj_t) { + list_obj_out_str(f, tmp2); + } + list_obj_push_back_new(tmp); + M_LET(str, string_t) { + list_obj_get_str(str, tmp, false); + bool b = list_obj_parse_str(list, string_get_cstr(str), NULL); + assert(b); + } + list_obj_emplace_back_ui(list, 345); + list_obj_emplace_back_str(list, "345"); + } + } M_CATCH(test1, 0) { + // Nothing to do + } + fclose(f); + + f = m_core_fopen ("a-edeque.dat", "rt"); + assert(f != NULL); + M_TRY(test1) { + M_LET(obj, test_obj_except__t) + M_LET(list, tmp, list_obj_t) { + bool b = list_obj_in_str(list, f); + (void)b; + } + } M_CATCH(test1, 0) { + // Nothing to do + } + fclose(f); +} + +static void test3(unsigned n) +{ + M_TRY(test1) { + M_LET(obj, test_obj_except__t) + M_LET(list, tmp, list_obj_t) { + for(unsigned i = 0; i < n; i++) { + test_obj_except__set_ui(obj, i); + list_obj_push_front(list, obj); + } + list_obj_push_front_new(list); + list_obj_emplace_front_ui(list, 345); + list_obj_emplace_front_str(list, "345"); + } + } M_CATCH(test1, 0) { + // Nothing to do + } +} + +int main(void) +{ + do_test1(test1); + do_test1(test3); + exit(0); +} diff --git a/tests/test-obj-except.h b/tests/test-obj-except.h index 62a1fde1..92cc0ee5 100644 --- a/tests/test-obj-except.h +++ b/tests/test-obj-except.h @@ -137,15 +137,19 @@ static inline void test_obj_except__set_ui(test_obj_except__t d, unsigned int v) static inline void test_obj_except__init_set_ui(test_obj_except__t d, unsigned int v) { - test_obj_except_trigger(); + // test_obj_except_trigger(); is already triggered by test_obj_except__init test_obj_except__init(d); + // Don't trigger exception for test_obj_except__set_ui now + test_obj_except__trigger_exception++; test_obj_except__set_ui(d, v); } static inline void test_obj_except__init_set_str(test_obj_except__t d, const char v[]) { - test_obj_except_trigger(); + // test_obj_except_trigger(); is already triggered by test_obj_except__init test_obj_except__init(d); + // Don't trigger exception for test_obj_except__set_ui now + test_obj_except__trigger_exception++; test_obj_except__set_ui(d, (unsigned int) atoi(v) ); }