Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
EST_Chunk.h
1 
2  /************************************************************************/
3  /* */
4  /* Centre for Speech Technology Research */
5  /* University of Edinburgh, UK */
6  /* Copyright (c) 1997 */
7  /* All Rights Reserved. */
8  /* */
9  /* Permission is hereby granted, free of charge, to use and distribute */
10  /* this software and its documentation without restriction, including */
11  /* without limitation the rights to use, copy, modify, merge, publish, */
12  /* distribute, sublicense, and/or sell copies of this work, and to */
13  /* permit persons to whom this work is furnished to do so, subject to */
14  /* the following conditions: */
15  /* 1. The code must retain the above copyright notice, this list of */
16  /* conditions and the following disclaimer. */
17  /* 2. Any modifications must be clearly marked as such. */
18  /* 3. Original authors' names are not deleted. */
19  /* 4. The authors' names are not used to endorse or promote products */
20  /* derived from this software without specific prior written */
21  /* permission. */
22  /* */
23  /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
24  /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
25  /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
26  /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
27  /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
28  /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
29  /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
30  /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
31  /* THIS SOFTWARE. */
32  /* */
33  /************************************************************************/
34  /* */
35  /* Author: Richard Caley (rjc@cstr.ed.ac.uk) */
36  /* Date: February 1997 */
37  /* -------------------------------------------------------------------- */
38  /* */
39  /* Use counted memory chunks and smart pointers to them. */
40  /* */
41  /************************************************************************/
42 
43 #if ! defined(__EST_CHUNK_H__)
44 #define __EST_CHUNK_H__
45 
46 #define HAVE_WALLOC_H (1)
47 
48 #include <iostream>
49 using namespace std;
50 #include <climits>
51 #include <sys/types.h>
52 
53 // Warn when getting a writable version of a shared chunk --
54 // useful for minimising copies.
55 
56 /* #define __INCLUDE_CHUNK_WARNINGS__ (1) */
57 
58 #if defined(__INCULDE_CHUNK_WARNINGS__)
59 # define CHUNK_WARN(WHAT) do { cerr << "chunk: " <<WHAT << "\n";} while (0)
60 #else
61 # define CHUNK_WARN(WHAT) // empty
62 #endif
63 
64 #define __CHUNK_INLINE_AGGRESSIVELY__ (1)
65 
66 #if defined(__CHUNK_INLINE_AGGRESSIVELY__)
67 # define CII(BODY) BODY
68 #else
69 # define CII(BODY) /* empty */
70 #endif
71 
72 #define __CHUNK_USE_WALLOC__ (1)
73 
74 #if __CHUNK_USE_WALLOC__
75 
76 #if HAVE_WALLOC_H
77 
78 # include "EST_walloc.h"
79 
80 #else
81 
82 # define walloc(T,N) ((T *)malloc(sizeof(T)*(N)))
83 # define wfree(P) free(P)
84 # define wrealloc(P,T,N) ((T *)realloc((P),sizeof(T)*(N)))
85 
86 #endif
87 
88 #endif
89 
90  /************************************************************************/
91  /* */
92  /* EST_Chunk is a use-counted chunk of memory. You shouldn't be able */
93  /* to do anything to it except create it and manipulate it via */
94  /* EST_ChunkPtr. The private operator::new takes a placement argument */
95  /* which is actually the number of bytes of memory in the body of the */
96  /* chunk. */
97  /* */
98  /* If the use counter overflows, it sticks. Anything with more than */
99  /* SHRT_MAX references to it is probably permanent. */
100  /* */
101  /************************************************************************/
102 
103 class EST_ChunkPtr;
104 
105 class EST_Chunk {
106  public:
107  typedef unsigned short use_counter;
108 # define MAX_CHUNK_COUNT (USHRT_MAX)
109  typedef int EST_chunk_size;
110 # define MAX_CHUNK_SIZE (INT_MAX)
111 
112  private:
113  use_counter count;
114  EST_chunk_size size;
115  int malloc_flag; // set if this was got from malloc (rather than new)
116  char memory[1];
117 
118  EST_Chunk(void);
119  ~EST_Chunk();
120 
121  EST_Chunk *operator & ();
122  void *operator new (size_t size, int bytes);
123  void operator delete (void *it);
124 
125  void operator ++ ()
126  CII({if (count < MAX_CHUNK_COUNT) ++count; });
127 
128  void operator -- ()
129  CII({if (count < MAX_CHUNK_COUNT) if (--count == 0) delete this;});
130 
131  public:
132  friend class EST_ChunkPtr;
133 
134  friend EST_ChunkPtr chunk_allocate(int bytes);
135  friend EST_ChunkPtr chunk_allocate(int bytes, const char *initial, int initial_len);
136  friend EST_ChunkPtr chunk_allocate(int bytes, const EST_ChunkPtr &initial, int initial_start, int initial_len);
137 
138  friend void cp_make_updatable(EST_ChunkPtr &shared, EST_chunk_size inuse);
139  friend void cp_make_updatable(EST_ChunkPtr &shared);
140 
141  friend void grow_chunk(EST_ChunkPtr &shared, EST_chunk_size inuse, EST_chunk_size newsize);
142  friend void grow_chunk(EST_ChunkPtr &shared, EST_chunk_size newsize);
143 
144  friend ostream &operator << (ostream &s, const EST_Chunk &chp);
145  friend void tester(void);
146 };
147 
148  /************************************************************************/
149  /* */
150  /* Pointers to chunks. Initialising them and assigning them around */
151  /* keeps track of use counts. We allow them to be cast to char * as a */
152  /* way of letting people work on them with standard functions, */
153  /* however it is bad voodoo to hold on to such a cast chunk for more */
154  /* than a trivial amount of time. */
155  /* */
156  /************************************************************************/
157 
159  private:
160  EST_Chunk *ptr;
161 
162  EST_ChunkPtr(EST_Chunk *chp) CII({
163  if ((ptr=chp))
164  ++ *ptr;
165  });
166  public:
167  EST_ChunkPtr(void) { ptr = (EST_Chunk *)NULL; };
168 
169  EST_ChunkPtr(const EST_ChunkPtr &cp) CII({
170  ptr=cp.ptr;
171  if (ptr)
172  ++ *ptr;
173  });
174 
175  ~EST_ChunkPtr(void) CII({ if (ptr) -- *ptr; });
176 
177  int size(void) const { return ptr?ptr->size:0; };
178  int shareing(void) const { return ptr?(ptr->count >1):0; };
179  int count(void) const { return ptr?(ptr->count):-1; };
180 
181  EST_ChunkPtr &operator = (EST_ChunkPtr cp) CII({
182  // doing it in this order means self assignment is safe.
183  if (cp.ptr)
184  ++ *(cp.ptr);
185  if (ptr)
186  -- *ptr;
187  ptr=cp.ptr;
188  return *this;
189  });
190 
191  // If they manage to get hold of one...
192  // Actually usually used to assign NULL and so (possibly) deallocate
193  // the chunk currently pointed to.
194  EST_ChunkPtr &operator = (EST_Chunk *chp) CII({
195  // doing it in this order means self assignment is safe.
196  if (chp)
197  ++ *chp;
198  if (ptr)
199  -- *ptr;
200  ptr=chp;
201  return *this;
202  });
203 
204  // Casting to a non-const pointer causes a
205  // warning to stderr if the chunk is shared.
206  operator char*() CII({
207  if (ptr && ptr->count > 1)
208  {
209  CHUNK_WARN("getting writable version of shared chunk\n");
210  cp_make_updatable(*this);
211  }
212  return ptr?&(ptr->memory[0]):(char *)NULL;
213  });
214  operator const char*() const CII({
215  return ptr?&(ptr->memory[0]):(const char *)NULL;
216  });
217  operator const char*() CII({
218  return ptr?&(ptr->memory[0]):(const char *)NULL;
219  });
220 
221 
222  const char operator [] (int i) const { return ptr->memory[i]; };
223  char &operator () (int i) CII({
224  if (ptr->count>1)
225  {
226  CHUNK_WARN("getting writable version of shared chunk\n");
227  cp_make_updatable(*this);
228  }
229  return ptr->memory[i];
230  });
231 
232  // Creating a new one
233  friend EST_ChunkPtr chunk_allocate(int size);
234  friend EST_ChunkPtr chunk_allocate(int bytes, const char *initial, int initial_len);
235  friend EST_ChunkPtr chunk_allocate(int bytes, const EST_ChunkPtr &initial, int initial_start, int initial_len);
236 
237  // Make sure the memory isn`t shared.
238  friend void cp_make_updatable(EST_ChunkPtr &shared, EST_Chunk::EST_chunk_size inuse);
239  friend void cp_make_updatable(EST_ChunkPtr &shared);
240 
241  // Make sure there is enough room (also makes updatable)
242  friend void grow_chunk(EST_ChunkPtr &shared, EST_Chunk::EST_chunk_size inuse, EST_Chunk::EST_chunk_size newsize);
243  friend void grow_chunk(EST_ChunkPtr &shared, EST_Chunk::EST_chunk_size newsize);
244 
245  // we print it by just printing the chunk
246  friend ostream &operator << (ostream &s, const EST_ChunkPtr &cp) { return (s<< *cp.ptr); };
247 
248  friend void tester(void);
249 };
250 
251 #endif