blob: 30a5bdce71831e7be830ed32dd48966dc941f94d [file] [log] [blame]
#pragma once
#ifndef GEODE_GFCPP_SHAREDPTR_H_
#define GEODE_GFCPP_SHAREDPTR_H_
/*
* 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.
*/
#include "SharedBase.hpp"
#include "Assert.hpp"
#include "TypeHelper.hpp"
#include <typeinfo>
#include "SharedPtrHelper.hpp"
/** @file
*/
namespace apache {
namespace geode {
namespace client {
#if GF_DEVEL_ASSERTS == 1
#define GF_CHECK_NPE(x) \
if (x != NULL) { \
} else \
apache::geode::client::SPEHelper::throwNullPointerException( \
typeid(*this).name())
#else
#define GF_CHECK_NPE(x)
#endif
class MapEntry;
class MapEntryImpl;
template <class Target>
/** Defines a reference counted shared pointer
*/
class SharedPtr {
public:
/** Constructor. */
inline SharedPtr() : m_ptr(NULL) {}
/** Constructor for the NULL pointer */
inline SharedPtr(const NullSharedBase* ptr) : m_ptr(NULL) {}
/** Explicit copy constructor, given a pointer.
* @throws ClassCastException if <code>Target</code> pointer cannot be
* converted to <code>SharedBase</code> pointer (dynamic_cast to
* <code>SharedBase*</code> fails).
*/
inline explicit SharedPtr(const Target* ptr)
: m_ptr(const_cast<Target*>(ptr)) {
if (NULL != m_ptr) getSB(m_ptr)->preserveSB();
}
/** Constructor, given another SharedPtr. */
inline SharedPtr(const SharedPtr& other) : m_ptr(other.m_ptr) {
if (NULL != m_ptr) getSB(m_ptr)->preserveSB();
}
/** Constructor, given another SharedPtr.
* @throws ClassCastException if <code>Other</code> pointer cannot be
* converted to <code>Target</code> pointer (dynamic_cast to
* <code>Target*</code> fails).
*/
template <class Other>
inline SharedPtr(const SharedPtr<Other>& other)
: m_ptr(getTarget<Target>(other.ptr())) {
if (NULL != m_ptr) getSB(m_ptr)->preserveSB();
}
/** Destructor. */
inline ~SharedPtr() {
if (NULL != m_ptr) getSB(m_ptr)->releaseSB();
m_ptr = NULL;
}
inline Target* operator->() const {
GF_CHECK_NPE(m_ptr);
GF_DEV_ASSERT(getSB(m_ptr)->refCount() > 0);
return m_ptr;
}
inline Target& operator*() const {
GF_CHECK_NPE(m_ptr);
return *m_ptr;
}
/** Assigns a pointer.
* @throws ClassCastException if <code>Target</code> pointer cannot be
* converted to <code>SharedBase</code> pointer (dynamic_cast to
* <code>SharedBase*</code> fails).
*/
inline SharedPtr& operator=(Target* other) {
if (NULL != other) getSB(other)->preserveSB();
if (NULL != m_ptr) getSB(m_ptr)->releaseSB();
m_ptr = other;
return *this;
}
inline SharedPtr& operator=(const SharedPtr& other) {
Target* otherPtr = other.m_ptr;
if (NULL != otherPtr) {
getSB(otherPtr)->preserveSB();
}
if (NULL != m_ptr) {
getSB(m_ptr)->releaseSB();
}
m_ptr = otherPtr;
GF_DEV_ASSERT(otherPtr == other.m_ptr);
return *this;
}
/** Assigns a pointer of type <code>Other</code> from a <code>SharedPtr</code>
* object.
* @throws ClassCastException if <code>Other</code> pointer cannot be
* converted to <code>Target</code> pointer (dynamic_cast to
* <code>Target*</code> fails).
*/
template <class Other>
inline SharedPtr& operator=(const SharedPtr<Other>& other) {
Other* otherPtr = other.ptr();
Target* otherTargetPtr = getTarget<Target>(otherPtr);
if (NULL != otherPtr) {
getSB(otherPtr)->preserveSB();
}
if (NULL != m_ptr) {
getSB(m_ptr)->releaseSB();
}
m_ptr = otherTargetPtr;
GF_DEV_ASSERT(otherPtr == other.ptr());
return *this;
}
inline SharedPtr& operator=(const NullSharedBase* nullOther) {
if (m_ptr != NULL) {
getSB(m_ptr)->releaseSB();
}
m_ptr = NULL;
return *this;
}
/** Assigns a pointer of type <code>Other</code>.
* @throws ClassCastException if <code>Other</code> pointer cannot be
* converted to <code>Target</code> pointer (dynamic_cast to
* <code>Target*</code> fails),
* or if <code>Other</code> pointer cannot be converted to
* <code>SharedBase</code> pointer (dynamic_cast to <code>SharedBase*</code>
* fails).
*/
template <class Other>
inline SharedPtr& operator=(Other* other) {
Target* otherTargetPtr = getTarget<Target>(other);
if (NULL != other) {
getSB(other)->preserveSB();
}
if (NULL != m_ptr) {
getSB(m_ptr)->releaseSB();
}
m_ptr = otherTargetPtr;
return *this;
}
inline bool operator==(const Target* other) const { return m_ptr == other; }
inline bool operator!=(const Target* other) const { return m_ptr != other; }
inline bool operator==(const NullSharedBase* nullOther) const {
return m_ptr == NULL;
}
inline bool operator!=(const NullSharedBase* nullOther) const {
return m_ptr != NULL;
}
inline bool operator==(const SharedPtr& other) const {
return m_ptr == other.m_ptr;
}
inline bool operator!=(const SharedPtr& other) const {
return m_ptr != other.m_ptr;
}
template <class Other>
inline bool operator==(const SharedPtr<Other>& other) {
return ((const void*)m_ptr) == ((const void*)other.ptr());
}
template <class Other>
inline bool operator!=(const SharedPtr<Other>& other) {
return !operator==(other);
}
inline Target* ptr() const { return m_ptr; }
private:
/** this constructor deliberately skips touching m_ptr or anything */
inline explicit SharedPtr(bool noInit) {}
Target* m_ptr;
friend class MapEntry;
friend class MapEntryImpl;
};
typedef SharedPtr<SharedBase> SharedBasePtr;
/** Statically cast the underlying pointer to the given type. The behaviour
* is similar to <code>static_cast</code>.
*
* Make use of this cast with care since it does not offer protection
* against incorrect casts. For most purposes <code>dynCast</code> is the
* better choice and this should be used only where the programmer knows
* the cast to be safe.
*
* Setting the macro <code>GF_DEBUG_ASSERTS</code> enables dynamic checking
* of the cast throwing an <code>AssertionException</code> if the cast fails.
*/
template <class TargetSP, class Other>
TargetSP staticCast(const SharedPtr<Other>& other) {
GF_D_ASSERT((other.ptr() == NULL) ||
(dynamic_cast<GF_UNWRAP_SP(TargetSP)*>(other.ptr()) != NULL));
return TargetSP(static_cast<GF_UNWRAP_SP(TargetSP)*>(other.ptr()));
}
/** Dynamically cast the underlying pointer to the given type and throw
* <code>ClassCastException</code> if the cast fails.
*/
template <class TargetSP, class Other>
TargetSP dynCast(const SharedPtr<Other>& other) {
GF_UNWRAP_SP(TargetSP) * otherPtr;
if ((other.ptr() == NULL)) {
return NULLPTR;
} else if ((otherPtr = dynamic_cast<GF_UNWRAP_SP(TargetSP)*>(other.ptr())) !=
NULL) {
return TargetSP(otherPtr);
} else {
SPEHelper::throwClassCastException(
"dynCast: cast failed", typeid(other).name(), typeid(TargetSP).name());
return NULLPTR;
}
}
/**
* Dynamically check if the underlying pointer is of the given SharedPtr type.
*/
template <class TargetSP, class Other>
bool instanceOf(const SharedPtr<Other>& other) {
return (dynamic_cast<GF_UNWRAP_SP(TargetSP)*>(other.ptr()) != NULL);
}
} // namespace client
} // namespace geode
} // namespace apache
#endif // GEODE_GFCPP_SHAREDPTR_H_