/*

  sshfastalloc.h

  Author: Antti Huima <huima@ssh.fi>

  Copyright (c) 1999 SSH Communications Security, Finland
  All rights reserved.

  Created Thu Aug 19 13:32:06 1999.

  */

#ifndef SSHFASTALLOC_H_INCLUDED
#define SSHFASTALLOC_H_INCLUDED

typedef struct SshFastMemoryAllocatorRec *SshFastMemoryAllocator;

/* Initialize a new memory allocator for fixed-sized blobs.
   `blob_size' is the size of the blobs. `blob_quant' is the number of
   blobs for which room will be reserved atomically. Both `blob_size'
   and `blob_quant' must be larger than zero. */   
SshFastMemoryAllocator ssh_fastalloc_initialize(int blob_size,
                                                int blob_quant);

/* Uninitialize a memory allocator. All allocated blobs must have been
   freed, otherwise ssh_fatal() may be triggered. */
void ssh_fastalloc_uninitialize(SshFastMemoryAllocator allocator);

/* Allocate a new blob of the size `blob_size'. The returned data is
   correctly aligned for all kinds of purposes. The data is not
   necessarily initialized. */
void *ssh_fastalloc_alloc(SshFastMemoryAllocator allocator);

/* Free an individual blob. */
void ssh_fastalloc_free(SshFastMemoryAllocator allocator, void *data);

/* Two macros. */
#define ssh_fastalloc_alloc_m(allocator, result)                              \
do                                                                            \
{                                                                             \
  if ((allocator)->free_chain == NULL)                                        \
    {                                                                         \
      result = ssh_fastalloc_alloc(allocator);                                \
    }                                                                         \
  else                                                                        \
    {                                                                         \
      result = ((void *)((allocator)->free_chain));                           \
      (allocator)->free_chain =                                               \
        (allocator)->free_chain->free_chain;                                  \
      (allocator)->allocated++;                                               \
    }                                                                         \
}                                                                             \
while(0)

#define ssh_fastalloc_free_m(allocator, blob)                                 \
do                                                                            \
{                                                                             \
  SSH_ASSERT((allocator)->allocated > 0);                                     \
  ((SshFastallocProtoBlob *)(blob))->free_chain = (allocator)->free_chain;    \
  (allocator)->free_chain = (void *)(blob);                                   \
  (allocator)->allocated--;                                                   \
}                                                                             \
while(0)

/* You do to need to access these structures directly but the
   declarations must be public so that the macros above can work. */
typedef struct {
  void *free_chain;
} SshFastallocProtoBlob;

typedef struct ssh_fastalloc_blobs {
  void *blobs;
  struct ssh_fastalloc_blobs *next;
} SshFastallocBlobs;

struct SshFastMemoryAllocatorRec {
  int total_size;
  int allocated;
  int blob_size;
  int blob_quant;
  SshFastallocBlobs *blobs;  
  SshFastallocProtoBlob *free_chain;
};

#endif /* SSHFASTALLOC_H_INCLUDED */
