[cfe-commits] r42260 - in /cfe/trunk/include/clang/Analysis/Support: ./ IntrusiveSPtr.h

Ted Kremenek kremenek at apple.com
Sun Sep 23 23:10:20 PDT 2007


Author: kremenek
Date: Mon Sep 24 01:10:20 2007
New Revision: 42260

URL: http://llvm.org/viewvc/llvm-project?rev=42260&view=rev
Log:
Added smart pointer class "IntrusiveSPtr" that handles reference
counted objects that maintain their own internal reference count.
This smart pointer implementation is compatible with LLVM-style
down-casting (see in llvm: include/llvm/Support/Casting.h).

Implemented "RefCounted", a base class that objects that wish to be
managed using IntrusiveSPtrs can subclass.

Reference counted objects are being targeted for use in path-sensitive
dataflow analyses where managing many live objects becomes difficult.

Added:
    cfe/trunk/include/clang/Analysis/Support/
    cfe/trunk/include/clang/Analysis/Support/IntrusiveSPtr.h

Added: cfe/trunk/include/clang/Analysis/Support/IntrusiveSPtr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Support/IntrusiveSPtr.h?rev=42260&view=auto

==============================================================================
--- cfe/trunk/include/clang/Analysis/Support/IntrusiveSPtr.h (added)
+++ cfe/trunk/include/clang/Analysis/Support/IntrusiveSPtr.h Mon Sep 24 01:10:20 2007
@@ -0,0 +1,205 @@
+//===--- IntrusiveSPtr.h - Smart Reference Counting Pointers ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Ted Kremenek and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines two classes: RefCounted, a generic base class for objects
+// that wish to have their lifetimes managed using reference counting, and
+// IntrusiveSPtr, a template class that implements a "smart" pointer for
+// objects that maintain their own internal reference count (e.g. RefCounted).
+//
+// IntrusiveSPtr is similar to Boost's intrusive_ptr with two main distinctions:
+//
+//  (1) We implement operator void*() instead of operator bool() so that
+//      different pointer values may be accurately compared within an
+//      expression.  This includes the comparison of smart pointers with their
+//      "unsmart" cousins.
+//
+//  (2) We provide LLVM-style casting, via cast<> and dyn_cast<>, for
+//      IntrusiveSPtrs.
+//  
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INTRUSIVESPTR
+#define LLVM_CLANG_INTRUSIVESPTR
+
+#include "llvm/Support/Casting.h"
+
+namespace clang {
+
+/// RefCounted - A generic base class for objects that wish to have
+///  their lifetimes managed using reference counts.  Classes subclass
+///  RefCounted to obtain such functionality, and are typically
+///  handled with IntrusiveSPtr "smart pointers" (see below) which
+///  automatically handle the management of reference counts.  Objects
+///  that subclass RefCounted should not be allocated on the stack, as
+///  invoking "delete" (which is called when the reference count hits
+///  0) on such objects is an error.
+class RefCounted {
+  unsigned ref_cnt;
+public:
+  RefCounted() : ref_cnt(0) {}
+  
+  void Retain() { ++ref_cnt; }
+  void Release() {
+    assert (ref_cnt > 0 && "Reference count is already zero.");
+    if (--ref_cnt == 0) delete this;
+  }
+  
+protected:
+  // Making the dstor protected (or private) prevents RefCounted
+  // objects from being stack-allocated.  Subclasses should similarly
+  // follow suit with this practice.
+  virtual ~RefCounted() {}
+};
+  
+} // end namespace clang
+
+/// intrusive_ptr_add_ref - A utility function used by IntrusiveSPtr
+///  to increment the reference count of a RefCounted object.  This
+///  particular naming was chosen to be compatible with
+///  boost::intrusive_ptr, which provides similar functionality to
+///  IntrusiveSPtr.
+void intrusive_ptr_add_ref(clang::RefCounted* p) { p->Retain(); }
+
+/// intrusive_ptr_release - The complement of intrusive_ptr_add_ref;
+///  decrements the reference count of a RefCounted object.
+void intrusive_ptr_release(clang::RefCounted* p) { p->Release(); }
+
+namespace clang {
+
+/// IntrusiveSPtr - A template class that implements a "smart pointer"
+///  that assumes the wrapped object has a reference count associated
+///  with it that can be managed via calls to
+///  intrusive_ptr_add_ref/intrusive_ptr_release.  The smart pointers
+///  manage reference counts via the RAII idiom: upon creation of
+///  smart pointer the reference count of the wrapped object is
+///  incremented and upon destruction of the smart pointer the
+///  reference count is decremented.  This class also safely handles
+///  wrapping NULL pointers.
+template <typename T>
+class IntrusiveSPtr {
+  T* Obj;
+public:
+  typedef T ObjType;
+  
+  explicit IntrusiveSPtr() : Obj(NULL) {}
+  
+  explicit IntrusiveSPtr(const T* obj) : Obj(const_cast<T*>(obj)) { 
+    retain();
+  }
+  
+  IntrusiveSPtr(const IntrusiveSPtr& S) : Obj(const_cast<T*>(S.Obj)) { 
+    retain(); 
+  }
+
+  template <typename X>
+  IntrusiveSPtr(const IntrusiveSPtr<X>& S) {
+    Obj = static_cast<T*>(const_cast<X*>(S.getPtr()));
+    retain();
+  }
+  
+  template <typename X>
+  IntrusiveSPtr& operator=(const IntrusiveSPtr<X>& S) {
+    replace(static_cast<const T*>(S.getPtr()));
+    return *this;
+  }
+  
+  ~IntrusiveSPtr() { release(); }
+  
+  T& operator*() { return *Obj; }
+  const T& operator*() const { return *Obj; }
+  
+  T* operator->() { return Obj; }
+  const T* operator->() const { return Obj; }
+  
+  T* getPtr() { return Obj; }
+  const T* getPtr() const { return Obj; }
+  
+  operator void*() { return Obj; }
+  operator const void*() const { return Obj; }  
+
+private:
+  void retain() { if (Obj) intrusive_ptr_add_ref(Obj); }
+  void release() { if (Obj) intrusive_ptr_release(Obj); }
+
+  void replace(const T* o) { 
+    release();
+    Obj = const_cast<T*>(o);
+    retain();
+  }
+};
+  
+} // end namespace clang
+
+//===----------------------------------------------------------------------===//
+// LLVM-style downcasting support for IntrusiveSPtr objects
+//===----------------------------------------------------------------------===//
+
+namespace llvm {
+
+/// cast<X> - Return the argument parameter (wrapped in an
+/// IntrusiveSPtr smart pointer) to the specified type.  This casting
+/// operator asserts that the type is correct, so it does not return a
+/// NULL smart pointer on failure.  Note that the cast returns a
+/// reference to an IntrusiveSPtr; thus no reference counts are
+/// modified by the cast itself.  Assigning the result of the cast,
+/// however, to a non-reference will obviously result in reference
+/// counts being adjusted when the copy constructor or operator=
+/// method for IntrusiveSPtr is invoked.
+template <typename X, typename Y>
+inline clang::IntrusiveSPtr<X>&
+cast(const clang::IntrusiveSPtr<Y>& V) {
+  assert (isa<X>(V.getPtr()) && 
+    "cast<Ty>() (IntrusiveSPtr) argument of incompatible type!");
+  clang::IntrusiveSPtr<Y>& W = const_cast<clang::IntrusiveSPtr<Y>&>(V);
+  return reinterpret_cast<clang::IntrusiveSPtr<X>&>(W);
+}
+
+/// cast_or_null<X> - Functionally idential to cast, except that an
+/// IntrusiveSPtr wrapping a NULL pointer is accepted.
+template <typename X, typename Y>
+inline clang::IntrusiveSPtr<X>&
+cast_or_null(const clang::IntrusiveSPtr<Y>& V) {
+  if (V == 0) return 0;
+  assert (isa<X>(V.getPtr()) && 
+    "cast_or_null<Ty>() (const IntrusiveSPtr) argument of incompatible type!");  
+  clang::IntrusiveSPtr<Y>& W = const_cast<clang::IntrusiveSPtr<Y>&>(V);
+  return reinterpret_cast<clang::IntrusiveSPtr<X>&>(W);
+}  
+
+/// dyn_cast<X> - Return the argument parameter (wrapped in an
+/// IntrusiveSPtr smart pointer) to the specified type.  This casting
+/// operator returns an IntrusiveSPtr wrapping a NULL pointer if the
+/// argument is of the wrong type, so it can be used to test for a
+/// type as well as cast if successful.  Unlike cast<>, a copy of the
+/// IntrusiveSPtr is always made, resulting in the reference counts
+/// being adjusted.
+template <typename X, typename Y>
+inline clang::IntrusiveSPtr<X>
+dyn_cast(const clang::IntrusiveSPtr<Y>& V) {
+  if (isa<X>(V.getPtr()))
+    return clang::IntrusiveSPtr<X>(static_cast<const X*>(V.getPtr()));
+  else
+    return clang::IntrusiveSPtr<X>(NULL);
+}
+
+/// dyn_cast_or_null<X> - Functionally identical to dyn_cast, except
+/// that an IntrusiveSPtr wrapping a NULL pointer is accepted.
+template <typename X, typename Y>
+inline clang::IntrusiveSPtr<X>
+dyn_cast_or_null(const clang::IntrusiveSPtr<Y>& V) {
+  if (V == 0) return clang::IntrusiveSPtr<X>();
+  if (isa<X>(V.getPtr()))
+    return clang::IntrusiveSPtr<X>(static_cast<const X*>(V.getPtr()));
+  else
+    return clang::IntrusiveSPtr<X>(NULL);
+}
+  
+} // end namespace llvm
+
+#endif





More information about the cfe-commits mailing list