#include "gskmempool.h"
#include <string.h>

#define ALIGN(size)	        _GSK_MEM_POOL_ALIGN(size)
#define SLAB_GET_NEXT_PTR(slab) _GSK_MEM_POOL_SLAB_GET_NEXT_PTR(slab)
#define CHUNK_SIZE	        8192

/* --- Allocate-only Memory Pool --- */
/**
 * gsk_mem_pool_construct:
 * @pool: the mem-pool to initialize.
 *
 * Initialize the members of a mem-pool.
 * (The memory for the mem-pool structure itself
 * must be provided: either as a part of another
 * structure or on the stack.)
 */

/**
 * gsk_mem_pool_construct_with_scratch_buf:
 * @pool: the mem-pool to initialize.
 * @buffer: the buffer to use.
 * @buffer_size: the number of bytes in buffer
 * to use as storage.
 *
 * Initialize the members of a mem-pool,
 * using a scratch-buffer that the user provides.
 * (The caller is responsible for ensuring that
 * the buffer exists long enough)
 */


/**
 * gsk_mem_pool_alloc:
 * @pool: area to allocate memory from.
 * @size: number of bytes to allocate.
 *
 * Allocate memory from a pool,
 * This function terminates the program if there is an
 * out-of-memory condition.
 *
 * returns: the slab of memory allocated from the pool.
 */


/**
 * gsk_mem_pool_alloc_unaligned:
 * @pool: area to allocate memory from.
 * @size: number of bytes to allocate.
 *
 * Allocate memory from a pool, without ensuring that
 * it is aligned.
 *
 * returns: the slab of memory allocated from the pool.
 */

/**
 * gsk_mem_pool_must_alloc:
 * @pool: area to allocate memory from.
 * @size: number of bytes to allocate.
 *
 * private
 *
 * returns: the slab of memory allocated from the pool.
 */

gpointer
gsk_mem_pool_must_alloc   (GskMemPool     *pool,
			   gsize           size)
{
  char *rv;
  if (size < CHUNK_SIZE)
    {
      /* Allocate a new chunk. */
      gpointer carved = g_malloc (CHUNK_SIZE + sizeof (gpointer));
      SLAB_GET_NEXT_PTR (carved) = pool->all_chunk_list;
      pool->all_chunk_list = carved;
      rv = carved;
      rv += sizeof (gpointer);
      pool->chunk = rv + size;
      pool->chunk_left = CHUNK_SIZE - size;
    }
  else
    {
      /* Allocate a chunk of exactly the right size. */
      gpointer carved = g_malloc (size + sizeof (gpointer));
      if (pool->all_chunk_list)
	{
	  SLAB_GET_NEXT_PTR (carved) = SLAB_GET_NEXT_PTR (pool->all_chunk_list);
	  SLAB_GET_NEXT_PTR (pool->all_chunk_list) = carved;
	}
      else
	{
	  SLAB_GET_NEXT_PTR (carved) = NULL;
	  pool->all_chunk_list = carved;
	}
      rv = carved;
      rv += sizeof (gpointer);
    }
  return rv;
}

/**
 * gsk_mem_pool_alloc0:
 * @pool: area to allocate memory from.
 * @size: number of bytes to allocate.
 *
 * Allocate memory from a pool, and initializes it to 0.
 * This function terminates the program if there is an
 * out-of-memory condition.
 *
 * returns: the slab of memory allocated from the pool.
 */
gpointer gsk_mem_pool_alloc0           (GskMemPool     *pool,
                                        gsize           size)
{
  return memset (gsk_mem_pool_alloc (pool, size), 0, size);
}

/**
 * gsk_mem_pool_strdup:
 * @pool: area to allocate memory from.
 * @str: a string to duplicate, or NULL.
 *
 * Allocated space from the mem-pool to store
 * the given string (including its terminal
 * NUL character) and copy the string onto that buffer.
 *
 * If @str is NULL, then NULL is returned.
 *
 * returns: a copy of @str, allocated from @pool.
 */
char *
gsk_mem_pool_strdup       (GskMemPool     *pool,
			   const char     *str)
{
  guint L;
  if (str == NULL)
    return NULL;
  L = strlen (str) + 1;
  return memcpy (gsk_mem_pool_alloc_unaligned (pool, L), str, L);
}

/**
 * gsk_mem_pool_destruct:
 * @pool: the pool to destroy.
 *
 * Destroy all chunk associated with the given mem-pool.
 */
#if 0           /* inlined */
void
gsk_mem_pool_destruct     (GskMemPool     *pool)
{
  gpointer slab = pool->all_chunk_list;
  while (slab)
    {
      gpointer new_slab = SLAB_GET_NEXT_PTR (slab);
      g_free (slab);
      slab = new_slab;
    }
#ifdef GSK_DEBUG
  memset (pool, 0xea, sizeof (GskMemPool));
#endif
}
#endif

/* === Fixed-Size MemPool's === */
/**
 * gsk_mem_pool_fixed_construct:
 * @pool: the fixed-size memory pool to construct.
 * @size: size of the allocation to take from the mem-pool.
 *
 * Set up a fixed-size memory allocator for use.
 */
void
gsk_mem_pool_fixed_construct (GskMemPoolFixed     *pool,
			      gsize           size)
{
  pool->slab_list = NULL;
  pool->chunk = NULL;
  pool->pieces_left = 0;
  pool->piece_size = MAX (ALIGN (size), sizeof (gpointer));
  pool->free_list = NULL;
}

/**
 * gsk_mem_pool_fixed_alloc:
 * @pool: the pool to allocate a block from.
 *
 * Allocate a block of the Fixed-Pool's size.
 *
 * returns: the allocated memory.
 */
gpointer
gsk_mem_pool_fixed_alloc     (GskMemPoolFixed     *pool)
{
  if (pool->free_list)
    {
      gpointer rv = pool->free_list;
      pool->free_list = SLAB_GET_NEXT_PTR (rv);
      return rv;
    }
  if (pool->pieces_left == 0)
    {
      gpointer slab = g_malloc (256 * pool->piece_size + sizeof (gpointer));
      SLAB_GET_NEXT_PTR (slab) = pool->slab_list;
      pool->slab_list = slab;
      pool->chunk = slab;
      pool->chunk += sizeof (gpointer);
      pool->pieces_left = 256;
    }
  {
    gpointer rv = pool->chunk;
    pool->chunk += pool->piece_size;
    pool->pieces_left--;
    return rv;
  }
}

/**
 * gsk_mem_pool_fixed_alloc0:
 * @pool: the pool to allocate a block from.
 *
 * Allocate a block of the Fixed-Pool's size.
 * Set its contents to 0.
 *
 * returns: the allocated, zeroed memory.
 */
gpointer gsk_mem_pool_fixed_alloc0    (GskMemPoolFixed     *pool)
{
  return memset (gsk_mem_pool_fixed_alloc (pool), 0, pool->piece_size);
}

/**
 * gsk_mem_pool_fixed_free:
 * @pool: the pool to return memory to.
 * @from_pool: the memory to return to this pool.
 * It must have been allocated from this pool.
 *
 * Recycle some of the pool's memory back to it.
 */
void     gsk_mem_pool_fixed_free      (GskMemPoolFixed     *pool,
                                       gpointer        from_pool)
{
  SLAB_GET_NEXT_PTR (from_pool) = pool->free_list;
  pool->free_list = from_pool;
}

/**
 * gsk_mem_pool_fixed_destruct:
 * @pool: the pool to destroy.
 *
 * Free all memory associated with this pool.
 */
void     gsk_mem_pool_fixed_destruct  (GskMemPoolFixed     *pool)
{
  while (pool->slab_list)
    {
      gpointer kill = pool->slab_list;
      pool->slab_list = SLAB_GET_NEXT_PTR (kill);
      g_free (kill);
    }
}


syntax highlighted by Code2HTML, v. 0.9.1