Program Listing for File component_impl.h#
↰ Return to documentation for file (support\component_impl.h)
/********************************************************************************
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Erik Verhoeven - initial API and implementation
********************************************************************************/
#ifndef COMPONENT_IMPL_H
#define COMPONENT_IMPL_H
#include <cstring>
#include <mutex>
#include <shared_mutex>
#include <vector>
#include <string>
#include <sstream>
#include "../interfaces/core_types.h"
#include "../interfaces/core.h"
#include "../interfaces/repository.h"
#include "sdv_core.h"
#include "interface_ptr.h"
#include "local_service_access.h"
#include "param_impl.h"
#include "toml.h"
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
#define SDV_STRINGIZE_HELPER2(txt) #txt
#define SDV_STRINGIZE_HELPER(txt) SDV_STRINGIZE_HELPER2(txt)
// NOLINTEND(cppcoreguidelines-macro-usage)
#ifdef _WIN32
// Resolve conflict
#pragma push_macro("interface")
#undef interface
#pragma push_macro("GetObject")
#undef GetObject
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <WinSock2.h>
#include <Windows.h>
#include <objbase.h>
// Resolve conflict
#pragma pop_macro("GetObject")
#pragma pop_macro("interface")
#ifdef GetClassInfo
#undef GetClassInfo
#endif
#elif defined __unix__
#else
#error OS is not supported!
#endif // defined _MSC_VER
namespace sdv
{
// Forward declarations
class CSdvObject;
// Object control classes //
struct ISdvObjectClassInfo
{
public:
virtual SClassInfo GetClassInfo() const = 0;
virtual u8string GetClassName() const = 0;
virtual sequence<u8string> GetClassAliases() const = 0;
virtual u8string GetDefaultObjectName() const = 0;
virtual u8string GetDefaultConfig(const u8string& rssTablePrefix = {}) const = 0;
virtual EObjectType GetObjectType() const = 0;
virtual uint32_t GetObjectFlags() const = 0;
virtual sequence<u8string> GetObjectDependencies() const = 0;
virtual std::unique_ptr<CSdvObject> CreateObject() = 0;
};
class CSdvObjectAccess : public IInterfaceAccess
{
public:
CSdvObjectAccess() = default;
CSdvObjectAccess(CSdvObjectAccess&) = delete;
CSdvObjectAccess& operator=(CSdvObjectAccess&) = delete;
CSdvObjectAccess(CSdvObjectAccess&&) = delete;
CSdvObjectAccess& operator=(CSdvObjectAccess&&) = delete;
virtual ~CSdvObjectAccess() = default;
IInterfaceAccess* GetObjectAccess()
{
return static_cast<IInterfaceAccess*>(this);
}
// Interface map
BEGIN_SDV_INTERFACE_MAP()
END_SDV_INTERFACE_MAP()
};
class CLifetimeCookie
{
public:
CLifetimeCookie() = default;
CLifetimeCookie(std::function<void()> fnLifetimeIncr, std::function<void()> fnLifetimeDecr) :
m_fnLifetimeIncr(fnLifetimeIncr), m_fnLifetimeDecr(fnLifetimeDecr)
{
if (m_fnLifetimeIncr) m_fnLifetimeIncr();
}
CLifetimeCookie(const CLifetimeCookie& rCookie) :
m_fnLifetimeIncr(rCookie.m_fnLifetimeIncr), m_fnLifetimeDecr(rCookie.m_fnLifetimeDecr)
{
if (m_fnLifetimeIncr) m_fnLifetimeIncr();
}
CLifetimeCookie(CLifetimeCookie&& rCookie) noexcept :
m_fnLifetimeIncr(rCookie.m_fnLifetimeIncr), m_fnLifetimeDecr(rCookie.m_fnLifetimeDecr)
{
rCookie.m_fnLifetimeIncr = nullptr;
rCookie.m_fnLifetimeDecr = nullptr;
}
~CLifetimeCookie()
{
if (m_fnLifetimeDecr) m_fnLifetimeDecr();
}
CLifetimeCookie& operator=(const CLifetimeCookie& rCookie)
{
if (m_fnLifetimeDecr) m_fnLifetimeDecr();
m_fnLifetimeIncr = rCookie.m_fnLifetimeIncr;
m_fnLifetimeDecr = rCookie.m_fnLifetimeDecr;
if (m_fnLifetimeIncr) m_fnLifetimeIncr();
return *this;
}
CLifetimeCookie& operator=(CLifetimeCookie&& rCookie) noexcept
{
if (m_fnLifetimeDecr) m_fnLifetimeDecr();
m_fnLifetimeIncr = rCookie.m_fnLifetimeIncr;
m_fnLifetimeDecr = rCookie.m_fnLifetimeDecr;
rCookie.m_fnLifetimeIncr = nullptr;
rCookie.m_fnLifetimeDecr = nullptr;
return *this;
}
private:
std::function<void()> m_fnLifetimeIncr;
std::function<void()> m_fnLifetimeDecr;
};
class CObjectFactory : public IInterfaceAccess, public IObjectFactory
{
// Friend class SDV object and definition
friend class CSdvObject;
template <class TSdvObject>
friend class CSdvObjectClass;
public:
CObjectFactory() = default;
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(IObjectFactory)
END_SDV_INTERFACE_MAP()
CLifetimeCookie CreateLifetimeCookie()
{
return CLifetimeCookie([this]() { m_uiActiveObjectCount++; },
[this]() { if (m_uiActiveObjectCount) m_uiActiveObjectCount--; });
}
uint32_t GetActiveObjects() const
{
return m_uiActiveObjectCount;
}
const char* GetManifest()
{
if (m_ssManifest.empty())
BuildManifest();
return m_ssManifest.c_str();
}
virtual sequence<u8string> GetClassNames() const override;
virtual SClassInfo GetClassInfo(const u8string& ssClassName) const override;
virtual IInterfaceAccess* CreateObject(const u8string& ssClassName) override;
virtual void DestroyObject(IInterfaceAccess* object) override;
virtual void DestroyAllObjects() override;
protected:
void BuildManifest();
void ExposeObjectClass(ISdvObjectClassInfo* pClassInfo);
void RevokeObjectClass(const ISdvObjectClassInfo* pClassInfo);
static std::string QuoteText(const std::string& rssText);
private:
std::atomic<uint32_t> m_uiActiveObjectCount{0};
mutable std::mutex m_mtxActiveObjects;
std::vector<std::unique_ptr<CSdvObject>> m_vecActiveObjects;
mutable std::shared_mutex m_mtxObjectClasses;
std::vector<ISdvObjectClassInfo*> m_vecObjectClasses;
std::string m_ssManifest;
};
// Framework module classes //
class CModule : public CSdvObjectAccess, public CObjectFactory
{
public:
CModule() = default;
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_CHAIN_BASE(CObjectFactory)
END_SDV_INTERFACE_MAP()
IInterfaceAccess* GetModuleControl(uint32_t interfaceVersion)
{
// No compatibility interfacing available yet.
return interfaceVersion == SDVFrameworkInterfaceVersion ? GetObjectAccess() : nullptr;
}
};
inline CModule& GetModule()
{
static CModule module;
return module;
}
inline CLifetimeCookie CreateLifetimeCookie()
{
return GetModule().CreateLifetimeCookie();
}
// Component object class //
template <class TSdvObject>
class CSdvObjectClass : public ISdvObjectClassInfo
{
public:
CSdvObjectClass()
{
// Add this object definition to the definition list.
GetModule().ExposeObjectClass(this);
}
CSdvObjectClass(CSdvObjectClass&) = delete;
CSdvObjectClass(CSdvObjectClass&&) = delete;
CSdvObjectClass& operator=(CSdvObjectClass&) = delete;
CSdvObjectClass& operator=(CSdvObjectClass&&) = delete;
virtual ~CSdvObjectClass()
{
GetModule().RevokeObjectClass(this);
}
SClassInfo GetClassInfo() const override
{
SClassInfo sClassInfo{};
sClassInfo.ssName = GetClassName();
sClassInfo.seqClassAliases = GetClassAliases();
sClassInfo.ssDefaultObjectName = GetDefaultObjectName();
sClassInfo.ssDefaultConfig = GetDefaultConfig("Parameters");
sClassInfo.eType = GetObjectType();
sClassInfo.uiFlags = GetObjectFlags();
sClassInfo.seqDependencies = GetObjectDependencies();
return sClassInfo;
}
virtual u8string GetClassName() const override
{
return TSdvObject::GetClassNameStatic();
}
virtual sequence<u8string> GetClassAliases() const override
{
return TSdvObject::GetClassAliasesStatic();
}
virtual u8string GetDefaultConfig(const u8string& rssTablePrefix /*= {}*/) const override
{
std::vector<std::shared_ptr<CSdvParamInfo>> vecParaminfo = TSdvObject::GetParamMapInfoStatic();
std::stringstream sstream;
u8string ssGroup;
for (const auto& ptrParam : vecParaminfo)
{
if (!ptrParam) continue;
// Only describe readable and non-temporary parameters
if (ptrParam->ReadOnly() || ptrParam->Temporary()) continue;
// Is there a value? If not, skip the parameter
if (ptrParam->DefaultVal().empty()) continue;
// Need a new group?
if (ptrParam->Group() != ssGroup)
{
if (sstream.rdbuf()->in_avail())
sstream << std::endl;
sstream << "[";
if (!rssTablePrefix.empty())
sstream << rssTablePrefix << ".";
sstream << ptrParam->Group() << "]" << std::endl;
ssGroup = ptrParam->Group();
}
// Store the parameter
// Quotation of parameter name needed?
u8string ssName;
if (ptrParam->Name().find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-")
!= u8string::npos)
ssName = CObjectFactory::QuoteText(ptrParam->Name());
else
ssName = ptrParam->Name();
sstream << ssName << " = ";
if (ptrParam->Numeric() || ptrParam->Bitmask() || ptrParam->Enum())
{
std::string ssValue = ptrParam->DefaultVal();
sstream << (ssValue.empty() ? "0" : ssValue);
}
else if (ptrParam->String())
sstream << CObjectFactory::QuoteText(ptrParam->DefaultVal());
else if (ptrParam->Boolean())
sstream << (ptrParam->DefaultVal().get<bool>() ? "true" : "false");
sstream << std::endl;
}
return sstream.str();
}
virtual u8string GetDefaultObjectName() const override
{
return TSdvObject::GetDefaultObjectNameStatic();
}
virtual EObjectType GetObjectType() const override
{
return TSdvObject::GetObjectType();
}
uint32_t GetObjectFlags() const override
{
uint32_t uiFlags = 0;
if (TSdvObject::IsSingletonStatic())
uiFlags |= static_cast<uint32_t>(EObjectFlags::singleton);
// Currently no other flags defined.
return uiFlags;
}
virtual sequence<u8string> GetObjectDependencies() const override
{
return TSdvObject::GetObjectDependenciesStatic();
}
virtual std::unique_ptr<CSdvObject> CreateObject() override;
};
class CSdvObject : public CSdvParamMap, public CSdvObjectAccess, public IObjectControl
{
public:
template <class TSdvObject>
using TSdvObjectCreator = CSdvObjectClass<TSdvObject>;
CSdvObject() = default;
CSdvObject(CSdvObject&) = delete;
CSdvObject& operator=(CSdvObject&) = delete;
CSdvObject(CSdvObject&&) = delete;
CSdvObject& operator=(CSdvObject&&) = delete;
~CSdvObject() override
{}
virtual void Initialize(/*in*/ const u8string& ssObjectConfig) override
{
// Not started before or ended completely?
if (GetObjectState() != EObjectState::initialization_pending && GetObjectState() != EObjectState::destruction_pending)
{
m_eObjectState = EObjectState::runtime_error;
return;
}
// Initializing
m_eObjectState = EObjectState::initializing;
// Initialize the parameter map.
InitParamMap();
// Copy the configuration
m_ssObjectConfig = ssObjectConfig;
// Prepare initialization
OnPreInitialize();
// Parse the object configuration if there is any.
if (!ssObjectConfig.empty())
{
try
{
// Parse the config TOML.
toml::CTOMLParser parser(ssObjectConfig);
if (!parser.IsValid())
{
m_eObjectState = EObjectState::config_error;
return;
}
// Read group function (iterative)
u8string ssGroup;
std::function<void(const toml::CNodeCollection&)> fnReadGroup;
fnReadGroup = [&](const toml::CNodeCollection& rTable)
{
// Iterate through the config.
for (size_t n = 0; n < rTable.GetCount(); n++)
{
const toml::CNode node = rTable.Get(n);
switch (node.GetType())
{
case toml::ENodeType::node_integer:
case toml::ENodeType::node_floating_point:
case toml::ENodeType::node_boolean:
case toml::ENodeType::node_string:
// Ignore the result. If it is not possible to set the parameter, this is not a failure.
SetParam(ssGroup + node.GetName(), node.GetValue());
break;
case toml::ENodeType::node_table:
{
const toml::CNodeCollection sub_table= node;
if (!sub_table.IsValid()) break;
ssGroup += sub_table.GetName() + ".";
fnReadGroup(sub_table);
}
default:
// Other node types cannot be processed.
break;
}
}
};
// Parse the root node
fnReadGroup(parser);
} catch (const toml::XTOMLParseException& rexcept)
{
SDV_LOG(core::ELogSeverity::error, "Cannot process object configuration TOML: ", rexcept.what());
m_eObjectState = EObjectState::initialization_failure;
return;
}
}
// Let the object initialize itself.
if (!OnInitialize())
{
m_eObjectState = EObjectState::initialization_failure;
return;
}
// Initialization is complete.
m_eObjectState = EObjectState::initialized;
}
virtual EObjectState GetObjectState() const override
{
return m_eObjectState;
}
virtual void SetOperationMode(/*in*/ EOperationMode eMode) override
{
switch (eMode)
{
case EOperationMode::configuring:
// Allowed?
if (GetObjectState() != EObjectState::initialized && GetObjectState() != EObjectState::running &&
GetObjectState() != EObjectState::runtime_error && GetObjectState() != EObjectState::config_error)
break;
// Inform derived class
OnChangeToConfigMode();
// Unlock the parameter map.
UnlockParamMap();
m_eObjectState = EObjectState::configuring;
break;
case EOperationMode::running:
// Allowed?
if (GetObjectState() != EObjectState::initialized && GetObjectState() != EObjectState::configuring &&
GetObjectState() != EObjectState::config_error)
break;
// Lock the parameter map.
LockParamMap();
// Inform the derived class
if (!OnChangeToRunningMode())
{
// Cannot enter running mode. Reconfiguration needed.
m_eObjectState = EObjectState::config_error;
UnlockParamMap();
break;
}
m_eObjectState = EObjectState::running;
break;
default:
// Wrong operation mode.
m_eObjectState = EObjectState::runtime_error;
break;
}
}
virtual u8string GetObjectConfig() const override
{
// During the initialization, return the stored object configuration.
if (m_eObjectState == EObjectState::initializing || m_eObjectState == EObjectState::initialization_pending)
return m_ssObjectConfig;
// Split path function (splits the group from the parameter names)
auto fnSplitPath = [](const u8string& rssPath) -> std::pair<u8string, u8string>
{
size_t nPos = rssPath.find_last_of('.');
if (nPos == u8string::npos)
return std::make_pair("", rssPath);
return std::make_pair(rssPath.substr(0, nPos), rssPath.substr(nPos + 1));
};
// Create a new configuration string from the parameters.
auto seqParameters = GetParamPaths();
if (seqParameters.empty()) return {};
// Iterate through the list of parameter names and create the TOML entries for it.
u8string ssGroup;
toml::CTOMLParser parser("");
toml::CNodeCollection table(parser);
for (auto ssParamPath : seqParameters)
{
// Get the parameter object
auto ptrParam = FindParamObject(ssParamPath);
// Read only and temporary parameters are not stored
if ((!ptrParam->Locked() && ptrParam->ReadOnly()) || !ptrParam->Temporary())
continue;
// Get the value
any_t anyValue = ptrParam->Get();
if (anyValue.empty())
continue;
// Split the path in group and parameter name
auto prParam = fnSplitPath(ssParamPath);
// Need to add a group?
if (prParam.first != ssGroup)
{
table = parser.AddTable(prParam.first);
ssGroup = prParam.first;
}
// Store the value
table.AddValue(prParam.second, anyValue);
}
return parser.GetTOML();
}
virtual void Shutdown() override
{
// Lock the parameter map - do not allow any more changes
LockParamMap();
// Set state
m_eObjectState = EObjectState::shutdown_in_progress;
// Inform derived class
OnShutdown();
// Set status
m_eObjectState = EObjectState::destruction_pending;
// Unlock parameter map to allow re-initialization.
UnlockParamMap();
}
void SetObjectIntoConfigErrorState()
{
if (m_eObjectState == EObjectState::initialized || m_eObjectState == EObjectState::configuring)
m_eObjectState = EObjectState::config_error;
}
void SetObjectIntoRuntimeErrorState()
{
if (m_eObjectState == EObjectState::running)
m_eObjectState = EObjectState::runtime_error;
}
static sequence<u8string> GetClassAliasesStatic() { return {}; }
static u8string GetDefaultObjectNameStatic() { return {}; }
static bool IsSingletonStatic() { return false; }
static sequence<u8string> GetObjectDependenciesStatic() { return sequence<u8string>(); }
virtual void OnPreInitialize() {}
virtual bool OnInitialize() { return true; }
virtual void OnChangeToConfigMode() {}
virtual bool OnChangeToRunningMode() { return true; }
virtual void OnShutdown() {}
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(IParameters)
SDV_INTERFACE_ENTRY(IObjectControl)
END_SDV_INTERFACE_MAP()
private:
std::atomic<EObjectState> m_eObjectState = EObjectState::initialization_pending;
std::string m_ssObjectConfig;
};
template <class TSdvObject>
class CObjectInstance : public TSdvObject
{
static_assert(std::is_base_of_v<CSdvObject, TSdvObject>, "TSdvObject must derive from sdv::CSdvObject!");
public:
// Interface map
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_CHAIN_BASE(CSdvObject)
SDV_INTERFACE_CHAIN_BASE(TSdvObject)
END_SDV_INTERFACE_MAP()
};
// Object control class implementation //
inline sequence<u8string> CObjectFactory::GetClassNames() const
{
std::shared_lock<std::shared_mutex> lock(m_mtxObjectClasses);
sequence<u8string> seqClassNames;
for (const ISdvObjectClassInfo* pClassInfo : m_vecObjectClasses)
{
if (!pClassInfo) continue;
seqClassNames.push_back(pClassInfo->GetClassName());
}
return seqClassNames;
}
inline SClassInfo CObjectFactory::GetClassInfo(const u8string& ssClassName) const
{
if (ssClassName.empty()) return {};
std::shared_lock<std::shared_mutex> lock(m_mtxObjectClasses);
for (ISdvObjectClassInfo* pClassInfo : m_vecObjectClasses)
{
if (!pClassInfo) continue;
// Check for the class name.
bool bFound = pClassInfo->GetClassName() == ssClassName;
// If not found, check for all aliases.
auto seqClassAliases = pClassInfo->GetClassAliases();
for (auto itAlias = seqClassAliases.begin(); !bFound && itAlias != seqClassAliases.end(); ++itAlias)
bFound = *itAlias == ssClassName;
if (!bFound) continue;
// Return the class information
return pClassInfo->GetClassInfo();
}
// No class information found
return {};
}
inline IInterfaceAccess* CObjectFactory::CreateObject(const u8string& ssClassName)
{
if (ssClassName.empty()) return nullptr;
std::shared_lock<std::shared_mutex> lock(m_mtxObjectClasses);
for (ISdvObjectClassInfo* pClassInfo : m_vecObjectClasses)
{
if (!pClassInfo) continue;
// Check for the class name.
bool bFound = pClassInfo->GetClassName() == ssClassName;
// If not found, check for all aliases.
auto seqClassAliases = pClassInfo->GetClassAliases();
for (auto itAlias = seqClassAliases.begin(); !bFound && itAlias != seqClassAliases.end(); ++itAlias)
bFound = *itAlias == ssClassName;
if (!bFound) continue;
++m_uiActiveObjectCount;
auto object = pClassInfo->CreateObject();
lock.unlock();
if(!object)
{
--m_uiActiveObjectCount;
return nullptr;
}
auto ret = object.get()->GetObjectAccess();
std::unique_lock<std::mutex> lockObjects (m_mtxActiveObjects);
m_vecActiveObjects.emplace_back(std::move(object));
return ret;
}
return nullptr;
}
inline void CObjectFactory::DestroyObject(IInterfaceAccess* object)
{
if (object == nullptr)
{
return;
}
std::unique_lock<std::mutex> lockObjects(m_mtxActiveObjects);
for(auto iter = m_vecActiveObjects.begin(); iter != m_vecActiveObjects.end(); ++iter)
{
if(iter->get()->GetObjectAccess() == object)
{
auto objectPtr = std::move(*iter);
m_vecActiveObjects.erase(iter);
lockObjects.unlock();
objectPtr = nullptr;
if (m_uiActiveObjectCount) --m_uiActiveObjectCount;
return;
}
}
}
inline void CObjectFactory::DestroyAllObjects()
{
std::unique_lock<std::mutex> lockObjects(m_mtxActiveObjects);
auto objects = std::move(m_vecActiveObjects);
lockObjects.unlock();
while(!objects.empty())
{
objects.pop_back();
if (m_uiActiveObjectCount) --m_uiActiveObjectCount;
}
}
inline void CObjectFactory::BuildManifest()
{
// Start the manifest
std::stringstream sstream;
sstream << R"toml(# Module manifest
[Interface]
Version = )toml" << SDVFrameworkInterfaceVersion
<< std::endl
<< std::endl;
// Add all classes to the manifest
std::shared_lock<std::shared_mutex> lock(m_mtxObjectClasses);
for (const ISdvObjectClassInfo* pClassInfo : m_vecObjectClasses)
{
sstream << "[[Class]]" << std::endl;
sstream << "Name = " << QuoteText(pClassInfo->GetClassName()) << std::endl;
if (pClassInfo->GetClassName().empty())
continue;
if (!pClassInfo->GetClassAliases().empty())
{
sstream << "Aliases = [";
bool bInitialAlias = true;
for (const u8string& rssAlias : pClassInfo->GetClassAliases())
{
if (!bInitialAlias)
sstream << ", ";
bInitialAlias = false;
sstream << QuoteText(rssAlias);
}
sstream << "]" << std::endl;
}
if (!pClassInfo->GetDefaultObjectName().empty())
sstream << "DefaultName = " << QuoteText(pClassInfo->GetDefaultObjectName()) << std::endl;
if (pClassInfo->GetObjectType() == EObjectType::undefined)
continue;
sstream << "Type = " << QuoteText(ObjectType2String(pClassInfo->GetObjectType())) << std::endl;
if (pClassInfo->GetObjectFlags() & static_cast<uint32_t>(EObjectFlags::singleton))
sstream << "Singleton = true" << std::endl;
if (!pClassInfo->GetObjectDependencies().empty())
{
sstream << "Dependencies = [";
bool bInitialDependency = true;
for (const u8string& rssDependsOn : pClassInfo->GetObjectDependencies())
{
if (!bInitialDependency)
sstream << ", ";
bInitialDependency = false;
sstream << "\"" << rssDependsOn << "\"";
}
sstream << "]" << std::endl;
}
// Assign the parameter table to the class. Prepend [Class.Parameters] to every table.
std::string ssParameters = pClassInfo->GetDefaultConfig("Class.Parameters");
if (!ssParameters.empty()) sstream << ssParameters;
}
m_ssManifest = sstream.str();
}
inline void CObjectFactory::ExposeObjectClass(ISdvObjectClassInfo* pClassInfo)
{
if (pClassInfo)
{
std::unique_lock<std::shared_mutex> lock(m_mtxObjectClasses);
m_vecObjectClasses.push_back(pClassInfo);
// Attention: pObjectClass is a pointer to ISdvObjectClassInfo even if the class was derived.
// Virtual functions are not available yet at this stage.
}
}
inline void CObjectFactory::RevokeObjectClass(const ISdvObjectClassInfo* pClassInfo)
{
std::unique_lock<std::shared_mutex> lock(m_mtxObjectClasses);
auto itObjectClass = std::find(m_vecObjectClasses.begin(), m_vecObjectClasses.end(), pClassInfo);
if (itObjectClass != m_vecObjectClasses.end())
m_vecObjectClasses.erase(itObjectClass);
// TODO EVE: Updated through cppcheck warning
//for (auto objectClassIter = m_vecObjectClasses.begin(); objectClassIter != m_vecObjectClasses.end();
// objectClassIter++)
//{
// if (*objectClassIter == pClassInfo)
// {
// m_vecObjectClasses.erase(objectClassIter);
// break;
// }
//}
}
inline std::string CObjectFactory::QuoteText(const std::string& rssText)
{
std::stringstream sstreamQuotedText;
sstreamQuotedText << "\"";
for (size_t nPos = 0; nPos < rssText.size(); nPos++)
{
uint8_t uiChar = static_cast<uint8_t>(rssText[nPos]);
uint32_t uiUTFChar = 0;
switch (uiChar)
{
case '\'':
sstreamQuotedText << '\'';
break; // Single quote character
case '\b':
sstreamQuotedText << "\\b";
break; // Escape backspace
case '\t':
sstreamQuotedText << "\\t";
break; // Escape tab
case '\n':
sstreamQuotedText << "\\n";
break; // Escape linefeed
case '\f':
sstreamQuotedText << "\\f";
break; // Escape form feed
case '\r':
sstreamQuotedText << "\\r";
break; // Escape carriage return
case '\"':
sstreamQuotedText << "\\\"";
break; // Escape quote
case '\\':
sstreamQuotedText << "\\\\";
break; // Escape backslash
default:
// Check for ASCII character
if (uiChar >= 0x20 && uiChar < 0x7f)
{
// Standard ASCII
sstreamQuotedText << static_cast<char>(uiChar);
break;
}
// Use UNICODE escape character for the quoted text
if (uiChar <= 0x80) // One byte UTF-8
uiUTFChar = static_cast<uint32_t>(uiChar);
else if (uiChar <= 0xDF) // Two bytes UTF-8
{
uiUTFChar = static_cast<size_t>(uiChar & 0b00011111) << 6;
// Expecting the next character to be between 0x80 and 0xBF
nPos++;
if (nPos >= rssText.size())
break;
uiUTFChar |= static_cast<size_t>(rssText[nPos] & 0b00111111);
}
else if (uiChar <= 0xEF) // Three bytes UTF-8
{
uiUTFChar = static_cast<size_t>(uiChar & 0b00001111) << 6;
// Expecting the next character to be between 0x80 and 0xBF
nPos++;
if (nPos >= rssText.size())
break;
uiUTFChar |= static_cast<size_t>(rssText[nPos] & 0b00111111);
uiUTFChar <<= 6;
// Expecting the next character to be between 0x80 and 0xBF
nPos++;
if (nPos >= rssText.size())
break;
uiUTFChar |= static_cast<size_t>(rssText[nPos] & 0b00111111);
}
else if (uiChar <= 0xF7) // Four bytes UTF-8
{
uiUTFChar = static_cast<size_t>(uiChar & 0b00000111) << 6;
// Expecting the next character to be between 0x80 and 0xBF
nPos++;
if (nPos >= rssText.size())
break;
uiUTFChar |= static_cast<size_t>(rssText[nPos] & 0b00111111);
uiUTFChar <<= 6;
// Expecting the next character to be between 0x80 and 0xBF
nPos++;
if (nPos >= rssText.size())
break;
uiUTFChar |= static_cast<size_t>(rssText[nPos] & 0b00111111);
uiUTFChar <<= 6;
// Expecting the next character to be between 0x80 and 0xBF
nPos++;
if (nPos >= rssText.size())
break;
uiUTFChar |= static_cast<size_t>(rssText[nPos] & 0b00111111);
}
// Stream the UTF character
if (uiUTFChar <= 0xFFFF)
sstreamQuotedText << "\\u" << std::uppercase << std::hex << std::setfill('0') << std::setw(4) << uiUTFChar;
else
sstreamQuotedText << "\\U" << std::uppercase << std::hex << std::setfill('0') << std::setw(8) << uiUTFChar;
break;
}
}
sstreamQuotedText << "\"";
return sstreamQuotedText.str();
}
template <class TSdvObject>
inline std::unique_ptr<CSdvObject> CSdvObjectClass<TSdvObject>::CreateObject()
{
std::unique_ptr<CSdvObject> ret;
try
{
ret = std::make_unique<CObjectInstance<TSdvObject>>();
}
catch (...)
{
SDV_LOG(core::ELogSeverity::error,
"Failed to instantiate object of class ",
GetClassName(),
" - exception thrown during construction! ");
}
return ret;
}
} // namespace sdv
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
#ifdef SDV_NO_CLASS_DEFINITION
#define DEFINE_SDV_OBJECT(sdv_object_class) \
extern "C" bool HasActiveObjects(); \
extern "C" sdv::IInterfaceAccess* GetModuleFactory(uint32_t uiInterfaceVersion); \
extern "C" const char* GetManifest();
#elif defined SDV_NO_EXPORT_DEFINITION
#define DEFINE_SDV_OBJECT(sdv_object_class) \
\
struct SObjectClassInstance_##sdv_object_class \
{ \
public: \
\
SObjectClassInstance_##sdv_object_class() \
{ \
/* Enforce derivation of sdv::CSdvObject. */ \
static_assert(std::is_base_of<sdv::CSdvObject, sdv_object_class>::value, \
"CSdvObject is not base of sdv_object_class"); \
/* Call the static function once to instantiate the definition. */ \
GetObjectClassInstance(); \
} \
\
static sdv_object_class::TSdvObjectCreator<sdv_object_class>& GetObjectClassInstance() \
{ \
static sdv_object_class::TSdvObjectCreator<sdv_object_class> object_class; \
return object_class; \
} \
}; \
\
static SObjectClassInstance_##sdv_object_class g_##sdv_object_class; \
bool HasActiveObjects(); \
sdv::IInterfaceAccess* GetModuleFactory(uint32_t uiInterfaceVersion); \
const char* GetManifest();
#else
#define DEFINE_SDV_OBJECT(sdv_object_class) \
\
struct SObjectClassInstance_##sdv_object_class \
{ \
public: \
\
SObjectClassInstance_##sdv_object_class() \
{ \
/* Enforce derivation of sdv::CSdvObject. */ \
static_assert(std::is_base_of<sdv::CSdvObject, sdv_object_class>::value, \
"CSdvObject is not base of sdv_object_class"); \
/* Call the static function once to instantiate the definition. */ \
GetObjectClassInstance(); \
} \
\
static sdv_object_class::TSdvObjectCreator<sdv_object_class>& GetObjectClassInstance() \
{ \
static sdv_object_class::TSdvObjectCreator<sdv_object_class> object_class; \
return object_class; \
} \
}; \
\
static SObjectClassInstance_##sdv_object_class g_##sdv_object_class; \
extern "C" SDV_SYMBOL_PUBLIC bool HasActiveObjects(); \
extern "C" SDV_SYMBOL_PUBLIC sdv::IInterfaceAccess* GetModuleFactory(uint32_t uiInterfaceVersion); \
extern "C" SDV_SYMBOL_PUBLIC const char* GetManifest();
#endif // !defined SDV_NO_CLASS_DEFINITION && !defined SDV_NO_EXPORT_DEFINITION
#define DECLARE_OBJECT_CLASS_TYPE(class_type) \
\
constexpr static sdv::EObjectType GetObjectType() \
{ \
return class_type; \
}
#define DECLARE_OBJECT_CLASS_NAME(class_name_string) \
\
static sdv::u8string GetClassNameStatic() \
{ \
return class_name_string; \
}
#define DECLARE_OBJECT_CLASS_ALIAS(...) \
\
static sdv::sequence<sdv::u8string> GetClassAliasesStatic() \
{ \
return sdv::sequence<sdv::u8string>({__VA_ARGS__}); \
}
#define DECLARE_DEFAULT_OBJECT_NAME(object_name_string) \
\
static sdv::u8string GetDefaultObjectNameStatic() \
{ \
return object_name_string; \
}
#define DECLARE_OBJECT_SINGLETON() \
\
static bool IsSingletonStatic() { return true; }
#define DECLARE_OBJECT_DEPENDENCIES(...) \
\
static sdv::sequence<sdv::u8string> GetObjectDependenciesStatic() { return sdv::sequence<sdv::u8string>({__VA_ARGS__}); }
// NOLINTEND(cppcoreguidelines-macro-usage)
/*
* @brief Returns whether or not instances of objects implemented by this module are running. If none, the module can be unloaded.
* @remarks Unloading the module with running instances could cause a crash and should be prevented at all costs. Unloading the
* module removes the code of the objects still running.
* @return Returns true when object instances are running; otherwise returns 'false'.
*/
inline extern bool HasActiveObjects()
{
return sdv::GetModule().GetActiveObjects() != 0;
}
/*
* @brief Get the module factory interface with a specific version.
* @details This function provides access to the objects being implemented in this module.
* @param[in] interfaceVersion Request the module factory for a specific interface version. Using another interface version than
* the one returned from the manifest, might cause the function to fail.
* @return Returns pointer to the IInterfaceAccess interface of the module factory object.
*/
inline extern sdv::IInterfaceAccess* GetModuleFactory(uint32_t interfaceVersion)
{
return sdv::GetModule().GetModuleControl(interfaceVersion);
}
/*
* @brief Get the the module manifest.
* @details Each module contains a manifest containing general information as well as information about the component classes. This
* allows installing the component without having to instantiate the classes.
* @return Returns the pointer to a zero terminated string containing the module manifest or NULL when there is no string.
*/
inline extern const char* GetManifest()
{
return sdv::GetModule().GetManifest();
}
#endif // !defined COMPONENT_IMPL_H