MPQC 2.3.1

- Main Page
- Related Pages
- Classes
- Files

- File List

ref.h
1 //
2 // ref.h --- definitions of the reference counting classes
3 //
4 // Copyright (C) 1996 Limit Point Systems, Inc.
5 //
6 // Author: Curtis Janssen <cljanss@limitpt.com>
7 // Maintainer: LPS
8 //
9 // This file is part of the SC Toolkit.
10 //
11 // The SC Toolkit is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU Library General Public License as published by
13 // the Free Software Foundation; either version 2, or (at your option)
14 // any later version.
15 //
16 // The SC Toolkit is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU Library General Public License for more details.
20 //
21 // You should have received a copy of the GNU Library General Public License
22 // along with the SC Toolkit; see the file COPYING.LIB. If not, write to
23 // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 //
25 // The U.S. Government is granted a limited license as per AL 91-7.
26 //
27
28 // This is the main include file for the reference counting classes.
29 // This includes two other files: reftmpl.h and refmacr.h. The
30 // former is a template declaration for the reference counted classes
31 // and the latter is generated from the former by a perl script and
32 // provides CPP macros that declare reference counting classes.
33 //
34 // The behaviour of the package can be modified with the following five
35 // macros, each of which should be undefined, 0, or 1:
36 //
37 // REF_CHECK_STACK: If this is 1 referenced objects are checked to see if they
38 // reside on the stack, in which case storage for the object is not managed,
39 // if management is enabled. This feature can be confused by multiple threads
40 // and memory checking libraries.
41 //
42 // REF_MANAGE: If this is 1 the manage and unmanage members are enabled.
43 //
44 // REF_CHECK_MAX_NREF: If this is 1 the reference count is checked before
45 // it is incremented to make sure it isn't too big.
46 //
47 // REF_CHECK_MIN_NREF: If this is 1 the reference count is checked before
48 // it is decremented to make sure it isn't already zero.
49 //
50 // REF_USE_LOCKS: If this is 1 then critical regions are locked before they
51 // are entered. This prevents erroneous behavior when multiple threads
52 // share reference counted objects. This will slow down certain operations,
53 // so it should be set to 0 if your application does not need to be thread
54 // safe.
55 //
56 // If a macro is undefined, then the behaviour is architecture
57 // dependent--usually, the macro will be set to 1 in this case.
58 // For maximum efficiency and for normal operation after the program is
59 // debugged, compile with all of the above macros defined to zero.
60 // This can also be done with -DREF_OPTIMIZE.
61 //
62 // An include file can be used to set these options as well. This has
63 // the advantage that dependency checking will force an automatic
64 // recompile of all affected files if the options change. The file
65 // <scconfig.h> will be include if -DHAVE_CONFIG_H is specified.
66 //
67 // Note that all source code that uses references must be compiled with
68 // the same value REF_MANAGE. Changing this can change the storage layout
69 // and the interpretation of the reference count data.
70
71
72 #ifdef __GNUC__
73 #pragma interface
74 #endif
75
76 #ifndef _util_ref_ref_h
77 #define _util_ref_ref_h
78
79 #include <iostream>
80 #include <stdlib.h>
81 #include <limits.h>
82
83 #include <util/ref/identity.h>
84
85 #ifdef HAVE_CONFIG_H
86 #include <scconfig.h>
87 #endif
88
89 #ifdef REF_OPTIMIZE
90 #ifndef REF_CHECK_STACK
91 # define REF_CHECK_STACK 0
92 #endif
93 #ifndef REF_MANAGE
94 # define REF_MANAGE 0
95 #endif
96 #ifndef REF_CHECK_MAX_NREF
97 # define REF_CHECK_MAX_NREF 0
98 #endif
99 #ifndef REF_CHECK_MIN_NREF
100 # define REF_CHECK_MIN_NREF 0
101 #endif
102 #endif
103
104 #ifdef SUNMOS
105 #ifndef REF_CHECK_STACK
106 #define REF_CHECK_STACK 0
107 #endif
108 #else
109 #ifndef REF_CHECK_STACK
110 #define REF_CHECK_STACK 0
111 #endif
112 #endif
113
114 #ifndef REF_MANAGE
115 #define REF_MANAGE 1
116 #endif
117
118 #ifndef REF_CHECK_MAX_NREF
119 #define REF_CHECK_MAX_NREF 1
120 #endif
121
122 #ifndef REF_CHECK_MIN_NREF
123 #define REF_CHECK_MIN_NREF 1
124 #endif
125
126 #ifndef REF_USE_LOCKS
127 # if HAVE_STHREAD || HAVE_CREATETHREAD || HAVE_PTHREAD
128 # define REF_USE_LOCKS 1
129 # endif
130 #endif
131
132 #ifndef REF_ALWAYS_USE_LOCKS
133 # define REF_ALWAYS_USE_LOCKS 1
134 #endif
135
136 #if REF_CHECK_STACK
137 #include <unistd.h>
138 #ifndef HAVE_SBRK_DEC
139 extern "C" void * sbrk(ssize_t);
140 #endif
141 #define DO_REF_CHECK_STACK(p) (((void*) (p) > sbrk(0)) && (p)->managed())
142 #else // REF_CHECK_STACK
143 #define DO_REF_CHECK_STACK(p) (0)
144 #endif // REF_CHECK_STACK
145
146 #if REF_MANAGE
147 #define DO_REF_UNMANAGE(p) ((p)->unmanage())
148 #else // REF_MANAGE
149 #define DO_REF_UNMANAGE(p)
150 #endif // REF_MANAGE
151
152 #if REF_USE_LOCKS
153 #define __REF_LOCK__(p) p->lock_ptr()
154 #define __REF_UNLOCK__(p) p->unlock_ptr()
155 #if REF_ALWAYS_USE_LOCKS
156 #define __REF_INITLOCK__() use_locks(true)
157 #else
158 #define __REF_INITLOCK__() ref_lock_ = 0xff
159 #endif
160 #else
161 #define __REF_LOCK__(p)
162 #define __REF_UNLOCK__(p)
163 #define __REF_INITLOCK__()
164 #endif
165
166 namespace sc {
167
168 typedef unsigned long refcount_t;
169
194 class RefCount: public Identity {
195 private:
196 #if REF_MANAGE
197 # define REF_MAX_NREF (UINT_MAX - 1)
198 # define REF_MANAGED_CODE UINT_MAX
199 #else
200 # define REF_MAX_NREF UINT_MAX
201 #endif
202 unsigned int _reference_count_;
203 #if REF_USE_LOCKS
204 unsigned char ref_lock_;
205 #endif
206
207 void error(const char*) const;
208 void too_many_refs() const;
209 void not_enough_refs() const;
210 protected:
211 RefCount(): _reference_count_(0) {
212 __REF_INITLOCK__();
213 //std::cout << "ref_lock_ = " << (int) ref_lock_ << std::endl;
214 }
215 RefCount(const RefCount&): _reference_count_(0) {
216 __REF_INITLOCK__();
217 //std::cout << "ref_lock_ = " << (int) ref_lock_ << std::endl;
218 }
219
220 // Assigment should not overwrite the reference count.
221 RefCount& operator=(const RefCount&) { return *this; }
222 public:
223 virtual ~RefCount();
224
226 int lock_ptr() const;
228 int unlock_ptr() const;
229
231 void use_locks(bool inVal);
232
234 refcount_t nreference() const {
235 # if REF_MANAGE
236 if (!managed()) return 1;
237 # endif
238 return _reference_count_;
239 }
240
242 refcount_t reference() {
243 # if REF_MANAGE
244 if (!managed()) return 1;
245 # endif
246 __REF_LOCK__(this);
247 # if REF_CHECK_MAX_NREF
248 if (_reference_count_ >= REF_MAX_NREF) too_many_refs();
249 # endif
250 _reference_count_++;
251 refcount_t r = _reference_count_;
252 __REF_UNLOCK__(this);
253 return r;
254 }
255
257 refcount_t dereference() {
258 # if REF_MANAGE
259 if (!managed()) return 1;
260 # endif
261 __REF_LOCK__(this);
262 # if REF_CHECK_MIN_NREF
263 if (_reference_count_ == 0) not_enough_refs();
264 # endif
265 _reference_count_--;
266 refcount_t r = _reference_count_;
267 __REF_UNLOCK__(this);
268 return r;
269 }
270
271 #if REF_MANAGE
272 int managed() const {
273 return _reference_count_ != REF_MANAGED_CODE;
274 }
280 void unmanage() {
281 _reference_count_ = REF_MANAGED_CODE;
282 }
283 #else // REF_MANAGE
284
285 int managed() const { return 1; }
286 #endif // REF_MANAGE
287 };
288
292 class RefBase {
293 protected:
295 void warn ( const char * msg) const;
297 void warn_ref_to_stack() const;
299 void warn_skip_stack_delete() const;
301 void warn_bad_ref_count() const;
303 void ref_info(RefCount*p,std::ostream& os) const;
304 void ref_info(std::ostream& os) const;
305 void check_pointer() const;
306 void reference(RefCount *);
307 int dereference(RefCount *);
308 public:
309 RefBase() {};
310 virtual ~RefBase();
312 virtual RefCount* parentpointer() const = 0;
315 void require_nonnull() const;
316 };
317
331 template <class T>
332 class Ref : public RefBase {
333 private:
334 T* p;
335 public:
337 Ref(): p(0) {}
339 Ref(T*a) : p(0)
340 {
341 if (a) {
342 p = a;
343 reference(p);
344 }
345 }
347 Ref(const Ref<T> &a) : p(0)
348 {
349 if (a.pointer()) {
350 p = a.pointer();
351 reference(p);
352 }
353 }
355 template <class A> Ref(const Ref<A> &a): p(0)
356 {
357 if (a.pointer()) {
358 p = a.pointer();
359 reference(p);
360 }
361 }
362 // /** Create a reference to the object a. Do a
363 // dynamic_cast to convert a to the appropiate type. */
364 // Ref(const RefBase&a) {
365 // p = dynamic_cast<T*>(a.parentpointer());
366 // reference(p);
367 // }
368 // /** Create a reference to the object a. Do a
369 // dynamic_cast to convert a to the appropiate type. */
370 // Ref(RefCount*a): p(0) {
371 // operator<<(a);
372 // }
375 ~Ref()
376 {
377 clear();
378 }
381 T* operator->() const { return p; }
383 T* pointer() const { return p; }
385 RefCount *parentpointer() const { return p; }
386
387 operator T*() const { return p; }
390 T& operator *() const { return *p; };
393 int null() const { return p == 0; }
395 int nonnull() const { return p != 0; }
398 template <class A> int operator==(const Ref<A>&a) const
399 { return eq(p,a.pointer()); }
400 template <class A> int operator>=(const Ref<A>&a) const
401 { return ge(p,a.pointer()); }
402 template <class A> int operator<=(const Ref<A>&a) const
403 { return le(p,a.pointer()); }
404 template <class A> int operator>(const Ref<A>&a) const
405 { return gt(p,a.pointer()); }
406 template <class A> int operator<(const Ref<A>&a) const
407 { return lt(p,a.pointer()); }
408 template <class A> int operator!=(const Ref<A>&a) const
409 { return ne(p,a.pointer()); }
412 int compare(const Ref<T> &a) const {
413 return eq(p,a.p)?0:((lt(p,a.p)?-1:1));
414 }
416 void clear()
417 {
418 if (p) {
419 int ref = dereference(p);
420 if (ref == 0)
421 delete p;
422 p = 0;
423 }
424 }
426 Ref<T>& operator=(const Ref<T> & c)
427 {
428 T *cp = c.pointer();
429 if (cp) {
430 cp->reference();
431 clear();
432 p=cp;
433 }
434 else {
435 clear();
436 }
437 return *this;
438 }
440 template <class A> Ref<T>& operator=(const Ref<A> & c)
441 {
442 A *cp = c.pointer();
443 if (cp) {
444 cp->reference();
445 clear();
446 p=cp;
447 }
448 else {
449 clear();
450 }
451 return *this;
452 }
454 Ref<T>& operator<<(const RefBase&a) {
455 T* cr = dynamic_cast<T*>(a.parentpointer());
456 if (cr) {
457 reference(cr);
458 clear();
459 }
460 p = cr;
461 return *this;
462 }
466 Ref<T>& operator<<(RefCount *a) {
467 T* cr = dynamic_cast<T*>(a);
468 if (cr) assign_pointer(cr);
469 else if (a && a->nreference() <= 0) delete a;
470 return *this;
471 }
473 Ref<T>& operator=(T* cr)
474 {
475 assign_pointer(cr);
476 return *this;
477 }
479 void assign_pointer(T* cr)
480 {
481 if (cr) {
482 if (DO_REF_CHECK_STACK(cr)) {
483 DO_REF_UNMANAGE(cr);
484 warn_ref_to_stack();
485 }
486 cr->reference();
487 }
488 clear();
489 p = cr;
490 }
492 void check_pointer() const
493 {
494 if (p && p->nreference() <= 0) {
495 warn_bad_ref_count();
496 }
497 }
499 void ref_info(std::ostream& os) const
500 {
501 RefBase::ref_info(p,os);
502 }
504 void warn(const char*s) const { RefBase::warn(s); }
505 };
506
507 }
508
509 #endif
510
511 // ///////////////////////////////////////////////////////////////////////////
512
513 // Local Variables:
514 // mode: c++
515 // c-file-style: "CLJ"
516 // End: