252 lines
9.6 KiB
C
252 lines
9.6 KiB
C
|
|
||
|
/************************************************************************/
|
||
|
/* */
|
||
|
/* Centre for Speech Technology Research */
|
||
|
/* University of Edinburgh, UK */
|
||
|
/* Copyright (c) 1997 */
|
||
|
/* All Rights Reserved. */
|
||
|
/* */
|
||
|
/* Permission is hereby granted, free of charge, to use and distribute */
|
||
|
/* this software and its documentation without restriction, including */
|
||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||
|
/* distribute, sublicense, and/or sell copies of this work, and to */
|
||
|
/* permit persons to whom this work is furnished to do so, subject to */
|
||
|
/* the following conditions: */
|
||
|
/* 1. The code must retain the above copyright notice, this list of */
|
||
|
/* conditions and the following disclaimer. */
|
||
|
/* 2. Any modifications must be clearly marked as such. */
|
||
|
/* 3. Original authors' names are not deleted. */
|
||
|
/* 4. The authors' names are not used to endorse or promote products */
|
||
|
/* derived from this software without specific prior written */
|
||
|
/* permission. */
|
||
|
/* */
|
||
|
/* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
|
||
|
/* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
|
||
|
/* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
|
||
|
/* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
|
||
|
/* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
|
||
|
/* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
|
||
|
/* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
|
||
|
/* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
|
||
|
/* THIS SOFTWARE. */
|
||
|
/* */
|
||
|
/************************************************************************/
|
||
|
/* */
|
||
|
/* Author: Richard Caley (rjc@cstr.ed.ac.uk) */
|
||
|
/* Date: February 1997 */
|
||
|
/* -------------------------------------------------------------------- */
|
||
|
/* */
|
||
|
/* Use counted memory chunks and smart pointers to them. */
|
||
|
/* */
|
||
|
/************************************************************************/
|
||
|
|
||
|
#if ! defined(__EST_CHUNK_H__)
|
||
|
#define __EST_CHUNK_H__
|
||
|
|
||
|
#define HAVE_WALLOC_H (1)
|
||
|
|
||
|
#include <iostream>
|
||
|
using namespace std;
|
||
|
#include <climits>
|
||
|
#include <sys/types.h>
|
||
|
|
||
|
// Warn when getting a writable version of a shared chunk --
|
||
|
// useful for minimising copies.
|
||
|
|
||
|
/* #define __INCLUDE_CHUNK_WARNINGS__ (1) */
|
||
|
|
||
|
#if defined(__INCULDE_CHUNK_WARNINGS__)
|
||
|
# define CHUNK_WARN(WHAT) do { cerr << "chunk: " <<WHAT << "\n";} while (0)
|
||
|
#else
|
||
|
# define CHUNK_WARN(WHAT) // empty
|
||
|
#endif
|
||
|
|
||
|
#define __CHUNK_INLINE_AGGRESSIVELY__ (1)
|
||
|
|
||
|
#if defined(__CHUNK_INLINE_AGGRESSIVELY__)
|
||
|
# define CII(BODY) BODY
|
||
|
#else
|
||
|
# define CII(BODY) /* empty */
|
||
|
#endif
|
||
|
|
||
|
#define __CHUNK_USE_WALLOC__ (1)
|
||
|
|
||
|
#if __CHUNK_USE_WALLOC__
|
||
|
|
||
|
#if HAVE_WALLOC_H
|
||
|
|
||
|
# include "EST_walloc.h"
|
||
|
|
||
|
#else
|
||
|
|
||
|
# define walloc(T,N) ((T *)malloc(sizeof(T)*(N)))
|
||
|
# define wfree(P) free(P)
|
||
|
# define wrealloc(P,T,N) ((T *)realloc((P),sizeof(T)*(N)))
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/************************************************************************/
|
||
|
/* */
|
||
|
/* EST_Chunk is a use-counted chunk of memory. You shouldn't be able */
|
||
|
/* to do anything to it except create it and manipulate it via */
|
||
|
/* EST_ChunkPtr. The private operator::new takes a placement argument */
|
||
|
/* which is actually the number of bytes of memory in the body of the */
|
||
|
/* chunk. */
|
||
|
/* */
|
||
|
/* If the use counter overflows, it sticks. Anything with more than */
|
||
|
/* SHRT_MAX references to it is probably permanent. */
|
||
|
/* */
|
||
|
/************************************************************************/
|
||
|
|
||
|
class EST_ChunkPtr;
|
||
|
|
||
|
class EST_Chunk {
|
||
|
public:
|
||
|
typedef unsigned short use_counter;
|
||
|
# define MAX_CHUNK_COUNT (USHRT_MAX)
|
||
|
typedef int EST_chunk_size;
|
||
|
# define MAX_CHUNK_SIZE (INT_MAX)
|
||
|
|
||
|
private:
|
||
|
use_counter count;
|
||
|
EST_chunk_size size;
|
||
|
int malloc_flag; // set if this was got from malloc (rather than new)
|
||
|
char memory[1];
|
||
|
|
||
|
EST_Chunk(void);
|
||
|
~EST_Chunk();
|
||
|
|
||
|
EST_Chunk *operator & ();
|
||
|
void *operator new (size_t size, int bytes);
|
||
|
void operator delete (void *it);
|
||
|
|
||
|
void operator ++ ()
|
||
|
CII({if (count < MAX_CHUNK_COUNT) ++count; });
|
||
|
|
||
|
void operator -- ()
|
||
|
CII({if (count < MAX_CHUNK_COUNT) if (--count == 0) delete this;});
|
||
|
|
||
|
public:
|
||
|
friend class EST_ChunkPtr;
|
||
|
|
||
|
friend EST_ChunkPtr chunk_allocate(int bytes);
|
||
|
friend EST_ChunkPtr chunk_allocate(int bytes, const char *initial, int initial_len);
|
||
|
friend EST_ChunkPtr chunk_allocate(int bytes, const EST_ChunkPtr &initial, int initial_start, int initial_len);
|
||
|
|
||
|
friend void cp_make_updatable(EST_ChunkPtr &shared, EST_chunk_size inuse);
|
||
|
friend void cp_make_updatable(EST_ChunkPtr &shared);
|
||
|
|
||
|
friend void grow_chunk(EST_ChunkPtr &shared, EST_chunk_size inuse, EST_chunk_size newsize);
|
||
|
friend void grow_chunk(EST_ChunkPtr &shared, EST_chunk_size newsize);
|
||
|
|
||
|
friend ostream &operator << (ostream &s, const EST_Chunk &chp);
|
||
|
friend void tester(void);
|
||
|
};
|
||
|
|
||
|
/************************************************************************/
|
||
|
/* */
|
||
|
/* Pointers to chunks. Initialising them and assigning them around */
|
||
|
/* keeps track of use counts. We allow them to be cast to char * as a */
|
||
|
/* way of letting people work on them with standard functions, */
|
||
|
/* however it is bad voodoo to hold on to such a cast chunk for more */
|
||
|
/* than a trivial amount of time. */
|
||
|
/* */
|
||
|
/************************************************************************/
|
||
|
|
||
|
class EST_ChunkPtr {
|
||
|
private:
|
||
|
EST_Chunk *ptr;
|
||
|
|
||
|
EST_ChunkPtr(EST_Chunk *chp) CII({
|
||
|
if ((ptr=chp))
|
||
|
++ *ptr;
|
||
|
});
|
||
|
public:
|
||
|
EST_ChunkPtr(void) { ptr = (EST_Chunk *)NULL; };
|
||
|
|
||
|
EST_ChunkPtr(const EST_ChunkPtr &cp) CII({
|
||
|
ptr=cp.ptr;
|
||
|
if (ptr)
|
||
|
++ *ptr;
|
||
|
});
|
||
|
|
||
|
~EST_ChunkPtr(void) CII({ if (ptr) -- *ptr; });
|
||
|
|
||
|
int size(void) const { return ptr?ptr->size:0; };
|
||
|
int shareing(void) const { return ptr?(ptr->count >1):0; };
|
||
|
int count(void) const { return ptr?(ptr->count):-1; };
|
||
|
|
||
|
EST_ChunkPtr &operator = (EST_ChunkPtr cp) CII({
|
||
|
// doing it in this order means self assignment is safe.
|
||
|
if (cp.ptr)
|
||
|
++ *(cp.ptr);
|
||
|
if (ptr)
|
||
|
-- *ptr;
|
||
|
ptr=cp.ptr;
|
||
|
return *this;
|
||
|
});
|
||
|
|
||
|
// If they manage to get hold of one...
|
||
|
// Actually usually used to assign NULL and so (possibly) deallocate
|
||
|
// the chunk currently pointed to.
|
||
|
EST_ChunkPtr &operator = (EST_Chunk *chp) CII({
|
||
|
// doing it in this order means self assignment is safe.
|
||
|
if (chp)
|
||
|
++ *chp;
|
||
|
if (ptr)
|
||
|
-- *ptr;
|
||
|
ptr=chp;
|
||
|
return *this;
|
||
|
});
|
||
|
|
||
|
// Casting to a non-const pointer causes a
|
||
|
// warning to stderr if the chunk is shared.
|
||
|
operator char*() CII({
|
||
|
if (ptr && ptr->count > 1)
|
||
|
{
|
||
|
CHUNK_WARN("getting writable version of shared chunk\n");
|
||
|
cp_make_updatable(*this);
|
||
|
}
|
||
|
return ptr?&(ptr->memory[0]):(char *)NULL;
|
||
|
});
|
||
|
operator const char*() const CII({
|
||
|
return ptr?&(ptr->memory[0]):(const char *)NULL;
|
||
|
});
|
||
|
operator const char*() CII({
|
||
|
return ptr?&(ptr->memory[0]):(const char *)NULL;
|
||
|
});
|
||
|
|
||
|
|
||
|
const char operator [] (int i) const { return ptr->memory[i]; };
|
||
|
char &operator () (int i) CII({
|
||
|
if (ptr->count>1)
|
||
|
{
|
||
|
CHUNK_WARN("getting writable version of shared chunk\n");
|
||
|
cp_make_updatable(*this);
|
||
|
}
|
||
|
return ptr->memory[i];
|
||
|
});
|
||
|
|
||
|
// Creating a new one
|
||
|
friend EST_ChunkPtr chunk_allocate(int size);
|
||
|
friend EST_ChunkPtr chunk_allocate(int bytes, const char *initial, int initial_len);
|
||
|
friend EST_ChunkPtr chunk_allocate(int bytes, const EST_ChunkPtr &initial, int initial_start, int initial_len);
|
||
|
|
||
|
// Make sure the memory isn`t shared.
|
||
|
friend void cp_make_updatable(EST_ChunkPtr &shared, EST_Chunk::EST_chunk_size inuse);
|
||
|
friend void cp_make_updatable(EST_ChunkPtr &shared);
|
||
|
|
||
|
// Make sure there is enough room (also makes updatable)
|
||
|
friend void grow_chunk(EST_ChunkPtr &shared, EST_Chunk::EST_chunk_size inuse, EST_Chunk::EST_chunk_size newsize);
|
||
|
friend void grow_chunk(EST_ChunkPtr &shared, EST_Chunk::EST_chunk_size newsize);
|
||
|
|
||
|
// we print it by just printing the chunk
|
||
|
friend ostream &operator << (ostream &s, const EST_ChunkPtr &cp) { return (s<< *cp.ptr); };
|
||
|
|
||
|
friend void tester(void);
|
||
|
};
|
||
|
|
||
|
#endif
|