/* 
 * 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 <http://www.gnu.org/licenses/>.
 */

/** @file
 *
 * Memory allocation tools.
 */

#ifndef GU_MEM_H_
#define GU_MEM_H_

#include <gu/defs.h>
#include <gu/fun.h>

/** @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.
 */

/// Create a pool stored in a memory mapped file.
GuPool* 
gu_mmap_pool(char* fpath, void* addr, size_t size, void**pptr);

//@}
/// @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 <string.h>

/** 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))))

// 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_
