Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions examples/array/simple.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,21 @@
int
main(int argc, const char *argv[])
{
BFDEV_DEFINE_ARRAY(array, NULL, TEST_SIZE);
BFDEV_CLASS(bfdev_array, array)(NULL, TEST_SIZE);
unsigned int count;

bfdev_array_append(&array, 0, 0);

for (count = 0; count < TEST_LOOP; ++count) {
unsigned int num;
void *buff;

num = rand() % TEST_SIZE;
buff = bfdev_array_push(&array, num);
buff = bfdev_array_push(array, num);
if (!buff)
return 1;

memset(buff, 0, TEST_SIZE * num);
printf("array bfdev_array_push test: %02u: %u\n", count, num);
}

bfdev_array_release(&array);

return 0;
}
6 changes: 6 additions & 0 deletions examples/guards/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,21 @@ add_executable(guards-cleanup cleanup.c)
target_link_libraries(guards-cleanup bfdev)
add_test(guards-cleanup guards-cleanup)

add_executable(guards-class class.c)
target_link_libraries(guards-class bfdev)
add_test(guards-class guards-class)

if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev")
install(FILES
cleanup.c
class.c
DESTINATION
${CMAKE_INSTALL_DOCDIR}/examples/guards
)

install(TARGETS
guards-cleanup
guards-class
DESTINATION
${CMAKE_INSTALL_DOCDIR}/bin
)
Expand Down
38 changes: 38 additions & 0 deletions examples/guards/class.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright(c) 2025 John Sanpe <sanpeqf@gmail.com>
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <bfdev/guards.h>

static const char *
test_ctor(void)
{
return strdup("helloworld");
}

static void
test_dtor(const char *obj)
{
free((void *)obj);
}

BFDEV_DEFINE_CLASS(test, const char *,
test_ctor(),
test_dtor(_T)
)

int
main(int argc, const char *argv[])
{
BFDEV_CLASS(test, str)();

if (!str)
return 1;
printf("%s\n", str);

return 0;
}
16 changes: 8 additions & 8 deletions examples/guards/cleanup.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,36 @@
#include <stdlib.h>
#include <bfdev/guards.h>

BFDEV_CLEAN_TEMPLATE(malloc, void *,
BFDEV_DEFINE_CLEAN(malloc, void *,
if (_T) {
printf("cleanup %p\n", _T);
free(_T);
}
)

static void
test_gc_cleanup(void)
test_clean_gc(void)
{
bfdev_clean(malloc) void *block;
BFDEV_CLEAN(malloc) void *block;
block = malloc(8);
(void)block;
}

static void *
test_gc_lasting(void)
test_clean_keep(void)
{
bfdev_clean(malloc) void *block;
BFDEV_CLEAN(malloc) void *block;
block = malloc(8);
bfdev_clean_return(block);
bfdev_return(block);
}

int
main(int argc, const char *argv[])
{
void *block;

test_gc_cleanup();
block = test_gc_lasting();
test_clean_gc();
block = test_clean_keep();
free(block);

return 0;
Expand Down
7 changes: 7 additions & 0 deletions include/bfdev/allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <bfdev/config.h>
#include <bfdev/types.h>
#include <bfdev/stddef.h>
#include <bfdev/guards.h>
#include <bfdev/errptr.h>

BFDEV_BEGIN_DECLS

Expand Down Expand Up @@ -125,6 +127,11 @@ bfdev_realloc_array(const bfdev_alloc_t *alloc,
return bfdev_realloc(alloc, block, size * nr);
}

BFDEV_DEFINE_CLEAN(bfdev_free, void *,
if (!BFDEV_IS_INVAL(_T))
bfdev_free(BFDEV_NULL, _T);
)

BFDEV_END_DECLS

#endif /* _BFDEV_ALLOCATOR_H_ */
27 changes: 27 additions & 0 deletions include/bfdev/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <bfdev/stddef.h>
#include <bfdev/string.h>
#include <bfdev/allocator.h>
#include <bfdev/guards.h>

BFDEV_BEGIN_DECLS

Expand Down Expand Up @@ -207,6 +208,32 @@ bfdev_array_reserve(bfdev_array_t *array, unsigned long num);
extern void
bfdev_array_release(bfdev_array_t *array);

static inline bfdev_array_t *
bfdev_array_create(const bfdev_alloc_t *alloc, bfdev_size_t cells)
{
bfdev_array_t *obj;

obj = bfdev_malloc(alloc, sizeof(*obj));
if (bfdev_unlikely(!obj))
return BFDEV_NULL;
bfdev_array_init(obj, alloc, cells);

return obj;
}

static inline void
bfdev_array_destroy(bfdev_array_t *obj)
{
bfdev_array_release(obj);
bfdev_free(obj->alloc, obj);
}

BFDEV_DEFINE_CLASS(bfdev_array, bfdev_array_t *,
bfdev_array_create(alloc, cells),
bfdev_array_destroy(_T),
const bfdev_alloc_t *alloc, bfdev_size_t cells
)

BFDEV_END_DECLS

#endif /* _BFDEV_ARRAY_H_ */
49 changes: 40 additions & 9 deletions include/bfdev/guards.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,55 @@

BFDEV_BEGIN_DECLS

#define BFDEV_CLEAN_TEMPLATE(name, type, free) \
/**
* Guards:
*
* The "goto error" pattern is notorious for introducing subtle resource
* leaks. It is tedious and error prone to add new resource acquisition
* constraints into code paths that already have several unwind
* conditions. The "cleanup" helpers enable the compiler to help with
* this tedium and can aid in maintaining LIFO (last in first out)
* unwind ordering to avoid unintentional leaks.
*/

#define BFDEV_DEFINE_CLEAN(name, type, free) \
static inline void \
__bfdev_cleanup_##name(void *object) \
{ \
type _T = *(type *)object; \
free; \
}

#define bfdev_clean_lasting(object) ({ \
__auto_type __ptr = (object); \
(object) = BFDEV_NULL; __ptr; \
})

#define bfdev_clean(name) \
#define BFDEV_CLEAN(name) \
__bfdev_cleanup(__bfdev_cleanup_##name)

#define bfdev_clean_return(object) \
return bfdev_clean_lasting(object)
#define BFDEV_DEFINE_CLASS(name, type, ctor, dtor, args...) \
typedef type __bfdev_class_##name##_t; \
static inline type \
__bfdev_class_##name##_constructor(args) \
{ \
type __tmp = ctor; \
return __tmp; \
} \
static inline void \
__bfdev_class_##name##_destructor(type *p) \
{ \
type _T = *p; \
dtor; \
}

#define BFDEV_CLASS(name, var) \
__bfdev_class_##name##_t var \
__bfdev_cleanup(__bfdev_class_##name##_destructor) = \
__bfdev_class_##name##_constructor

#define bfdev_lasting(object) ({ \
__auto_type __ptr = (object); \
(object) = BFDEV_NULL; __ptr; \
})

#define bfdev_return(object) \
return bfdev_lasting(object)

BFDEV_END_DECLS

Expand Down
Loading