/* * Copyright 2010 University of Helsinki. * * This file is part of libgu. * * Libgu is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * Libgu is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with libgu. If not, see . */ /** @file * * Memory allocation tools. */ #ifndef GU_MEM_H_ #define GU_MEM_H_ #include #include /** @defgroup GuPool Memory pools */ //@{ /// A memory pool. typedef struct GuPool GuPool; /// @name Creating a pool //@{ /// Create a new memory pool. GU_ONLY GuPool* gu_new_pool(void); /**< * @return A new memory pool. */ //@private GuPool* gu_local_pool_(uint8_t* init_buf, size_t sz); //@private #define GU_LOCAL_POOL_INIT_SIZE (16 * sizeof(GuWord)) /// Create a stack-allocated memory pool. #define gu_local_pool() \ gu_local_pool_(gu_alloca(GU_LOCAL_POOL_INIT_SIZE), \ GU_LOCAL_POOL_INIT_SIZE) /**< * @return A memory pool whose first chunk is allocated directly from * the stack. This makes its creation faster, and more suitable for * functions that usually allocate only a little memory from the pool * until it is freed. * * @note The pool created with #gu_local_pool \e must be freed with * #gu_pool_free before the end of the block where #gu_local_pool was * called. * * @note Because #gu_local_pool uses relatively much stack space, it * should not be used in the bodies of recursive functions. */ //@} /// @name Destroying a pool //@{ /// Free a memory pool and all objects allocated from it. void gu_pool_free(GU_ONLY GuPool* pool); /**< * When the pool is freed, all finalizers registered by * #gu_pool_finally on \p pool are invoked in reverse order of * registration. * * @note After the pool is freed, all objects allocated from it become * invalid and may no longer be used. */ //@} /// @name Allocating from a pool //@{ /// Allocate memory with a specified alignment. void* gu_malloc_aligned(GuPool* pool, size_t size, size_t alignment); void* gu_malloc_prefixed(GuPool* pool, size_t pre_align, size_t pre_size, size_t align, size_t size); /// Allocate memory from a pool. inline void* gu_malloc(GuPool* pool, size_t size) { return gu_malloc_aligned(pool, size, 0); } #include //@private static inline void* gu_malloc_init_aligned(GuPool* pool, size_t size, size_t alignment, const void* init) { void* p = gu_malloc_aligned(pool, size, alignment); memcpy(p, init, size); return p; } //@private static inline void* gu_malloc_init(GuPool* pool, size_t size, const void* init) { return gu_malloc_init_aligned(pool, size, 0, init); } /** Allocate memory to store an array of objects of a given type. */ #define gu_new_n(type, n, pool) \ ((type*)gu_malloc_aligned((pool), \ sizeof(type) * (n), \ gu_alignof(type))) /**< * @param type The C type of the objects to allocate. * * @param n The number of objects to allocate. * * @param pool The memory pool to allocate from. * * @return A pointer to a heap-allocated array of \p n uninitialized * objects of type \p type. */ /** Allocate memory to store an object of a given type. */ #define gu_new(type, pool) \ gu_new_n(type, 1, pool) /**< * @param type The C type of the object to allocate. * * @param pool The memory pool to allocate from. * * @return A pointer to a heap-allocated uninitialized object of type * \p type. */ #define gu_new_prefixed(pre_type, type, pool) \ ((type*)(gu_malloc_prefixed((pool), \ gu_alignof(pre_type), sizeof(pre_type), \ gu_alignof(type), sizeof(type)))) #ifdef GU_HAVE_STATEMENT_EXPRESSIONS #define gu_new_i(pool, type, ...) \ ({ \ type *gu_new_p_ = gu_new(type, pool); \ memcpy((void*) gu_new_p_, &(type){ __VA_ARGS__ }, \ sizeof(type)); \ gu_new_p_; \ }) #else // GU_HAVE_STATEMENT_EXPRESSIONS #define gu_new_i(pool, type, ...) \ ((type*)gu_malloc_init_aligned((pool), sizeof(type), \ gu_alignof(type), \ &(type){ __VA_ARGS__ })) #endif // GU_HAVE_STATEMENT_EXPRESSIONS /** @def gu_new_i(pool, type, ...) * * Allocate and initialize an object. * * @param pool The pool to allocate from. * * @param type The C type of the object to allocate. * * @param ... An initializer list for the object to allocate. */ #define gu_new_s gu_new_i // Alas, there's no portable way to get the alignment of flex structs. #define gu_new_flex(pool_, type_, flex_member_, n_elems_) \ ((type_ *)gu_malloc_aligned( \ (pool_), \ GU_FLEX_SIZE(type_, flex_member_, n_elems_), \ gu_flex_alignof(type_))) //@} /// @name Finalizers //@{ typedef struct GuFinalizer GuFinalizer; struct GuFinalizer { void (*fn)(GuFinalizer* self); ///< @param self A pointer to this finalizer. }; /// Register a finalizer. void gu_pool_finally(GuPool* pool, GuFinalizer* fini); /**< Register \p fini to be called when \p pool is destroyed. The * finalizers are called in reverse order of registration. */ //@} //@} /** @defgroup GuMemBuf Memory buffers * * Resizable blocks of heap-allocated memory. These operations differ * from standard \c malloc, \c realloc and \c free -functions in that * memory buffers are not allocated by exact size. Instead, a minimum * size is requested, and the returned buffer may be larger. This * gives the memory allocator more flexibility when the client code * can make use of larger buffers than requested. * */ //@{ /// Allocate a new memory buffer. GU_ONLY void* gu_mem_buf_alloc(size_t min_size, size_t* real_size); /**< * @param min_size The minimum acceptable size for a returned memory block. * * @param[out] real_size The actual size of the returned memory * block. This is never less than \p min_size. * * @return A pointer to the memory buffer. */ /// Allocate a new memory buffer to replace an old one. GU_ONLY void* gu_mem_buf_realloc( GU_NULL GU_ONLY GU_RETURNED void* buf, size_t min_size, size_t* real_size_out); /// Free a memory buffer. void gu_mem_buf_free(GU_ONLY void* buf); //@} #endif // GU_MEM_H_