/*

  sshfastalloc.h

  Author: Antti Huima <huima@ssh.fi>

  Copyright (c) 1999, 2000 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);

/* Uninitialize a memory allocator, with the provision that some of the blobs
   can be unfreed at this point.  No error will be triggered for that.  Should
   be used only if it is clearly not an error to have unfreed blobs. */
void ssh_fastalloc_uninitialize_forced(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.

   This can return NULL if lower-level memory allocation can. */
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 not 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 */
