diff options
author | David Robillard <d@drobilla.net> | 2021-09-14 20:35:30 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2021-09-14 23:55:44 -0400 |
commit | 939a47fb457128358b1c6553893be26b9b4fe060 (patch) | |
tree | bfd2c18db5add83dcd2c64c07b25638ec2c3bf09 /src | |
parent | c45ea80190de9745bcfaabb4858815a85d93c92a (diff) | |
download | zix-939a47fb457128358b1c6553893be26b9b4fe060.tar.gz zix-939a47fb457128358b1c6553893be26b9b4fe060.tar.bz2 zix-939a47fb457128358b1c6553893be26b9b4fe060.zip |
Add aligned allocation interface and use it in ZixBTree
Diffstat (limited to 'src')
-rw-r--r-- | src/.clang-tidy | 17 | ||||
-rw-r--r-- | src/allocator.c | 44 | ||||
-rw-r--r-- | src/btree.c | 26 | ||||
-rw-r--r-- | src/zix_config.h | 54 |
4 files changed, 132 insertions, 9 deletions
diff --git a/src/.clang-tidy b/src/.clang-tidy new file mode 100644 index 0000000..aa4ea77 --- /dev/null +++ b/src/.clang-tidy @@ -0,0 +1,17 @@ +Checks: > + *, + -*-magic-numbers, + -*-uppercase-literal-suffix, + -altera-struct-pack-align, + -bugprone-reserved-identifier, + -cert-dcl37-c, + -cert-dcl51-cpp, + -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, + -hicpp-multiway-paths-covered, + -llvm-header-guard, + -llvmlibc-*, + -misc-no-recursion, + -readability-function-cognitive-complexity, +WarningsAsErrors: '*' +HeaderFilterRegex: '.*' +FormatStyle: file diff --git a/src/allocator.c b/src/allocator.c index c998463..bedef47 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -1,7 +1,18 @@ // Copyright 2011-2021 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC +#define _POSIX_C_SOURCE 200809L + +#include "zix_config.h" + #include "zix/allocator.h" +#include "zix/attributes.h" + +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN 1 +# include <malloc.h> +# include <windows.h> +#endif #include <stdlib.h> @@ -39,6 +50,37 @@ zix_default_free(ZixAllocator* const allocator, void* const ptr) free(ptr); } +ZIX_MALLOC_FUNC +static void* +zix_default_aligned_alloc(ZixAllocator* const allocator, + const size_t alignment, + const size_t size) +{ + (void)allocator; + +#if defined(_WIN32) + return _aligned_malloc(size, alignment); +#elif USE_POSIX_MEMALIGN + void* ptr = NULL; + const int ret = posix_memalign(&ptr, alignment, size); + return ret ? NULL : ptr; +#else +# error No aligned memory allocation available +#endif +} + +static void +zix_default_aligned_free(ZixAllocator* const allocator, void* const ptr) +{ + (void)allocator; + +#if defined(_WIN32) + _aligned_free(ptr); +#else + free(ptr); +#endif +} + ZixAllocator* zix_default_allocator(void) { @@ -47,6 +89,8 @@ zix_default_allocator(void) zix_default_calloc, zix_default_realloc, zix_default_free, + zix_default_aligned_alloc, + zix_default_aligned_free, }; return &default_allocator; diff --git a/src/btree.c b/src/btree.c index 869b98a..9bb0904 100644 --- a/src/btree.c +++ b/src/btree.c @@ -50,6 +50,7 @@ struct ZixBTreeNodeImpl { #if ((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112l) || \ (defined(__cplusplus) && __cplusplus >= 201103L)) +static_assert(sizeof(ZixBTree) <= ZIX_BTREE_PAGE_SIZE, ""); static_assert(sizeof(ZixBTreeNode) <= ZIX_BTREE_PAGE_SIZE, ""); static_assert(sizeof(ZixBTreeNode) >= ZIX_BTREE_PAGE_SIZE - 2u * sizeof(ZixBTreeNode*), @@ -66,8 +67,8 @@ zix_btree_node_new(ZixAllocator* const allocator, const bool leaf) ZIX_BTREE_PAGE_SIZE - 2u * sizeof(ZixBTreeNode*)); #endif - ZixBTreeNode* const node = - (ZixBTreeNode*)zix_malloc(allocator, sizeof(ZixBTreeNode)); + ZixBTreeNode* const node = (ZixBTreeNode*)zix_aligned_alloc( + allocator, ZIX_BTREE_PAGE_SIZE, ZIX_BTREE_PAGE_SIZE); if (node) { node->is_leaf = leaf; @@ -91,15 +92,22 @@ zix_btree_new(ZixAllocator* const allocator, const ZixComparator cmp, const void* const cmp_data) { +#if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112l) || \ + (defined(__cplusplus) && __cplusplus >= 201103L)) + assert(sizeof(ZixBTree) <= ZIX_BTREE_PAGE_SIZE); +#endif + assert(cmp); - ZixBTree* const t = (ZixBTree*)zix_malloc(allocator, sizeof(ZixBTree)); + ZixBTree* const t = (ZixBTree*)zix_aligned_alloc( + allocator, ZIX_BTREE_PAGE_SIZE, ZIX_BTREE_PAGE_SIZE); + if (!t) { return NULL; } if (!(t->root = zix_btree_node_new(allocator, true))) { - zix_free(allocator, t); + zix_aligned_free(allocator, t); return NULL; } @@ -121,7 +129,7 @@ zix_btree_free_children(ZixBTree* const t, for (ZixShort i = 0; i < n->n_vals + 1u; ++i) { zix_btree_free_children( t, zix_btree_child(n, i), destroy, destroy_user_data); - zix_free(t->allocator, zix_btree_child(n, i)); + zix_aligned_free(t->allocator, zix_btree_child(n, i)); } } @@ -145,8 +153,8 @@ zix_btree_free(ZixBTree* const t, { if (t) { zix_btree_clear(t, destroy, destroy_user_data); - zix_free(t->allocator, t->root); - zix_free(t->allocator, t); + zix_aligned_free(t->allocator, t->root); + zix_aligned_free(t->allocator, t); } } @@ -618,10 +626,10 @@ zix_btree_merge(ZixBTree* const t, ZixBTreeNode* const n, const unsigned i) // Root is now empty, replace it with its only child assert(n == t->root); t->root = lhs; - zix_free(t->allocator, n); + zix_aligned_free(t->allocator, n); } - zix_free(t->allocator, rhs); + zix_aligned_free(t->allocator, rhs); return lhs; } diff --git a/src/zix_config.h b/src/zix_config.h new file mode 100644 index 0000000..832b50f --- /dev/null +++ b/src/zix_config.h @@ -0,0 +1,54 @@ +// Copyright 2021 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC + +/* + Configuration header that defines reasonable defaults at compile time. + + This allows compile-time configuration from the command line (typically via + the build system) while still allowing the source to be built without any + configuration. The build system can define ZIX_NO_DEFAULT_CONFIG to disable + defaults, in which case it must define things like HAVE_FEATURE to enable + features. The design here ensures that compiler warnings or + include-what-you-use will catch any mistakes. +*/ + +#ifndef ZIX_CONFIG_H +#define ZIX_CONFIG_H + +#if !defined(ZIX_NO_DEFAULT_CONFIG) + +// We need unistd.h to check _POSIX_VERSION +# ifndef ZIX_NO_POSIX +# ifdef __has_include +# if __has_include(<unistd.h>) +# include <unistd.h> +# endif +# elif defined(__unix__) +# include <unistd.h> +# endif +# endif + +// POSIX.1-2001: posix_memalign() +# ifndef HAVE_POSIX_MEMALIGN +# if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L +# define HAVE_POSIX_MEMALIGN +# endif +# endif + +#endif // !defined(ZIX_NO_DEFAULT_CONFIG) + +/* + Make corresponding USE_FEATURE defines based on the HAVE_FEATURE defines from + above or the command line. The code checks for these using #if (not #ifdef), + so there will be an undefined warning if it checks for an unknown feature, + and this header is always required by any code that checks for features, even + if the build system defines them all. +*/ + +#ifdef HAVE_POSIX_MEMALIGN +# define USE_POSIX_MEMALIGN 1 +#else +# define USE_POSIX_MEMALIGN 0 +#endif + +#endif // ZIX_CONFIG_H |