123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- /*
- * Copyright (c) 2016, Blender Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "Apache License")
- * with the following modification; you may not use this file except in
- * compliance with the Apache License and the following modification to it:
- * Section 6. Trademarks. is deleted and replaced with:
- *
- * 6. Trademarks. This License does not grant permission to use the trade
- * names, trademarks, service marks, or product names of the Licensor
- * and its affiliates, except as required to comply with Section 4(c) of
- * the License and to reproduce the content of the NOTICE file.
- *
- * You may obtain a copy of the Apache License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the Apache License with the above modification is
- * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the Apache License for the specific
- * language governing permissions and limitations under the Apache License.
- */
- /**
- * Simple Memory Chunking Allocator
- * ================================
- *
- * Defines need to be set:
- * - #TPOOL_IMPL_PREFIX: Prefix to use for the API.
- * - #TPOOL_ALLOC_TYPE: Struct type this pool handles.
- * - #TPOOL_STRUCT: Name for pool struct name.
- * - #TPOOL_CHUNK_SIZE: Chunk size (optional), use 64kb when not defined.
- *
- * \note #TPOOL_ALLOC_TYPE must be at least ``sizeof(void *)``.
- *
- * Defines the API, uses #TPOOL_IMPL_PREFIX to prefix each function.
- *
- * - *_pool_create()
- * - *_pool_destroy()
- * - *_pool_clear()
- *
- * - *_pool_elem_alloc()
- * - *_pool_elem_calloc()
- * - *_pool_elem_free()
- */
- /* check we're not building directly */
- #if !defined(TPOOL_IMPL_PREFIX) || \
- !defined(TPOOL_ALLOC_TYPE) || \
- !defined(TPOOL_STRUCT)
- # error "This file can't be compiled directly, include in another source file"
- #endif
- #define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1 ## MACRO_ARG2
- #define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
- #define _TPOOL_PREFIX(id) _CONCAT(TPOOL_IMPL_PREFIX, _##id)
- /* local identifiers */
- #define pool_create _TPOOL_PREFIX(pool_create)
- #define pool_destroy _TPOOL_PREFIX(pool_destroy)
- #define pool_clear _TPOOL_PREFIX(pool_clear)
- #define pool_elem_alloc _TPOOL_PREFIX(pool_elem_alloc)
- #define pool_elem_calloc _TPOOL_PREFIX(pool_elem_calloc)
- #define pool_elem_free _TPOOL_PREFIX(pool_elem_free)
- /* private identifiers (only for this file, undefine after) */
- #define pool_alloc_chunk _TPOOL_PREFIX(pool_alloc_chunk)
- #define TPoolChunk _TPOOL_PREFIX(TPoolChunk)
- #define TPoolChunkElemFree _TPOOL_PREFIX(TPoolChunkElemFree)
- #ifndef TPOOL_CHUNK_SIZE
- #define TPOOL_CHUNK_SIZE (1 << 16) /* 64kb */
- #define _TPOOL_CHUNK_SIZE_UNDEF
- #endif
- #ifndef UNLIKELY
- # ifdef __GNUC__
- # define UNLIKELY(x) __builtin_expect(!!(x), 0)
- # else
- # define UNLIKELY(x) (x)
- # endif
- #endif
- #ifdef __GNUC__
- # define MAYBE_UNUSED __attribute__((unused))
- #else
- # define MAYBE_UNUSED
- #endif
- struct TPoolChunk {
- struct TPoolChunk *prev;
- unsigned int size;
- unsigned int bufsize;
- TPOOL_ALLOC_TYPE buf[0];
- };
- struct TPoolChunkElemFree {
- struct TPoolChunkElemFree *next;
- };
- struct TPOOL_STRUCT {
- /* Always keep at least one chunk (never NULL) */
- struct TPoolChunk *chunk;
- /* when NULL, allocate a new chunk */
- struct TPoolChunkElemFree *free;
- };
- /**
- * Number of elems to include per #TPoolChunk when no reserved size is passed,
- * or we allocate past the reserved number.
- *
- * \note Optimize number for 64kb allocs.
- */
- #define _TPOOL_CHUNK_DEFAULT_NUM \
- (((1 << 16) - sizeof(struct TPoolChunk)) / sizeof(TPOOL_ALLOC_TYPE))
- /** \name Internal Memory Management
- * \{ */
- static struct TPoolChunk *pool_alloc_chunk(
- unsigned int tot_elems, struct TPoolChunk *chunk_prev)
- {
- struct TPoolChunk *chunk = malloc(
- sizeof(struct TPoolChunk) + (sizeof(TPOOL_ALLOC_TYPE) * tot_elems));
- chunk->prev = chunk_prev;
- chunk->bufsize = tot_elems;
- chunk->size = 0;
- return chunk;
- }
- static TPOOL_ALLOC_TYPE *pool_elem_alloc(struct TPOOL_STRUCT *pool)
- {
- TPOOL_ALLOC_TYPE *elem;
- if (pool->free) {
- elem = (TPOOL_ALLOC_TYPE *)pool->free;
- pool->free = pool->free->next;
- }
- else {
- struct TPoolChunk *chunk = pool->chunk;
- if (UNLIKELY(chunk->size == chunk->bufsize)) {
- chunk = pool->chunk = pool_alloc_chunk(_TPOOL_CHUNK_DEFAULT_NUM, chunk);
- }
- elem = &chunk->buf[chunk->size++];
- }
- return elem;
- }
- MAYBE_UNUSED
- static TPOOL_ALLOC_TYPE *pool_elem_calloc(struct TPOOL_STRUCT *pool)
- {
- TPOOL_ALLOC_TYPE *elem = pool_elem_alloc(pool);
- memset(elem, 0, sizeof(*elem));
- return elem;
- }
- static void pool_elem_free(struct TPOOL_STRUCT *pool, TPOOL_ALLOC_TYPE *elem)
- {
- struct TPoolChunkElemFree *elem_free = (struct TPoolChunkElemFree *)elem;
- elem_free->next = pool->free;
- pool->free = elem_free;
- }
- static void pool_create(struct TPOOL_STRUCT *pool, unsigned int tot_reserve)
- {
- pool->chunk = pool_alloc_chunk((tot_reserve > 1) ? tot_reserve : _TPOOL_CHUNK_DEFAULT_NUM, NULL);
- pool->free = NULL;
- }
- MAYBE_UNUSED
- static void pool_clear(struct TPOOL_STRUCT *pool)
- {
- /* Remove all except the last chunk */
- while (pool->chunk->prev) {
- struct TPoolChunk *chunk_prev = pool->chunk->prev;
- free(pool->chunk);
- pool->chunk = chunk_prev;
- }
- pool->chunk->size = 0;
- pool->free = NULL;
- }
- static void pool_destroy(struct TPOOL_STRUCT *pool)
- {
- struct TPoolChunk *chunk = pool->chunk;
- do {
- struct TPoolChunk *chunk_prev;
- chunk_prev = chunk->prev;
- free(chunk);
- chunk = chunk_prev;
- } while (chunk);
- pool->chunk = NULL;
- pool->free = NULL;
- }
- /** \} */
- #undef _TPOOL_CHUNK_DEFAULT_NUM
- #undef _CONCAT_AUX
- #undef _CONCAT
- #undef _TPOOL_PREFIX
- #undef TPoolChunk
- #undef TPoolChunkElemFree
- #ifdef _TPOOL_CHUNK_SIZE_UNDEF
- # undef TPOOL_CHUNK_SIZE
- # undef _TPOOL_CHUNK_SIZE_UNDEF
- #endif
|