Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

more/gen/memory.h

Go to the documentation of this file.
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

Generated on Sat Sep 7 19:11:13 2002 for more with Doxygen 1.2.13.1. Doxygen 1.2.13.1 is written and copyright 1997-2002 by Dimitri van Heesch.