aboutsummaryrefslogtreecommitdiffstats
path: root/include/qpdf/PointerHolder.hh
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2008-04-29 14:55:25 +0200
committerJay Berkenbilt <ejb@ql.org>2008-04-29 14:55:25 +0200
commit9a0b88bf7777c153dc46ace22db74ef24d51583a (patch)
treef567ac1cf2bf5071a611eb49323a935b6ac938ff /include/qpdf/PointerHolder.hh
downloadqpdf-9a0b88bf7777c153dc46ace22db74ef24d51583a.tar.zst
update release date to actual daterelease-qpdf-2.0
git-svn-id: svn+q:///qpdf/trunk@599 71b93d88-0707-0410-a8cf-f5a4172ac649
Diffstat (limited to 'include/qpdf/PointerHolder.hh')
-rw-r--r--include/qpdf/PointerHolder.hh170
1 files changed, 170 insertions, 0 deletions
diff --git a/include/qpdf/PointerHolder.hh b/include/qpdf/PointerHolder.hh
new file mode 100644
index 00000000..b4e9bb64
--- /dev/null
+++ b/include/qpdf/PointerHolder.hh
@@ -0,0 +1,170 @@
+// Copyright (c) 2005-2008 Jay Berkenbilt
+//
+// This file is part of qpdf. This software may be distributed under
+// the terms of version 2 of the Artistic License which may be found
+// in the source distribution. It is provided "as is" without express
+// or implied warranty.
+
+#ifndef __POINTERHOLDER_HH__
+#define __POINTERHOLDER_HH__
+
+#include <iostream>
+
+// This class is basically boost::shared_pointer but predates that by
+// several years.
+
+// This class expects to be initialized with a dynamically allocated
+// object pointer. It keeps a reference count and deletes this once
+// the reference count goes to zero. PointerHolder objects are
+// explicitly safe for use in STL containers.
+
+// It is very important that a client who pulls the pointer out of
+// this holder does not let the holder go out of scope until it is
+// finished with the pointer. It is also important that exactly one
+// instance of this object ever gets initialized with a given pointer.
+// Otherwise, the pointer will be deleted twice, and before that, some
+// objects will be left with a pointer to a deleted object. In other
+// words, the only legitimate way for two PointerHolder objects to
+// contain the same pointer is for one to be a copy of the other.
+// Copy and assignment semantics are well-defined and essentially
+// allow you to use PointerHolder as a means to get pass-by-reference
+// semantics in a pass-by-value environment without having to worry
+// about memory management details.
+
+// Comparison (== and <) are defined and operate on the internally
+// stored pointers, not on the data. This makes it possible to store
+// PointerHolder objects in sorted lists or to find them in STL
+// containers just as one would be able to store pointers. Comparing
+// the underlying pointers provides a well-defined, if not
+// particularly meaningful, ordering.
+
+template <class T>
+class PointerHolder
+{
+ private:
+ class Data
+ {
+ public:
+ Data(T* pointer, bool tracing) :
+ pointer(pointer),
+ tracing(tracing),
+ refcount(0)
+ {
+ static int next_id = 0;
+ this->unique_id = ++next_id;
+ }
+ ~Data()
+ {
+ if (this->tracing)
+ {
+ std::cerr << "PointerHolder deleting pointer "
+ << (void*)pointer
+ << std::endl;
+ }
+ delete this->pointer;
+ if (this->tracing)
+ {
+ std::cerr << "PointerHolder done deleting pointer "
+ << (void*)pointer
+ << std::endl;
+ }
+ }
+ T* pointer;
+ bool tracing;
+ int refcount;
+ int unique_id;
+ private:
+ Data(Data const&);
+ Data& operator=(Data const&);
+ };
+
+ public:
+ PointerHolder(T* pointer = 0, bool tracing = false)
+ {
+ this->init(new Data(pointer, tracing));
+ }
+ PointerHolder(PointerHolder const& rhs)
+ {
+ this->copy(rhs);
+ }
+ PointerHolder& operator=(PointerHolder const& rhs)
+ {
+ if (this != &rhs)
+ {
+ this->destroy();
+ this->copy(rhs);
+ }
+ return *this;
+ }
+ ~PointerHolder()
+ {
+ this->destroy();
+ }
+ bool operator==(PointerHolder const& rhs) const
+ {
+ return this->data->pointer == rhs.data->pointer;
+ }
+ bool operator<(PointerHolder const& rhs) const
+ {
+ return this->data->pointer < rhs.data->pointer;
+ }
+
+ // NOTE: The pointer returned by getPointer turns into a pumpkin
+ // when the last PointerHolder that contains it disappears.
+ T* getPointer()
+ {
+ return this->data->pointer;
+ }
+ T const* getPointer() const
+ {
+ return this->data->pointer;
+ }
+ int getRefcount() const
+ {
+ return this->data->refcount;
+ }
+
+ private:
+ void init(Data* data)
+ {
+ this->data = data;
+ {
+ ++this->data->refcount;
+ if (this->data->tracing)
+ {
+ std::cerr << "PointerHolder " << this->data->unique_id
+ << " refcount increased to " << this->data->refcount
+ << std::endl;
+ }
+ }
+ }
+ void copy(PointerHolder const& rhs)
+ {
+ this->init(rhs.data);
+ }
+ void destroy()
+ {
+ bool gone = false;
+ {
+ if (--this->data->refcount == 0)
+ {
+ gone = true;
+ }
+ if (this->data->tracing)
+ {
+ std::cerr << "PointerHolder " << this->data->unique_id
+ << " refcount decreased to "
+ << this->data->refcount
+ << std::endl;
+ }
+ }
+ if (gone)
+ {
+ delete this->data;
+ }
+ }
+
+ Data* data;
+};
+
+#endif // __POINTERHOLDER_HH__