Program Listing for File interface_ptr.h#
↰ Return to documentation for file (support\interface_ptr.h)
#ifndef INTERFACE_IMPL_H
#define INTERFACE_IMPL_H
#include <atomic>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <typeinfo> // AXIVION Same Line AutosarC++19_03-A16.2.2
#ifndef DONT_LOAD_CORE_TYPES
#include "../interfaces/core.h"
#endif
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
namespace sdv
{
namespace internal
{
class CSectionSelector
{
public:
void DefineDefaultSection()
{
m_uiSection = -1;
}
void DefineSection(int uiSection)
{
m_uiSection = uiSection;
}
void Select(int uiSection)
{
m_uiUseSection = uiSection;
}
bool Selected() const
{
return m_uiSection < 0 || m_uiSection == m_uiUseSection;
}
private:
int m_uiUseSection = -1;
int m_uiSection = -1;
};
}
}
#define BEGIN_SDV_INTERFACE_MAP() \
\
sdv::interface_t GetInterface(sdv::interface_id idInterface) override \
{ \
if (!idInterface) return nullptr; \
::sdv::internal::CSectionSelector selector; \
if (selector.Selected()) \
{
#define SDV_INTERFACE_USE_NAMESPACE(namespace_name) using namespace namespace_name;
#define SDV_INTERFACE_ENTRY(ifc) \
if (idInterface == sdv::GetInterfaceId<ifc>()) \
return static_cast<ifc*>(this);
#define SDV_INTERFACE_ENTRY_MEMBER(ifc, member_or_pointer) \
{ \
sdv::interface_t tifc = sdv::SInterfaceMemberHelper<ifc>::InterfaceMapEntryHelper(member_or_pointer, idInterface); \
if (tifc) \
return tifc; \
}
#define SDV_INTERFACE_ENTRY_INDIRECT(ifc, ifc_cast) \
if (idInterface == sdv::GetInterfaceId<ifc>()) \
return static_cast<ifc*>(static_cast<ifc_cast*>(this));
#define SDV_INTERFACE_DENY_ENTRY(ifc) \
if (idInterface == sdv::GetInterfaceId<ifc>()) \
return nullptr;
#define SDV_INTERFACE_CHAIN_BASE(base_class) \
{ \
sdv::interface_t ifc = base_class::GetInterface(idInterface); \
if (ifc) \
return ifc; \
}
#define SDV_INTERFACE_CHAIN_MEMBER(member_or_pointer) \
{ \
sdv::interface_t ifc = sdv::InterfaceMapChainHelper(member_or_pointer, idInterface); \
if (ifc) \
return ifc; \
}
#define SDV_INTERFACE_CHECK_CONDITION(condition) \
if (!(condition)) \
return nullptr;
#define SDV_INTERFACE_SET_SECTION_CONDITION(condition, section_number) \
if (condition) \
selector.Select(section_number); \
} \
if (selector.Selected()) \
{
#define SDV_INTERFACE_SET_SECTION(section_number) \
selector.Select(section_number); \
} \
if (selector.Selected()) \
{
#define SDV_INTERFACE_DEFAULT_SECTION() \
} \
selector.DefineDefaultSection(); \
if (selector.Selected()) \
{
#define SDV_INTERFACE_SECTION(section_number) \
} \
selector.DefineSection(section_number); \
if (selector.Selected()) \
{
#define END_SDV_INTERFACE_MAP() \
} \
return nullptr; /* None found */ \
}
// NOLINTEND(cppcoreguidelines-macro-usage)
namespace sdv
{
class CInterfacePtr
{
public:
CInterfacePtr(IInterfaceAccess* pInterface = nullptr) : m_pInterface(pInterface)
{}
CInterfacePtr(const CInterfacePtr& rptrInterface) : m_pInterface(rptrInterface.m_pInterface.load())
{}
CInterfacePtr(CInterfacePtr&& rptrInterface) noexcept
{
IInterfaceAccess* pInterface = rptrInterface.m_pInterface.load();
rptrInterface.m_pInterface = nullptr;
m_pInterface = pInterface;
}
virtual ~CInterfacePtr() = default;
CInterfacePtr& operator=(IInterfaceAccess* pInterface)
{
m_pInterface = pInterface;
return *this;
}
CInterfacePtr& operator=(const CInterfacePtr& rptrInterface)
{
m_pInterface = rptrInterface.m_pInterface.load();
return *this;
}
CInterfacePtr& operator=(CInterfacePtr&& rptrInterface) noexcept
{
IInterfaceAccess* pInterface = rptrInterface.m_pInterface.load();
rptrInterface.m_pInterface = nullptr;
m_pInterface = pInterface;
return *this;
}
operator IInterfaceAccess*()
{
return m_pInterface;
}
operator const IInterfaceAccess*() const
{
return m_pInterface;
}
operator bool() const
{
return static_cast<bool>(m_pInterface);
}
bool IsValid() const
{
return static_cast<bool>(m_pInterface);
}
template <typename TIfc>
TIfc* GetInterface() const
{
return m_pInterface ? m_pInterface.load()->GetInterface(GetInterfaceId<TIfc>()).template get<TIfc>() : nullptr;
}
private:
std::atomic<IInterfaceAccess*> m_pInterface{nullptr};
};
template <>
inline IInterfaceAccess* CInterfacePtr::GetInterface<IInterfaceAccess>() const
{
return m_pInterface;
}
using TInterfaceAccessPtr = CInterfacePtr;
template <typename TMember>
inline sdv::interface_t InterfaceMapChainHelper(TMember& rtMember, interface_id idInterface)
{
return rtMember.GetInterface(idInterface);
}
// Warning of cppchgeck for a potential const variable cannot be applied due to the non-const nature of interfaces. Suppress
// warning.
// cppcheck-suppress constParameterReference
inline sdv::interface_t InterfaceMapChainHelper(CInterfacePtr& rptrMember, interface_id idInterface)
{
return rptrMember ? static_cast<IInterfaceAccess*>(rptrMember)->GetInterface(idInterface) : nullptr;
}
template <typename TMember>
inline sdv::interface_t InterfaceMapChainHelper(TMember* ptMember, interface_id idInterface)
{
return ptMember ? ptMember->GetInterface(idInterface) : nullptr;
}
template <typename TMember>
inline sdv::interface_t InterfaceMapChainHelper(std::shared_ptr<TMember>& rptrMember, interface_id idInterface)
{
return rptrMember ? rptrMember->GetInterface(idInterface) : nullptr;
}
template <typename TMember>
inline sdv::interface_t InterfaceMapChainHelper(std::weak_ptr<TMember>& rweakMember, interface_id idInterface)
{
std::shared_ptr<TMember> ptrMember = rweakMember.lock();
return InterfaceMapChainHelper(ptrMember, idInterface);
}
template <typename TInterface>
struct SInterfaceMemberHelper
{
template <typename TMember>
static sdv::interface_t InterfaceMapEntryHelper(TMember& rtMember, interface_id idInterface)
{
static_assert(std::is_same_v<TInterface, TMember> || std::is_base_of_v<TInterface, TMember>);
if (sdv::GetInterfaceId<TInterface>() == idInterface)
{
return static_cast<TInterface*>(&rtMember);
}
return nullptr;
}
template <typename TMember>
static sdv::interface_t InterfaceMapEntryHelper(TMember* ptMember, interface_id idInterface)
{
static_assert(std::is_same_v<TInterface, TMember> || std::is_base_of_v<TInterface, TMember>);
if (sdv::GetInterfaceId<TInterface>() == idInterface)
{
return static_cast<TInterface*>(ptMember);
}
return nullptr;
}
template <typename TMember>
static sdv::interface_t InterfaceMapEntryHelper(std::shared_ptr<TMember>& rptrMember, interface_id idInterface)
{
static_assert(std::is_same_v<TInterface, TMember> || std::is_base_of_v<TInterface, TMember>);
if (sdv::GetInterfaceId<TInterface>() == idInterface)
{
return static_cast<TInterface*>(rptrMember.get());
}
return nullptr;
}
template <typename TMember>
static sdv::interface_t InterfaceMapEntryHelper(std::weak_ptr<TMember>& rweakMember, interface_id idInterface)
{
static_assert(std::is_same_v<TInterface, TMember> || std::is_base_of_v<TInterface, TMember>);
std::shared_ptr<TMember> ptrMember = rweakMember.lock();
return InterfaceMapEntryHelper<TMember>(ptrMember, idInterface);
}
};
class CObjectLifetimeWrapper : public IInterfaceAccess, public IObjectLifetime, public IObjectDestroy
{
public:
CObjectLifetimeWrapper() = default;
~CObjectLifetimeWrapper()
{}
// Interface map
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(IObjectLifetime)
SDV_INTERFACE_ENTRY(IObjectDestroy)
SDV_INTERFACE_CHAIN_MEMBER(m_pObject)
END_SDV_INTERFACE_MAP()
static IInterfaceAccess* CreateWrapper(IInterfaceAccess* pObject)
{
if (!pObject) return nullptr; // Nothing to manage
std::unique_ptr<CObjectLifetimeWrapper> ptrWrapper = std::make_unique<CObjectLifetimeWrapper>();
// Ignore cppcheck warning; normally the returned pointer should always have a value at this stage (otherwise an
// exception was triggered).
// cppcheck-suppress knownConditionTrueFalse
if (!ptrWrapper)
return nullptr;
ptrWrapper->Increment();
ptrWrapper->m_pObject = pObject;
// Store the pointer internally - this will keep the pointer alive, but invalidates ptrWrapper.
std::unique_ptr<CObjectLifetimeWrapper>& rptrKeepAlive = ptrWrapper->m_ptrKeepAlive;
rptrKeepAlive = std::move(ptrWrapper);
// Return the interface pointer
return rptrKeepAlive.get();
}
virtual void Increment() override
{
m_iCounter++;
}
virtual bool Decrement() override
{
if (!m_iCounter) return false;
m_iCounter--;
if (!m_iCounter)
{
IObjectDestroy* pObjectDestroy = CInterfacePtr(m_pObject).GetInterface<IObjectDestroy>();
if (pObjectDestroy) pObjectDestroy->DestroyObject();
m_pObject = nullptr;
m_ptrKeepAlive.reset();
return true;
}
return false;
}
virtual uint32_t GetCount() const override
{
return static_cast<uint32_t>(m_iCounter);
}
virtual void DestroyObject() override
{
// Destroy object is only allowed when the counter is 1.
if (static_cast<int32_t>(m_iCounter) != 1)
std::cerr << "Trying to destroy an object having references." << std::endl;
if (static_cast<int32_t>(m_iCounter) > 0)
Decrement();
}
IInterfaceAccess* m_pObject = nullptr;
std::atomic<int32_t> m_iCounter = 0;
std::unique_ptr<CObjectLifetimeWrapper> m_ptrKeepAlive;
};
class CObjectPtr
{
public:
CObjectPtr(IInterfaceAccess* pInterface = nullptr)
{
Assign(pInterface);
}
CObjectPtr(const CObjectPtr& rptrInterface) : m_ptrObject(rptrInterface.m_ptrObject)
{
IObjectLifetime* pObjectLifetime = GetInterface<IObjectLifetime>();
if (pObjectLifetime) pObjectLifetime->Increment();
}
CObjectPtr(CObjectPtr&& rptrInterface) noexcept : m_ptrObject(std::move(rptrInterface.m_ptrObject))
{}
virtual ~CObjectPtr()
{
Clear();
}
CObjectPtr& operator=(IInterfaceAccess* pInterface)
{
Assign(pInterface);
return *this;
}
CObjectPtr& operator=(const CObjectPtr& rptrInterface)
{
Clear();
m_ptrObject = rptrInterface.m_ptrObject;
IObjectLifetime* pObjectLifetime = GetInterface<IObjectLifetime>();
if (pObjectLifetime) pObjectLifetime->Increment();
return *this;
}
CObjectPtr& operator=(CObjectPtr&& rptrInterface) noexcept
{
Attach(rptrInterface.Detach());
return *this;
}
operator IInterfaceAccess*()
{
return m_ptrObject;
}
operator const IInterfaceAccess*() const
{
return m_ptrObject;
}
operator CInterfacePtr() const
{
return m_ptrObject;
}
operator bool() const
{
return IsValid();
}
bool IsValid() const
{
return static_cast<bool>(m_ptrObject);
}
template <typename TIfc>
TIfc* GetInterface() const
{
return m_ptrObject.GetInterface<TIfc>();
}
void Assign(IInterfaceAccess* pObject)
{
Clear();
if (!pObject) return;
IObjectLifetime* pLifetime = CInterfacePtr(pObject).GetInterface<IObjectLifetime>();
if (pLifetime) // Object provides lifetime management. Use this...
{
m_ptrObject = pObject;
pLifetime->Increment();
}
else // Create a lifetime management wrapper. Do not increase count... this has already been done during creation
m_ptrObject = CObjectLifetimeWrapper::CreateWrapper(pObject);
}
void Clear()
{
IObjectLifetime* pLifetime = m_ptrObject.GetInterface<IObjectLifetime>();
if (pLifetime) // Object provides lifetime management. Use this...
pLifetime->Decrement();
m_ptrObject = nullptr;
}
void Attach(IInterfaceAccess* pObject)
{
Clear();
if (CInterfacePtr(pObject).GetInterface<IObjectLifetime>())
m_ptrObject = pObject;
}
CInterfacePtr Detach()
{
if (!m_ptrObject) return CInterfacePtr();
CInterfacePtr ptr = std::move(m_ptrObject);
m_ptrObject = nullptr;
return ptr;
}
private:
CInterfacePtr m_ptrObject;
};
using TObjectPtr = CObjectPtr;
} // namespace sdv
#ifndef DONT_LOAD_CORE_TYPES
#include "mem_access.h"
#endif
#endif // !defined INTERFACE_IMPL_H