/*

  sshadt.h

  Author: Antti Huima <huima@ssh.fi>

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

  Created Wed Sep  8 17:01:04 1999.

  */

#ifndef SSHADT_H_INCLUDED
#define SSHADT_H_INCLUDED

#define SSHADT_INSIDE_SSHADT_H

/* Generic header type. */
typedef struct {
  void *ptr[4];
} SshADTHeaderRec;

typedef struct SshADTContainerRec *SshADTContainer;

/* Handles for doing iteration, inserting objs etc. */
typedef void *SshADTHandle;

/* Function type to compare two user-supplied data items. */
typedef int (* SshADTCompareFunc)(void *obj1, void *obj2,
                                  void *context);

/* Function type to duplicate a user-supplied data item when the
   void pointer semantics are used. */
typedef void *(* SshADTDuplicateFunc)(void *obj, void *context);

/* Function type to initialize an object from an another --- to do copy ---
   when internally allocated objects are used. */
typedef void (* SshADTCopyFunc)(void *dst, size_t dst_size,
                                void *src, void *context);

/* Function type to destroy a user-supplied data item. */
typedef void (* SshADTDestroyFunc)(void *obj, void *context);

/* Function type to initialize a user-supplied data item when it is
   allocated by the library. */
typedef void (* SshADTInitFunc)(void *obj, size_t size, void *context);

/* Function type to calculate the hash of a user-supplied data item. */
typedef SshUInt32 (* SshADTHashFunc)(void *obj, void *context);

typedef enum {
  /* Argument type identifier           C type of the next argument
     ========================           =========================== */

  /* Set the user-supplied context. */
  SSH_ADT_CONTEXT,                      /* void * */

  /* Set the compare func. */
  SSH_ADT_COMPARE,                      /* SshADTCompareFunc */

  /* Set the duplicate func. */
  SSH_ADT_DUPLICATE,                    /* SshADTDuplicateFunc */

  /* Set the copy func. */
  SSH_ADT_COPY,                         /* SshADTCopyFunc */

  /* Set the destroy func. */
  SSH_ADT_DESTROY,                      /* SshADTDestroyFunc */

  /* Set the hash func. */
  SSH_ADT_HASH,                         /* SshADTHashFunc */

  /* Set the init func. */
  SSH_ADT_INIT,                         /* SshADTInitFunc */

  /* Tell the ADT library to use a header inside the objects instead
     of allocating auxiliary data outside the objects. The next
     argument must be the offset (SshUInt32) to an SshADTHeader field. */
  SSH_ADT_HEADER,                       /* SSH_ADT_OFFSET_OF(...) */

  /* Tell the ADT library the default size of the objects. This turns
     automatic object allocation on. */
  SSH_ADT_SIZE,                         /* size_t */

  /* Tell the ADT library to allocate objects by using the
     sshfastalloc utility. Two restrictions: 1) SSH_ADT_SIZE must be
     set also. 2) If you use SSH_ADT_FASTALLOC you cannot allocate
     objects that are not of the default size. Thus, ssh_adt_realloc
     is not available and ssh_adt_alloc does not work with non-default
     size. */
  SSH_ADT_FASTALLOC,                    /* int */

  /* End of args marker. */
  SSH_ADT_ARGS_END                      /* None */
} SshADTArgumentType;

#define SSH_ADT_OFFSET_OF(type,field) ((SshUInt32)(&(((type *)0)->field)))

/* Container types. */

typedef void *SshADTContainerType;

/* Invalid handle. */

#define SSH_ADT_INVALID   NULL

/******************************************** Handling containers as a whole */

/* Generic container allocation. */
SshADTContainer ssh_adt_create_generic(SshADTContainerType type,
                                       ...);

/* Destroy a container and all objects contained. */
void ssh_adt_destroy(SshADTContainer container);

/* Make the container empty: destroy the contained objects but not the
   container itself. This returns the container basically to the state
   just after create. */
void ssh_adt_clear(SshADTContainer container);

/****************************************** Absolute and relative locations. */

typedef int SshADTAbsoluteLocation;

/* The negative integers denote `special' values. */
#define SSH_ADT_BEGINNING -1
#define SSH_ADT_END       -2
#define SSH_ADT_DEFAULT   -3

/* Integers >= 0 denote positions in a total order (e.g. dynamic array
   slots). */
#define SSH_ADT_INDEX(n)  (n)

typedef enum {
  SSH_ADT_BEFORE,
  SSH_ADT_AFTER
} SshADTRelativeLocation;

/******************************************* Creating and inserting objects. */

/* 1. Void pointer semantics. */

/* Insert an object to container. This interface works only 
   when the void pointers semantics is used. Returns a handle to the
   inserted object. */
SshADTHandle ssh_adt_insert_at(SshADTContainer container,
                               SshADTRelativeLocation location,
                               SshADTHandle handle,
                               void *object);

SshADTHandle ssh_adt_insert_to(SshADTContainer container,
                               SshADTAbsoluteLocation location,
                               void *object);

#define ssh_adt_insert(c, o) ssh_adt_insert_to((c), SSH_ADT_DEFAULT, (o))

/* Duplicate a void pointer object. */
void *ssh_adt_duplicate_object(SshADTContainer container, void *object);

/* Insert a duplicant. */
#define ssh_adt_duplicate_at(c,l,h,o) \
  ssh_adt_insert_at((c), (l), (h),ssh_adt_duplicate_object((c),(o)))

#define ssh_adt_duplicate_to(c,l,o) \
  ssh_adt_insert_to((c), (l), ssh_adt_duplicate_object((c),(o)))

#define ssh_adt_duplicate(c,o) \
  ssh_adt_insert((c), ssh_adt_duplicate_object((c),(o)))

/* 2. Internally allocated objects. */
SshADTHandle ssh_adt_alloc_n_at(SshADTContainer container,
                                SshADTRelativeLocation location,
                                SshADTHandle handle,
                                size_t size);

SshADTHandle ssh_adt_alloc_n_to(SshADTContainer container,
                                SshADTAbsoluteLocation location,
                                size_t size);

#define ssh_adt_alloc_at(c,l,h) \
  ssh_adt_alloc_n_at((c),(l),(h),SSH_ADT_DEFAULT_SIZE(c))

#define ssh_adt_alloc_to(c,l) \
  ssh_adt_alloc_n_to((c),(l),SSH_ADT_DEFAULT_SIZE(c))

#define ssh_adt_alloc(c) ssh_adt_alloc_to((c), SSH_ADT_DEFAULT)

#define ssh_adt_alloc_n(c,s) ssh_adt_alloc_n_to((c), SSH_ADT_DEFAULT, (s))

/* These perform copy operation from the object *obj instead of new
   initialization. Cannot use a separate duplication function as above
   is used because internally allocated objects are initialized using
   the initialization `callback' and now we want to avoid the
   initialization when using copy constructor. */
SshADTHandle ssh_adt_put_n_at(SshADTContainer container,
                              SshADTRelativeLocation location,
                              SshADTHandle handle,
                              size_t size,
                              void *obj);

SshADTHandle ssh_adt_put_n_to(SshADTContainer container,
                              SshADTAbsoluteLocation location,
                              size_t size,
                              void *obj);

#define ssh_adt_put_at(c,l,h,o)                                 \
  ssh_adt_put_n_at((c),(l),(h),SSH_ADT_DEFAULT_SIZE(c),(o))     \

#define ssh_adt_put_to(c,l,o)   \
  ssh_adt_put_n_to((c),(l),SSH_ADT_DEFAULT_SIZE(c),(o))

#define ssh_adt_put(c,o) ssh_adt_put_to((c), SSH_ADT_DEFAULT, (o))

#define ssh_adt_put_n(c,s1,o)        \
  ssh_adt_put_n_to((c), SSH_ADT_DEFAULT, (s1), (o))

/********************************************************* Accessing objects */

/* Get the object at the handle. */
void *ssh_adt_get(SshADTContainer container, SshADTHandle handle);

/* Get the number of objects inside a container. */
size_t ssh_adt_num_objects(SshADTContainer container);

/*********************************************************** Setting handles */

/* Get a handle to the object. The pointers must match exactly. This
   can be a slow operation if the void pointer semantics is used. */
SshADTHandle ssh_adt_get_handle_to(SshADTContainer container,
                                   void *object);

/* Get a handle to some object that is equal to `object'. */
SshADTHandle ssh_adt_get_handle_to_equal(SshADTContainer container,
                                         void *object);

/* Moving handles in rudimentary was for containers that support some
   kind of ordering (the most assumedly do). */

/* Move the handle to the next object. */
SshADTHandle ssh_adt_next(SshADTContainer container, SshADTHandle handle);

/* Move the handle to the previous object. */
SshADTHandle ssh_adt_previous(SshADTContainer container, SshADTHandle handle);

SshADTHandle ssh_adt_get_handle_to_location(SshADTContainer container,
                                            SshADTAbsoluteLocation location);

/***************************************** Removing objects from a container */

/* Detach the object that ssh_adt_get(container, handle) would return
   from the container. After this the handle is invalidated and must
   be set before it is used. */

void *ssh_adt_detach(SshADTContainer container,              
                     SshADTHandle handle);

#define ssh_adt_detach_from(container, location) \
ssh_adt_detach(container, ssh_adt_get_handle_to_location(container, location))

/* Convenience function. */
void *ssh_adt_detach_object(SshADTContainer container,
                            void *object);

/*********************************** Deleting objects when inside container */

/* Destroy the object that ssh_adt_get(container, handle) would
   return. Invalidates the handle. */
void ssh_adt_delete(SshADTContainer container,
                    SshADTHandle handle);

#define ssh_adt_delete_from(container, location) \
ssh_adt_delete(container, ssh_adt_get_handle_to_location(container, location))

/* Convenience function. */
void ssh_adt_delete_object(SshADTContainer container,
                           void *object);

/************************************* Resizing internally allocated objects */

/* Reallocate a object inside a container. */
void *ssh_adt_realloc(SshADTContainer container, void *object,
                      size_t new_size);

/* Return the default object size. */
size_t ssh_adt_default_size(SshADTContainer container);

/********************************************* Generic enumeration functions */

/* Start enumerating a container. */
SshADTHandle ssh_adt_enumerate_start(SshADTContainer container);

/* Continue enumeration. Returns `SSH_ADT_INVALID' when all objects have been
   enumerated. */
SshADTHandle ssh_adt_enumerate_next(SshADTContainer container,
                                    SshADTHandle handle);

#include "sshadt_structs.h"
#include "sshadt_impls.h"

#undef SSHADT_INSIDE_SSHADT_H

#endif /* SSHADT_H_INCLUDED */
