00001 // Copyright (C) 2001--2002 Petter Urkedal
00002 //
00003 // This file is free software; you can redistribute it and/or modify
00004 // it under the terms of the GNU General Public License as published by
00005 // the Free Software Foundation; either version 2 of the License, or
00006 // (at your option) any later version.
00007 //
00008 // This file is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00011 // GNU General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU General Public License
00014 // along with this program; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00016 //
00017 // As a special exception, you may use this file as part of a free
00018 // software library without restriction. Specifically, if other files
00019 // instantiate templates or use macros or inline functions from this
00020 // file, or you compile this file and link it with other files to
00021 // produce an executable, this file does not by itself cause the
00022 // resulting executable to be covered by the GNU General Public
00023 // License. This exception does not however invalidate any other
00024 // reasons why the executable file might be covered by the GNU General
00025 // Public License.
00026 //
00027 // $Id: memory.h,v 1.2 2002/08/24 13:58:27 petter_urkedal Exp $
00028
00029
00030 #ifndef MORE_GEN_MEMORY_H
00031 #define MORE_GEN_MEMORY_H
00032
00033 #include <memory>
00034 #include <stdexcept>
00035 #include <more/bits/config.h>
00036 #if HAVE_BDWGC
00037 # include <bdwgc/gc.h>
00038 # include <bdwgc/gc_cpp.h>
00039 # include <limits>
00040 #endif
00041
00042 namespace more {
00043 namespace gen {
00044
00045 /** \class bad_deref memory.h more/gen/memory.h
00046 **
00047 ** Exception when an invalid dereferece is detected. */
00048 struct bad_deref
00049 : std::exception
00050 {
00051 explicit bad_deref(char const* str = 0) throw() : m_what(str) {}
00052 virtual char const* what() const throw();
00053 virtual ~bad_deref() throw();
00054 private:
00055 char const* m_what;
00056 };
00057
00058 /** \class allocator memory.h more/gen/memory.h
00059 **
00060 ** An allocator which supports default construction without
00061 ** copying. This is a trivial extension of the STL container. */
00062 template<typename T>
00063 struct allocator : ::std::allocator<T>
00064 {
00065 using std::allocator<T>::construct;
00066 typedef typename ::std::allocator<T>::pointer pointer;
00067
00068 /** Provides to typedef other. */
00069 template<typename U>
00070 struct rebind
00071 {
00072 /** The type of equivalen allocator except that it
00073 allocates objects of type U. */
00074 typedef allocator<U> other;
00075 };
00076
00077 /** No-op construction. */
00078 allocator() {}
00079
00080 /** No-op copy construction. */
00081 allocator(allocator const& x) : std::allocator<T>(x) {}
00082
00083 /** No-op construction. */
00084 template<typename U>
00085 allocator(allocator<U> const& x) : std::allocator<T>(x) {}
00086
00087 /** Invoke the default constructor on \a p. */
00088 void construct(pointer p) { new(p) T; }
00089
00090 /** Returns a deep copy of the object at \c p. */
00091 pointer copy(pointer p) { return new T(*p, *this); }
00092 };
00093
00094 #ifdef HAVE_BDWGC
00095
00096 /** \class gc_allocator memory.h more/gen/memory.h
00097 **
00098 ** An allocator which allocates garbage collected objects. */
00099 template<typename T>
00100 struct gc_allocator
00101 {
00102 typedef T* pointer;
00103 typedef T const* const_pointer;
00104 typedef T& reference;
00105 typedef T const& const_reference;
00106 typedef T value_type;
00107 typedef std::size_t size_type;
00108 typedef std::ptrdiff_t difference_type;
00109 template<typename U> struct rebind { typedef gc_allocator<U> other; };
00110
00111 /** Trivial constructor. */
00112 gc_allocator() {}
00113 /** Trivial copy constructor. */
00114 gc_allocator(gc_allocator const&) {}
00115 /** Trivial converting copy constructor. */
00116 template<typename U> gc_allocator(gc_allocator<U> const&) {}
00117
00118 /** Returns true. */
00119 bool operator==(gc_allocator const&) { return true; }
00120 /** Returns false. */
00121 bool operator!=(gc_allocator const&) { return false; }
00122
00123 /** Returns \c &x. */
00124 pointer address(reference x) const { return &x; }
00125 /** Returns \c &x. */
00126 const_pointer address(const_reference x) const { return &x; }
00127
00128 /** Returns a pointer to \c n bytes of collected memory. */
00129 pointer allocate(size_type n, const_pointer hint = 0)
00130 {
00131 return static_cast<pointer>(GC_malloc(n*sizeof(T)));
00132 }
00133
00134 /** Does nothing. */
00135 void deallocate(pointer p, size_type) {}
00136
00137 /** Returns a huge number, more than your RAM chips supports. */
00138 size_type max_size()
00139 {
00140 return std::numeric_limits<size_type>::max();
00141 }
00142
00143 /** Invokes \c new((void*)p) v. */
00144 void construct(pointer p, const_reference v) { ::new((void*)p) T(v); }
00145
00146 /** Does nothing. */
00147 void destroy(pointer p) {}
00148
00149 /** Returns a shallow copy of \c p. Actually, that is just the
00150 ** pointer itself. */
00151 pointer copy(pointer p) { return p; }
00152 };
00153
00154 ///\if bits
00155 namespace bits {
00156 struct weak_ptr_base
00157 {
00158 protected:
00159 explicit weak_ptr_base(void* ptr) throw();
00160
00161 void reset_base(void* ptr) throw();
00162
00163 static void* mt_get(void*) throw();
00164 static void* mt_eq(void*) throw();
00165 static void* mt_lt(void*) throw();
00166
00167 typedef void* atom_type[2];
00168 atom_type* m_atom;
00169 };
00170 }
00171 ///\endif
00172
00173 /** \class weak_ptr memory.h more/gen/memory.h
00174 **
00175 ** A weak pointer. A weak_ptr holds a hidden instance of a
00176 ** pointer, and has methods which will return the pointer if it is
00177 ** still vaild, or 0 if the segment it points to is collected.
00178 ** This implementation provides equality and a strict ordering
00179 ** which is unaffected by the garbage collection. That makes it
00180 ** possible to use weak_ptr as keys in maps and sets. XXX Thread
00181 ** safety is not verified. */
00182 template <typename T>
00183 struct weak_ptr
00184 : private bits::weak_ptr_base
00185 {
00186 typedef T element_type;
00187
00188 /** Construct a weak pointer which equals ptr. The segment
00189 that ptr points into must not be explicitely
00190 deallocated. */
00191 weak_ptr(T* ptr = 0) throw()
00192 : weak_ptr_base(ptr) {}
00193
00194 weak_ptr(weak_ptr const& wp) throw()
00195 : weak_ptr_base(wp) {}
00196
00197 weak_ptr& operator=(weak_ptr const& wp) throw()
00198 {
00199 m_atom = wp.m_atom;
00200 return *this;
00201 }
00202
00203 /** Returns the hidden pointer or 0 if its segment is collected. */
00204 T* get() const throw()
00205 {
00206 #ifdef MORE_CF_WITH_THREADS
00207 if (more::cf::there_are_other_treads())
00208 return static_cast<T*>(
00209 GC_call_with_alloc_lock(mt_get, (weak_ptr_base*)this));
00210 #endif
00211 return static_cast<T*>((*m_atom)[0]);
00212 }
00213
00214 /** If valid, return *get(), otherwise throw bad_deref. */
00215 T& operator*() const throw(bad_deref, std::logic_error)
00216 {
00217 if (T* ptr = get())
00218 return *ptr;
00219 else if ((*m_atom)[1])
00220 throw bad_deref("more::gen::weak_ptr::operator->: "
00221 "Dereference of collected memory.");
00222 else
00223 throw std::logic_error("more::gen::weak_ptr::operator->: "
00224 "Dereference of null pointer.");
00225 }
00226
00227 /** If non-null, return get(), otherwise throw bad_deref. */
00228 T* operator->() const throw(bad_deref, std::logic_error)
00229 {
00230 if (T* ptr = get())
00231 return *ptr;
00232 else if ((*m_atom)[1])
00233 throw bad_deref("more::gen::weak_ptr::operator->: "
00234 "Dereference of collected memory.");
00235 else
00236 throw std::logic_error("more::gen::weak_ptr::operator->: "
00237 "Dereference of null pointer.");
00238 }
00239
00240 /** GC-invariant equality comparison. That is, it is
00241 guaranteed to be unaffected by the collection of the
00242 segment it points to. */
00243 bool operator==(weak_ptr const& rhs) const throw()
00244 {
00245 #ifdef MORE_CF_WITH_THREADS
00246 if (more::cf::threre_are_other_threads()) {
00247 void* args[2] = { (weak_ptr_base*)this,
00248 (weak_ptr_base*)&rhs };
00249 return GC_call_with_alloc_lock(mt_eq, args);
00250 }
00251 #endif
00252 return (*m_atom)[1] == (*rhs.m_atom)[1];
00253 }
00254
00255 /** GC-invariant less-than predicate. The implied ordering of
00256 weak_ptr objects it is guaranteed to be unaffected by the
00257 collection of the segments they point to. */
00258 bool operator<(weak_ptr const& rhs) const throw()
00259 {
00260 #ifdef MORE_CF_WITH_THREADS
00261 if (more::cf::threre_are_other_threads()) {
00262 void* args[2] = { (weak_ptr_base*)this,
00263 (weak_ptr_base*)&rhs };
00264 return GC_call_with_alloc_lock(mt_lt, args);
00265 }
00266 #endif
00267 return (*m_atom)[1] < (*rhs.m_atom)[1];
00268 }
00269
00270 /** Set the pointer to a new value. */
00271 T* reset(T* p) throw() { reset_base(p); }
00272 };
00273
00274 /** \class hidden_ptr memory.h more/gen/memory.h
00275 **
00276 ** A pointer that is hidden to the garbage collector. The pointer
00277 ** accessible by the get() method is invalidated when the segment
00278 ** it points (in)to is collected. Typically the object pointed to
00279 ** has a cleanup function which removes all instances of hidden_ptr
00280 ** pointing to it. hidden_ptr has lower time and space complexity
00281 ** than weak_ptr, especially in multithreaded applications. */
00282 template <typename T>
00283 struct hidden_ptr
00284 {
00285 typedef T element_type;
00286 private:
00287 typedef T* atom_type;
00288 public:
00289
00290 /** Construct a hidden pointer which equals ptr. The segment
00291 that ptr points into must not be explicitely
00292 deallocated. */
00293 hidden_ptr(T* ptr = 0) throw()
00294 : m_atom(GC_NEW_ATOMIC(atom_type)) { *m_atom = ptr; }
00295
00296 hidden_ptr(hidden_ptr const& wp) throw()
00297 : m_atom(wp.m_atom) {}
00298
00299 hidden_ptr& operator=(hidden_ptr const& wp) throw()
00300 {
00301 m_atom = wp.m_atom;
00302 return *this;
00303 }
00304
00305 /** Returns the hidden pointer. Note that the segment
00306 containing the object pointed to may be colleced and so
00307 that the pointer is not dereferenceable. It is up to the
00308 client to make sure such hidden_ptr instances are
00309 removed. */
00310 T* get() const throw() { return *m_atom; }
00311
00312 /** Returns *get(), see note on get(). */
00313 T& operator*() const throw() { return *get(); }
00314
00315 /** Returns get(), see note on get(). */
00316 T* operator->() const throw() { return get(); }
00317
00318 /** GC-invariant equality predicate. */
00319 bool operator==(hidden_ptr const& rhs) const throw()
00320 {
00321 return *m_atom == *rhs.m_atom;
00322 }
00323
00324 /** GC-invariant less-than predicate. */
00325 bool operator<(hidden_ptr const& rhs) const throw()
00326 {
00327 return *m_atom < *rhs.m_atom;
00328 }
00329
00330 /** Set the pointer to a new value. */
00331 T* reset(T* ptr) throw()
00332 {
00333 m_atom = GC_NEW_ATOMIC(atom_type);
00334 *m_atom = ptr;
00335 }
00336
00337 private:
00338 atom_type* m_atom;
00339 };
00340
00341 #endif
00342
00343 }} // more::gen
00344
00345 #endif