blob: 338abc6f60a5ab5b1bef6063f180f554edbd6e42 [file] [log] [blame]
// ***********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
// ***********************************************************************
// -*-C++-*-
// ***********************************************************************
//
// File: SharedPtr.h
// Description: A shared pointer implementation that works with the
// NAMemory class and supports some of the programming
// styles used by the SQLMX code. Standard shared_ptr
// classes cannot be used for the compiler (or executor)
// because of the memory management used by the NAMemory
// class. Standard implementations use new/delete and
// this would cause memory leaks when the NAMemory heaps
// are reinitialized or are destructed.
//
// Created: 04/04/07
// Language: C++
// ***********************************************************************
#ifndef _SHAREDPTR_H
#define _SHAREDPTR_H
// ***********************************************************************
// USAGE NOTES:
// The SharedPtr class should be used in most cases. However, if a
// regular pointer needs to be converted into a SharedPtr, then an
// IntrusiveSharedPtr should be used. An example is if you are in
// a member function of a particular class, and you need to pass the
// "this" pointer to something that requires a SharedPtr, then you
// most likely need to be using an IntrusiveSharedPtr.
//
// A SharedPtr allocates memory externally for a reference count, while
// an IntrusiveSharedPtr places the reference count within the user
// object itself. This means that a heap must be passed to the
// SharedPtr constructor, but does not need to be passed to the
// IntrusiveSharedPtr constructor. IntrusiveSharedPtr user classes
// will have a "INTRUSIVE_SHARED_PTR(class);" declaration included
// in the public section of the class. Failure to do this will result
// in a compile-time error.
//
// A good practice to follow is to specify a typedef for a new
// SharedPtr. Each place that allocates a user object will need some
// syntax changes.
//
// EXAMPLE:
// #include "SharedPtr.h"
// #include "NAMemory.h"
// #include "iostream"
// class MyClass {
// public:
// MyClass(int a) : a_(a) {}
// int getVal() { return a_; }
// private:
// int a_;
// };
// typedef SharedPtr<MyClass> MyClassSharedPtr;
//
// int myFunction(CollHeap* heap)
// {
// // This allocates a MyClass object, which is pointed to by the
// // "mcp" SharedPtr. The internal reference count will be 1
// // after "mcp" is constructed
// MyClassSharedPtr mcp(new (heap) MyClass(5), heap);
//
// // This shows that "mcp" can be used just like a regular pointer
// if (mcp) {
// std::cout << "Value of mcp " << mcp->getVal() << std::end;
// }
//
// // The "MyClass" object will be automatically destroyed once
// // "mcp" goes out of scope.
// }
// ***********************************************************************
#include "NAMemory.h"
#include "NAAssert.h"
// Classes and structs defined in this file.
struct nullDeleter;
template <class T> struct SharedRefCountBase;
template <class T> struct SharedRefCount;
template <class T, class D> struct SharedRefCountDel;
template <class T> struct IntrusiveSharedRefCount;
template <class T> class SharedPtr;
template <class T> class IntrusiveSharedPtr;
// Classes that must use an embedded shared count must declare
// INTRUSIVE_SHARED_PTR in the public section of the class.
#define INTRUSIVE_SHARED_PTR(TYPE) IntrusiveSharedRefCount<TYPE> ISHP_
// ***********************************************************************
// NullDeleter struct
// Description: This may be used when constructing a SharedPtr object
// that references an object that should not be deleted.
// For instance, objects constructed on the stack should
// not be deleted.
// ***********************************************************************
struct NullDeleter {
void operator() (void const *) const {}
};
// ***********************************************************************
// SharedRefCountBase struct
// Description: This provides the base class that the shared reference
// counting classes may use.
// ***********************************************************************
template <class T>
struct SharedRefCountBase {
SharedRefCountBase() : useCount_(0), objectP_(0) {}
SharedRefCountBase(T* t, Int32 use_count) :
useCount_(use_count), objectP_(t) {}
// Functions to increment and decrement the use count
void incrUseCount() { ++useCount_; }
void decrUseCount() { if (--useCount_ == 0) destroyObjects(); }
// Function that properly destroys the object and reference count
// objects.
virtual void destroyObjects() = 0;
Lng32 useCount_; // Reference count of this object
T *objectP_; // Pointer to object
};
// ***********************************************************************
// SharedRefCount struct
// Description: This struct provides shared reference counting that
// is used by the SharedPtr class.
// ***********************************************************************
template <class T>
struct SharedRefCount : public SharedRefCountBase<T> {
SharedRefCount(T* t, NAMemory* heap, Int32 use_count) :
SharedRefCountBase<T>(t, use_count), heap_(heap) {}
virtual void destroyObjects()
{
delete SharedRefCountBase<T>::objectP_;
if (heap_)
NADELETEBASIC(this, heap_);
else
::operator delete((void*)this);
}
private:
NAMemory *heap_; // Heap used to construct SharedRefCount.
};
// ***********************************************************************
// SharedRefCountDel class
// Description: This provides a reference counted object with a
// specialized delete function. It has two main purposes:
// 1) Used in conjuntion with nullDeleter to prevent
// objects on the stack from being deleted when used in
// conjunction with the SharedPtr class.
// 2) Provide a special deleter class if some special
// deletion is necessary.
// ***********************************************************************
template<class T, class D>
struct SharedRefCountDel : public SharedRefCountBase<T> {
SharedRefCountDel(T *t, NAMemory *heap, Int32 use_count, D deleter) :
SharedRefCountBase<T>(t, use_count), heap_(heap), del_(deleter) {}
virtual void destroyObjects()
{
del_(SharedRefCountBase<T>::objectP_);
if (heap_)
// heap_->deallocateMemory(this);
NADELETEBASIC(this, heap_);
else
::operator delete((void*)this);
}
private:
NAMemory *heap_; // Heap used to construct SharedRefCount.
D del_; // Deletion class
};
// ***********************************************************************
// IntrusiveSharedRefCount struct
// Description: This provides the ability for a class to contain the
// reference count instead of it being allocated externally.
// This allows a SharedPtr object to be created correctly
// from the "this" pointer.
//
// Usage: An object that uses this mechanism must add the following
// to the public section of the object (where objectType is
// the class name):
//
// CMP_INTRUSIVE_SHARED_PTR(objectType);
//
// ***********************************************************************
template<class T>
struct IntrusiveSharedRefCount : public SharedRefCountBase<T> {
IntrusiveSharedRefCount() {}
IntrusiveSharedRefCount(T *t, Int32 use_count) :
SharedRefCountBase<T>(t, use_count) {}
virtual void destroyObjects()
{
// Only the object pointer should be deleted for this class.
delete SharedRefCountBase<T>::objectP_;
}
};
// ***********************************************************************
// SharedPtr class
// Description: This provides a reference counted smart pointer
// implementation. For SQL/MX, it is assumed that objects
// that use this class will be derived from classes that
// provide their own operator new and operator delete.
// ***********************************************************************
template<class T>
class SharedPtr {
public:
// Constructors
SharedPtr(): objectP_(0), refCount_(0) {}
// Normal constructor
template<class Y>
SharedPtr(Y *t, NAMemory *heap) : objectP_(t) {
if (heap)
refCount_ = new (heap) SharedRefCount<Y> (t, heap, 1);
else
refCount_ = new SharedRefCount<Y> (t, heap, 1);
}
// Constructor with a special deleter object
template<class Y, class D>
SharedPtr(Y *t, NAMemory *heap, D deleter_class) : objectP_(t) {
if (heap)
refCount_ = new (heap) SharedRefCountDel<Y, D> (t, heap, 1, deleter_class);
else
refCount_ = new SharedRefCountDel<Y, D> (t, heap, 1, deleter_class);
}
// Constructor that allows construction with a NULL pointer
SharedPtr(const long i) : refCount_(0), objectP_((T*)i) {}
// Copy constructor
SharedPtr(SharedPtr<T> const & r) :
objectP_(r.objectP_),
refCount_(r.refCount_)
{
if (refCount_)
refCount_->incrUseCount();
}
// Destructor
~SharedPtr()
{
if (refCount_) {
#ifdef _DEBUG
assert(objectP_ == refCount_->objectP_);
#endif
refCount_->decrUseCount();
}
}
// Assignment operator
SharedPtr<T>& operator= (SharedPtr<T> const & r)
{
if (objectP_ != r.objectP_) {
if (refCount_) {
#ifdef _DEBUG
assert(objectP_ == refCount_->objectP_);
#endif
refCount_->decrUseCount();
}
objectP_ = r.objectP_;
refCount_ = r.refCount_;
if (refCount_)
refCount_->incrUseCount();
}
return *this;
}
// Allow assignment of pointer to NULL.
SharedPtr<T>& operator= (const long i)
{
if (refCount_) {
#ifdef _DEBUG
assert(objectP_ == refCount_->objectP_);
#endif
refCount_->decrUseCount();
}
objectP_ = (T*)i;
refCount_ = 0;
return *this;
}
// Access operations
T& operator* () const
{
#ifdef _DEBUG
if (refCount_)
assert(objectP_ == refCount_->objectP_);
#endif
return *objectP_;
}
T* operator->() const
{
#ifdef _DEBUG
if (refCount_)
assert(objectP_ == refCount_->objectP_);
#endif
return objectP_;
}
// Return a pointer to the object.
T* get() const { return objectP_; }
// Return the reference count
Lng32 getUseCount() const { return (refCount_ ? refCount_->useCount_ : 0); }
// Return whether this SharePtr is not null.
operator bool () const { return objectP_ != 0; }
// reset() may be used for special cases where it is possible to
// tell that a SharedPtr is no longer valid. The current SharedPtr
// can then be reset to point to nothing.
void reset() { objectP_ = 0; refCount_ = 0; }
protected:
T* objectP_; // Pointer to contained object
SharedRefCountBase<T>* refCount_; // Pointer to reference count object
};
// Equality operator
template<class T, class O>
inline bool operator==(SharedPtr<T> const &a, SharedPtr<O> const &b)
{
return a.get() == b.get();
}
// Inequality operator
template<class T, class O>
inline bool operator!=(SharedPtr<T> const &a, SharedPtr<O> const &b)
{
return a.get() != b.get();
}
// ***********************************************************************
// IntrusiveSharedPtr class
// Description: This is a specialized SharedPtr in which the object
// contains the reference count instead of it being
// allocated externally. This allows for a shared pointer
// to be allocated from an existing object pointer.
// ***********************************************************************
template<class T>
class IntrusiveSharedPtr : public SharedPtr<T> {
public:
// Constructors
IntrusiveSharedPtr() {}
// Normal constructor
template<class Y>
IntrusiveSharedPtr(Y *t)
{
// Reconstruct the reference count from object
SharedPtr<T>::objectP_ = (T*)t;
SharedPtr<T>::refCount_ = (SharedRefCountBase<T>*)&t->ISHP_;
SharedPtr<T>::refCount_->objectP_ = (T*)t;
SharedPtr<T>::refCount_->useCount_++;
}
// Allow construction with a NULL
IntrusiveSharedPtr(const long i) : SharedPtr<T>(i) {}
// Return a pointer to a shared pointer given an object with an intrusive
// shared pointer.
static IntrusiveSharedPtr<T> getIntrusiveSharedPtr(const T *t)
{
IntrusiveSharedPtr retPtr;
// Copy information to the returned shared pointer. The casts done
// below are to get rid of "const" errors.
retPtr.refCount_ = (SharedRefCountBase<T>*)&t->ISHP_;
retPtr.objectP_ = (T*)t;
retPtr.refCount_->objectP_ = (T*)t;
retPtr.refCount_->useCount_++;
return retPtr;
}
// Provide an assignment operator to prevent the compiler from writing one.
IntrusiveSharedPtr<T>& operator= (const long i)
{
(void)SharedPtr<T>::operator=(i);
return *this;
}
};
// Equality operator (for comparing an intrusive pointer to a regular pointer)
template<class T>
inline bool operator==(IntrusiveSharedPtr<T> const &a, T const *b)
{
return a.get() == b;
}
// Inequality operator (for comparing an intrusive pointer to a regular pointer)
template<class T>
inline bool operator!=(IntrusiveSharedPtr<T> const &a, T const *b)
{
return a.get() != b;
}
#endif // _SHAREDPTR_H