#ifndef Smem_includeD
#define Smem_includeD


/* compile time adjustable parameters : */

/* if not defined, flat malloc() and free() is used */
#define Smem_own_functionS
#ifdef Smem_no_own_functionS
#undef Smem_own_functionS
#endif /* Smem_no_own_functionS */

/* if not defined, the record items will be smaller by 8 byte
   but deletion of items may be much slower */
#define Smem_with_hasH



struct SmemiteM {

 char *data;
 size_t size;

 struct SmemiteM *prev,*next;

 struct SmemiteM *hash_prev,*hash_next;

};




#ifdef Smem_own_functionS

char *Smem_malloc();
int Smem_free();

#define TSOB_FELD(typ,anz) (typ *) Smem_malloc((anz)*sizeof(typ));
#define Smem_malloC Smem_malloc
#define Smem_freE Smem_free

#else /* Smem_own_functionS */

#define TSOB_FELD(typ,anz) (typ *) malloc((anz)*sizeof(typ));
#define Smem_malloC malloc
#define Smem_freE free

#endif /* ! Smem_own_functionS */

int Smem_set_record_items();
int Smem_stderr();
int Smem_clone_string();


#define Smem_hashsizE 251
#define Smem_hashshifT 8

#ifdef Smem_included_by_smem_C

double Smem_malloc_counT= 0.0;
double Smem_free_counT= 0.0;
double Smem_pending_counT= 0.0;
struct SmemiteM *Smem_start_iteM= NULL;
struct SmemiteM *Smem_hasH[Smem_hashsizE];
double Smem_hash_counteR[Smem_hashsizE];

/* these both init values are essential, since setting Smem_record_itemS=1
   by use of Smem_set_record_items() initializes the hash array
   (i do not really trust the compiler producers to have read K&R) */
int Smem_hash_initializeD= 0;
int Smem_record_itemS= 0;

double Smem_record_counT= 0.0;
double Smem_record_byteS= 0.0;

#else /* Smem_included_by_smem_C */

extern double Smem_malloc_counT;
extern double Smem_free_counT;
extern double Smem_pending_counT;
extern struct SmemiteM *Smem_start_iteM;
extern struct SmemiteM *Smem_hasH[Smem_hashsizE];
extern double Smem_hash_counteR[Smem_hashsizE];
extern int Smem_hash_initializeD;
extern int Smem_record_itemS;
extern double Smem_record_counT;
extern double Smem_record_byteS;

#endif /* ! Smem_included_by_smem_C */



#endif /* ! Smem_includeD */


/*

                                   smem

 Functions to replace  malloc()  and  free() in order to get more control
 over memory leaks or spurious errors caused by faulty usage of malloc()
 and free(). 


 Sourcecode provisions:
 
 Use only the following macros for memory management:
    TSOB_FELD(type,count)  creates an array of items of given type 
    Smem_malloC()          analogue of malloc()
    Smem_freE()            analogue of free()
 One may #define malloc Smem_malloC resp. #define free Smem_freE 
 but better would be to review (and often to streamline) the sourcecode
 in respect to those two functions. 


 Speed versus control:

 In production versions, where maximum speed is required, one may undefine
 the macro  Smem_own_functionS  in  smem.h . 
 This causes the above macros to directly invoke malloc() and free() without
 any speed reduction (and without any additional use).
 Undefinitio can be done globaly by modifying smem.h or locally by defining
  Smem_no_own_functionS  before including smem.h .

 If Smem_own_functionS remains defined, then the functions
   Smem_malloc() 
   Smem_free()
 are used rather than malloc() and free().
 They count the number of calls to maintain a rough overview of memory usage.
 Smem_malloc() additionally checks for 0 size and Smem_free() checks for
 NULL pointers, which they both report to stderr. Eventually one should set
 a breakpoint in function Smem_protest() to learn about the origin of such
 messages.
 A status line may be obtained by  Smem_report()  or printed by Smem_stderr().

 As long as the variable Smem_record_itemS is set to 0, there is not very much
 overhead compared with malloc() and free().
 If the variable is set to 1 by Smem_set_record_items() then all malloc()
 results are kept in a list where they will be deleted by their corresponding
 Smem_free() calls. If a pointer is to be freed, which is not recorded in the
 list then an error message will be printed to stderr. The memory will not
 be freed !
 This mode not only may be very slow, it also consumes at least 16 byte per
 piece of data which was obtained by malloc as long as it has not been freed.
 Due to the current nature of the list, large numbers of memory items are freed
 much faster in the reverse order of their creation. If there is a list of
 100000 strings to delete, it is very rewarding to free the youngest ones first.
 A shortcut via hashing is available but consumes 24 bytes rather than 16.
 (see above  Smem_with_hasH  )

 The function Smem_is_recorded() can be used to check wether a pointer is
 valid according to the list. It returns :
   0 = is not in list , 1 = is in list , 2 = recording is off 

 If one decides to start recording malloc() results in the midst of a program
 run, one has to be aware of false protests of Smem_free() if a memory piece
 has been allocated before recording started. This will also cause those pieces
 to be memory leaks because Smem_free() refuses to delete them. (Freeing memory
 that was not obtained by malloc or was already freed previously can result in
 deferred SIGSEGV or similar trouble, depending on OS and library.)
 Also in that case one should stop recording before ending the program, to
 avoid a lot of false complaints about longliving memory objects.    

*/