blitz  Version 0.9
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
memblock.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 /***************************************************************************
3  * blitz/memblock.h MemoryBlock<T> and MemoryBlockReference<T>
4  *
5  * $Id: memblock.h,v 1.18 2005/10/11 21:54:57 julianc Exp $
6  *
7  * Copyright (C) 1997-1999 Todd Veldhuizen <tveldhui@oonumerics.org>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * Suggestions: blitz-dev@oonumerics.org
20  * Bugs: blitz-bugs@oonumerics.org
21  *
22  * For more information, please see the Blitz++ Home Page:
23  * http://oonumerics.org/blitz/
24  *
25  ***************************************************************************/
26 
27 #ifndef BZ_MEMBLOCK_H
28 #define BZ_MEMBLOCK_H
29 
30 #include <blitz/blitz.h>
31 
32 #include <stddef.h> // ptrdiff_t
33 
34 #ifdef BZ_THREADSAFE
35  #include <pthread.h>
36 #endif
37 
38 BZ_NAMESPACE(blitz)
39 
44 };
45 
46 // Forward declaration of MemoryBlockReference
47 template<typename T_type> class MemoryBlockReference;
48 
49 // Class MemoryBlock provides a reference-counted block of memory. This block
50 // may be referred to by multiple vector, matrix and array objects. The memory
51 // is automatically deallocated when the last referring object is destructed.
52 // MemoryBlock may be subclassed to provide special allocators.
53 template<typename P_type>
54 class MemoryBlock {
55 
56  friend class MemoryBlockReference<P_type>;
57 
58 public:
59  typedef P_type T_type;
60 
61 protected:
63  {
64  length_ = 0;
65  data_ = 0;
67  references_ = 0;
68 
69  BZ_MUTEX_INIT(mutex)
70  }
71 
72  explicit MemoryBlock(size_t items)
73  {
74  length_ = items;
76 
77 #ifdef BZ_DEBUG_LOG_ALLOCATIONS
78  cout << "MemoryBlock: allocated " << setw(8) << length_
79  << " at " << ((void *)dataBlockAddress_) << endl;
80 #endif
81 
82  BZASSERT(dataBlockAddress_ != 0);
83 
84  references_ = 0;
85 
86  BZ_MUTEX_INIT(mutex)
87  }
88 
90  {
91  length_ = length;
92  data_ = data;
94  references_ = 0;
95  BZ_MUTEX_INIT(mutex)
96  }
97 
98  virtual ~MemoryBlock()
99  {
100  if (dataBlockAddress_)
101  {
102 
103 #ifdef BZ_DEBUG_LOG_ALLOCATIONS
104  cout << "MemoryBlock: freed " << setw(8) << length_
105  << " at " << ((void *)dataBlockAddress_) << endl;
106 #endif
107 
108  deallocate();
109  }
110 
111  BZ_MUTEX_DESTROY(mutex)
112  }
113 
115  {
116  BZ_MUTEX_LOCK(mutex)
117  ++references_;
118 
119 #ifdef BZ_DEBUG_LOG_REFERENCES
120  cout << "MemoryBlock: reffed " << setw(8) << length_
121  << " at " << ((void *)dataBlockAddress_) << " (r="
122  << (int)references_ << ")" << endl;
123 #endif
124  BZ_MUTEX_UNLOCK(mutex)
125 
126  }
127 
129  {
130  return data_;
131  }
132 
133  const T_type* restrict data() const
134  {
135  return data_;
136  }
137 
139  {
140  return dataBlockAddress_;
141  }
142 
143  size_t length() const
144  {
145  return length_;
146  }
147 
149  {
150 
151  BZ_MUTEX_LOCK(mutex)
152  int refcount = --references_;
153 
154 #ifdef BZ_DEBUG_LOG_REFERENCES
155  cout << "MemoryBlock: dereffed " << setw(8) << length_
156  << " at " << ((void *)dataBlockAddress_) << " (r=" << (int)references_
157  << ")" << endl;
158 #endif
159  BZ_MUTEX_UNLOCK(mutex)
160  return refcount;
161  }
162 
163  int references() const
164  {
165  BZ_MUTEX_LOCK(mutex)
166  int refcount = references_;
167  BZ_MUTEX_UNLOCK(mutex)
168 
169  return refcount;
170  }
171 
172 protected:
173  inline void allocate(size_t length);
174  void deallocate();
175 
176 private: // Disabled member functions
178  { }
179 
181  { }
182 
183 private: // Data members
186 
187 #ifdef BZ_DEBUG_REFERENCE_ROLLOVER
188  volatile unsigned char references_;
189 #else
190  volatile int references_;
191 #endif
192 
193  BZ_MUTEX_DECLARE(mutex)
194  size_t length_;
195 };
196 
197 template<typename P_type>
198 class UnownedMemoryBlock : public MemoryBlock<P_type> {
199 public:
200  UnownedMemoryBlock(size_t length, P_type* data)
201  : MemoryBlock<P_type>(length,data)
202  {
203  // This ensures that MemoryBlock destructor will not
204  // attempt to delete data
206  }
207 
209  {
210  }
211 };
212 
213 template<typename P_type>
214 class NullMemoryBlock : public MemoryBlock<P_type> {
215 public:
217  {
218  // This ensures that the delete operator will not be invoked
219  // on an instance of NullMemoryBlock in removeReference().
221  }
222 
223  virtual ~NullMemoryBlock()
224  { }
225 };
226 
227 template<typename P_type>
229 
230 public:
231  typedef P_type T_type;
232 
233 protected:
235 
236 private:
239 
240 public:
241 
243  {
244  block_ = &nullBlock_;
245  block_->addReference();
246  data_ = 0;
247  }
248 
250  {
251  block_ = ref.block_;
252  block_->addReference();
253  data_ = ref.data_ + offset;
254  }
255 
257  preexistingMemoryPolicy deletionPolicy)
258  {
259  // Create a memory block using already allocated memory.
260 
261  // Note: if the deletionPolicy is duplicateData, this must
262  // be handled by the leaf class. In MemoryBlockReference,
263  // this is treated as neverDeleteData; the leaf class (e.g. Array)
264  // must duplicate the data.
265 
266  if ((deletionPolicy == neverDeleteData)
267  || (deletionPolicy == duplicateData))
268  block_ = new UnownedMemoryBlock<T_type>(length, data);
269  else if (deletionPolicy == deleteDataWhenDone)
270  block_ = new MemoryBlock<T_type>(length, data);
271  block_->addReference();
272 
273 #ifdef BZ_DEBUG_LOG_ALLOCATIONS
274  cout << "MemoryBlockReference: created MemoryBlock at "
275  << ((void*)block_) << endl;
276 #endif
277 
278  data_ = data;
279  }
280 
281  explicit MemoryBlockReference(size_t items)
282  {
283  block_ = new MemoryBlock<T_type>(items);
284  block_->addReference();
285  data_ = block_->data();
286 
287 #ifdef BZ_DEBUG_LOG_ALLOCATIONS
288  cout << "MemoryBlockReference: created MemoryBlock at "
289  << ((void*)block_) << endl;
290 #endif
291 
292  }
293 
294  void blockRemoveReference()
295  {
296  int refcount = block_->removeReference();
297  if ((refcount == 0) && (block_ != &nullBlock_))
298  {
299 #ifdef BZ_DEBUG_LOG_ALLOCATIONS
300  cout << "MemoryBlock: no more refs, delete MemoryBlock object at "
301  << ((void*)block_) << endl;
302 #endif
303 
304  delete block_;
305  }
306  }
307 
309  {
310  blockRemoveReference();
311  }
312 
313  int numReferences() const
314  {
315  return block_->references();
316  }
317 
318 
319 protected:
320 
321  void changeToNullBlock()
322  {
323  blockRemoveReference();
324  block_ = &nullBlock_;
325  block_->addReference();
326  data_ = 0;
327  }
328 
329  void changeBlock(MemoryBlockReference<T_type>& ref, size_t offset=0)
330  {
331  blockRemoveReference();
332  block_ = ref.block_;
333  block_->addReference();
334  data_ = ref.data_ + offset;
335  }
336 
337  void newBlock(size_t items)
338  {
339  blockRemoveReference();
340  block_ = new MemoryBlock<T_type>(items);
341  block_->addReference();
342  data_ = block_->data();
343 
344 #ifdef BZ_DEBUG_LOG_ALLOCATIONS
345  cout << "MemoryBlockReference: created MemoryBlock at "
346  << ((void*)block_) << endl;
347 #endif
348  }
349 
350 private:
352  { }
353 };
354 
355 
357 
358 #include <blitz/memblock.cc>
359 
360 #endif // BZ_MEMBLOCK_H