Precommit (#1)

* first commit

* cleanup
This commit is contained in:
tompzf
2025-11-04 13:28:06 +01:00
committed by GitHub
parent dba45dc636
commit 6ed4b1534e
898 changed files with 256340 additions and 0 deletions

491
export/support/any.h Normal file
View File

@@ -0,0 +1,491 @@
#ifndef SDV_ANY_H
#define SDV_ANY_H
#include <string>
#include <algorithm>
#include <ostream>
#include <istream>
#include <filesystem>
#include "string.h"
#include "interface.h"
#include "except.h"
namespace sdv
{
/**
* @brief The 'any' class implementation.
*/
class any_t
{
public:
/**
* @brief Value type enumeration
*/
enum class EValType : uint32_t
{
val_type_empty = 0, ///< Empty value
val_type_bool = 1, ///< Boolean value; bVal is used.
val_type_int8 = 8, ///< 8-Bit signed value; i8Val is used.
val_type_uint8 = 9, ///< 8-Bit unsigned value; ui8Val is used.
val_type_int16 = 16, ///< 16-Bit signed value; i16Val is used.
val_type_uint16 = 17, ///< 16-Bit unsigned value; ui16Val is used.
val_type_int32 = 32, ///< 32-Bit signed value; i32Val is used.
val_type_uint32 = 33, ///< 32-Bit unsigned value; ui32Val is used.
val_type_int64 = 64, ///< 64-Bit signed value; i64Val is used.
val_type_uint64 = 65, ///< 64-Bit unsigned value; ui64Val is used.
val_type_char = 100, ///< ANSI Character value; cVal is used.
val_type_char16 = 116, ///< UTF-16 Character value; c16Val is used.
val_type_char32 = 132, ///< UTF-32 Character value; c32Val is used.
val_type_wchar = 101, ///< Wide character value; cwVal is used.
val_type_float = 232, ///< Singled precision floating point value; fVal is used.
val_type_double = 264, ///< Double precision floating point value; dVal is used.
val_type_long_double = 265, ///< Long double precision floating point value; ldVal is used.
val_type_fixed = 300, ///< Fixed point value; fixValue is used.
val_type_string = 1000, ///< ANSI string value; ssVal is used.
val_type_u8string = 1008, ///< UTF-8 string value; ss8Val is used.
val_type_u16string = 1016, ///< UTF-16 string value; ss16Val is used.
val_type_u32string = 1032, ///< UTF-32 string value; ss32Val is used.
val_type_wstring = 1001, ///< Wide string value; sswVal is used.
val_type_interface = 2000, ///< Interface type value; ifcVal is used.
val_type_interface_id = 2001, ///< Interface id value; idIfcVal is used.
val_type_exception_id = 3000, ///< Exception id value; idExceptVal is used.
} eValType = EValType::val_type_empty; ///< The value type
/// Anonymous union
union
{
bool bVal; ///< Boolean value
int8_t i8Val; ///< 8-Bit signed value
uint8_t ui8Val; ///< 8-Bit unsigned value
int16_t i16Val; ///< 16-Bit signed value
uint16_t ui16Val; ///< 16-Bit unsigned value
int32_t i32Val; ///< 32-Bit signed value
uint32_t ui32Val; ///< 32-Bit unsigned value
int64_t i64Val; ///< 64-Bit signed value
uint64_t ui64Val; ///< 64-Bit unsigned value
char cVal; ///< ANSI Character value
char16_t c16Val; ///< UTF-16 Character value
char32_t c32Val; ///< UTF-32 Character value
wchar_t cwVal; ///< Wide character value
float fVal; ///< Singled precision floating point value
double dVal; ///< Double precision floating point value
long double ldVal; ///< Long double precision floating point value
//fixed fixValue; ///< Fixed point value
string ssVal; ///< ANSI string value
u8string ss8Val; ///< UTF-8 string value
u16string ss16Val; ///< UTF-16 string value
u32string ss32Val; ///< UTF-32 string value
wstring sswVal; ///< Wide string value
interface_t ifcVal; ///< Interface type value
interface_id idIfcVal; ///< Interface id value
exception_id idExceptVal; ///< Exception id value
};
/**
* @brief Default constructor; construct an empty any
*/
any_t();
/**
* @brief destructor
*/
~any_t();
/**
* @brief Assignment constructor.
* @param[in] tVal The value to assign.
*/
template <typename TType>
explicit any_t(TType tVal);
/**
* @{
* @brief SDV string constructors.
* @param[in] rssVal Reference to the string object.
*/
explicit any_t(const string& rssVal);
explicit any_t(const u8string& rssVal);
explicit any_t(const u16string& rssVal);
explicit any_t(const u32string& rssVal);
explicit any_t(const wstring& rssVal);
/**
* @}
*/
/**
* @brief C-style string constructors.
* @param[in] sz Zero terminated string.
*/
any_t(const char* sz);
/**
* @brief C-style string constructors.
* @param[in] sz Zero terminated string.
*/
any_t(const char16_t* sz);
/**
* @brief C-style string constructors.
* @param[in] sz Zero terminated string.
*/
any_t(const char32_t* sz);
/**
* @brief C-style string constructors.
* @param[in] sz Zero terminated string.
*/
any_t(const wchar_t* sz);
/**
* @{
* @brief STD string constructors.
* @param[in] rssVal Reference to the string object.
*/
explicit any_t(const std::string& rssVal);
explicit any_t(const std::u16string& rssVal);
explicit any_t(const std::u32string& rssVal);
explicit any_t(const std::wstring& rssVal);
/**
* @}
*/
/**
* @brief Assignment constructor.
* @param[in] tVal The value to assign.
* @param[in] eValTypeParam The target value type.
*/
template <typename TType>
any_t(TType tVal, EValType eValTypeParam);
/**
* @brief Copy constructor
* @param[in] rany Reference to any class to copy from.
*/
any_t(const any_t& rany);
/**
* @brief Move constructor.
* @param[in] rany Reference to any class to move from.
*/
any_t(any_t&& rany) noexcept;
/**
* @brief Assignment operator.
* @param[in] tVal The value to assign.
* @return Reference to this class.
*/
template <typename TType>
any_t& operator=(TType tVal);
/**
* @brief Copy assignment operator.
* @param[in] rany Reference to any class to copy from.
* @return Reference to this class.
*/
any_t& operator=(const any_t& rany);
/**
* @brief Move operator.
* @param[in] rany Reference to any class to move from.
* @return Reference to this class.
*/
any_t& operator=(any_t&& rany) noexcept;
/**
* @{
* @brief Cast operators (provides conversion if not identical to the original type).
* @remarks The operators for ANSI string, interface id and exception id are rerpresented by u8string and uint64_t
* respectively and cannot be used to cast to automatically.
* @return The value stored.
*/
operator bool() const;
operator int8_t() const;
operator uint8_t() const;
operator int16_t() const;
operator uint16_t() const;
operator int32_t() const;
operator uint32_t() const;
operator int64_t() const;
operator uint64_t() const;
#ifdef __linux__
operator long long int() const { return static_cast<long long int>(operator int64_t()); }
operator unsigned long long int() const { return static_cast<long long int>(operator uint64_t()); }
#endif
operator char() const;
operator char16_t() const;
operator char32_t() const;
operator wchar_t() const;
operator float() const;
operator double() const;
operator long double() const;
//operator fixed() const;
operator string() const;
operator u8string() const;
operator u16string() const;
operator u32string() const;
operator wstring() const;
operator interface_t() const;
//operator interface_id() const;
//operator exception_id() const;
operator std::string() const;
operator std::u16string() const;
operator std::u32string() const;
operator std::wstring() const;
/**
* @}
*/
/**
* @brief Check for an empty any.
* @return Retrurns whether the any is empty.
*/
bool empty() const;
/**
* @brief Empty the any.
*/
void clear();
/**
* @brief Assign the value to the any. The any takes the value type based on the value.
* @tparam TType The type of the value to set.
* @param[in] tVal The value to set.
*/
template <typename TType>
void set(TType tVal);
/**
* @brief Assign the value to the any. The value will be converted to the provided value type.
* @tparam TType The type of the value to set.
* @param[in] tVal The valiue to set.
* @param[in] eValTypeParam The value type of the any.
*/
template <typename TType>
void set(TType tVal, EValType eValTypeParam);
/**
* @brief Get the value converted to the provided type.
* @tparam TType The type of the value to get,
* @return The value to get.
*/
template <typename TType>
TType get() const;
/**
* @brief Comparison type.
*/
enum class ECompareType
{
compare_equal,
compare_inequal,
compare_smaller,
compare_smaller_equal,
compare_larger,
compare_larger_equal,
};
/**
* @brief Compare the provided value with the contained value.
* @tparam TType Type of the supplied value.
* @tparam eType Type of comparison to do.
* @param[in] rtVal Reference to the value to use for comparison.
* @return The result of the comparison.
*/
template <typename TType, ECompareType eType>
bool Compare(const TType& rtVal) const;
/**
* @brief Compare the provided value with the contained value.
* @tparam eType Type of comparison to do.
* @param[in] ranyVal Reference to the value to use for comparison.
* @return The result of the comparison.
*/
template <ECompareType eType>
bool Compare(const any_t& ranyVal) const;
private:
/**
* @brief Convert the value from one type to the other.
* @remarks This function doesn't check for correct sizes. Invalid conversions lead to an empty destination.
* @tparam TSourceType The source type to convert from.
* @tparam TDestTyoe The destination type to convert to.
* @param[in] rtSrcVal Reference to the source value.
* @param[in] rtDstVal Reference to the destination value.
*/
template <typename TSourceType, typename TDestType>
static void convert(const TSourceType& rtSrcVal, TDestType& rtDstVal);
};
/**
* @brief Equality comparison operator.
* @tparam TType The type to use for the comparison.
* @param[in] ranyVal1 Reference to the any value to compare with.
* @param[in] tVal2 Value to compare with.
* @return The result of the comparison.
*/
template <typename TType>
bool operator==(const sdv::any_t& ranyVal1, TType tVal2);
/**
* @brief Equality comparison operator.
* @tparam TType The type to use for the comparison.
* @param[in] tVal1 Value to compare with.
* @param[in] ranyVal2 Reference to the any value to compare with.
* @return The result of the comparison.
*/
template <typename TType>
bool operator==(TType tVal1, const sdv::any_t& ranyVal2);
/**
* @brief Equality comparison operator.
* @param[in] ranyVal1 Reference to the any value to compare with.
* @param[in] ranyVal2 Reference to the any value to compare with.
* @return The result of the comparison.
*/
bool operator==(const sdv::any_t& ranyVal1, const sdv::any_t& ranyVal2);
/**
* @brief Inequality comparison operator.
* @tparam TType The type to use for the comparison.
* @param[in] ranyVal1 Reference to the any value to compare with.
* @param[in] tVal2 Value to compare with.
* @return The result of the comparison.
*/
template <typename TType>
bool operator!=(const sdv::any_t& ranyVal1, TType tVal2);
/**
* @brief Inequality comparison operator.
* @tparam TType The type to use for the comparison.
* @param[in] tVal1 Value to compare with.
* @param[in] ranyVal2 Reference to the any value to compare with.
* @return The result of the comparison.
*/
template <typename TType>
bool operator!=(TType tVal1, const sdv::any_t& ranyVal2);
/**
* @brief Inequality comparison operator.
* @param[in] ranyVal1 Reference to the any value to compare with.
* @param[in] ranyVal2 Reference to the any value to compare with.
* @return The result of the comparison.
*/
bool operator!=(const sdv::any_t& ranyVal1, const sdv::any_t& ranyVal2);
/**
* @brief Smaller than comparison operator.
* @tparam TType The type to use for the comparison.
* @param[in] ranyVal1 Reference to the any value to compare with.
* @param[in] tVal2 Value to compare with.
* @return The result of the comparison.
*/
template <typename TType>
bool operator<(const sdv::any_t& ranyVal1, TType tVal2);
/**
* @brief Smaller than comparison operator.
* @tparam TType The type to use for the comparison.
* @param[in] tVal1 Value to compare with.
* @param[in] ranyVal2 Reference to the any value to compare with.
* @return The result of the comparison.
*/
template <typename TType>
bool operator<(TType tVal1, const sdv::any_t& ranyVal2);
/**
* @brief Smaller than comparison operator.
* @param[in] ranyVal1 Reference to the any value to compare with.
* @param[in] ranyVal2 Reference to the any value to compare with.
* @return The result of the comparison.
*/
bool operator<(const sdv::any_t& ranyVal1, const sdv::any_t& ranyVal2);
/**
* @brief Smaller than or equality comparison operator.
* @tparam TType The type to use for the comparison.
* @param[in] ranyVal1 Reference to the any value to compare with.
* @param[in] tVal2 Value to compare with.
* @return The result of the comparison.
*/
template <typename TType>
bool operator<=(const sdv::any_t& ranyVal1, TType tVal2);
/**
* @brief Smaller than or equality comparison operator.
* @tparam TType The type to use for the comparison.
* @param[in] tVal1 Value to compare with.
* @param[in] ranyVal2 Reference to the any value to compare with.
* @return The result of the comparison.
*/
template <typename TType>
bool operator<=(TType tVal1, const sdv::any_t& ranyVal2);
/**
* @brief Smaller than or equality comparison operator.
* @param[in] ranyVal1 Reference to the any value to compare with.
* @param[in] ranyVal2 Reference to the any value to compare with.
* @return The result of the comparison.
*/
bool operator<=(const sdv::any_t& ranyVal1, const sdv::any_t& ranyVal2);
/**
* @brief Greater than comparison operator.
* @tparam TType The type to use for the comparison.
* @param[in] ranyVal1 Reference to the any value to compare with.
* @param[in] tVal2 Value to compare with.
* @return The result of the comparison.
*/
template <typename TType>
bool operator>(const sdv::any_t& ranyVal1, TType tVal2);
/**
* @brief Greater than comparison operator.
* @tparam TType The type to use for the comparison.
* @param[in] tVal1 Value to compare with.
* @param[in] ranyVal2 Reference to the any value to compare with.
* @return The result of the comparison.
*/
template <typename TType>
bool operator>(TType tVal1, const sdv::any_t& ranyVal2);
/**
* @brief Greater than comparison operator.
* @param[in] ranyVal1 Reference to the any value to compare with.
* @param[in] ranyVal2 Reference to the any value to compare with.
* @return The result of the comparison.
*/
bool operator>(const sdv::any_t& ranyVal1, const sdv::any_t& ranyVal2);
/**
* @brief Greater than or equality comparison operator.
* @tparam TType The type to use for the comparison.
* @param[in] ranyVal1 Reference to the any value to compare with.
* @param[in] tVal2 Value to compare with.
* @return The result of the comparison.
*/
template <typename TType>
bool operator>=(const sdv::any_t& ranyVal1, TType tVal2);
/**
* @brief Greater than or equality comparison operator.
* @tparam TType The type to use for the comparison.
* @param[in] tVal1 Value to compare with.
* @param[in] ranyVal2 Reference to the any value to compare with.
* @return The result of the comparison.
*/
template <typename TType>
bool operator>=(TType tVal1, const sdv::any_t& ranyVal2);
/**
* @brief Greater than or equality comparison operator.
* @param[in] ranyVal1 Reference to the any value to compare with.
* @param[in] ranyVal2 Reference to the any value to compare with.
* @return The result of the comparison.
*/
bool operator>=(const sdv::any_t& ranyVal1, const sdv::any_t& ranyVal2);
}
#include "any.inl"
#endif // !defined SDV_ANY_H

1460
export/support/any.inl Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,476 @@
#ifndef SDV_APP_CONTROL_H
#define SDV_APP_CONTROL_H
#include "sdv_core.h"
#include "../interfaces/app.h"
#include "../interfaces/config.h"
#include "interface_ptr.h"
#include "local_service_access.h"
namespace sdv
{
namespace app
{
/**
* @brief Application control class.
*/
class CAppControl : public IInterfaceAccess, public IAppEvent
{
public:
/**
* @brief Default constructor; doesn't start the application control.
*/
CAppControl() = default;
/**
* @brief Constructor; starts the application control with the supplied configuration.
* @param[in] rssConfig Reference to the configuration string.
*/
CAppControl(const std::string& rssConfig) : CAppControl()
{
Startup(rssConfig);
}
/**
* @brief Shuts down during destruction if not explicitly done before.
*/
~CAppControl()
{
Shutdown();
}
// Interface map
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(IAppEvent)
END_SDV_INTERFACE_MAP()
/**
* @brief Starts the application control with the supplied configuration.
* @param[in] rssConfig Reference to the configuration string.
* @return Returns 'true' on success; otherwise returns 'false'.
*/
bool Startup(const std::string& rssConfig)
{
IAppControl* pAppControl = core::GetCore() ? core::GetCore<IAppControl>() : nullptr;
if (!pAppControl) return false;
if (m_eState != EAppOperationState::not_started) return false;
try
{
// Start the application control
bool bRet = pAppControl->Startup(rssConfig, this);
// Get the application context
const IAppContext* pAppContext = core::GetCore<IAppContext>();
if (pAppContext)
{
m_eContext = pAppContext->GetContextType();
m_uiInstanceID = pAppContext->GetInstanceID();
m_uiRetries = pAppContext->GetRetries();
}
// Automatically connect to the server
if (m_eContext == EAppContext::external)
{
// Try to connect
m_ptrServerRepository = sdv::com::ConnectToLocalServerRepository(m_uiInstanceID, m_uiRetries);
if (!m_ptrServerRepository)
{
if (!ConsoleIsSilent())
std::cerr << "ERROR: Failed to connect to the server repository." << std::endl;
Shutdown();
return false;
}
// Get access to the module control service
sdv::core::IObjectAccess* pObjectAccess = m_ptrServerRepository.GetInterface<sdv::core::IObjectAccess>();
const sdv::core::IRepositoryControl* pRepoControl = nullptr;
if (pObjectAccess)
pRepoControl = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("RepositoryService")).
GetInterface<sdv::core::IRepositoryControl>();
if (!pRepoControl)
{
if (!ConsoleIsSilent())
std::cerr << "ERROR: Failed to access the server repository." << std::endl;
return false;
}
// Link the local repository to the server repository.
sdv::core::ILinkCoreRepository* pLinkCoreRepo =
sdv::core::GetObject<sdv::core::ILinkCoreRepository>("RepositoryService");
if (!pLinkCoreRepo)
{
if (!ConsoleIsSilent())
std::cerr << "ERROR: Cannot link local and server repositories." << std::endl;
return false;
}
pLinkCoreRepo->LinkCoreRepository(m_ptrServerRepository);
}
return bRet;
}
catch (const XSysExcept& rxException)
{
if (!ConsoleIsSilent())
std::cerr << "ERROR: " << rxException.what() << std::endl;
return false;
}
}
/**
* @brief Running loop until shutdown request is triggered.
* @return Returns whether running the loop was successful.
*/
bool RunLoop()
{
IAppControl* pAppControl = core::GetCore() ? core::GetCore<IAppControl>() : nullptr;
if (!pAppControl) return false;
try
{
pAppControl->RunLoop();
} catch (const XSysExcept&)
{
return false;
}
return true;
}
/**
* @brief Shutdown the application control
* @attention The created objects are destroyed and the module unloaded in reverse order of their creation.
*/
void Shutdown()
{
// Disconnect local and remote repositories.
if (m_ptrServerRepository)
{
// Link the local repository to the server repository.
sdv::core::ILinkCoreRepository* pLinkCoreRepo =
sdv::core::GetObject<sdv::core::ILinkCoreRepository>("RepositoryService");
if (!pLinkCoreRepo)
{
if (!ConsoleIsSilent())
std::cerr << "ERROR: Cannot unlink local and server repositories." << std::endl;
} else
pLinkCoreRepo->UnlinkCoreRepository();
}
// Disconnect from the server (if connected at all).
m_ptrServerRepository.Clear();
// Shutdown.
IAppControl* pAppControl = core::GetCore() ? core::GetCore<IAppControl>() : nullptr;
try
{
if (pAppControl) pAppControl->Shutdown(false);
} catch (const XSysExcept&)
{
if (!ConsoleIsSilent())
std::cerr << "ERROR: Failed to shutdown app control." << std::endl;
}
m_eContext = EAppContext::no_context;
m_uiInstanceID = 0u;
}
/**
* @brief Is the system running?
* @return Returns whether the system is running.
*/
bool IsRunning() const
{
return m_eState == EAppOperationState::running;
}
/**
* @brief Get the SDV_FRAMEWORK_RUNTIME environment variable for this application.
* @return Path directing to the SDV V-API Framework directory if available or an empty path if not.
*/
static std::filesystem::path GetFrameworkRuntimeDirectory()
{
#ifdef _WIN32
const wchar_t* szFrameworkDir = _wgetenv(L"SDV_FRAMEWORK_RUNTIME");
if (!szFrameworkDir) return {};
return szFrameworkDir;
#elif defined __unix__
const char* szFrameworkDir = getenv("SDV_FRAMEWORK_RUNTIME");
if (!szFrameworkDir) return {};
return szFrameworkDir;
#else
#error The OS is not supported!
#endif
}
/**
* @brief Set or overwrite the SDV_FRAMEWORK_RUNTIME environment variable for this application.
* @param[in] rpathDir Reference of the path directing to the SDV V-API Framework directory.
*/
static void SetFrameworkRuntimeDirectory(const std::filesystem::path& rpathDir)
{
#ifdef _WIN32
// NOTE: In windows there are two environment variable stacks which need to be updated.
std::ignore = SetEnvironmentVariable(L"SDV_FRAMEWORK_RUNTIME", rpathDir.native().c_str());
std::ignore = _wputenv((std::wstring(L"SDV_FRAMEWORK_RUNTIME=") + rpathDir.native()).c_str());
#elif defined __unix__
std::ignore = setenv("SDV_FRAMEWORK_RUNTIME", rpathDir.generic_u8string().c_str(), 1);
#else
#error The OS is not supported!
#endif
}
/**
* @brief Get the SDV_COMPONENT_INSTALL environment variable for this application.
* @return Path directing to the SDV V-API component installation directory if available or an empty path if not.
*/
static std::filesystem::path GetComponentInstallDirectory()
{
#ifdef _WIN32
const wchar_t* szComponentDir = _wgetenv(L"SDV_COMPONENT_INSTALL");
if (!szComponentDir) return {};
return szComponentDir;
#elif defined __unix__
const char* szComponentDir = getenv("SDV_COMPONENT_INSTALL");
if (!szComponentDir) return {};
return szComponentDir;
#else
#error The OS is not supported!
#endif
}
/**
* @brief Set or overwrite the SDV_COMPONENT_INSTALL environment variable for this application.
* @param[in] rpathDir Reference of the path directing to the SDV V-API component installation directory.
*/
static void SetComponentInstallDirectory(const std::filesystem::path& rpathDir)
{
#ifdef _WIN32
// NOTE: In windows there are two environment variable stacks which need to be updated.
std::ignore = SetEnvironmentVariable(L"SDV_COMPONENT_INSTALL", rpathDir.native().c_str());
std::ignore = _wputenv((std::wstring(L"SDV_COMPONENT_INSTALL=") + rpathDir.native()).c_str());
#elif defined __unix__
std::ignore = setenv("SDV_COMPONENT_INSTALL", rpathDir.generic_u8string().c_str(), 1);
#else
#error The OS is not supported!
#endif
}
/**
* @brief Get the application context.
* @return The application context.
*/
EAppContext GetAppContext() const
{
return m_eContext;
}
/**
* @brief Get the core instance ID.
* @return The core instance ID.
*/
uint32_t GetInstanceID() const
{
return m_uiInstanceID;
}
/**
* @brief Set the operation to running mode.
* @pre The system is operating in configuration mode.
*/
void SetRunningMode()
{
IAppOperation* pAppOperation = core::GetObject<IAppOperation>("AppControlService");
if (pAppOperation)
pAppOperation->SetRunningMode();
}
/**
* @brief Is the system in configuration state?
* @return Returns whether the system is being configured.
*/
bool IsConfiguring() const
{
return m_eState == EAppOperationState::configuring;
}
/**
* @brief Set the operation to config mode.
* @pre The system is operating in running mode.
*/
void SetConfigMode()
{
IAppOperation* pAppOperation = core::GetObject<IAppOperation>("AppControlService");
if (pAppOperation)
pAppOperation->SetConfigMode();
}
/**
* @brief Process the provided configuration by loading modules and creating objects/stubs/proxies defined in the
* configuration string.
* @attention Configuration changes can only occur when the system is in configuration mode.
* @param[in] ssContent The contents of the configuration file (TOML).
* @return Returns 'true' on success; 'false' otherwise.
*/
core::EConfigProcessResult ProcessConfig(/*in*/ const sdv::u8string& ssContent)
{
core::IConfig* pAppConfig = nullptr;
sdv::TInterfaceAccessPtr ptrConfigObj = core::GetObject("ConfigService");
if (ptrConfigObj) pAppConfig = ptrConfigObj.GetInterface<core::IConfig>();
if (!pAppConfig) return core::EConfigProcessResult::failed;
bool bRunning = IsRunning();
SetConfigMode();
core::EConfigProcessResult eResult = pAppConfig->ProcessConfig(ssContent);
if (bRunning) SetRunningMode();
return eResult;
}
/**
* @brief Read file pointed to by the provided file path and load modules and create objects/stubs/proxies as defined
* in the configuration file.
* @attention Configuration changes can only occur when the system is in configuration mode.
* @param[in] ssFilename Path to the file containing the configuration (TOML). The path can be absolute as well as relative.
* In case a relative path is provided, the current directory is searched as well as all directories supplied through
* the AddConfigSearchDir function.
* @return Returns 'true' on success; 'false' otherwise.
*/
core::EConfigProcessResult LoadConfig(/*in*/ const sdv::u8string& ssFilename)
{
core::IConfig* pAppConfig = nullptr;
sdv::TInterfaceAccessPtr ptrConfigObj = core::GetObject("ConfigService");
if (ptrConfigObj) pAppConfig = ptrConfigObj.GetInterface<core::IConfig>();
if (!pAppConfig) return core::EConfigProcessResult::failed;
bool bRunning = IsRunning();
SetConfigMode();
core::EConfigProcessResult eResult = pAppConfig->LoadConfig(ssFilename);
if (bRunning) SetRunningMode();
return eResult;
}
/**
* @brief Add a search path to a folder where a config file can be found.
* @param[in] rpathDir Reference to the relative or absolute path to an existing folder.
* @return Returns 'true' on success; 'false' otherwise.
*/
bool AddConfigSearchDir(/*in*/ const std::filesystem::path& rpathDir)
{
core::IConfig* pAppConfig = nullptr;
sdv::TInterfaceAccessPtr ptrConfigObj = core::GetObject("ConfigService");
if (ptrConfigObj) pAppConfig = ptrConfigObj.GetInterface<core::IConfig>();
if (!pAppConfig) return false;
return pAppConfig->AddConfigSearchDir(rpathDir.generic_u8string());
}
/**
* @brief Add a search path to a folder where a config file can be found.
* @param[in] ssDir Relative or absolute path to an existing folder.
* @return Returns 'true' on success; 'false' otherwise.
*/
bool AddConfigSearchDir(/*in*/ const sdv::u8string& ssDir)
{
core::IConfig* pAppConfig = nullptr;
sdv::TInterfaceAccessPtr ptrConfigObj = core::GetObject("ConfigService");
if (ptrConfigObj) pAppConfig = ptrConfigObj.GetInterface<core::IConfig>();
if (!pAppConfig) return false;
return pAppConfig->AddConfigSearchDir(ssDir);
}
/**
* @brief Add a search path to a folder where a config file can be found.
* @param[in] ssDir Relative or absolute path to an existing folder.
* @return Returns 'true' on success; 'false' otherwise.
*/
bool AddConfigSearchDir(/*in*/ const std::string& ssDir)
{
core::IConfig* pAppConfig = nullptr;
sdv::TInterfaceAccessPtr ptrConfigObj = core::GetObject("ConfigService");
if (ptrConfigObj) pAppConfig = ptrConfigObj.GetInterface<core::IConfig>();
if (!pAppConfig) return false;
return pAppConfig->AddConfigSearchDir(ssDir);
}
/**
* @brief Add a search path to a folder where a config file can be found.
* @param[in] szDir Zero terminated string to the relative or absolute path to an existing folder.
* @return Returns 'true' on success; 'false' otherwise.
*/
bool AddConfigSearchDir(/*in*/ const char* szDir)
{
if (!szDir) return false;
core::IConfig* pAppConfig = nullptr;
sdv::TInterfaceAccessPtr ptrConfigObj = core::GetObject("ConfigService");
if (ptrConfigObj) pAppConfig = ptrConfigObj.GetInterface<core::IConfig>();
if (!pAppConfig) return false;
return pAppConfig->AddConfigSearchDir(szDir);
}
/**
* @brief Add a search path to a folder where a module can be found.
* @param[in] rpathDir Reference to the relative or absolute path to an existing folder.
* @return Returns 'true' on success; 'false' otherwise.
*/
bool AddModuleSearchDir(/*in*/ const std::filesystem::path& rpathDir)
{
sdv::core::IModuleControlConfig* pModuleConfig = sdv::core::GetCore<sdv::core::IModuleControlConfig>();
if (!pModuleConfig) return false;
return pModuleConfig->AddModuleSearchDir(rpathDir.generic_u8string());
}
/**
* @brief Add a search path to a folder where a module can be found.
* @param[in] rssDir Reference to the relative or absolute path to an existing folder.
* @return Returns 'true' on success; 'false' otherwise.
*/
bool AddModuleSearchDir(/*in*/ const sdv::u8string& rssDir)
{
sdv::core::IModuleControlConfig* pModuleConfig = sdv::core::GetCore<sdv::core::IModuleControlConfig>();
if (!pModuleConfig) return false;
return pModuleConfig->AddModuleSearchDir(rssDir);
}
/**
* @brief Add a search path to a folder where a module can be found.
* @param[in] rssDir Reference to the relative or absolute path to an existing folder.
* @return Returns 'true' on success; 'false' otherwise.
*/
bool AddModuleSearchDir(/*in*/ const std::string& rssDir)
{
sdv::core::IModuleControlConfig* pModuleConfig = sdv::core::GetCore<sdv::core::IModuleControlConfig>();
if (!pModuleConfig) return false;
return pModuleConfig->AddModuleSearchDir(rssDir);
}
/**
* @brief Add a search path to a folder where a module can be found.
* @param[in] szDir Zero terminated string to the relative or absolute path to an existing folder.
* @return Returns 'true' on success; 'false' otherwise.
*/
bool AddModuleSearchDir(/*in*/ const char* szDir)
{
if (!szDir) return false;
sdv::core::IModuleControlConfig* pModuleConfig = sdv::core::GetCore<sdv::core::IModuleControlConfig>();
if (!pModuleConfig) return false;
return pModuleConfig->AddModuleSearchDir(szDir);
}
private:
/**
* @brief Process the event. Overload of IAppEvent::ProcessEvent.
* @param[inout] sEvent Event structure containing the information to process.
*/
virtual void ProcessEvent(/*inout*/ SAppEvent& sEvent) override
{
// Only process state change events
if (sEvent.uiEventID != EVENT_OPERATION_STATE_CHANGED) return;
m_eState = static_cast<EAppOperationState>(sEvent.uiInfo);
}
EAppOperationState m_eState = EAppOperationState::not_started; ///< Application state.
EAppContext m_eContext = EAppContext::no_context; ///< Application context.
uint32_t m_uiInstanceID = 0u; ///< Core instance.
uint32_t m_uiRetries = 0u; ///< Number of retries to establish a connection.
sdv::TObjectPtr m_ptrServerRepository; ///< Server repository interface.
};
} // namespace app
} // namespace sdv
#endif // !defined SDV_APP_CONTROL_H

View File

@@ -0,0 +1,954 @@
/**
*
* @file component_impl.h
* @brief This file provides all necessary definitions to implement SDV object.
* @version 0.1
* @date 2022.11.14
* @author Thomas.pfleiderer@zf.com
* @copyright Copyright ZF Friedrichshaven AG (c) 2022
*
*/
#ifndef COMPONENT_IMPL_H
#define COMPONENT_IMPL_H
#include <cstring>
#include <mutex>
#include <shared_mutex>
#include <vector>
#include "../interfaces/core_types.h"
#include "../interfaces/core.h"
#include "../interfaces/repository.h"
#include "interface_ptr.h"
#include "local_service_access.h"
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
/**
* @brief Stringize helper.
*/
#define SDV_STRINGIZE_HELPER2(txt) #txt
/**
* @brief Stringize helper.
*/
#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
/**
* @brief Software Defined Vehicle framework.
*/
namespace sdv
{
// Forward declarations
class CSdvObject;
////////////////////////////////////
// Object control classes //
////////////////////////////////////
/**
* @brief SDV object create interface.
* @remarks This is an internal interface not exposed through IInterfaceAccess.
*/
struct ISdvObjectClassInfo
{
public:
/**
* @brief Get the class information struct.
* @return Returns the class information struct.
*/
virtual sdv::SClassInfo GetClassInfo() const = 0;
/**
* @brief Create the SDV object.
* @return Returns an instance of the SDV object or nullptr when the object could not be created.
*/
virtual std::unique_ptr<CSdvObject> CreateObject() = 0;
};
/**
* @brief Top level SDV object to solve ambiguities in the use of IInterfaceAccess. THis class is used by
* CSdvObjectClass during the instantiation of the SDV object.
*/
class CSdvObjectAccess : public IInterfaceAccess
{
public:
/**
* @brief Default constructor
*/
CSdvObjectAccess() = default;
CSdvObjectAccess(CSdvObjectAccess&) = delete;
CSdvObjectAccess& operator=(CSdvObjectAccess&) = delete;
CSdvObjectAccess(CSdvObjectAccess&&) = delete;
CSdvObjectAccess& operator=(CSdvObjectAccess&&) = delete;
/**
* @brief Default virtual destructor
*/
virtual ~CSdvObjectAccess() = default;
/**
* @brief Get access to the implemented IInterfaceAccess interface.
* @return Returns a pointer to the implementation of IInterfaceAccess.
*/
IInterfaceAccess* GetObjectAccess()
{
return static_cast<IInterfaceAccess*>(this);
}
// Interface map
BEGIN_SDV_INTERFACE_MAP()
END_SDV_INTERFACE_MAP()
};
/**
* @brief Lifetime cookie to automatically manage the module lifetime.
* @details The lifetime cookie uses an increment and decrement function to increment for every assigned instantiation of
* the cookie and to decrement every previously instantiated cookie. This allows the classfactory to keep track of its lifetime
* even with dynamically created objects.
*/
class CLifetimeCookie
{
public:
/**
* @brief Default constructor.
*/
CLifetimeCookie() = default;
/**
* @brief Assignment constructor, assigning the increment and decrement functions.
* @details Assign the increment and decrement functions and increase the incrementation.
* @param[in] fnLifetimeIncr Increment function object.
* @param[in] fnLifetimeDecr Decrement function object.
*/
CLifetimeCookie(std::function<void()> fnLifetimeIncr, std::function<void()> fnLifetimeDecr) :
m_fnLifetimeIncr(fnLifetimeIncr), m_fnLifetimeDecr(fnLifetimeDecr)
{
if (m_fnLifetimeIncr) m_fnLifetimeIncr();
}
/**
* @brief Copy constructor.
* @details Construct a lifetime cookie object and copy the increment and decrement functions and call the increment
* function if valid.
* @param[in] rCookie Reference to the cookie to copy from.
*/
CLifetimeCookie(const CLifetimeCookie& rCookie) :
m_fnLifetimeIncr(rCookie.m_fnLifetimeIncr), m_fnLifetimeDecr(rCookie.m_fnLifetimeDecr)
{
if (m_fnLifetimeIncr) m_fnLifetimeIncr();
}
/**
* @brief Move constructor.
* @details Construct a lifetime cookie object and move the functions from the provided cookie. Then reset the functions
* of the provided cookie.
* @param[in] rCookie Reference to the cookie to copy from.
*/
CLifetimeCookie(CLifetimeCookie&& rCookie) noexcept :
m_fnLifetimeIncr(rCookie.m_fnLifetimeIncr), m_fnLifetimeDecr(rCookie.m_fnLifetimeDecr)
{
rCookie.m_fnLifetimeIncr = nullptr;
rCookie.m_fnLifetimeDecr = nullptr;
}
/**
* @brief Destroy the lifetime cookie.
* @details Decrement the lifetime by calling the decrement function if valid and destroy the cookie object.
*/
~CLifetimeCookie()
{
if (m_fnLifetimeDecr) m_fnLifetimeDecr();
}
/**
* @brief Assignment operator.
* @details Release the current lifetime by calling the decrement function and assign the increment and decrement functions
* of the provided cookie and call the increment function if valid.
* @param[in] rCookie Reference to the cookie to copy from.
* @return Reference to this class.
*/
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;
}
/**
* @brief Move operator.
* @details Release the current lifetime by calling the decrement function and move the functions from the provided cookie.
* Then reset the functions of the provided cookie.
* @param[in] rCookie Reference to the cookie to copy from.
* @return Reference to this class.
*/
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; ///< Lifetime increment function
std::function<void()> m_fnLifetimeDecr; ///< Lifetime decrement function
};
/**
* @brief Global tracking of active objects. Functions in this class will only be called by CSdvObject and CSdvObjectClass
*/
class CObjectFactory : public IInterfaceAccess, public IObjectFactory
{
// Friend class SDV object and definition
friend class CSdvObject; ///< SDV object base class.
template <class TSdvObject>
friend class CSdvObjectClass; ///< SDV object creator class.
public:
/**
* @brief Constructor
*/
CObjectFactory() = default;
/**
* @brief Interface map.
*/
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(IObjectFactory)
END_SDV_INTERFACE_MAP()
/**
* @brief Create a lifetime cookie that keeps track of the module lifetime as long as it is alive.
* @return Returns a lifetime cookie.
*/
CLifetimeCookie CreateLifetimeCookie()
{
return CLifetimeCookie([this]() { m_uiActiveObjectCount++; },
[this]() { if (m_uiActiveObjectCount) m_uiActiveObjectCount--; });
}
/**
* @brief Gets the amount of active SDV objects.
* @return Returns the number of active SDV objects.
*/
uint32_t GetActiveObjects() const
{
return m_uiActiveObjectCount;
}
/**
* @brief Get the module manifest.
* @return Returns the pointer to a zero terminated string containing the module manifest or NULL when there is no string.
*/
const char* GetManifest()
{
if (m_ssManifest.empty())
BuildManifest();
return m_ssManifest.c_str();
}
/**
* @brief Create or get the object using the name from the object class info. Overload of
* sdv::IObjectFactory::CreateObject.
* @attention The objects lifetime is ended by a call to the DestroyObject function or the unloading of he module.
* @param[in] ssClassName The name of the class object to instantiate.
* @return Pointer to IInterfaceAccess interface of the object or NULL when the requested object doesn't exist.
*/
virtual IInterfaceAccess* CreateObject(const sdv::u8string& ssClassName) override;
/**
* @brief Destroy an instantiated object using the name of the object class info. Overload of
* sdv::IObjectFactory::DestroyObject.
* @param[in] object The object to destroy.
*/
virtual void DestroyObject(IInterfaceAccess* object) override;
/**
* @brief Destroys all active objects in reverse order of creation
*/
virtual void DestroyAllObjects() override;
protected:
/**
* @brief Build the module manifest.
* @return Returns the pointer to a zero terminated string containing the module manifest or NULL when there is no string.
*/
void BuildManifest()
{
std::stringstream sstream;
sstream << R"code(# Module manifest
[Interface]
Version = )code" << SDVFrameworkInterfaceVersion
<< R"code(
)code";
std::shared_lock<std::shared_mutex> lock(m_mtxObjectClasses);
for (const ISdvObjectClassInfo* pClassInfo : m_vecObjectClasses)
{
sdv::SClassInfo sInfo = pClassInfo->GetClassInfo();
sstream << "[[Component]]" << std::endl;
sstream << "Class=\"" << sInfo.ssClassName << "\"" << std::endl;
if (!sInfo.seqClassAliases.empty())
{
sstream << "Aliases=[";
bool bInitialAlias = true;
for (const sdv::u8string& rssAlias : sInfo.seqClassAliases)
{
if (!bInitialAlias)
sstream << ", ";
bInitialAlias = false;
sstream << "\"" << rssAlias << "\"";
}
sstream << "]" << std::endl;
}
if (!sInfo.ssDefaultObjectName.empty())
sstream << "DefaultName=\"" << sInfo.ssDefaultObjectName << "\"" << std::endl;
bool bSkip = false;
switch (sInfo.eType)
{
case sdv::EObjectType::SystemObject:
sstream << "Type=\""
<< "System"
<< "\"" << std::endl;
break;
case sdv::EObjectType::Device:
sstream << "Type=\""
<< "Device"
<< "\"" << std::endl;
break;
case sdv::EObjectType::BasicService:
sstream << "Type=\""
<< "BasicService"
<< "\"" << std::endl;
break;
case sdv::EObjectType::ComplexService:
sstream << "Type=\""
<< "ComplexService"
<< "\"" << std::endl;
break;
case sdv::EObjectType::Application:
sstream << "Type=\""
<< "App"
<< "\"" << std::endl;
break;
case sdv::EObjectType::Proxy:
sstream << "Type=\""
<< "Proxy"
<< "\"" << std::endl;
break;
case sdv::EObjectType::Stub:
sstream << "Type=\""
<< "Stub"
<< "\"" << std::endl;
break;
case sdv::EObjectType::Utility:
sstream << "Type=\""
<< "Utility"
<< "\"" << std::endl;
break;
default:
bSkip = true;
break;
}
if (bSkip)
continue;
if (sInfo.uiFlags & static_cast<uint32_t>(sdv::EObjectFlags::singleton))
sstream << "Singleton=true" << std::endl;
if (!sInfo.seqDependencies.empty())
{
sstream << "Dependencies=[";
bool bInitialDependency = true;
for (const sdv::u8string& rssDependsOn : sInfo.seqDependencies)
{
if (!bInitialDependency)
sstream << ", ";
bInitialDependency = false;
sstream << "\"" << rssDependsOn << "\"";
}
sstream << "]" << std::endl;
}
}
m_ssManifest = sstream.str();
}
/**
* @brief Expose the object prototype by placing it into the object prototype list.
* @details Expose the object class to allow class access. This function is called by the constructor of the
* class object.
* @param[in] pObjectClassInfo The object class internal interface.
*/
void ExposeObjectClass(ISdvObjectClassInfo* pObjectClassInfo)
{
if (pObjectClassInfo)
{
std::unique_lock<std::shared_mutex> lock(m_mtxObjectClasses);
m_vecObjectClasses.push_back(pObjectClassInfo);
// Attention: pObjectClass is a pointer to ISdvObjectClassInfo even if the class was derived.
// Virtual functions are not available yet at this stage.
}
}
/**
* @brief Revoke the object prototype from the object prototype list.
* @param[in] pObjectClassInfo The object class internal interface.
*/
void RevokeObjectClass(const ISdvObjectClassInfo* pObjectClassInfo)
{
std::unique_lock<std::shared_mutex> lock(m_mtxObjectClasses);
auto itObjectClass = std::find(m_vecObjectClasses.begin(), m_vecObjectClasses.end(), pObjectClassInfo);
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 == pObjectClassInfo)
// {
// m_vecObjectClasses.erase(objectClassIter);
// break;
// }
//}
}
private:
std::atomic<uint32_t> m_uiActiveObjectCount{0}; ///< The amount of active SDV objects.
mutable std::mutex m_mtxActiveObjects; ///< Synchronize access to m_vecActiveObjects
std::vector<std::unique_ptr<CSdvObject>> m_vecActiveObjects; ///< List of objects actively kept alive
mutable std::shared_mutex m_mtxObjectClasses; ///< Synchronize access to the object classes.
std::vector<ISdvObjectClassInfo*> m_vecObjectClasses; ///< List of object classes contained in this module.
std::string m_ssManifest; ///< Manifest of this module.
};
////////////////////////////////////
// Framework module classes //
////////////////////////////////////
/**
* @brief Class that manages the object instantiation and module lifetime.
* @remarks A pointer to an instance of this class is exposed across dll boundaries and used to implement
* CModuleInstance for SDV DLLs
* The instance is created by the DEFINE_SDV_OBJECT macro and the macro also registers a helper capable of
* instantiating the SDV object with the instance (see CObjectFactory for details)
*/
class CModule
: public CSdvObjectAccess
, public CObjectFactory
{
public:
/**
* @brief Default constructor
*/
CModule() = default;
/**
* @brief Interface map.
*/
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_CHAIN_BASE(CObjectFactory)
END_SDV_INTERFACE_MAP()
/**
* @brief Check whether the requested interface version corresponds to the one implemented here and return this
* object.
* @param[in] interfaceVersion The version of module interface that is requested for.
* @return Returns the IInterfaceAccess interface of the module if the interface versions match, nullptr otherwise
*/
IInterfaceAccess* GetModuleControl(uint32_t interfaceVersion)
{
// No compatibility interfacing available yet.
return interfaceVersion == SDVFrameworkInterfaceVersion ? GetObjectAccess() : nullptr;
}
};
/**
* @brief Module access (global per module).
* @return Reference to the global module.
*/
inline CModule& GetModule()
{
static CModule module;
return module;
}
/**
* @brief Create a lifetime cookie that keeps track of the module lifetime as long as it is alive.
* @return Returns a lifetime cookie.
*/
inline CLifetimeCookie CreateLifetimeCookie()
{
return GetModule().CreateLifetimeCookie();
}
////////////////////////////
// Component object class //
////////////////////////////
/**
* @brief SDV object creator class. Used to define the SDV class object and register its definition into the system
* as welll a as providing the creation interface for creating an object instance.
* @tparam TSdvObject Class type of the SDV object derived from CSdvObject.
*/
template <class TSdvObject>
class CSdvObjectClass
: public ISdvObjectClassInfo
{
public:
/**
* @brief Constructor assigning the SDV prototype to the module.
*/
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;
/**
* @brief Destructor revoking the object prototype.
*/
virtual ~CSdvObjectClass()
{
GetModule().RevokeObjectClass(this);
}
/**
* @brief Gets the object class name.
* @return Returns the class name of the object.
* @remarks Default implementation gets the information from the object class if not defined in the definition.
*/
virtual sdv::u8string GetClassName() const
{
return TSdvObject::GetClassNameStatic();
}
/**
* @brief Gets the class name aliases.
* @return Returns a sequence containing zero or more class name aliases.
* @remarks Default implementation gets the information from the object class if not defined in the definition.
*/
virtual sdv::sequence<sdv::u8string> GetClassAliases() const
{
return TSdvObject::GetClassAliasesStatic();
}
/**
* @brief Gets the default object name.
* @return Returns the default name of the object if exists.
*/
virtual sdv::u8string GetDefaultObjectName() const
{
return TSdvObject::GetDefaultObjectNameStatic();
}
/**
* @brief Is the object marked as singleton.
* @return Returns whether the object is a singleton object.
*/
virtual bool IsSingleton() const
{
return TSdvObject::IsSingletonStatic();
}
/**
* @brief Get object dependencies.
* @return Returns a vector containing the class names of the objects this component is dependent on.
*/
virtual sdv::sequence<sdv::u8string> GetObjectDependencies() const
{
return TSdvObject::GetObjectDependenciesStatic();
}
/**
* @brief Gets the object type.
* @return Returns the type of the object
* @remarks Default implementation gets the information from the object class if not defined in the definition.
*/
virtual EObjectType GetObjectType() const
{
return TSdvObject::GetObjectType();
}
protected:
/**
* @brief Helper function to retrieve the object creation flags.
* @return Returns the current flags of the object
*/
uint32_t GetObjectFlags() const
{
uint32_t flags = 0;
if (IsSingleton()) flags |= static_cast<uint32_t>(EObjectFlags::singleton);
// Currently no other flags known.
return flags;
}
/**
* @brief Get the class information struct. Overload of ISdvObjectClassInfo::GetClassInfo.
* @return Returns the class information struct.
*/
sdv::SClassInfo GetClassInfo() const override
{
sdv::SClassInfo classInfo{};
classInfo.ssClassName = GetClassName();
classInfo.seqClassAliases = GetClassAliases();
classInfo.ssDefaultObjectName = GetDefaultObjectName();
classInfo.eType = GetObjectType();
classInfo.uiFlags = GetObjectFlags();
classInfo.seqDependencies = GetObjectDependencies();
return classInfo;
}
/**
* @brief Create the SDV object. Overload of ISdvObjectClassInfo::CreateObject.
* @return Returns an instance of the SDV object or nullptr when the object could not be created (exception thrown during construction).
*/
std::unique_ptr<CSdvObject> CreateObject() override
{
std::unique_ptr<CSdvObject> ret;
try
{
ret = std::make_unique<TSdvObject>();
}
catch(...)
{
SDV_LOG(core::ELogSeverity::error, "Failed to instantiate object of class ", GetClassName(), " - exception thrown during construction! ");
}
return ret;
}
};
/**
* @brief SDV object base class.
*/
class CSdvObject : public CSdvObjectAccess
{
public:
/**
* @brief Use the default object creator class.
*/
template <class TSdvObject>
using TSdvObjectCreator = CSdvObjectClass<TSdvObject>;
/**
* @brief Constructor
*/
CSdvObject() = default;
CSdvObject(CSdvObject&) = delete;
CSdvObject& operator=(CSdvObject&) = delete;
CSdvObject(CSdvObject&&) = delete;
CSdvObject& operator=(CSdvObject&&) = delete;
/**
* @brief Destructor
*/
~CSdvObject() override
{}
/**
* @brief Class aliases sequence if not provided.
* @return An empty sequence of class aliases.
*/
static sdv::sequence<sdv::u8string> GetClassAliasesStatic() { return {}; }
/**
* @brief Default object name is not set.
* @return The empty default object name
*/
static sdv::u8string GetDefaultObjectNameStatic() { return {}; }
/**
* @brief Return whether the object is a singleton object (only one instance will be created of the object).
* @return Returns whether the object is a singleton.
*/
static bool IsSingletonStatic() { return false; }
/**
* @brief Get object dependencies.
* @return Returns a vector containing the class names of the objects this component is dependent on.
*/
static sdv::sequence<sdv::u8string> GetObjectDependenciesStatic() { return sdv::sequence<sdv::u8string>(); }
/**
* @brief Interface map
*/
BEGIN_SDV_INTERFACE_MAP()
END_SDV_INTERFACE_MAP()
};
/////////////////////////////////////////
// Object control class implementation //
/////////////////////////////////////////
inline IInterfaceAccess* CObjectFactory::CreateObject(const sdv::u8string& ssClassName)
{
if (ssClassName.empty())
{
return nullptr;
}
std::shared_lock<std::shared_mutex> lock(m_mtxObjectClasses);
for (ISdvObjectClassInfo* pObjectClassInfo : m_vecObjectClasses)
{
if (pObjectClassInfo == nullptr)continue;
sdv::SClassInfo sClassInfo = pObjectClassInfo->GetClassInfo();
// Check for the class name.
bool bFound = sClassInfo.ssClassName == ssClassName;
// If not found, check for all aliases.
for (auto itAlias = sClassInfo.seqClassAliases.begin(); !bFound && itAlias != sClassInfo.seqClassAliases.end(); itAlias++)
bFound = *itAlias == ssClassName;
if (!bFound) continue;
++m_uiActiveObjectCount;
auto object = pObjectClassInfo->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;
}
}
} // namespace sdv
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
/**
* @brief Define the SDV object (derived from CSdvObject) to be exposed to the framework.
* @param sdv_object_class The object class must derive from sdv::CSdvObject.
*/
#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();
/**
* @brief Define the SDV object (derived from CSdvObject) to be exposed to the framework. Do not define export functions.
* @param sdv_object_class The object class must derive from sdv::CSdvObject.
*/
#define DEFINE_SDV_OBJECT_NO_EXPORT(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();
/**
* @brief Declare the object class type. To be placed in the SDV object class derived from CSdvObject.
* \param class_type The type of the object (EObjectType).
*/
#define DECLARE_OBJECT_CLASS_TYPE(class_type) \
/** \
* @brief Declare the object class type. To be placed in the SDV object class derived from CSdvObject. \
* @return Returns the type of the object (EObjectType). \
*/ \
constexpr static sdv::EObjectType GetObjectType() \
{ \
return class_type; \
}
/**
* @brief Declare the object class name. To be placed in the SDV object class derived from CSdvObject.
* @param class_name_string The UTF-8 string containing the name of the object.
*/
#define DECLARE_OBJECT_CLASS_NAME(class_name_string) \
static sdv::u8string GetClassNameStatic() \
{ \
return class_name_string; \
}
/**
* @brief Declare the object class aliases. To be placed in the SDV object class derived from CSdvObject.
* @param ... Multiple UTF-8 strings containing the alias names for the object class.
*/
#define DECLARE_OBJECT_CLASS_ALIAS(...) \
static sdv::sequence<sdv::u8string> GetClassAliasesStatic() \
{ \
return sdv::sequence<sdv::u8string>({__VA_ARGS__}); \
}
/**
* @brief Declare the default object name. To be placed in the SDV object class derived from CSdvObject.
* @param object_name_string The UTF-8 string containing the name of the object.
*/
#define DECLARE_DEFAULT_OBJECT_NAME(object_name_string) \
static sdv::u8string GetDefaultObjectNameStatic() \
{ \
return object_name_string; \
}
/**
* @brief Declare the object to be a singleton object (only one instance will be created of the object).
*/
#define DECLARE_OBJECT_SINGLETON() \
static bool IsSingletonStatic() { return true; }
/**
* @brief Declare the object to be a singleton object (only one instance will be created of the object).
* One or more strings with the class/default names of the objects the component is dependent on.
*/
#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

207
export/support/crc.h Normal file
View File

@@ -0,0 +1,207 @@
#ifndef SDV_CRC_H
#define SDV_CRC_H
#include <array>
#include <cstdint>
#include <stddef.h>
namespace sdv
{
/**
* @brief Reflect the bits within the data type (change the order MSB <--> LSB).
* @tparam T The type to use for bit reflection.
* @param[in] tValue The value to reflect. Must be a arithmetic or boolean type.
* @return The reflected value.
*/
template <typename T>
constexpr T reflect(T tValue)
{
static_assert(std::is_arithmetic_v<T> || std::is_same_v<T, bool>);
T tMask = 1;
T tReflection{0};
for (size_t nBit = 0; nBit < sizeof(T) * 8; nBit++)
{
tReflection <<= 1;
if (tValue & tMask)
tReflection |= 0x1;
tMask <<= 1;
}
return tReflection;
}
/**
* @brief Templated CRC calculation class
* @tparam TCRC The CRC type to use for the calculation.
* @tparam tPolynomial The polynomial of the CRC function.
* @tparam tInitVal The initial value to use for the calculation.
* @tparam tXorOut XOR the result with the provided value.
* @tparam bReflectIn Reflect the input bits.
* @tparam bReflectOut Reflect the output bits.
*/
template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
class crc
{
public:
using TCRCType = TCRC; ///< CRC type
/**
* @brief Calculate the CRC checksum value providing a buffer with data of type T.
* @attention This function doesn't reset the CRC that was calculated before.
* @remarks The CRC calculation occurs byte-wise regardless of the endianness of the the processor architecture.
* @tparam T Type of the value buffer to calculate the CRC for.
* @param[in] pData Pointer to the value buffer.
* @param[in] nCount Amount of values in the buffer.
* @return The calculated CRC checksum.
*/
template <typename T>
TCRCType calc_checksum(const T* pData, size_t nCount) noexcept;
/**
* @brief Add one value to the calculation.
* @remarks The CRC calculation occurs byte-wise regardless of the endianness of the the processor architecture.
* @tparam T Type of the value buffer to calculate the CRC for.
* @param[in] tValue The value to add to the calculation.
*/
template <typename T>
void add(T tValue) noexcept;
/**
* @brief Get the currently calculated checksum.
* @return The CRC checksum.
*/
TCRCType get_checksum() const noexcept;
/**
* @brief Set a CRC checksum to continue the calculation with additional data.
* @param[in] tCrcValue The previously calculated CRC value.
*/
void set_checksum(TCRCType tCrcValue) noexcept;
/**
* @brief Reset the current calculation (resets the CRC value to its initial value).
*/
void reset() noexcept;
private:
/**
* @brief With of the CRC type in bits.
*/
static constexpr uint64_t m_nWidth = 8 * sizeof(TCRCType);
/**
* @brief MSB for the CRC type.
*/
static constexpr uint64_t m_nMsb = 1ull << (m_nWidth - 1);
/**
* @brief CRC lookup table.
*/
static constexpr auto m_arrTable = []
{
std::array<TCRCType, 256> arrTemp{};
for (size_t tDividend = 0; tDividend < 256; ++tDividend)
{
TCRCType tRemainder = static_cast<TCRCType>(tDividend << (m_nWidth - 8));
for (uint8_t bit = 8; bit > 0; --bit)
{
if (tRemainder & m_nMsb)
tRemainder = (tRemainder << 1) ^ tPolynomial;
else
tRemainder = (tRemainder << 1);
}
arrTemp[tDividend] = tRemainder;
}
return arrTemp;
}();
TCRCType m_tCrcValue = tInitVal; ///< Calculated CRC value.
};
/// SAE-J1850: polynomial 0x1D, initial = 0xFF, final_xor = 0xFF, reflect_input = false, reflect_output = false
using crcSAE_J1850 = sdv::crc<uint8_t, 0x1du, 0xff, 0xff, false, false>;
/// AUTOSAR_8H2F: polynomial 0x2F, initial = 0xFF, final_xor = 0xFF, reflect_input = false, reflect_output = false)
using crcAUTOSAR_8H2F = sdv::crc<uint8_t, 0x2fu, 0xff, 0xff, false, false>;
/// CCITT-FALSE: polynomial 0x1021, initial = 0xFFFF, final_xor = 0, reflect_input = false, reflect_output = false
using crcCCITT_FALSE = sdv::crc<uint16_t, 0x1021u, 0xffffu, 0, false, false> ;
/// ARC: polynomial 0x8005, initial = 0, final_xor = 0, reflect_input = true, reflect_output = true
using crcARC = sdv::crc<uint16_t, 0x8005, 0, 0, true, true>;
/// IEEE_802_3 polynomial 0x04C11DB7, initial = 0xFFFFFFFF, final_xor = 0xFFFFFFFF, reflect_input = true, reflect_output = true
using crcIEEE_802_3 = sdv::crc<uint32_t, 0x04C11DB7u, 0xffffffffu, 0xffffffffu, true, true> ;
/// AUTOSAR_P4 polynomial 0xF4ACFB13, initial = 0xFFFFFFFF, final_xor = 0xFFFFFFFF, reflect_input = true, reflect_output = true
using crcAUTOSAR_P4 = sdv::crc<uint32_t, 0xF4ACFB13u, 0xffffffffu, 0xffffffffu, true, true> ;
/// CRC32-C Castagnoli polynomial 0x1EDC6F41, initial = 0xFFFFFFFF, final_xor = 0xFFFFFFFF, reflect_input = true,
/// reflect_output = true
using crcCRC32C = sdv::crc<uint32_t, 0x1EDC6F41, 0xffffffffu, 0xffffffffu, true, true> ;
/// ECMA (polynomial 0x42F0E1EBA9EA3693, initial = 0xFFFFFFFFFFFFFFFF, final_xor = 0xFFFFFFFFFFFFFFFF, reflect_input = true,
/// reflect_output = true
using crcECMA = sdv::crc<uint64_t, 0x42F0E1EBA9EA3693, 0xffffffffffffffffu, 0xffffffffffffffffu, true, true>;
template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
template <typename T>
typename crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::TCRCType
crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::calc_checksum(const T* pData, size_t nCount) noexcept
{
if (!pData || !nCount) return get_checksum();
for (size_t nIndex = 0; nIndex < nCount; nIndex++)
add(pData[nIndex]);
return get_checksum();
}
template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
template <typename T>
inline void crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::add(T tValue) noexcept
{
if constexpr (bReflectIn)
{
for (size_t nIndex = 0; nIndex < sizeof(T); ++nIndex)
{
uint8_t data = static_cast<uint8_t>(reflect(reinterpret_cast<uint8_t*>(&tValue)[nIndex]) ^ (m_tCrcValue >> (m_nWidth - 8)));
m_tCrcValue = m_arrTable[data] ^ (m_tCrcValue << 8);
}
}
else
{
for (size_t nIndex = 0; nIndex < sizeof(T); ++nIndex)
{
uint8_t data = static_cast<uint8_t>((reinterpret_cast<uint8_t*>(&tValue)[nIndex]) ^ (m_tCrcValue >> (m_nWidth - 8)));
m_tCrcValue = m_arrTable[data] ^ (m_tCrcValue << 8);
}
}
}
template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
inline typename crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::TCRCType
crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::get_checksum() const noexcept
{
if constexpr (bReflectOut)
return static_cast<TCRCType>(reflect(m_tCrcValue) ^ tXorOut);
else
return static_cast<TCRCType>(m_tCrcValue ^ tXorOut);
}
template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
inline void crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::set_checksum(TCRCType tCrcValue) noexcept
{
if constexpr (bReflectOut)
m_tCrcValue = static_cast<TCRCType>(reflect(static_cast<TCRCType>(tCrcValue ^ tXorOut)));
else
m_tCrcValue = static_cast<TCRCType>(tCrcValue ^ tXorOut);
}
template <typename TCRC, TCRC tPolynomial, TCRC tInitVal, TCRC tXorOut, bool bReflectIn, bool bReflectOut>
inline void crc<TCRC, tPolynomial, tInitVal, tXorOut, bReflectIn, bReflectOut>::reset() noexcept
{
m_tCrcValue = tInitVal;
}
} // namespace sdv
#endif // SDV_CRC_H

31
export/support/except.h Normal file
View File

@@ -0,0 +1,31 @@
#ifndef SDV_EXCEPT_H
#define SDV_EXCEPT_H
#include <cstdint>
#ifndef except
/** Define the except keyword */
#define except struct
#endif
namespace sdv
{
/**
* @brief exception ID type
*/
using exception_id = uint64_t;
/**
* @brief Get the exception ID.
* @tparam TException The exception type
* @return The ID of the exception
*/
template <typename TExcept>
constexpr inline exception_id GetExceptionId() noexcept
{
// Return the exception ID.
return TExcept::_id;
}
}
#endif // !defined SDV_EXCEPT_H

279
export/support/interface.h Normal file
View File

@@ -0,0 +1,279 @@
#ifndef SDV_INTERFACE_H
#define SDV_INTERFACE_H
#include <cstdint>
#ifndef interface
/** Define the interface keyword */
#define interface struct
#endif
namespace sdv
{
/**
* @brief Interface ID type
*/
using interface_id = uint64_t;
/**
* @brief Get the interface ID.
* @tparam TIfc The interface type
* @return The ID of the interface
*/
template <typename TIfc>
constexpr inline interface_id GetInterfaceId() noexcept
{
// Return the interface ID.
return TIfc::_id;
}
/**
* @brief Interface type class
*/
class interface_t
{
public:
/**
* @brief Default constructor
*/
interface_t() noexcept;
/**
* @brief Copy constructor
* @param[in] rifc Reference to the interface to copy the pointer from.
*/
interface_t(const interface_t& rifc) noexcept;
/**
* @brief Move constructor
* @param[in] rifc Reference to the interface to move the pointer from.
*/
interface_t(interface_t&& rifc) noexcept;
/**
* @brief Null-pointer constructor
*/
interface_t(std::nullptr_t) noexcept;
/**
* @brief Assignment constructor
* @tparam TInterface Interface type
* @param[in] pInterface Interface pointer
*/
template <typename TInterface>
interface_t(TInterface* pInterface) noexcept;
/**
* @brief Copy assignment
* @param[in] rifc Reference to the interface to copy the pointer from.
* @return Reference to this interface type.
*/
interface_t& operator=(const interface_t& rifc) noexcept;
/**
* @brief Move assignment
* @param[in] rifc Reference to the interface to move the pointer from.
* @return Reference to this interface type.
*/
interface_t& operator=(interface_t&& rifc) noexcept;
/**
* @brief Null-pointer assignment
* @return Reference to this interface type.
*/
interface_t& operator=(std::nullptr_t) noexcept;
/**
* @brief Interface assignment operator
* @tparam TInterface Interface type
* @param[in] pInterface Interface pointer
* @return Reference to this interface type.
*/
template <typename TInterface>
interface_t& operator=(TInterface* pInterface) noexcept;
/**
* @brief Boolean cast operator. Returns whether an interface (!= nullptr) has been assigned.
* @return Returns 'true' when assigned; 'false' when not.
*/
operator bool() const noexcept;
/**
* @brief Reset the interface pointer.
*/
void reset() noexcept;
/**
* @brief Get the interface ID.
* @return The ID of the stored interface.
*/
interface_id id() const noexcept;
/**
* @brief Get a pointer to the stored interface.
* @tparam TInterface The interface to get the pointer for.
* @return Returns the stored interface pointer if the ID of the requested interface corresponds to the stored interface.
* Returns a NULL-pointer if not.
*/
template <typename TInterface>
TInterface* get() noexcept;
/**
* @brief Get a pointer to the stored interface.
* @tparam TInterface The interface to get the pointer for.
* @return Returns the stored interface pointer if the ID of the requested interface corresponds to the stored interface.
* Returns a NULL-pointer if not.
*/
template <typename TInterface>
const TInterface* get() const noexcept;
/**
* @brief Compare the interface with another interface.
* @param[in] rifc Reference to the interface to compare with.
* @return Returns negative when the stored interface is smaller, 0 when the interfaces are equal and positive when the
* stored interface is larger.
*/
int compare(const interface_t& rifc) const noexcept;
private:
interface_id m_id = 0ull; ///< The interface ID of the stored interface.
void* m_pInterface = nullptr; ///< Interface pointer.
};
/**
* @brief Compare two interfaces for equality.
* @param[in] rifcLeft Reference to the left interface.
* @param[in] rifcRight Reference to the right interface.
* @return Returns whether both interfaces are equal.
*/
bool operator==(const interface_t& rifcLeft, const interface_t& rifcRight) noexcept;
/**
* @brief Compare the interface for equality to NULL-pointer.
* @param[in] rifcLeft Reference to the left interface.
* @return Returns whether the interface is a NULL-pointer.
*/
bool operator==(const interface_t& rifcLeft, std::nullptr_t) noexcept;
/**
* @brief Compare the interface for equality to NULL-pointer.
* @param[in] rifcRight Reference to the right interface.
* @return Returns whether the interface is a NULL-pointer.
*/
bool operator==(std::nullptr_t, const interface_t& rifcRight) noexcept;
/**
* @brief Compare two interfaces for in-equality.
* @param[in] rifcLeft Reference to the left interface.
* @param[in] rifcRight Reference to the right interface.
* @return Returns whether both interfaces are not equal.
*/
bool operator!=(const interface_t& rifcLeft, const interface_t& rifcRight) noexcept;
/**
* @brief Compare the interfaces for in-equality to NULL-pointer.
* @param[in] rifcLeft Reference to the left interface.
* @return Returns whether the interface is not a NULL-pointer.
*/
bool operator!=(const interface_t& rifcLeft, std::nullptr_t) noexcept;
/**
* @brief Compare the interfaces for in-equality to NULL-pointer.
* @param[in] rifcRight Reference to the right interface.
* @return Returns whether the interface is not a NULL-pointer.
*/
bool operator!=(std::nullptr_t, const interface_t& rifcRight) noexcept;
/**
* @brief Compare whether the left interface is smaller than the right interface.
* @param[in] rifcLeft Reference to the left interface.
* @param[in] rifcRight Reference to the right interface.
* @return Returns whether the left interface is smaller.
*/
bool operator<(const interface_t& rifcLeft, const interface_t& rifcRight) noexcept;
/**
* @brief Compare whether the left interface is smaller than a NULL-pointer.
* @param[in] rifcLeft Reference to the left interface.
* @return Returns whether the left interface is smaller.
*/
bool operator<(const interface_t& rifcLeft, std::nullptr_t) noexcept;
/**
* @brief Compare whether a NULL-pointer is smaller than the right interface.
* @param[in] rifcRight Reference to the right interface.
* @return Returns whether the NULL-pointer is smaller.
*/
bool operator<(std::nullptr_t, const interface_t& rifcRight) noexcept;
/**
* @brief Compare whether the left interface is smaller than or equal to the right interface.
* @param[in] rifcLeft Reference to the left interface.
* @param[in] rifcRight Reference to the right interface.
* @return Returns whether the left interface is smaller or equal.
*/
bool operator<=(const interface_t& rifcLeft, const interface_t& rifcRight) noexcept;
/**
* @brief Compare whether the left interface is smaller than or equal to a NULL-pointer.
* @param[in] rifcLeft Reference to the left interface.
* @return Returns whether the left interface is smaller.
*/
bool operator<=(const interface_t& rifcLeft, std::nullptr_t) noexcept;
/**
* @brief Compare whether a NULL-pointer is smaller than or equal to the right interface.
* @param[in] rifcRight Reference to the right interface.
* @return Returns whether the NULL-pointer is smaller or equal.
*/
bool operator<=(std::nullptr_t, const interface_t& rifcRight) noexcept;
/**
* @brief Compare whether the left interface is larger than the right interface.
* @param[in] rifcLeft Reference to the left interface.
* @param[in] rifcRight Reference to the right interface.
* @return Returns whether the left interface is larger.
*/
bool operator>(const interface_t& rifcLeft, const interface_t& rifcRight) noexcept;
/**
* @brief Compare whether the left interface is larger than a NULL-pointer.
* @param[in] rifcLeft Reference to the left interface.
* @return Returns whether the left interface is larger.
*/
bool operator>(const interface_t& rifcLeft, std::nullptr_t) noexcept;
/**
* @brief Compare whether a NULL-pointer is larger than the right interface.
* @param[in] rifcRight Reference to the right interface.
* @return Returns whether the NULL-pointer is larger.
*/
bool operator>(std::nullptr_t, const interface_t& rifcRight) noexcept;
/**
* @brief Compare whether the left interface is larger than or equal to the right interface.
* @param[in] rifcLeft Reference to the left interface.
* @param[in] rifcRight Reference to the right interface.
* @return Returns whether the left interface is larger or equal.
*/
bool operator>=(const interface_t& rifcLeft, const interface_t& rifcRight) noexcept;
/**
* @brief Compare whether the left interface is larger than or equal to a NULL-pointer.
* @param[in] rifcLeft Reference to the left interface.
* @return Returns whether the left interface is larger or equal.
*/
bool operator>=(const interface_t& rifcLeft, std::nullptr_t) noexcept;
/**
* @brief Compare whether a NULL-pointer is larger than or equal to the right interface.
* @param[in] rifcRight Reference to the right interface.
* @return Returns whether the NULL-pointer larger or equal.
*/
bool operator>=(std::nullptr_t, const interface_t& rifcRight) noexcept;
} // namespace idl
#include "interface.inl"
#endif // !defined SDV_INTERFACE_H

View File

@@ -0,0 +1,208 @@
#ifndef SDV_INTERFACE_INL
#define SDV_INTERFACE_INL
#ifndef SDV_INTERFACE_H
#error Do not include "interface.inl" directly. Include "interface.h" instead!
#endif //!defined SDV_INTERFACE_H
#include <cstddef>
namespace sdv
{
inline interface_t::interface_t() noexcept
{
// Ensure the layout is the same on all platforms.
static_assert(offsetof(interface_t, m_id) == 0);
static_assert(offsetof(interface_t, m_pInterface) == 8);
static_assert(sizeof(interface_t) == 16);
}
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
inline interface_t::interface_t(const interface_t& rifc) noexcept :
m_id(rifc.m_id), m_pInterface(rifc.m_pInterface)
{}
inline interface_t::interface_t(interface_t&& rifc) noexcept :
m_id(rifc.m_id), m_pInterface(rifc.m_pInterface)
{
rifc.reset();
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
inline interface_t::interface_t(std::nullptr_t) noexcept
{}
template <typename TInterface>
inline interface_t::interface_t(TInterface* pInterface) noexcept :
m_id(GetInterfaceId<TInterface>()), m_pInterface(pInterface)
{}
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
inline interface_t& interface_t::operator=(const interface_t& rifc) noexcept
{
m_id = rifc.m_id;
m_pInterface = rifc.m_pInterface;
return *this;
}
inline interface_t& interface_t::operator=(interface_t&& rifc) noexcept
{
m_id = rifc.m_id;
m_pInterface = rifc.m_pInterface;
rifc.reset();
return *this;
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
inline interface_t& interface_t::operator=(std::nullptr_t) noexcept
{
reset();
return *this;
}
template <typename TInterface>
inline interface_t& interface_t::operator=(TInterface* pInterface) noexcept
{
m_id = GetInterfaceId<TInterface>();
m_pInterface = pInterface;
return *this;
}
inline interface_t::operator bool() const noexcept
{
return m_pInterface ? true : false;
}
inline void interface_t::reset() noexcept
{
m_id = 0ull;
m_pInterface = nullptr;
}
inline interface_id interface_t::id() const noexcept
{
return m_id;
}
template <typename TInterface>
inline TInterface* interface_t::get() noexcept
{
return GetInterfaceId<TInterface>() == m_id ? reinterpret_cast<TInterface*>(m_pInterface) : nullptr;
}
template <typename TInterface>
inline const TInterface* interface_t::get() const noexcept
{
return GetInterfaceId<TInterface>() == m_id ? reinterpret_cast<const TInterface*>(m_pInterface) : nullptr;
}
inline int interface_t::compare(const interface_t& rifc) const noexcept
{
if (m_id < rifc.m_id) return -1;
if (m_id > rifc.m_id) return 1;
if (m_pInterface < rifc.m_pInterface) return -1;
if (m_pInterface > rifc.m_pInterface) return 1;
return 0;
}
inline bool operator==(const interface_t& rifcLeft, const interface_t& rifcRight) noexcept
{
return rifcLeft.compare(rifcRight) == 0;
}
inline bool operator==(const interface_t& rifcLeft, std::nullptr_t) noexcept
{
return !rifcLeft;
}
inline bool operator==(std::nullptr_t, const interface_t& rifcRight) noexcept
{
return !rifcRight;
}
inline bool operator!=(const interface_t& rifcLeft, const interface_t& rifcRight) noexcept
{
return rifcLeft.compare(rifcRight) != 0;
}
inline bool operator!=(const interface_t& rifcLeft, std::nullptr_t) noexcept
{
return static_cast<bool>(rifcLeft);
}
inline bool operator!=(std::nullptr_t, const interface_t& rifcRight) noexcept
{
return static_cast<bool>(rifcRight);
}
inline bool operator<(const interface_t& rifcLeft, const interface_t& rifcRight) noexcept
{
return rifcLeft.compare(rifcRight) < 0;
}
inline bool operator<(const interface_t& /*rifcLeft*/, std::nullptr_t) noexcept
{
return false;
}
inline bool operator<(std::nullptr_t, const interface_t& rifcRight) noexcept
{
return static_cast<bool>(rifcRight);
}
inline bool operator<=(const interface_t& rifcLeft, const interface_t& rifcRight) noexcept
{
return rifcLeft.compare(rifcRight) <= 0;
}
inline bool operator<=(const interface_t& rifcLeft, std::nullptr_t) noexcept
{
return !rifcLeft;
}
inline bool operator<=(std::nullptr_t, const interface_t& /*rifcRight*/) noexcept
{
return true;
}
inline bool operator>(const interface_t& rifcLeft, const interface_t& rifcRight) noexcept
{
return rifcLeft.compare(rifcRight) > 0;
}
inline bool operator>(const interface_t& rifcLeft, std::nullptr_t) noexcept
{
return static_cast<bool>(rifcLeft);
}
inline bool operator>(std::nullptr_t, const interface_t& /*rifcRight*/) noexcept
{
return false;
}
inline bool operator>=(const interface_t& rifcLeft, const interface_t& rifcRight) noexcept
{
return rifcLeft.compare(rifcRight) >= 0;
}
inline bool operator>=(const interface_t& /*rifcLeft*/, std::nullptr_t) noexcept
{
return true;
}
inline bool operator>=(std::nullptr_t, const interface_t& rifcRight) noexcept
{
return !rifcRight;
}
}
#endif // !defined SDV_INTERFACE_INL

View File

@@ -0,0 +1,835 @@
/**
*
* @file interface_ptr.h
* @brief This file provides all necessary definitions to use and implement interface maps.
* @version 0.1
* @date 2022.11.14
* @author Thomas.pfleiderer@zf.com
* @copyright Copyright ZF Friedrichshaven AG (c) 2022
*
*/
#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)
/**
* @brief Software Defined Vehicle framework.
*/
namespace sdv
{
/**
* @brief Internal namespace
*/
namespace internal
{
/**
* @brief Helper struct for section selection during interface map processing.
*/
class CSectionSelector
{
public:
/**
* @brief Any processing of interfaces after this the call to this function belongs to the default section.
*/
void DefineDefaultSection()
{
m_uiSection = -1;
}
/**
* @brief Any processing of interfaces after the call of this function, belongs to the section with the provided
* section number.
* @param[in] uiSection The section number the interface table entries belong to.
*/
void DefineSection(int uiSection)
{
m_uiSection = uiSection;
}
/**
* Select the section that is supported now.
*/
void Select(int uiSection)
{
m_uiUseSection = uiSection;
}
/**
* @brief Is the current section selected.
* @return Returns whether the section is currently within the selection.
*/
bool Selected() const
{
return m_uiSection < 0 || m_uiSection == m_uiUseSection;
}
private:
int m_uiUseSection = -1; ///< The number of the section to process the interface table entries for.
int m_uiSection = -1; ///< The number of the section the interface table entries belong to.
};
}
}
/**
* @brief Interface map containing the supported interface definitions.
* @pre The class using the interface map should derive from IInterfaceAccess.
*/
#define BEGIN_SDV_INTERFACE_MAP() \
/** \
* @brief Gets the requested interface \
* @param[in] idInterface The id representing the requested interface \
* @return Returns the IInterfaceAccess pointer to this if the requested interface is found, nullptr otherwise \
*/ \
sdv::interface_t GetInterface(sdv::interface_id idInterface) override \
{ \
if (!idInterface) return nullptr; \
::sdv::internal::CSectionSelector selector; \
if (selector.Selected()) \
{
/**
* @brief Using a namespace in the interface map.
*/
#define SDV_INTERFACE_USE_NAMESPACE(namespace_name) using namespace namespace_name;
/**
* @brief Interface entry containing the interface this class is derived from.
* @param ifc The interface to return.
*/
#define SDV_INTERFACE_ENTRY(ifc) \
if (idInterface == sdv::GetInterfaceId<ifc>()) \
return static_cast<ifc*>(this);
/**
* @brief Interface entry containing the interface a member class is derived from.
* @param ifc The interface to return. The member must derive from this interface.
* @param member_or_pointer The interface of the member to return.
*/
#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; \
}
/**
* @brief Interface entry containing the interface this class is derived from. The indirect implementation solves
* ambiguous casts when the class is derived from the same interface more than once.
* @param ifc The interface to return.
* @param ifc_cast The interface to use for casting before casting to the interface. This is usually one of the
* interfaces/classes derived from the interface
*/
#define SDV_INTERFACE_ENTRY_INDIRECT(ifc, ifc_cast) \
if (idInterface == sdv::GetInterfaceId<ifc>()) \
return static_cast<ifc*>(static_cast<ifc_cast*>(this));
/**
* @brief Interface entry containing the interface this class is definitely not supporting (used to overload an entry
* in an interface map in a base class).
* @attention When the interface map was chained, this will end the current processing for the chained map, but the
* calling map will still continue the processing.
* @param ifc The interface to deny.
*/
#define SDV_INTERFACE_DENY_ENTRY(ifc) \
if (idInterface == sdv::GetInterfaceId<ifc>()) \
return nullptr;
/**
* @brief Chain the interface map of a base class.
* @param base_class The class implementing the GetInterface function.
*/
#define SDV_INTERFACE_CHAIN_BASE(base_class) \
{ \
sdv::interface_t ifc = base_class::GetInterface(idInterface); \
if (ifc) \
return ifc; \
}
/**
* @brief Chain the interface map of a member as reference or as pointer.
* @param member_or_pointer The member implementing the GetInterface function.
*/
#define SDV_INTERFACE_CHAIN_MEMBER(member_or_pointer) \
{ \
sdv::interface_t ifc = sdv::InterfaceMapChainHelper(member_or_pointer, idInterface); \
if (ifc) \
return ifc; \
}
/**
* @brief Conditional check; when true continue the checking for interfaces.
* @param condition The condition to be checked. When 'false' processing will be stopped; otherwise processing
* continues. Example: @code SDV_INTERFACE_CHECK_CONDITION(CheckFunc()) @endcode
*/
#define SDV_INTERFACE_CHECK_CONDITION(condition) \
if (!(condition)) \
return nullptr;
/**
* @brief Use the condition, to select a section to process.
* @param condition Condition to be checked. When 'true' processing will be limited to the section.
* Example: @code SDV_INTERFACE_PROCESS_SECTION(CheckFunc(), 1) @endcode
* @param section_number The section to be processed when the condition is true.
*/
#define SDV_INTERFACE_SET_SECTION_CONDITION(condition, section_number) \
if (condition) \
selector.Select(section_number); \
} \
if (selector.Selected()) \
{
/**
* @brief Set section to process.
* @param section_number The section to process.
*/
#define SDV_INTERFACE_SET_SECTION(section_number) \
selector.Select(section_number); \
} \
if (selector.Selected()) \
{
/**
* @brief Define that the interface map entries following this statement are to be processed regardless of the section
* selection.
*/
#define SDV_INTERFACE_DEFAULT_SECTION() \
} \
selector.DefineDefaultSection(); \
if (selector.Selected()) \
{
/**
* @brief Define that the interface map entries following this statement belong to a dedicated section and should only
* be processed when that section is selected.
* @param section_number Begin of a section with the section number.
*/
#define SDV_INTERFACE_SECTION(section_number) \
} \
selector.DefineSection(section_number); \
if (selector.Selected()) \
{
/**
* @brief End of interface map.
*/
#define END_SDV_INTERFACE_MAP() \
} \
return nullptr; /* None found */ \
}
// NOLINTEND(cppcoreguidelines-macro-usage)
/**
* @brief Software Defined Vehicle framework.
*/
namespace sdv
{
/**
* @brief Interface access wrapper class.
* @tparam IInterfaceAccess Interface type to wrap
*/
class CInterfacePtr
{
public:
/**
* @brief Construct a new CInterfacePtr object.
* @param[in] pInterface Pointer to the interface to wrap or nullptr when no interface is to be wrapped yet.
*/
CInterfacePtr(IInterfaceAccess* pInterface = nullptr) : m_pInterface(pInterface)
{}
/**
* @brief Copy construct a new CInterfacePtr object
* @param[in] rptrInterface Reference to the CInterfacePtr object to copy from.
*/
CInterfacePtr(const CInterfacePtr& rptrInterface) : m_pInterface(rptrInterface.m_pInterface.load())
{}
/**
* @brief Move construct a new CInterfacePtr object
* @param[in] rptrInterface Reference to the CInterfacePtr object to move from.
*/
CInterfacePtr(CInterfacePtr&& rptrInterface) noexcept
{
IInterfaceAccess* pInterface = rptrInterface.m_pInterface.load();
rptrInterface.m_pInterface = nullptr;
m_pInterface = pInterface;
}
/**
* @brief Default destructor.
*/
virtual ~CInterfacePtr() = default;
/**
* @brief Assignment operator
* @param[in] pInterface Pointer to the interface to wrap or nullptr to clear the wrapping.
* @return Returns *this
*/
CInterfacePtr& operator=(IInterfaceAccess* pInterface)
{
m_pInterface = pInterface;
return *this;
}
/**
* @brief Assignment operator
* @param[in] rptrInterface Reference to the CInterfacePtr object to copy from.
* @return Returns *this
*/
CInterfacePtr& operator=(const CInterfacePtr& rptrInterface)
{
m_pInterface = rptrInterface.m_pInterface.load();
return *this;
}
/**
* @brief Move operator
* @param[in] rptrInterface Reference to the CInterfacePtr object to move from.
* @return Returns *this
*/
CInterfacePtr& operator=(CInterfacePtr&& rptrInterface) noexcept
{
IInterfaceAccess* pInterface = rptrInterface.m_pInterface.load();
rptrInterface.m_pInterface = nullptr;
m_pInterface = pInterface;
return *this;
}
/**
* @brief Get a pointer to the interface
*/
operator IInterfaceAccess*()
{
return m_pInterface;
}
/**
* @brief Get a pointer to the interface
*/
operator const IInterfaceAccess*() const
{
return m_pInterface;
}
/**
* @brief Is there a valid interface?
* @return Returns 'true' when an interface is wrapped; 'false' otherwise.
*/
operator bool() const
{
return static_cast<bool>(m_pInterface);
}
/**
* @brief Return whether there is a valid interface.
* @return Returns 'true' when an interface is wrapped; 'false' otherwise.
*/
bool IsValid() const
{
return static_cast<bool>(m_pInterface);
}
/**
* @brief Gets an interface by using the IInterfaceAccess::GetInterface function.
* @tparam TIfc The interface type to request.
* @return Returns a pointer to the requested interface if the object has itregistered, nullptr otherwise
*/
template <typename TIfc>
TIfc* GetInterface() const
{
return m_pInterface ? m_pInterface.load()->GetInterface(GetInterfaceId<TIfc>()).template get<TIfc>() : nullptr;
}
private:
/**
* @brief Contained pointer to the interface.
*/
std::atomic<IInterfaceAccess*> m_pInterface{nullptr};
};
/**
* @brief Specialization for sdv::IInterfaceAccess interface.
* @tparam TIfc The interface type to request.
* @return Returns a pointer to the requested interface if the object has itregistered, nullptr otherwise
*/
template <>
inline IInterfaceAccess* CInterfacePtr::GetInterface<IInterfaceAccess>() const
{
return m_pInterface;
}
/**
* @brief IInterfaceAccess smart pointer.
*/
using TInterfaceAccessPtr = CInterfacePtr;
/**
* @brief Helper function for interface chaining using a member variable.
* @tparam TMember Type of the member variable.
* @param[in] rtMember Reference to the member to chain to.
* @param[in] idInterface ID of the interface to request.
* @return Pointer to the interface.
*/
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
/**
* @brief Helper function for interface chaining using a member variable.
* @tparam IInterfaceAccess Type of the interface wrapped by the member variable.
* @param[in] rptrMember Reference to the interface wrapper class to chain to.
* @param[in] idInterface ID of the interface to request.
* @return Pointer to the interface.
*/
inline sdv::interface_t InterfaceMapChainHelper(CInterfacePtr& rptrMember, interface_id idInterface)
{
return rptrMember ? static_cast<IInterfaceAccess*>(rptrMember)->GetInterface(idInterface) : nullptr;
}
/**
* @brief Helper function for interface chaining using a member variable.
* @tparam TMember Type of the member variable.
* @param[in] ptMember Pointer to the member to chain to.
* @param[in] idInterface ID of the interface.
* @return Pointer to the interface.
*/
template <typename TMember>
inline sdv::interface_t InterfaceMapChainHelper(TMember* ptMember, interface_id idInterface)
{
return ptMember ? ptMember->GetInterface(idInterface) : nullptr;
}
/**
* @brief Helper function for interface chaining using a member variable.
* @tparam TMember Type of the member variable.
* @param[in] rptrMember Reference to the shared pointer to the member to chain to.
* @param[in] idInterface ID of the interface.
* @return Pointer to the interface.
*/
template <typename TMember>
inline sdv::interface_t InterfaceMapChainHelper(std::shared_ptr<TMember>& rptrMember, interface_id idInterface)
{
return rptrMember ? rptrMember->GetInterface(idInterface) : nullptr;
}
/**
* @brief Helper function for interface chaining using a member variable.
* @tparam TMember Type of the member variable.
* @param[in] rweakMember Reference to the weak pointer to the member to chain to.
* @param[in] idInterface ID of the interface.
* @return Pointer to the interface.
*/
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);
}
/**
* @brief Interface member helper class.
* @tparam TInterface The interface the member is to implement.
*/
template <typename TInterface>
struct SInterfaceMemberHelper
{
/**
* @brief Helper function for interface entries in the interface map.
* @tparam TMember Type of the member variable.
* @param[in] rtMember Reference to the member implementing the interface.
* @param[in] idInterface ID of the interface.
* @return Pointer to the interface.
*/
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;
}
/**
* @brief Helper function for interface entries in the interface map.
* @tparam TMember Type of the member variable.
* @param[in] ptMember Pointer to the member implementing the interface.
* @param[in] idInterface ID of the interface.
* @return Pointer to the interface.
*/
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;
}
/**
* @brief Helper function for interface entries in the interface map.
* @tparam TMember Type of the member variable.
* @param[in] rptrMember Reference to the shared pointer to the member implementing the interface.
* @param[in] idInterface ID of the interface.
* @return Pointer to the interface.
*/
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;
}
/**
* @brief Helper function for interface entries in the interface map.
* @tparam TMember Type of the member variable.
* @param[in] rweakMember Reference to the weak pointer to the member implementing the interface.
* @param[in] idInterface ID of the interface.
* @return Pointer to the interface.
*/
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);
}
};
/**
* @brief Helper class to implement the IObjectLifetime interface for objects not supporting this.
*/
class CObjectLifetimeWrapper : public IInterfaceAccess, public IObjectLifetime, public IObjectDestroy
{
public:
/**
* @brief Default constructor
*/
CObjectLifetimeWrapper() = default;
/**
* @brief Destructor automatically destroying the object.
*/
~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()
/**
* @brief Create a object lifetime wrapper object.
* @details Create an object lifetime wrapper object and assign the provided interface to the wrapper. The wrapper object
* blocks calls to IObjectDestroy since it will take ober the management of object lifetime.
* @param[in] pObject Interface of the object to wrap. This object needs to expose IObjectDestroy and could expose
* IObjectLifetime.
* @return Returns an interface giving access to a IObjectLifetime interface, forwarding all other interface calls.
*/
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();
}
/**
* @brief Increment the lifetime. Needs to be balanced by a call to Decrement. Overload of IObjectLifetime::Increment.
*/
virtual void Increment() override
{
m_iCounter++;
}
/**
* @brief Decrement the lifetime. If the lifetime reaches zero, the object will be destroyed (through the exposed
* IObjectDestroy interface). Overload of IObjectLifetime::Decrement.
* @return Returns 'true' if the object was destroyed, false if not.
*/
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;
}
/**
* Get the current lifetime count. Overload of IObjectLifetime::GetCount.
* @remarks The GetCount function returns a momentary value, which can be changed at any moment.
* @return Returns the current counter value.
*/
virtual uint32_t GetCount() const override
{
return static_cast<uint32_t>(m_iCounter);
}
/**
* @brief Destroy the object. Overload of IObjectDestroy::DestroyObject.
* @attention After a call of this function, all exposed interfaces render invalid and should not be used any more.
*/
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; ///< The interface pointer.
std::atomic<int32_t> m_iCounter = 0; ///< The lifetime counter.
std::unique_ptr<CObjectLifetimeWrapper> m_ptrKeepAlive; ///< The one instance of this wrapper class.
};
/**
* @brief Object smart pointer. Implements destruction of the object.
*/
class CObjectPtr
{
public:
/**
* @brief Construct a new CObjectPtr object.
* @param[in] pInterface Pointer to the interface to wrap or nullptr when no interface is to be wrapped yet.
*/
CObjectPtr(IInterfaceAccess* pInterface = nullptr)
{
Assign(pInterface);
}
/**
* @brief Copy construct a new CInterfacePtr object
* @param[in] rptrInterface Reference to the CInterfacePtr object to copy from.
*/
CObjectPtr(const CObjectPtr& rptrInterface) : m_ptrObject(rptrInterface.m_ptrObject)
{
IObjectLifetime* pObjectLifetime = GetInterface<IObjectLifetime>();
if (pObjectLifetime) pObjectLifetime->Increment();
}
/**
* @brief Move construct a new CInterfacePtr object
* @param[in] rptrInterface Reference to the CInterfacePtr object to move from.
*/
CObjectPtr(CObjectPtr&& rptrInterface) noexcept : m_ptrObject(std::move(rptrInterface.m_ptrObject))
{}
/**
* @brief Destructor.
*/
virtual ~CObjectPtr()
{
Clear();
}
/**
* @brief Assignment operator
* @param[in] pInterface Pointer to the interface to wrap or nullptr to clear the wrapping.
* @return Returns *this
*/
CObjectPtr& operator=(IInterfaceAccess* pInterface)
{
Assign(pInterface);
return *this;
}
/**
* @brief Assignment operator
* @param[in] rptrInterface Reference to the CInterfacePtr object to copy from.
* @return Returns *this
*/
CObjectPtr& operator=(const CObjectPtr& rptrInterface)
{
Clear();
m_ptrObject = rptrInterface.m_ptrObject;
IObjectLifetime* pObjectLifetime = GetInterface<IObjectLifetime>();
if (pObjectLifetime) pObjectLifetime->Increment();
return *this;
}
/**
* @brief Move operator
* @param[in] rptrInterface Reference to the CInterfacePtr object to move from.
* @return Returns *this
*/
CObjectPtr& operator=(CObjectPtr&& rptrInterface) noexcept
{
Attach(rptrInterface.Detach());
return *this;
}
/**
* @brief Get a pointer to the interface
*/
operator IInterfaceAccess*()
{
return m_ptrObject;
}
/**
* @brief Get a pointer to the interface
*/
operator const IInterfaceAccess*() const
{
return m_ptrObject;
}
/**
* @brief Get a pointer to the interface
*/
operator CInterfacePtr() const
{
return m_ptrObject;
}
/**
* @brief Is there a valid interface?
* @return Returns 'true' when an interface is wrapped; 'false' otherwise.
*/
operator bool() const
{
return IsValid();
}
/**
* @brief Return whether there is a valid interface.
* @return Returns 'true' when an interface is wrapped; 'false' otherwise.
*/
bool IsValid() const
{
return static_cast<bool>(m_ptrObject);
}
/**
* @brief Gets an interface by using the IInterfaceAccess::GetInterface function.
* @tparam TIfc The interface type to request.
* @return Returns a pointer to the requested interface if the object has itregistered, nullptr otherwise
*/
template <typename TIfc>
TIfc* GetInterface() const
{
return m_ptrObject.GetInterface<TIfc>();
}
/**
* @brief Assign the object to this object pointer and increment the lifetime counter.
* @param[in] pObject Interface pointer to the object.
*/
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);
}
/**
* @brief Destroy the object and clear the interface.
*/
void Clear()
{
IObjectLifetime* pLifetime = m_ptrObject.GetInterface<IObjectLifetime>();
if (pLifetime) // Object provides lifetime management. Use this...
pLifetime->Decrement();
m_ptrObject = nullptr;
}
/**
* @brief Attach an object which is managed by lifetime. The lifetime counter is not increased.
* @remarks Attachment only succeeds when the object exposes the IObjectLifetime pointer.
* @param[in] pObject Pointer to the object.
*/
void Attach(IInterfaceAccess* pObject)
{
Clear();
if (CInterfacePtr(pObject).GetInterface<IObjectLifetime>())
m_ptrObject = pObject;
}
/**
* @brief Detach the pointer without change the object lifetime. The internal pointer will beeome NULL.
* @attention Detaching the pointer means it is not managed any more. A call to IObjectLifetime::Decrement needs to be done
* manually.
* @return The detached interface pointer.
*/
CInterfacePtr Detach()
{
if (!m_ptrObject) return CInterfacePtr();
CInterfacePtr ptr = std::move(m_ptrObject);
m_ptrObject = nullptr;
return ptr;
}
private:
CInterfacePtr m_ptrObject; ///< The object pointer.
};
/**
* @brief IObjectAccess smart pointer.
*/
using TObjectPtr = CObjectPtr;
} // namespace sdv
#ifndef DONT_LOAD_CORE_TYPES
#include "mem_access.h"
#endif
#endif // !defined INTERFACE_IMPL_H

355
export/support/iterator.h Normal file
View File

@@ -0,0 +1,355 @@
#ifndef SDV_ITERATOR_H
#define SDV_ITERATOR_H
#include <iterator>
#ifndef DONT_LOAD_CORE_TYPES
#include "../interfaces/core_types.h"
#endif
namespace sdv
{
namespace internal
{
/**
* @brief Index based iterators used for linear array based containers.
* @tparam TContainer Container type to use for this iterator.
* @tparam bConstIterator When set, the iterator is a const iterator not allowing to change values within the container.
* @tparam bReserseIterator When set, the iterator starts at the end instead of at the beginning and decreases the location.
*/
template <class TContainer, bool bConstIterator, bool bReverseIterator>
class index_iterator
{
friend index_iterator<TContainer, !bConstIterator, bReverseIterator>;
public:
/**
* @brief Container type reference
*/
using container_reference = std::conditional_t<bConstIterator, const TContainer&, TContainer&>;
/**
* @brief Contaioner type pointer
*/
using container_pointer = std::conditional_t<bConstIterator, const TContainer*, TContainer*>;
/**
* @brief Iterator category
*/
using iterator_category = std::random_access_iterator_tag;
/**
* @brief Value type
*/
using value_type = typename TContainer::value_type;
/**
* @brief Indexing type
*/
using difference_type = size_t;
/**
* @brief Value type pointer
*/
using pointer = std::conditional_t<bConstIterator, const value_type*, value_type*>;
/**
* @brief Value type reference
*/
using reference = std::conditional_t<bConstIterator, const value_type&, value_type&>;
/**
* @brief Default constructor
*/
index_iterator() {}
/**
* @brief Iterator initialization
* @param[in] pContainer Pointer to the container.
*/
index_iterator(container_pointer pContainer) : m_pContainer(pContainer)
{}
/**
* @brief Copy constructor
* @param[in] rit Reference to the iterator to copy from.
*/
index_iterator(const index_iterator& rit) : m_pContainer(rit.m_pContainer), m_nIndex(rit.m_nIndex)
{}
/**
* @brief Copy constructor
* @param[in] rit Reference to the iterator to copy from.
*/
index_iterator(const index_iterator<TContainer, !bConstIterator, bReverseIterator>& rit) :
m_pContainer(const_cast<container_pointer>(rit.m_pContainer)), m_nIndex(rit.m_nIndex)
{}
/**
* @brief Move constructor
* @param[in] rit Reference to the iterator to move from.
*/
index_iterator(index_iterator&& rit) noexcept : m_pContainer(rit.m_pContainer), m_nIndex(rit.m_nIndex)
{
rit.m_pContainer = nullptr;
rit.m_nIndex = 0;
}
/**
* @brief Assignment operator
* @param[in] rit Reference to the iterator to copy from.
* @return Returns a reference to the iterator.
*/
index_iterator& operator=(const index_iterator& rit)
{
m_pContainer = rit.m_pContainer;
m_nIndex = rit.m_nIndex;
return *this;
}
/**
* @brief Assignment operator
* @param[in] rit Reference to the iterator to copy from.
* @return Returns a reference to the iterator.
*/
index_iterator& operator=(const index_iterator<TContainer, !bConstIterator, bReverseIterator>& rit)
{
m_pContainer = rit.m_pContainer;
m_nIndex = rit.m_nIndex;
return *this;
}
/**
* @brief Move operator
* @param[in] rit Reference to the iterator to move from.
* @return Returns a reference to the iterator.
*/
index_iterator& operator=(index_iterator&& rit) noexcept
{
m_pContainer = rit.m_pContainer;
m_nIndex = rit.m_nIndex;
rit.m_pContainer = nullptr;
rit.m_nIndex = 0;
return *this;
}
/**
* @brief Does the iterator iterate the same container.
* @param[in] rContainer Reference to the container to check whether the iterators are iterating the same container.
* @return Returns 'true' when the iterator iterates the same container; otherwise returns 'false'.
*/
bool is_valid(container_reference rContainer) const
{
return m_pContainer == &rContainer;
}
/**
* @brief Compare two iterators for iterating the same container and pointing to the same position.
* @param[in] rit Reference to the iterator to use for the comparison.
* @return Returns 'true' when the iterators point to the same container and have the same position.
*/
bool operator==(const index_iterator& rit) const
{
return m_pContainer == rit.m_pContainer && m_nIndex == rit.m_nIndex;
}
/**
* @brief Compare two iterators for iterating the same container and pointing to the same position.
* @param[in] rit Reference to the iterator to use for the comparison.
* @return Returns 'true' when the iterators point to the same container and have the same position.
*/
bool operator==(const index_iterator<TContainer, !bConstIterator, bReverseIterator>& rit) const
{
return m_pContainer == rit.m_pContainer && m_nIndex == rit.m_nIndex;
}
/**
* @brief Compare two iterators for iterating the different containers or pointing to the another position.
* @param[in] rit Reference to the iterator to use for the comparison.
* @return Returns 'true' when the iterators point to different containers or have different positions.
*/
bool operator!=(const index_iterator& rit) const
{
return !(*this == rit);
}
/**
* @brief Compare two iterators for iterating the different containers or pointing to the another position.
* @param[in] rit Reference to the iterator to use for the comparison.
* @return Returns 'true' when the iterators point to different containers or have different positions.
*/
bool operator!=(const index_iterator<TContainer, !bConstIterator, bReverseIterator>& rit) const
{
return !(*this == rit);
}
/**
* @brief Get the value from the container at the location the iterator is pointing to.
* @return Reference to the value.
*/
reference operator*() const
{
size_t nIndex = m_nIndex;
if (!m_pContainer || m_nIndex >= m_pContainer->size())
{
XIndexOutOfRange exception;
exception.uiIndex = static_cast<uint32_t>(nIndex);
exception.uiSize = static_cast<uint32_t>(m_pContainer ? m_pContainer->size() : 0);
throw exception;
}
if constexpr (bReverseIterator)
nIndex = m_pContainer->size() - m_nIndex - 1;
return (*m_pContainer)[nIndex];
}
/**
* @brief Pointer operation the value from the container at the location the iterator is pointing to.
* @remarks Only valid for container storing pointers.
* @return Reference to the value.
*/
pointer operator->() const
{
return std::pointer_traits<pointer>::pointer_to(**this);
}
/**
* @brief Increase the iterator with one position. Doesn't go past the one position behind the back.
* @return Reference to the iterator.
*/
index_iterator& operator++()
{
if (m_pContainer && m_nIndex < m_pContainer->size())
m_nIndex++;
return *this;
}
/**
* @brief Copy the current iterator and increase the copied iterator with one position. Doesn't go past the one
* position behind the back.
* @return Copied and increased iterator.
*/
index_iterator operator++(int)
{
index_iterator itCopy = *this;
operator++();
return itCopy;
}
/**
* @brief Decrease the iterator with one position. Doesn't go before the front position.
* @return Reference to the iterator.
*/
index_iterator& operator--() noexcept
{
if (m_pContainer && m_nIndex > 0)
m_nIndex--;
return *this;
}
/**
* @brief Copy the current iterator and decrease the copied iterator with one position. Doesn't go before the front
* position.
* @return Copied and decreased iterator.
*/
index_iterator operator--(int) noexcept
{
index_iterator itCopy = *this;
operator--();
return itCopy;
}
/**
* @brief Increase the iterator with nOsset positions. Doesn't go past the one position behind the back.
* @param[in] nOffset The amount of positions to increase.
* @return Reference to the iterator.
*/
index_iterator& operator+=(size_t nOffset) noexcept
{
if (!m_pContainer) return *this;
if (nOffset > m_pContainer->size() - m_nIndex)
m_nIndex = m_pContainer->size();
else
m_nIndex += nOffset;
return *this;
}
/**
* @brief Copy the current iterator and increase the copied iterator with nOffset positions. Doesn't go past the one
* position behind the back.
* @param[in] nOffset The amount of positions to increase.
* @return Copied and increased iterator.
*/
index_iterator operator+(size_t nOffset) const noexcept
{
index_iterator itCopy = *this;
itCopy += nOffset;
return itCopy;
}
/**
* @brief Decrease the iterator with nOffset positions. Doesn't go before the front position.
* @param[in] nOffset The amount of positions to decrease.
* @return Reference to the iterator.
*/
index_iterator& operator-=(size_t nOffset) noexcept
{
if (!m_pContainer) return *this;
if (m_nIndex > nOffset)
m_nIndex -= nOffset;
else if (m_nIndex)
m_nIndex = 0;
return *this;
}
/**
* @brief Copy the current iterator and decrease the copied iterator with nOffset positions. Doesn't go before the
* front position.
* @param[in] nOffset The amount of positions to increase.
* @return Copied and decreased iterator.
*/
index_iterator operator-(size_t nOffset) const noexcept
{
index_iterator itCopy = *this;
itCopy -= nOffset;
return itCopy;
}
/**
* @brief Subtract the indices of two iterators of the same type.
* @param[in] it The iterator to use for subtraction.
* @return The difference between the contained index and the index of the supplied iterator.
*/
difference_type operator-(index_iterator it) const
{
if (m_pContainer != it.m_pContainer) return 0;
if (m_nIndex > it.m_nIndex)
return m_nIndex - it.m_nIndex;
else
return it.m_nIndex - m_nIndex;
}
/**
* @brief Get the value from the container at the location the iterator is pointing to added with an offset.
* @param[in] nOffset The offset to increase the location.
* @return Reference to the value at the location increased with an offset.
*/
reference operator[](size_t nOffset) const
{
if (!m_pContainer || m_pContainer->empty())
{
XIndexOutOfRange exception;
exception.uiIndex = static_cast<uint32_t>(nOffset + m_nIndex);
exception.uiSize = static_cast<uint32_t>(0);
throw exception;
}
return *(operator+(nOffset));
}
private:
container_pointer m_pContainer = nullptr; ///< Pointer to the container.
size_t m_nIndex = 0; ///< Current index within the container.
};
} // namespace internal
} // namespace sdv
#endif // !defined SDV_ITERATOR_H

View File

@@ -0,0 +1,310 @@
#ifndef LOCAL_SERVICE_ACCESS_H
#define LOCAL_SERVICE_ACCESS_H
#include "../interfaces/core.h"
#include "../interfaces/log.h"
#include "../interfaces/repository.h"
#include "../interfaces/com.h"
#include "interface_ptr.h"
#include <sstream>
#include <utility>
#ifdef __GNUC__
// Needed for getpid()
#include <unistd.h>
#endif
/**
* @brief Software Defined Vehicle framework.
*/
namespace sdv
{
// Forward declaration
interface IInterfaceAccess;
/**
* @brief Core features.
*/
namespace core
{
#ifndef SDV_CUSTOM_GETOBJECT
/**
* @brief Get an object from the repository service.
* @attention This function only work when called from modules loaded via the repository service.
* @param[in] rssObjectName Reference to the name of the requested object (as defined via DECLARE_OBJECT_CLASS_NAME).
* @return Returns the smart interface pointer of the object instance if found or nullptr otherwise.
*/
inline TInterfaceAccessPtr GetObject(const std::string& rssObjectName)
{
if (!GetCore()) return nullptr;
IObjectAccess* pRepository = GetCore<IObjectAccess>();
if (!pRepository) return nullptr;
return pRepository->GetObject(rssObjectName);
}
/**
* @brief Get an object from the repository service.
* @attention This function can only be used on controlled objects. Local object are not returned using this function.
* @param[in] tObjectID Object ID of the object instantiation.
* @return Returns the smart interface pointer of the object instance if found or nullptr otherwise.
*/
inline TInterfaceAccessPtr GetObject(TObjectID tObjectID)
{
if (!GetCore()) return nullptr;
IObjectAccess* pRepository = GetCore<IObjectAccess>();
if (!pRepository) return nullptr;
return pRepository->GetObjectByID(tObjectID);
}
#else
/**
* @brief Get an object from the repository service.
* @attention This function only work when called from modules loaded via the repository service.
* @param[in] rssObjectName Reference to the name of the requested object (as defined via DECLARE_OBJECT_CLASS_NAME).
* @return Returns the smart interface pointer of the object instance if found or nullptr otherwise.
*/
TInterfaceAccessPtr GetObject(const std::string& rssObjectName);
/**
* @brief Get an object from the repository service.
* @attention This function can only be used on controlled objects. Local object are not returned using this function.
* @param[in] tObjectID Object ID of the object instantiation.
* @return Returns the smart interface pointer of the object instance if found or nullptr otherwise.
*/
TInterfaceAccessPtr GetObject(TObjectID tObjectID);
#endif
/**
* @brief Get an object from the repository service.
* @tparam TInterface The type of interface to return.
* @attention This function can only be used on controlled objects. Local object are not returned using this function.
* @param[in] rssObjectName Reference to the name of the requested object (as defined via DECLARE_OBJECT_CLASS_NAME).
* @return Returns the interface pointer of the object instance if found or nullptr otherwise.
*/
template <typename TInterface>
inline TInterface* GetObject(const std::string& rssObjectName)
{
return GetObject(rssObjectName).GetInterface<TInterface>();
}
/**
* @brief Get an object from the repository service.
* @tparam TInterface The type of interface to return.
* @attention This function can only be used on controlled objects. Local object are not returned using this function.
* @param[in] tObjectID Object ID of the object instantiation.
* @return Returns the interface pointer of the object instance if found or nullptr otherwise.
*/
template <typename TInterface>
inline TInterface* GetObject(TObjectID tObjectID)
{
return GetObject(tObjectID).GetInterface<TInterface>();
}
/**
* @brief Log function enables logging for SDV.
* @param[in] eSeverity Severity level of the log message which will be logged, e.g. Info, Warning, Error etc.
* @param[in] rssSrcFile Name of the file from which the message is logged.
* @param[in] uiSrcLine Line of the file from which the message is logged.
* @param[in] rssMessage Reference to the log message to be logged.
*/
inline void Log(ELogSeverity eSeverity, const u8string& rssSrcFile, uint32_t uiSrcLine, const u8string& rssMessage)
{
ILogger* pLogger = GetCore() ? GetCore<ILogger>() : nullptr;
#ifdef _WIN32
if (pLogger) pLogger->Log(eSeverity, rssSrcFile, uiSrcLine, _getpid(), "", rssMessage);
#elif defined __unix__
if (pLogger) pLogger->Log(eSeverity, rssSrcFile, uiSrcLine, getpid(), "", rssMessage);
#else
#error The OS is currently not supported!
#endif
}
/**
* @brief Log a message with line and position.
* @param severity The severity of the message. One of the entries from ELogServerity.
*/
#define SDV_LOG(severity, ...) sdv::core::internal::CSDVLogImpl(severity, __FILE__, __LINE__, __VA_ARGS__)
/**
* @brief Log a trace message with line and position.
*/
#define SDV_LOG_TRACE(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::trace, __FILE__, __LINE__, __VA_ARGS__)
/**
* @brief Log a debug message with line and position.
*/
#define SDV_LOG_DEBUG(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::debug, __FILE__, __LINE__, __VA_ARGS__)
/**
* @brief Log an information message with line and position.
*/
#define SDV_LOG_INFO(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::info, __FILE__, __LINE__, __VA_ARGS__)
/**
* @brief Log a warning message with line and position.
*/
#define SDV_LOG_WARNING(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::warning, __FILE__, __LINE__, __VA_ARGS__)
/**
* @brief Log an error message with line and position.
*/
#define SDV_LOG_ERROR(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::error, __FILE__, __LINE__, __VA_ARGS__)
/**
* @brief Log a fatal message with line and position.
*/
#define SDV_LOG_FATAL(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::fatal, __FILE__, __LINE__, __VA_ARGS__)
namespace internal
{
/**
* @brief Template to log messages with line and position.
* @param[in] eSeverity Severity level of the message.
* @param[in] szSrcFile Name of the file from which the message is logged. Specified by C++ standard.
* @param[in] uiSrcLine Line of the file from which the message is logged. Specified by C++ standard.
* @param[in] ...args identifier specified by C++ standard that uses the ellipsis notation in the parameters.
*/
template <typename ...Args>
inline void CSDVLogImpl(ELogSeverity eSeverity, const char* szSrcFile, uint32_t uiSrcLine, Args&& ...args)
{
std::ostringstream stream;
(stream << ... << std::forward<Args>(args));
Log(eSeverity, szSrcFile ? szSrcFile : "", uiSrcLine, stream.str().c_str());
}
}
/**
* @brief Create a utility
* @param[in] rssUtilityName Reference to the utility name.
* @param[in] rssUtilityConfig Optional reference to the utility configuration.
* @return Smart pointer to the utility or NULL when the utility could not be found.
*/
inline TObjectPtr CreateUtility(const std::string& rssUtilityName, const std::string& rssUtilityConfig = std::string())
{
TInterfaceAccessPtr ptrRepository = GetObject("RepositoryService");
IRepositoryUtilityCreate* pUtilityCreate = ptrRepository.GetInterface<IRepositoryUtilityCreate>();
if (!pUtilityCreate) return nullptr;
return pUtilityCreate->CreateUtility(rssUtilityName, rssUtilityConfig);
}
} // namespace core
namespace app
{
/**
* @brief Get application attribute.
* @param[in] rssAttribute Name of the attribute.
* @return The attribute value or an empty any-value if the attribute wasn't found or didn't have a value.
*/
inline any_t GetAppAttribute(const std::string& rssAttribute)
{
const IAttributes* ptrAppAttributes = core::GetObject<IAttributes>("AppControlService");
if (!ptrAppAttributes) return {};
return ptrAppAttributes->Get(rssAttribute);
}
/**
* @brief Returns true if the current application is configured for silent console reporting.
* @return Returns whether the silent console reporting has been enabled.
*/
inline bool ConsoleIsSilent()
{
return GetAppAttribute("console.info_level") == "silent";
}
/**
* @brief Returns true if the current application is configured for verbose console reporting.
* @return Returns whether the verbose console reporting has been enabled.
*/
inline bool ConsoleIsVerbose()
{
return GetAppAttribute("console.info_level") == "verbose";
}
/**
* @brief Get the instance ID of the application.
* @return The instance ID.
*/
inline uint32_t GetAppInstanceID()
{
return GetAppAttribute("app.instance_id");
}
} // namespace app
namespace com
{
/**
* @brief Create a repository connection to a local server.
* @param[in] uiInstanceID Optionally the instance ID of the target system to connect to or 0 (default) to connect to the
* instance identified by app-control.
* @param[in] nRetries Number of retries to connect (optional, default 30, minimum 3).
* @return Returns a smart pointer to the repository proxy. Disconnection takes place when IObjectDestroy::DestroyObject is
* called.
*/
inline TObjectPtr ConnectToLocalServerRepository(uint32_t uiInstanceID = 0, size_t nRetries = 30)
{
com::IClientConnect* pClientConnect = core::GetObject<com::IClientConnect>("ConnectionService");
if (!pClientConnect)
{
if (!app::ConsoleIsSilent())
std::cerr << "ERROR: Could not access the connection service." << std::endl;
return {};
}
// Connect the client to the server and return the server repository interface.
std::string ssConnectString = R"code([Client]
Type = "Local"
)code";
if (uiInstanceID)
ssConnectString += "Instance = " + std::to_string(uiInstanceID) + R"code(
)code";
try
{
// Try to connect (30 times with 1 second in between).
size_t nCnt = 0;
sdv::TObjectPtr ptrRepository;
while (!ptrRepository && nCnt < nRetries)
{
nCnt++;
ptrRepository = pClientConnect->Connect(ssConnectString);
if (!ptrRepository)
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
// Return the result
return ptrRepository;
}
catch (const XAccessDenied& /*rExcept*/)
{
if (!app::ConsoleIsSilent())
std::cout << "Access denied trying to connect to a local repository with server instance ID#" <<
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << "." << std::endl;
return {};
}
catch (const XNotFound& /*rExcept*/)
{
if (!app::ConsoleIsSilent())
std::cout << "Local repository with server instance ID#" <<
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << " not found." << std::endl;
return {};
}
catch (const XInvalidState& rExcept)
{
if (!app::ConsoleIsSilent())
std::cout << "The local repository with server instance ID#" <<
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << " is in an invalid state: " << rExcept.what() <<
std::endl;
return {};
}
catch (const XTimeout& /*rExcept*/)
{
if (!app::ConsoleIsSilent())
std::cout << "Timeout occurred trying to connect to a local repository with server instance ID#" <<
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << "." << std::endl;
return {};
}
}
} // namespace core
} // namespace sdv
#endif // !defined LOCAL_SERVICE_ACCESS_H

View File

@@ -0,0 +1,85 @@
#ifndef MEM_SUPPORT_H
#define MEM_SUPPORT_H
#include "../interfaces/mem.h"
#include <map>
#include <thread>
#include <iostream>
#include "interface_ptr.h"
#include "sdv_core.h"
namespace sdv
{
namespace core
{
// Forward declarations
TInterfaceAccessPtr GetCore();
template <typename TInterface>
TInterface* GetCore();
/**
* @brief Get access to the memory manager.
* @return Pointer to the memory allocation interface of the memory manager.
*/
inline sdv::core::IMemoryAlloc* GetMemMgr()
{
static sdv::core::IMemoryAlloc* pAlloc = nullptr;
static const sdv::IInterfaceAccess* pLocalServices = nullptr;
// cppcheck warns that GetCore is always returning a pointer. This mechanism is preparing for the situation where the
// core might be shut down and therefore there is no memory management any more. Suppress the warning.
// cppcheck-suppress knownConditionTrueFalse
if (GetCore())
{
if (GetCore() != pLocalServices || !pAlloc)
pAlloc = GetCore<IMemoryAlloc>();
}
else
pAlloc = nullptr;
pLocalServices = GetCore();
return pAlloc;
}
/**
* @brief Allocate memory as byte pointer.
* @param[in] nAmount The amount of bytes to allocate.
* @return Returns a pointer to the allocated memory or NULL when the allocation failed.
*/
inline pointer<uint8_t> AllocMemBytes(size_t nAmount)
{
sdv::core::IMemoryAlloc* pMemMgr = GetMemMgr();
if (!pMemMgr)
throw sdv::core::XNoMemMgr{};
pointer<uint8_t> ptrBuffer = pMemMgr->Allocate(static_cast<uint32_t>(nAmount));
if (!ptrBuffer)
{
sdv::core::XAllocFailed exception;
exception.uiSize = static_cast<uint32_t>(nAmount);
throw exception;
}
return ptrBuffer;
}
/**
* @brief Allocate memory
* @tparam T The type to use for the allocation. Default is uint8_t.
* @param[in] nAmount The amount of elements to allocate memory for.
* @return Returns a pointer to the allocated memory of type T or NULL when the allocation failed.
*/
template <typename T /*= uint8_t*/>
inline pointer<T> AllocMem(size_t nAmount)
{
return make_ptr<T>(nAmount);
//pointer<uint8_t> ptrBuffer = AllocMemBytes(nAmount * sizeof(T));
//T* pT = reinterpret_cast<T*>(ptrBuffer.get());
//for (size_t nIndex = 0; nIndex < nAmount; nIndex++)
// new (pT + nIndex) T();
//pointer<T> ptr;
//ptr.attach(std::move(ptrBuffer));
//return ptr;
}
} // namespace core
} // namespace sdv
#endif // !defined(MEM_SUPPORT_H)

665
export/support/pointer.h Normal file
View File

@@ -0,0 +1,665 @@
#ifndef SDV_PTR_H
#define SDV_PTR_H
#include <ostream>
#include <atomic>
#include <algorithm>
#include "iterator.h"
#ifndef DONT_LOAD_CORE_TYPES
#include "../interfaces/core_types.h"
#endif
namespace sdv
{
// Forward declaration
template <typename, size_t>
class pointer;
/**
* @brief Managed pointer class.
* @details Buffer management class. There are two versions of buffer management, fixed buffer management (nFixedSize template
* parameter larger than 0) and dynamic buffer management (nFixedSize template parameter is 0). The fixed buffer management
* contains a fixed memory allocation of the amount of elements (capacity) and manages the size within this buffer. Copies of
* this pointer class will copy the buffer as well. The dynamic buffer behaves like a shared pointer. Copies of the pointer class will
* copy the pointer, but not the content. The lifetime of the content is managed through reference counter. The functions of
* this class are similar to the functions of the std::shared_ptr class.
* @tparam T Type to use for the buffer allocation.
* @tparam nFixedSize Size of the fixed size buffer or 0 for a dynamic sized buffer.
*/
template <typename T, size_t nFixedSize = 0>
class pointer
{
public:
/**
* @brief The element type of this pointer.
*/
using element_type = T;
/**
* @brief The size of this pointer allocation element in bytes.
*/
static const size_t size_bytes = nFixedSize * sizeof(T);
/**
* @brief The size of this pointer allocation in bytes aligned to 64-bits.
*/
static const size_t aligned_size_bytes = nFixedSize * sizeof(T) + ((nFixedSize * sizeof(T) % 8) ? (8 - nFixedSize * sizeof(T) % 8) : 0);
/**
* @brief Default constructor
*/
pointer() noexcept;
/**
* @brief Copy constructor of same pointer type.
* @param[in] rptr Reference to the pointer to copy.
*/
pointer(const pointer& rptr);
/**
* @brief Copy constructor of other pointer types.
* @tparam nFixedSize2 The fixed size of the provided pointer.
* @param[in] rptr Reference to the pointer to copy.
*/
template <size_t nFixedSize2>
pointer(const pointer<T, nFixedSize2>& rptr);
/**
* @brief Move constructor of same pointer type.
* @param[in] rptr Reference to the pointer to copy.
*/
pointer(pointer&& rptr);
/**
* @brief Move constructor of other pointer types.
* @tparam nFixedSize2 The fixed size of the provided pointer.
* @param[in] rptr Reference to the pointer to copy.
*/
template <size_t nFixedSize2>
pointer(pointer<T, nFixedSize2>&& rptr);
/**
* @brief Destructor
*/
~pointer();
/**
* @brief Assignment operator of same pointer type.
* @param[in] rptr Reference to the pointer to assign.
* @return Reference to this pointer.
*/
pointer& operator=(const pointer& rptr);
/**
* @brief Assignment operator of other pointer types.
* @tparam nFixedSize2 The fixed size of the provided pointer.
* @param[in] rptr Reference to the pointer to assign.
* @return Reference to this pointer.
*/
template <size_t nFixedSize2>
pointer& operator=(const pointer<T, nFixedSize2>& rptr);
/**
* @brief Move operator of same pointer type.
* @param[in] rptr Reference to the pointer to assign.
* @return Reference to this pointer.
*/
pointer& operator=(pointer&& rptr);
/**
* @brief Move operator of other pointer types.
* @tparam nFixedSize2 The fixed size of the provided pointer.
* @param[in] rptr Reference to the pointer to assign.
* @return Reference to this pointer.
*/
template <size_t nFixedSize2>
pointer& operator=(pointer<T, nFixedSize2>&& rptr);
/**
* @brief Reduces the reference count and if zero deletes the allocation. Clears the pointer.
*/
void reset();
/**
* @brief Swaps this pointer with the provided pointer.
* tparam nFixedSizeRight The fixed size of the provided pointer.
* @param[in] rptr Reference to the provided pointer to swap with.
*/
template <size_t nFixedSizeRight>
void swap(pointer<T, nFixedSizeRight>& rptr);
/**
* @brief Get access to the underlying buffer.
* @return Pointer to the buffer.
*/
element_type* get() const noexcept;
/**
* @brief Get a reference to the pointer.
* @return Reference to the value.
*/
T& operator*() const;
/**
* @brief Get a reference to the pointer.
* @return Pointer to the value.
*/
T* operator->() const;
/**
* @brief Get the indexed value of the pointer.
* @param[in] nIndex Index to request the value of.
* @return Reference to the indexed value.
*/
element_type& operator[](size_t nIndex) const;
/**
* @brief Return whether a pointer is assigned.
* @return Returns 'true' when a pointer is assigned; 'false' otherwise.
*/
operator bool() const noexcept;
/**
* @brief Return the amount of elements allocated for this pointer.
* @return The size of the pointer.
*/
size_t size() const noexcept;
/**
* @brief Resize the pointer.
* @param[in] nSize Size of the new pointer.
*/
void resize(size_t nSize);
/**
* @brief Return the capacity (in amount of elements) this buffer can hold.
* @return The capacity of the buffer pointed to by this pointer.
*/
size_t capacity() const noexcept;
private:
uint32_t m_uiSize = 0; ///< Amount of elements allocated.
uint32_t m_uiReserved = 0; ///< Reserved for alignment purposes.
union
{
T m_rgtData[nFixedSize] = {}; ///< The size of the buffer.
uint8_t m_rguiBuffer[aligned_size_bytes]; ///< The buffer aligned to 64 bits.
};
};
namespace internal
{
/// @cond DOXYGEN_IGNORE
// Forward declaration
interface IInternalMemAlloc;
template <typename T>
pointer<T, 0> make_ptr(IInternalMemAlloc* pAllocator, size_t nSize = 1);
/// @endcond
}
/**
* @brief Create a pointer class using the allocator and allocating the memory with the given size.
* @tparam T Type to use for the allocation.
* @param[in] nSize Size to allocate (in elements).
* @return The pointer class.
*/
template <typename T>
pointer<T> make_ptr(size_t nSize = 1);
/**
* @brief Specialization for dynamic sized buffer management.
* @tparam T Type to use for the buffer allocation.
*/
template <typename T>
class pointer<T, 0>
{
friend pointer<T> internal::make_ptr<T>(internal::IInternalMemAlloc* pAllocator, size_t nSize /*= 1*/);
friend pointer<T> make_ptr<T>(size_t);
public:
/**
* @brief The element type of this pointer.
*/
using element_type = T;
/**
* @brief Default constructor
*/
pointer() noexcept;
/**
* @brief Copy constructor of same pointer type.
* @param[in] rptr Reference to the pointer to copy.
*/
pointer(const pointer& rptr);
/**
* @brief Copy constructor of other pointer types.
* @tparam nFixedSize2 The fixed size of the provided pointer.
* @param[in] rptr Reference to the pointer to copy.
*/
template <size_t nFixedSize2>
pointer(const pointer<T, nFixedSize2>& rptr);
/**
* @brief Move constructor
* @param[in] rptr Reference to the pointer to move.
*/
pointer(pointer&& rptr) noexcept;
/**
* @brief Move constructor of other pointer types.
* @tparam nFixedSize2 The fixed size of the provided pointer.
* @param[in] rptr Reference to the pointer to copy.
*/
template <size_t nFixedSize2>
pointer(const pointer<T, nFixedSize2>&& rptr);
/**
* @brief Destructor
*/
~pointer();
/**
* @brief Assignment operator of same pointer type.
* @param[in] rptr Reference to the pointer to assign.
* @return Reference to this pointer.
*/
pointer& operator=(const pointer& rptr);
/**
* @brief Assignment operator of other pointer types.
* @param[in] rptr Reference to the pointer to assign.
* @return Reference to this pointer.
*/
template <size_t nFixedSize2>
pointer& operator=(const pointer<T, nFixedSize2>& rptr);
/**
* @brief Move operator of same pointer type.
* @param[in] rptr Reference to the pointer to move.
* @return Reference to this pointer.
*/
pointer& operator=(pointer&& rptr) noexcept;
/**
* @brief Move operator of other pointer types.
* @param[in] rptr Reference to the pointer to assign.
* @return Reference to this pointer.
*/
template <size_t nFixedSize2>
pointer& operator=(pointer<T, nFixedSize2>&& rptr);
protected:
/**
* @brief Attach an uint8_t buffer.
* @param[in] rptrBuffer Reference to the pointer to attach.
*/
void attach(pointer<uint8_t>&& rptrBuffer);
/**
* @brief Detach the uint8_t buffer.
* @return Reference to the pointer to detach.
*/
pointer<uint8_t>&& detach();
public:
/**
* @brief Reduces the reference count and if zero deletes the allocation. Clears the pointer.
*/
void reset();
/**
* @brief Swaps this pointer with the provided pointer.
* tparam nFixedSizeRight The fixed size of the provided pointer.
* @param[in] rptr Reference to the provided pointer to swap with.
*/
template <size_t nFixedSizeRight>
void swap(pointer<T, nFixedSizeRight>& rptr);
/**
* @brief Get access to the underlying buffer.
* @return Pointer to the buffer.
*/
element_type* get() const noexcept;
/**
* @brief Get a reference to the pointer.
* @return Reference to the value.
*/
T& operator*() const;
/**
* @brief Get a reference to the pointer.
* @return Pointer to the value.
*/
T* operator->() const;
/**
* @brief Get the indexed value of the pointer.
* @param[in] nIndex Index to request the value of.
* @return Reference to the indexed value.
*/
element_type& operator[](size_t nIndex) const;
/**
* @brief Return whether a pointer is assigned.
* @return Returns 'true' when a pointer is assigned; 'false' otherwise.
*/
operator bool() const noexcept;
/**
* @brief Return the amount of elements allocated for this pointer.
* @return The size of the pointer.
*/
size_t size() const noexcept;
/**
* @brief Resize the pointer.
* @attention A call to this function is not synchronized with other functions.
* @param[in] nSize Size of the new pointer.
*/
void resize(size_t nSize);
/**
* @brief Return the capacity (in amount of elements) this buffer can hold.
* @return The capacity of the buffer pointed to by this pointer.
*/
size_t capacity() const noexcept;
/**
* @brief Get reference count on current shares.
* @return Reference count.
*/
size_t ref_count() const noexcept;
private:
/**
* @brief The internal data structure holding the pointer information.
*/
struct SAllocation
{
internal::IInternalMemAlloc* pAllocator = nullptr; ///< Pointer to the memory allocator.
T* pData = nullptr; ///< Pointer to the data.
uint32_t uiSize = 0; ///< Amount of bytes allocated.
std::atomic_uint32_t uiRefCnt = 0; ///< Reference count.
};
SAllocation* m_psAllocation = nullptr; ///< Actual pointer to the allocation
};
/**
* @brief Swap two pointers.
* @tparam T Type to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left pointer.
* @tparam nFixedSizeRight The fixed size of the right pointer.
* @param[in] rptrLeft Reference to the first pointer.
* @param[in] rptrRight Reference to the second pointer.
*/
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
void swap(pointer<T, nFixedSizeLeft>& rptrLeft, pointer<T, nFixedSizeRight>& rptrRight);
/**
* @brief Compare two pointers for equality.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left pointer.
* @tparam nFixedSizeRight The fixed size of the right pointer.
* @param[in] rptrLeft Reference to the left pointer.
* @param[in] rptrRight Reference to the right pointer.
* @return Returns 'true' when both pointers are equal; false when not.
*/
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
bool operator==(const pointer<T, nFixedSizeLeft>& rptrLeft, const pointer<T, nFixedSizeRight>& rptrRight) noexcept;
/**
* @brief Compare two pointers for inequality.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left pointer.
* @tparam nFixedSizeRight The fixed size of the right pointer.
* @param[in] rptrLeft Reference to the left pointer.
* @param[in] rptrRight Reference to the right pointer.
* @return Returns 'true' when both pointers are not equal; false when not.
*/
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
bool operator!=(const pointer<T, nFixedSizeLeft>& rptrLeft, const pointer<T, nFixedSizeRight>& rptrRight) noexcept;
/**
* @brief Compare whether one pointer is smaller than another pointer.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left pointer.
* @tparam nFixedSizeRight The fixed size of the right pointer.
* @param[in] rptrLeft Reference to the left pointer.
* @param[in] rptrRight Reference to the right pointer.
* @return Returns 'true' when the left pointer is smaller than the right pointer; false when not.
*/
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
bool operator<(const pointer<T, nFixedSizeLeft>& rptrLeft, const pointer<T, nFixedSizeRight>& rptrRight) noexcept;
/**
* @brief Compare whether one pointer is smaller than or equal to another pointer.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left pointer.
* @tparam nFixedSizeRight The fixed size of the right pointer.
* @param[in] rptrLeft Reference to the left pointer.
* @param[in] rptrRight Reference to the right pointer.
* @return Returns 'true' when the left pointer is smaller than or equal to the right pointer; false when not.
*/
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
bool operator<=(const pointer<T, nFixedSizeLeft>& rptrLeft, const pointer<T, nFixedSizeRight>& rptrRight) noexcept;
/**
* @brief Compare whether one pointer is larger than another pointer.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left pointer.
* @tparam nFixedSizeRight The fixed size of the right pointer.
* @param[in] rptrLeft Reference to the left pointer.
* @param[in] rptrRight Reference to the right pointer.
* @return Returns 'true' when the left pointer is larger than the right pointer; false when not.
*/
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
bool operator>(const pointer<T, nFixedSizeLeft>& rptrLeft, const pointer<T, nFixedSizeRight>& rptrRight) noexcept;
/**
* @brief Compare whether one pointer is larger than or equal to another pointer.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left pointer.
* @tparam nFixedSizeRight The fixed size of the right pointer.
* @param[in] rptrLeft Reference to the left pointer.
* @param[in] rptrRight Reference to the right pointer.
* @return Returns 'true' when the left pointer is larger than or equal to the right pointer; false when not.
*/
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
bool operator>=(const pointer<T, nFixedSizeLeft>& rptrLeft, const pointer<T, nFixedSizeRight>& rptrRight) noexcept;
/**
* @brief Compare whether the left pointer is equal too NULL.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left pointer.
* @param[in] rptrLeft Reference to the left pointer.
* @param[in] pNull Pointer to a nullptr.
* @return Returns 'true' if the left pointer equals NULL; 'false' when not.
*/
template <class T, size_t nFixedSizeLeft>
bool operator==(const pointer<T, nFixedSizeLeft>& rptrLeft, std::nullptr_t pNull) noexcept;
/**
* @brief Compare whether the right pointer is equal too NULL.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeRight The fixed size of the right pointer.
* @param[in] rptrRight Reference to the right pointer.
* @param[in] pNull Pointer to a nullptr.
* @return Returns 'true' if the right pointer equals NULL; 'false' when not.
*/
template <class T, size_t nFixedSizeRight>
bool operator==(std::nullptr_t pNull, const pointer<T, nFixedSizeRight>& rptrRight) noexcept;
/**
* @brief Compare whether the left pointer is not equal too NULL.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left pointer.
* @param[in] rptrLeft Reference to the left pointer.
* @param[in] pNull Pointer to a nullptr.
* @return Returns 'true' if the left pointer does not equal to NULL; 'false' when not.
*/
template <class T, size_t nFixedSizeLeft>
bool operator!=(const pointer<T, nFixedSizeLeft>& rptrLeft, std::nullptr_t pNull) noexcept;
/**
* @brief Compare whether the right pointer is not equal too NULL.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeRight The fixed size of the right pointer.
* @param[in] rptrRight Reference to the right pointer.
* @param[in] pNull Pointer to a nullptr.
* @return Returns 'true' if the right pointer does not equal to NULL; 'false' when not.
*/
template <class T, size_t nFixedSizeRight>
bool operator!=(std::nullptr_t pNull, const pointer<T, nFixedSizeRight>& rptrRight) noexcept;
/**
* @brief Compare whether the left pointer is smaller than NULL.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left pointer.
* @param[in] rptrLeft Reference to the left pointer.
* @param[in] pNull Pointer to a nullptr.
* @return Returns 'true' if the left pointer is smaller than NULL; 'false' when not.
*/
template <class T, size_t nFixedSizeLeft>
bool operator<(const pointer<T, nFixedSizeLeft>& rptrLeft, std::nullptr_t pNull) noexcept;
/**
* @brief Compare whether the NULL is smaller than the left pointer.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeRight The fixed size of the right pointer.
* @param[in] rptrRight Reference to the right pointer.
* @param[in] pNull Pointer to a nullptr.
* @return Returns 'true' if NULL is smaller than the left pointer; 'false' when not.
*/
template <class T, size_t nFixedSizeRight>
bool operator<(std::nullptr_t pNull, const pointer<T, nFixedSizeRight>& rptrRight) noexcept;
/**
* @brief Compare whether the left pointer is smaller than or equal to NULL.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left pointer.
* @param[in] rptrLeft Reference to the left pointer.
* @param[in] pNull Pointer to a nullptr.
* @return Returns 'true' if the left pointer is smaller than or equal to NULL; 'false' when not.
*/
template <class T, size_t nFixedSizeLeft>
bool operator<=(const pointer<T, nFixedSizeLeft>& rptrLeft, std::nullptr_t pNull) noexcept;
/**
* @brief Compare whether the NULL is smaller than or equal to the left pointer.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeRight The fixed size of the right pointer.
* @param[in] rptrRight Reference to the right pointer.
* @param[in] pNull Pointer to a nullptr.
* @return Returns 'true' if NULL is smaller than or equal to the left pointer; 'false' when not.
*/
template <class T, size_t nFixedSizeRight>
bool operator<=(std::nullptr_t pNull, const pointer<T, nFixedSizeRight>& rptrRight) noexcept;
/**
* @brief Compare whether the left pointer is larger than NULL.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left pointer.
* @param[in] rptrLeft Reference to the left pointer.
* @param[in] pNull Pointer to a nullptr.
* @return Returns 'true' if the left pointer is larger than NULL; 'false' when not.
*/
template <class T, size_t nFixedSizeLeft>
bool operator>(const pointer<T, nFixedSizeLeft>& rptrLeft, std::nullptr_t pNull) noexcept;
/**
* @brief Compare whether the NULL is larger than the left pointer.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeRight The fixed size of the right pointer.
* @param[in] rptrRight Reference to the right pointer.
* @param[in] pNull Pointer to a nullptr.
* @return Returns 'true' if NULL is larger than the left pointer; 'false' when not.
*/
template <class T, size_t nFixedSizeRight>
bool operator>(std::nullptr_t pNull, const pointer<T, nFixedSizeRight>& rptrRight) noexcept;
/**
* @brief Compare whether the left pointer is smaller than or equal to NULL.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left pointer.
* @param[in] rptrLeft Reference to the left pointer.
* @param[in] pNull Pointer to a nullptr.
* @return Returns 'true' if the left pointer is smaller than or equal to NULL; 'false' when not.
*/
template <class T, size_t nFixedSizeLeft>
bool operator>=(const pointer<T, nFixedSizeLeft>& rptrLeft, std::nullptr_t pNull) noexcept;
/**
* @brief Compare whether the NULL is smaller than or equal to the left pointer.
* @tparam T Type of the pointer to use as a base.
* @tparam nFixedSizeRight The fixed size of the right pointer.
* @param[in] rptrRight Reference to the right pointer.
* @param[in] pNull Pointer to a nullptr.
* @return Returns 'true' if NULL is smaller than or equal to the left pointer; 'false' when not.
*/
template <class T, size_t nFixedSizeRight>
bool operator>=(std::nullptr_t pNull, const pointer<T, nFixedSizeRight>& rptrRight) noexcept;
/**
* @brief Stream the value of a the pointer to an output stream.
* @tparam T Type of pointer.
* @tparam U Character type of output stream.
* @tparam V Character traits of output stream.
* @tparam nFixedSize The fixed size of the pointer.
* @param[in] rstream Reference to the stream.
* @param[in] rptr Reference to the pointer.
* @return Reference to the stream.
*/
template <class T, class U, class V, size_t nFixedSize>
std::basic_ostream<U, V>& operator<<(std::basic_ostream<U, V>& rstream, const pointer<T, nFixedSize>& rptr);
/**
* @brief C++ library stream support - reading from stream.
* @tparam TTraits Character traits of the stream buffer.
* @param[in, out] pStreamBuf Pointer to the stream buffer to read from.
* @return Pointer object created from the stream buffer.
*/
template <typename TTraits = std::char_traits<char>>
pointer<uint8_t> from_stream(std::basic_streambuf<char, TTraits>* pStreamBuf);
/**
* @brief C++ library stream support - writing to stream.
* @tparam TTraits Character traits of the stream buffer.
* @param[in] rptr Reference to the pointer to write to the stream.
* @param[in, out] pStreamBuf Pointer to the stream buffer to write to.
*/
template <typename TTraits = std::char_traits<char>>
void to_stream(const pointer<uint8_t>& rptr, std::basic_streambuf<char, TTraits>* pStreamBuf);
/**
* @brief For the uint8_t pointer a specific cast operation exists.
* @attention Use with care. There is no guarantee that the pointer corresponds to the layout of the requested type. If
* possible use serialization instead.
* @tparam T Type to cast to. T must be a standard-layout-type.
* @param[in] rptr Reference to the pointer containing the data buffer.
* @param[in] nOffset Offset the type starts.
* @return Returns a casted pointer if the buffer is large enough (offset + sizeof(T)); NULL otherwise.
*/
template <typename T>
T* cast(pointer<uint8_t>& rptr, size_t nOffset = 0);
/**
* @brief For the uint8_t pointer a specific cast operation exists.
* @attention Use with care. There is no guarantee that the pointer corresponds to the layout of the requested type. If
* possible use serialization instead.
* @tparam T Type to cast to. T must be a standard-layout-type.
* @param[in] rptr Reference to the pointer containing the data buffer.
* @param[in] nOffset Offset the type starts.
* @return Returns a casted pointer if the buffer is large enough (offset + sizeof(T)); NULL otherwise.
*/
template <typename T>
const T* cast(const pointer<uint8_t>& rptr, size_t nOffset = 0);
} // namespace sdv
#include "pointer.inl"
#endif // !defined SDV_PTR_H

877
export/support/pointer.inl Normal file
View File

@@ -0,0 +1,877 @@
#ifndef SDV_PTR_INL
#define SDV_PTR_INL
#ifdef min
#undef min
#endif
#ifndef SDV_PTR_H
#error Do not include "pointer.inl" directly. Include "pointer.h" instead!
#endif //!defined SDV_PTR_H
#include "pointer.h"
#include <iostream>
#include <algorithm>
// There are some versions of GCC that produce bogus warnings for -Wstringop-overflow (e.g. version 9.4 warns, 11.4 not - changing
// the compile order without changing the logical behavior, will produce different results).
// See also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100477
// And https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115074
// Suppress this warning for the string class.
// NOTE 03.08.2025: Additional bogus warnigs/errors are suppressed for newer versions of the compiler.
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#pragma GCC diagnostic ignored "-Warray-bounds"
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
#ifdef _MSC_VER
// Prevent static code analysis warnings about noexcept for mode constructors and operators. Due to a constexpr if statement,
// the constructor might or might not use exceptions and therefore noexcept might or might not be applied.
#pragma warning(push)
#pragma warning(disable : 26439)
#endif
/// @cond DOXYGEN_IGNORE
namespace sdv
{
template <typename T, size_t nFixedSize>
inline pointer<T, nFixedSize>::pointer() noexcept
{
// Ensure the layout is the same on all platforms.
static_assert(offsetof(pointer, m_uiSize) == 0);
static_assert(offsetof(pointer, m_rgtData) == 8);
static_assert(sizeof(pointer) == 8 + aligned_size_bytes);
}
template <typename T, size_t nFixedSize>
inline pointer<T, nFixedSize>::pointer(const pointer& rptr)
{
resize(rptr.size());
std::copy_n(rptr.get(), rptr.size(), get());
}
template <typename T, size_t nFixedSize>
template <size_t nFixedSize2>
inline pointer<T, nFixedSize>::pointer(const pointer<T, nFixedSize2>& rptr)
{
resize(rptr.size());
std::copy_n(rptr.get(), rptr.size(), get());
}
template <typename T, size_t nFixedSize>
inline pointer<T, nFixedSize>::pointer(pointer&& rptr)
{
resize(rptr.size());
std::copy_n(rptr.get(), rptr.size(), get());
rptr.reset();
}
template <typename T, size_t nFixedSize>
template <size_t nFixedSize2>
inline pointer<T, nFixedSize>::pointer(pointer<T, nFixedSize2>&& rptr)
{
resize(rptr.size());
std::copy_n(rptr.get(), rptr.size(), get());
rptr.reset();
}
template <typename T, size_t nFixedSize>
inline pointer<T, nFixedSize>::~pointer()
{
if constexpr (!std::is_scalar_v<T>)
{
for (size_t nIndex = 0; nIndex < nFixedSize; nIndex++)
m_rgtData[nIndex].~T();
}
}
template <typename T, size_t nFixedSize>
// Member m_uiReserved is not copied. Suppress static code analysis warning.
// cppcheck-suppress operatorEqVarError
inline pointer<T, nFixedSize>& pointer<T, nFixedSize>::operator=(const pointer& rptr)
{
resize(rptr.size());
std::copy_n(rptr.get(), rptr.size(), get());
return *this;
}
template <typename T, size_t nFixedSize>
template <size_t nFixedSize2>
// Member m_uiReserved is not copied. Suppress static code analysis warning.
// cppcheck-suppress operatorEqVarError
inline pointer<T, nFixedSize>& pointer<T, nFixedSize>::operator=(const pointer<T, nFixedSize2>& rptr)
{
resize(rptr.size());
std::copy_n(rptr.get(), rptr.size(), get());
return *this;
}
template <typename T, size_t nFixedSize>
// Member m_uiReserved is not copied. Suppress static code analysis warning.
// cppcheck-suppress operatorEqVarError
inline pointer<T, nFixedSize>& pointer<T, nFixedSize>::operator=(pointer&& rptr)
{
resize(rptr.size());
std::copy_n(rptr.get(), rptr.size(), get());
rptr.reset();
return *this;
}
template <typename T, size_t nFixedSize>
template <size_t nFixedSize2>
// Member m_uiReserved is not copied. Suppress static code analysis warning.
// cppcheck-suppress operatorEqVarError
inline pointer<T, nFixedSize>& pointer<T, nFixedSize>::operator=(pointer<T, nFixedSize2>&& rptr)
{
resize(rptr.size());
std::copy_n(rptr.get(), rptr.size(), get());
rptr.reset();
return *this;
}
template <typename T, size_t nFixedSize>
inline void pointer<T, nFixedSize>::reset()
{
resize(0);
}
template <typename T, size_t nFixedSize>
template <size_t nFixedSizeRight>
inline void pointer<T, nFixedSize>::swap(pointer<T, nFixedSizeRight>& rptr)
{
// Copy the provided content into a temporary buffer.
T rgtTemp[nFixedSizeRight];
size_t nSizeRight = rptr.size();
std::copy_n(rptr.get(), nSizeRight, rgtTemp);
// Copy the member buffer into the buffer of the provided pointer
rptr.resize(size());
std::copy_n(get(), size(), rptr.get());
// Copy the temporary buffer into this class' buffer.
resize(nSizeRight);
std::copy_n(rgtTemp, nSizeRight, get());
}
template <typename T, size_t nFixedSize>
inline typename pointer<T, nFixedSize>::element_type* pointer<T, nFixedSize>::get() const noexcept
{
return const_cast<element_type*>(m_rgtData);
}
template <typename T, size_t nFixedSize>
inline T& pointer<T, nFixedSize>::operator*() const
{
return *get();
}
template <typename T, size_t nFixedSize>
inline T* pointer<T, nFixedSize>::operator->() const
{
return get();
}
template <typename T, size_t nFixedSize>
inline typename pointer<T, nFixedSize>::element_type& pointer<T, nFixedSize>::operator[](size_t nIndex) const
{
if (nIndex >= size())
{
XIndexOutOfRange exception;
exception.uiIndex = static_cast<uint32_t>(nIndex);
exception.uiSize = static_cast<uint32_t>(size());
throw exception;
}
return get()[nIndex];
}
template <typename T, size_t nFixedSize>
inline pointer<T, nFixedSize>::operator bool() const noexcept
{
// Always true
return true;
}
template <typename T, size_t nFixedSize>
inline size_t pointer<T, nFixedSize>::size() const noexcept
{
return m_uiSize;
}
template <typename T, size_t nFixedSize>
inline void pointer<T, nFixedSize>::resize(size_t nSize)
{
// Replace all deleted elements with the default constructed elements
for (size_t nIndex = nSize; nIndex < std::min(nFixedSize, static_cast<size_t>(m_uiSize)); nIndex++)
{
// Destruct the existing and construct the new
if constexpr (!std::is_scalar_v<T>)
{
m_rgtData[nIndex].~T();
new (m_rgtData + nIndex) T();
}
else
if (nIndex < nFixedSize)
m_rgtData[nIndex] = static_cast<T>(0);
}
if (nSize > nFixedSize)
{
XBufferTooSmall exception;
exception.uiSize = static_cast<uint64_t>(nSize);
exception.uiCapacity = static_cast<uint64_t>(nFixedSize);
throw exception;
}
m_uiSize = static_cast<uint32_t>(nSize);
}
template <typename T, size_t nFixedSize>
inline size_t pointer<T, nFixedSize>::capacity() const noexcept
{
return nFixedSize;
}
template <typename T>
inline pointer<T, 0>::pointer() noexcept
{
// The size of the pointer class should not be larger than the size of a pointer.
static_assert(sizeof(pointer<T>) == sizeof(T*));
// The size of the allocation class should be the size of two pointers and two ints. This is important to ensure that the
// location of each element is exactly the same for every process regardless of compiler and library version.
static_assert(sizeof(SAllocation) == sizeof(internal::IInternalMemAlloc*) + sizeof(T*) + sizeof(uint32_t) * 2);
}
namespace core
{
// Forward declarations
pointer<uint8_t> AllocMemBytes(size_t nAmount);
} // namespace core
namespace internal
{
/**
* @brief Internal memory allocation interface doing the actual allocation. This interface is not exposed publicly and
* should only be used by the memory manager.
*/
interface IInternalMemAlloc
{
/**
* @brief Allocate memory.
* @param[in] nSize The size of the memory to allocate (in bytes).
* @return Pointer to the memory allocation or NULL when memory allocation failed.
*/
virtual void* Alloc(size_t nSize) = 0;
/**
* @brief Reallocate memory.
* @param[in] pData Pointer to a previous allocation or NULL when no previous allocation was available.
* @param[in] nSize The size of the memory to allocate (in bytes).
* @return Pointer to the memory allocation or NULL when memory allocation failed.
*/
virtual void* Realloc(void* pData, size_t nSize) = 0;
/**
* @brief Free a memory allocation.
* @param[in] pData Pointer to a previous allocation.
*/
virtual void Free(void* pData) = 0;
};
} // namespace internal
template <typename T>
inline pointer<T, 0>::pointer(const pointer& rptr)
{
m_psAllocation = rptr.m_psAllocation;
if (m_psAllocation)
m_psAllocation->uiRefCnt++;
}
template <typename T>
template <size_t nFixedSize2>
inline pointer<T, 0>::pointer(const pointer<T, nFixedSize2>& rptr)
{
// Fixed sized buffer; copy the content
resize(rptr.size());
std::copy_n(rptr.get(), rptr.size(), get());
}
template <typename T>
inline pointer<T, 0>::pointer(pointer&& rptr) noexcept
{
m_psAllocation = rptr.m_psAllocation;
rptr.m_psAllocation = nullptr;
}
template <typename T>
template <size_t nFixedSize2>
inline pointer<T, 0>::pointer(const pointer<T, nFixedSize2>&& rptr)
{
// Fixed sized buffer; copy the content and reset supplied pointer
resize(rptr.size());
std::copy_n(rptr.get(), rptr.size(), get());
rptr.reset();
}
template <typename T>
inline pointer<T, 0>::~pointer()
{
try
{
reset();
}
catch (const sdv::XSysExcept&)
{
}
catch (const std::exception&)
{
}
}
template <typename T>
inline pointer<T>& pointer<T, 0>::operator=(const pointer& rptr)
{
// Dynamic buffer, share the allocation
reset();
m_psAllocation = rptr.m_psAllocation;
if (m_psAllocation)
m_psAllocation->uiRefCnt++;
return *this;
}
template <typename T>
template <size_t nFixedSize2>
inline pointer<T>& pointer<T, 0>::operator=(const pointer<T, nFixedSize2>& rptr)
{
// Fixed sized buffer; copy the content
resize(rptr.size());
std::copy_n(rptr.get(), rptr.size(), get());
return *this;
}
template <typename T>
inline pointer<T>& pointer<T, 0>::operator=(pointer<T>&& rptr) noexcept
{
// Dynamic buffer, take over the allocation.
try
{
reset();
}
catch (const sdv::XSysExcept&)
{
}
catch (const std::exception&)
{
}
m_psAllocation = rptr.m_psAllocation;
rptr.m_psAllocation = nullptr;
return *this;
}
template <typename T>
template <size_t nFixedSize2>
inline pointer<T>& pointer<T, 0>::operator=(pointer<T, nFixedSize2>&& rptr)
{
// Fixed sized buffer; copy the content and reset supplied pointer
resize(rptr.size());
std::copy_n(rptr.get(), rptr.size(), get());
rptr.reset();
return *this;
}
template <typename T>
inline void pointer<T, 0>::attach(pointer<uint8_t>&& rptrBuffer)
{
// Move buffer pointer (structures are identical).
operator=(std::move(*reinterpret_cast<pointer<T>*>(&rptrBuffer)));
}
template <typename T>
inline pointer<uint8_t>&& pointer<T, 0>::detach()
{
// Move this pointer (structures are identical).
return std::move(*reinterpret_cast<pointer<uint8_t>*>(this));
}
template <typename T>
inline void pointer<T, 0>::reset()
{
// Reduce allocation sharing reference counter. If 0, no more share; delete allocation.
if (!m_psAllocation) return;
if (!m_psAllocation->pAllocator) throw core::XNoMemMgr();
if (!m_psAllocation->uiRefCnt)
{
XInvalidRefCount exception;
exception.uiCount = 0;
throw exception;
}
if (!--m_psAllocation->uiRefCnt)
{
// Call the destructor on all elements
if constexpr (!std::is_scalar_v<T>)
{
for (size_t nIndex = 0; m_psAllocation->pData && nIndex < m_psAllocation->uiSize / sizeof(T); nIndex++)
m_psAllocation->pData[nIndex].~T();
}
// Delete the data
if (m_psAllocation->pData)
m_psAllocation->pAllocator->Free(m_psAllocation->pData);
// Delete the allocation structure
delete m_psAllocation;
}
m_psAllocation = nullptr;
}
template <typename T>
template <size_t nFixedSizeRight>
inline void pointer<T, 0>::swap(pointer<T, nFixedSizeRight>& rptr)
{
if constexpr (nFixedSizeRight != 0)
{
// Fixed sized buffer; copy the content
// Copy the provided content into a temporary buffer.
T rgtTemp[nFixedSizeRight];
size_t nSizeRight = rptr.size();
std::copy_n(rptr.get(), nSizeRight, rgtTemp);
// Copy the member buffer into the buffer of the provided pointer
rptr.resize(size());
std::copy_n(get(), size(), rptr.get());
// Copy the temporary buffer into this class' buffer.
resize(nSizeRight);
std::copy_n(rgtTemp, nSizeRight, get());
}
else
{
// Dynamic sized buffer; exchange the pointer
SAllocation* pTemp = m_psAllocation;
m_psAllocation = rptr.m_psAllocation;
rptr.m_psAllocation = pTemp;
}
}
template <typename T>
inline typename pointer<T, 0>::element_type* pointer<T, 0>::get() const noexcept
{
return m_psAllocation ? m_psAllocation->pData : nullptr;
}
template <typename T>
inline T& pointer<T, 0>::operator*() const
{
if (!m_psAllocation) throw XNullPointer();
return *get();
}
template <typename T>
inline T* pointer<T, 0>::operator->() const
{
if (!m_psAllocation) throw XNullPointer();
return get();
}
template <typename T>
inline typename pointer<T, 0>::element_type& pointer<T, 0>::operator[](size_t nIndex) const
{
if (!m_psAllocation) throw XNullPointer();
if (nIndex >= size())
{
XIndexOutOfRange exception;
exception.uiIndex = static_cast<uint32_t>(nIndex);
exception.uiSize = static_cast<uint32_t>(size());
throw exception;
}
return get()[nIndex];
}
template <typename T>
inline pointer<T, 0>::operator bool() const noexcept
{
return m_psAllocation && m_psAllocation->pData;
}
template <typename T>
inline size_t pointer<T, 0>::size() const noexcept
{
return m_psAllocation ? m_psAllocation->uiSize / sizeof(T) : 0;
}
template <typename T>
inline void pointer<T, 0>::resize(size_t nSize)
{
if (!m_psAllocation || !m_psAllocation->pAllocator || !m_psAllocation->pData)
{
operator=(std::move(make_ptr<T>(nSize)));
return;
}
size_t nTotalSize = nSize * sizeof(T);
// Is the new size smaller than the old size, call the destructors for the deleted
if (nSize < m_psAllocation->uiSize / sizeof(T))
{
if constexpr (!std::is_scalar_v<T>)
{
for (size_t nIndex = nSize; nIndex < m_psAllocation->uiSize / sizeof(T); nIndex++)
m_psAllocation->pData[nIndex].~T();
}
// Since the destructors are called; update the size info already.
m_psAllocation->uiSize = static_cast<uint32_t>(nSize * sizeof(T));
}
// Treat reallocation differently between objects and scalars. Objects might have pointers and therefore need to be
// copied. Scalars can be reallocated without reinitialization.
T* ptAllocation = nullptr;
if constexpr (std::is_scalar_v<T>)
{
ptAllocation = reinterpret_cast<T*>(m_psAllocation->pAllocator->Realloc(m_psAllocation->pData, nTotalSize));
if (nTotalSize && !ptAllocation)
{
core::XAllocFailed exception;
exception.uiSize = static_cast<uint32_t>(nTotalSize);
throw exception;
}
// Is the new size larger than the old size, call the constructors for the new elements
for (size_t nIndex = m_psAllocation->uiSize / sizeof(T); nIndex < nSize; nIndex++)
ptAllocation[nIndex] = static_cast<T>(0);
}
else
{
// Allocate new size
ptAllocation = reinterpret_cast<T*>(m_psAllocation->pAllocator->Alloc(nTotalSize));
if (nTotalSize && !ptAllocation)
{
core::XAllocFailed exception;
exception.uiSize = static_cast<uint32_t>(nTotalSize);
throw exception;
}
// Move the elements from the existing allocation to the new allocation.
for (size_t nIndex = 0; nIndex < std::min(static_cast<size_t>(m_psAllocation->uiSize / sizeof(T)), nSize); nIndex++)
new (ptAllocation + nIndex) T(std::move(m_psAllocation->pData[nIndex]));
// Is the new size larger than the old size, call the constructors for the new elements
for (size_t nIndex = m_psAllocation->uiSize / sizeof(T); nIndex < nSize; nIndex++)
new (ptAllocation + nIndex) T();
// Free the old data.
if (m_psAllocation->pData) m_psAllocation->pAllocator->Free(m_psAllocation->pData);
}
// Set new information
m_psAllocation->pData = ptAllocation;
m_psAllocation->uiSize = static_cast<uint32_t>(nSize * sizeof(T));
}
template <typename T>
inline size_t pointer<T, 0>::capacity() const noexcept
{
return m_psAllocation ? m_psAllocation->uiSize / sizeof(T) : 0;
}
template <typename T>
inline size_t pointer<T, 0>::ref_count() const noexcept
{
return m_psAllocation ? static_cast<size_t>(m_psAllocation->uiRefCnt) : 0;
}
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
inline void swap(pointer<T, nFixedSizeLeft>& rptrLeft, pointer<T, nFixedSizeRight>& rptrRight)
{
rptrLeft.swap(rptrRight);
}
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
inline bool operator==(const pointer<T, nFixedSizeLeft>& rptrLeft, const pointer<T, nFixedSizeRight>& rptrRight) noexcept
{
if constexpr (nFixedSizeLeft || nFixedSizeRight) // Compare content
{
// Prevent comparing NULL-pointer.
if (rptrLeft.get() == rptrRight.get()) return true; // Pointers are identical; comparing same object.
if (!rptrLeft.size() && !rptrRight.size()) return true; // Both pointers are empty.
if (rptrLeft.get() && !rptrRight.get()) return false; // Right is NULL; left not.
if (!rptrLeft.get() && rptrRight.get()) return false; // Left is NULL; right not.
return std::equal(rptrLeft.get(), rptrLeft.get() + rptrLeft.size(),
rptrRight.get(), rptrRight.get() + rptrRight.size());
} else // Compare pointers
return rptrLeft.get() == rptrRight.get();
}
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
inline bool operator!=(const pointer<T, nFixedSizeLeft>& rptrLeft, const pointer<T, nFixedSizeRight>& rptrRight) noexcept
{
return !operator==(rptrLeft, rptrRight);
}
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
inline bool operator<(const pointer<T, nFixedSizeLeft>& rptrLeft, const pointer<T, nFixedSizeRight>& rptrRight) noexcept
{
if constexpr (nFixedSizeLeft || nFixedSizeRight) // Compare content
return std::lexicographical_compare(rptrLeft.get(), rptrLeft.get() + rptrLeft.size(),
rptrRight.get(), rptrRight.get() + rptrRight.size());
else // Compare pointers
return rptrLeft.get() < rptrRight.get();
}
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
inline bool operator<=(const pointer<T, nFixedSizeLeft>& rptrLeft, const pointer<T, nFixedSizeRight>& rptrRight) noexcept
{
if constexpr (nFixedSizeLeft || nFixedSizeRight) // Compare content
return !std::lexicographical_compare(rptrRight.get(), rptrRight.get() + rptrRight.size(),
rptrLeft.get(), rptrLeft.get() + rptrLeft.size());
else // Compare pointers
return rptrLeft.get() <= rptrRight.get();
}
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
inline bool operator>(const pointer<T, nFixedSizeLeft>& rptrLeft, const pointer<T, nFixedSizeRight>& rptrRight) noexcept
{
if constexpr (nFixedSizeLeft || nFixedSizeRight) // Compare content
return std::lexicographical_compare(rptrRight.get(), rptrRight.get() + rptrRight.size(),
rptrLeft.get(), rptrLeft.get() + rptrLeft.size());
else // Compare pointers
return rptrLeft.get() > rptrRight.get();
}
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
inline bool operator>=(const pointer<T, nFixedSizeLeft>& rptrLeft, const pointer<T, nFixedSizeRight>& rptrRight) noexcept
{
if constexpr (nFixedSizeLeft || nFixedSizeRight) // Compare content
return !std::lexicographical_compare(rptrLeft.get(), rptrLeft.get() + rptrLeft.size(),
rptrRight.get(), rptrRight.get() + rptrRight.size());
else // Compare pointers
return rptrLeft.get() >= rptrRight.get();
}
template <class T, size_t nFixedSizeLeft>
inline bool operator==(const pointer<T, nFixedSizeLeft>& rptrLeft, std::nullptr_t) noexcept
{
return rptrLeft.get() == nullptr;
}
template <class T, size_t nFixedSizeRight>
inline bool operator==(std::nullptr_t, const pointer<T, nFixedSizeRight>& rptrRight) noexcept
{
return nullptr == rptrRight.get();
}
template <class T, size_t nFixedSizeLeft>
inline bool operator!=(const pointer<T, nFixedSizeLeft>& rptrLeft, std::nullptr_t) noexcept
{
return rptrLeft.get() != nullptr;
}
template <class T, size_t nFixedSizeRight>
inline bool operator!=(std::nullptr_t, const pointer<T, nFixedSizeRight>& rptrRight) noexcept
{
return nullptr != rptrRight.get();
}
template <class T, size_t nFixedSizeLeft>
inline bool operator<(const pointer<T, nFixedSizeLeft>& /*rptrLeft*/, std::nullptr_t) noexcept
{
return false;
}
template <class T, size_t nFixedSizeRight>
inline bool operator<(std::nullptr_t, const pointer<T, nFixedSizeRight>& rptrRight) noexcept
{
return nullptr != rptrRight.get();
}
template <class T, size_t nFixedSizeLeft>
inline bool operator<=(const pointer<T, nFixedSizeLeft>& rptrLeft, std::nullptr_t) noexcept
{
return rptrLeft.get() == nullptr;
}
template <class T, size_t nFixedSizeRight>
inline bool operator<=(std::nullptr_t, const pointer<T, nFixedSizeRight>& /*rptrRight*/) noexcept
{
return true;
}
template <class T, size_t nFixedSizeLeft>
inline bool operator>(const pointer<T, nFixedSizeLeft>& rptrLeft, std::nullptr_t) noexcept
{
return rptrLeft.get() != nullptr;
}
template <class T, size_t nFixedSizeRight>
inline bool operator>(std::nullptr_t, const pointer<T, nFixedSizeRight>& /*rptrRight*/) noexcept
{
return false;
}
template <class T, size_t nFixedSizeLeft>
inline bool operator>=(const pointer<T, nFixedSizeLeft>& /*rptrLeft*/, std::nullptr_t) noexcept
{
return true;
}
template <class T, size_t nFixedSizeRight>
inline bool operator>=(std::nullptr_t, const pointer<T, nFixedSizeRight>& rptrRight) noexcept
{
return nullptr == rptrRight.get();
}
template <class T, class U, class V, size_t nFixedSize>
inline std::basic_ostream<U, V>& operator<<(std::basic_ostream<U, V>& rstream, const pointer<T, nFixedSize>& rptr)
{
for (size_t nIndex = 0; nIndex < rptr.size(); nIndex++)
rstream << rptr[nIndex];
return rstream;
}
template <typename T>
inline pointer<T> make_ptr(size_t nSize /*= 1*/)
{
pointer<uint8_t> ptrBuffer = core::AllocMemBytes(nSize * sizeof(T));
T* pT = reinterpret_cast<T*>(ptrBuffer.get());
for (size_t nIndex = 0; nIndex < nSize; nIndex++)
new (pT + nIndex) T();
pointer<T> ptr;
ptr.attach(std::move(ptrBuffer));
return ptr;
}
namespace internal
{
/**
* @brief Create a pointer class using the allocator and allocating the memory with the given size.
* @tparam T Type to use for the allocation.
* @param[in] pAllocator Pointer to the allocator. Must not be NULL.
* @param[in] nSize Size to allocate (in elements).
* @return The pointer class.
*/
template <typename T>
inline pointer<T> make_ptr(internal::IInternalMemAlloc* pAllocator, size_t nSize /*= 1*/)
{
pointer<T> pointer;
if (!pAllocator) throw core::XNoMemMgr();
size_t nTotalSize = nSize * sizeof(T);
// Create a new allocation structure
using SAllocation = std::remove_pointer_t<decltype(pointer.m_psAllocation)>;
pointer.m_psAllocation = new SAllocation;
if (!pointer.m_psAllocation)
{
core::XAllocFailed exception;
exception.uiSize = static_cast<uint32_t>(sizeof(SAllocation));
throw exception;
}
pointer.m_psAllocation->pAllocator = pAllocator;
// Allocate the amount of elements
pointer.m_psAllocation->pData = reinterpret_cast<T*>(pAllocator->Alloc(nTotalSize));
if (!pointer.m_psAllocation->pData)
{
core::XAllocFailed exception;
exception.uiSize = static_cast<uint32_t>(nTotalSize);
throw exception;
}
// Call the constructors for each memory allocation
if constexpr (std::is_scalar_v<T>)
std::fill(pointer.m_psAllocation->pData, pointer.m_psAllocation->pData + nSize, static_cast<T>(0));
else
{
for (size_t nIndex = 0; nIndex < nSize; nIndex++)
new (pointer.m_psAllocation->pData + nIndex) T();
}
// Fill in allocation details
pointer.m_psAllocation->uiSize = static_cast<uint32_t>(nSize * sizeof(T));
pointer.m_psAllocation->uiRefCnt = 1;
return pointer;
}
} // namespace internal
template <typename TTraits /*= std::char_traits<char>*/>
inline pointer<uint8_t> from_stream(std::basic_streambuf<char, TTraits>* pStreamBuf)
{
if (!pStreamBuf) throw sdv::XNullPointer();
// Determine the size of the buffer.
std::streampos current_pos = pStreamBuf->pubseekoff(0, std::ios::cur, std::ios::in);
std::streampos end_pos = pStreamBuf->pubseekoff(0, std::ios::end, std::ios::in);
pStreamBuf->pubseekpos(current_pos, std::ios::in);
// Allocate the buffer
pointer<uint8_t, 0> ptr;
ptr.resize(end_pos);
// Fill the buffer
size_t nPos = 0;
while (true)
{
auto nAvail = pStreamBuf->in_avail();
if (nAvail)
{
if (ptr.size() < nPos + nAvail)
ptr.resize(nPos + nAvail);
pStreamBuf->sgetn(reinterpret_cast<char*>(ptr.get() + nPos), nAvail);
nPos += nAvail;
}
else
{
auto nVal = pStreamBuf->sbumpc();
if (nVal == TTraits::eof()) break;
else
{
if (ptr.size() < nPos + 1)
ptr.resize(nPos + 1);
ptr[nPos] = static_cast<uint8_t>(nVal);
nPos++;
}
}
}
// Resize needed?
if (nPos != ptr.size())
ptr.resize(nPos);
return ptr;
}
template <typename TTraits /*= std::char_traits<char>*/>
inline void to_stream(const pointer<uint8_t>& rptr, std::basic_streambuf<char, TTraits>* pStreamBuf)
{
if (!pStreamBuf) throw sdv::XNullPointer();
if (rptr.size())
pStreamBuf->sputn(reinterpret_cast<const char*>(rptr.get()), rptr.size());
}
template <typename T>
inline T* cast(pointer<uint8_t>& rptr, size_t nOffset /*= 0*/)
{
if (nOffset + sizeof(T) > rptr.size()) return nullptr;
return reinterpret_cast<T*>(rptr.get() + nOffset);
}
template <typename T>
inline const T* cast(const pointer<uint8_t>& rptr, size_t nOffset /*= 0*/)
{
if (nOffset + sizeof(T) > rptr.size()) return nullptr;
return reinterpret_cast<const T*>(rptr.get() + nOffset);
}
} // namespace sdv
/// @endcond
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#endif // !defined SDV_PTR_INL

464
export/support/pssup.h Normal file
View File

@@ -0,0 +1,464 @@
#ifndef SDV_PS_SUPPORT_H
#define SDV_PS_SUPPORT_H
#include "../interfaces/core_ps.h"
#include "../interfaces/serdes/core_ps_serdes.h"
#include "../interfaces/serdes/core_types_serdes.h"
/**
* @brief Compare two marshall IDs.
* @param[in] rtID1 Reference to the first ID.
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the first ID is identical to the second ID.
*/
bool operator==(const sdv::ps::TMarshallID& rtID1, const sdv::ps::TMarshallID& rtID2);
/**
* @brief Compare the marshall ID with zero.
* @param[in] rtID1 Reference to the first ID.
* @param[in] nVal The value to use for comparison (only 0 is allowed).
* @return Returns whether the ID is zero.
*/
bool operator==(const sdv::ps::TMarshallID& rtID1, size_t nVal);
/**
* @brief Compare the marshall ID with zero.
* @param[in] nVal The value to use for comparison (only 0 is allowed).
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the ID is zero.
*/
bool operator==(size_t nVal, const sdv::ps::TMarshallID& rtID2);
/**
* @brief Compare two marshall IDs.
* @param[in] rtID1 Reference to the first ID.
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the first ID is different from the second ID.
*/
bool operator!=(const sdv::ps::TMarshallID& rtID1, const sdv::ps::TMarshallID& rtID2);
/**
* @brief Compare the marshall ID with zero.
* @param[in] rtID1 Reference to the first ID.
* @param[in] nVal The value to use for comparison (only 0 is allowed).
* @return Returns whether the ID is not zero.
*/
bool operator!=(const sdv::ps::TMarshallID& rtID1, size_t nVal);
/**
* @brief Compare the marshall ID with zero.
* @param[in] nVal The value to use for comparison (only 0 is allowed).
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the ID is not zero.
*/
bool operator!=(size_t nVal, const sdv::ps::TMarshallID& rtID2);
/**
* @brief Compare two marshall IDs.
* @param[in] rtID1 Reference to the first ID.
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the first ID is smaller than the second ID.
*/
bool operator<(const sdv::ps::TMarshallID& rtID1, const sdv::ps::TMarshallID& rtID2);
/**
* @brief Compare two marshall IDs.
* @param[in] rtID1 Reference to the first ID.
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the first ID is smaller or equal the than second ID.
*/
bool operator<=(const sdv::ps::TMarshallID& rtID1, const sdv::ps::TMarshallID& rtID2);
/**
* @brief Compare two marshall IDs.
* @param[in] rtID1 Reference to the first ID.
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the first ID is larger than the second ID.
*/
bool operator>(const sdv::ps::TMarshallID& rtID1, const sdv::ps::TMarshallID& rtID2);
/**
* @brief Compare two marshall IDs.
* @param[in] rtID1 Reference to the first ID.
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the first ID is larger or equal than the second ID.
*/
bool operator>=(const sdv::ps::TMarshallID& rtID1, const sdv::ps::TMarshallID& rtID2);
/**
* @brief Check for validity of the marshall ID.
* @param[in] rtID Reference to the ID.
* @return Returns whether the ID is valid.
*/
bool operator!(const sdv::ps::TMarshallID& rtID);
#ifndef DOXYGEN_IGNORE
/**
* @brief Specialization of std::less for sdv::ps::TMarshallID.
*/
template <>
struct std::less<sdv::ps::TMarshallID>
{
/// The result type
using result_type = bool;
/// The first argument type.
using first_argument_type = sdv::ps::TMarshallID;
/// The second argument type.
using second_argument_type = sdv::ps::TMarshallID;
/**
* @brief Compare ID1 < ID2.
* @param[in] rtID1 Reference to the first ID.
* @param[in] rtID2 Reference to the second ID.
* @return Result of the comparison.
*/
bool operator()(const sdv::ps::TMarshallID& rtID1, const sdv::ps::TMarshallID& rtID2) const { return ::operator<(rtID1, rtID2); }
};
#endif // !defined DOXYGEN_IGNORE
/**
* @brief Compare two connection IDs.
* @param[in] rtID1 Reference to the first ID.
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the first ID is identical to the second ID.
*/
bool operator==(const sdv::com::TConnectionID& rtID1, const sdv::com::TConnectionID& rtID2);
/**
* @brief Compare the connection ID with zero.
* @param[in] rtID1 Reference to the first ID.
* @param[in] nVal The value to use for comparison (only 0 is allowed).
* @return Returns whether the ID is zero.
*/
bool operator==(const sdv::com::TConnectionID& rtID1, size_t nVal);
/**
* @brief Compare the connection ID with zero.
* @param[in] nVal The value to use for comparison (only 0 is allowed).
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the ID is zero.
*/
bool operator==(size_t nVal, const sdv::com::TConnectionID& rtID2);
/**
* @brief Compare two connection IDs.
* @param[in] rtID1 Reference to the first ID.
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the first ID is different from the second ID.
*/
bool operator!=(const sdv::com::TConnectionID& rtID1, const sdv::com::TConnectionID& rtID2);
/**
* @brief Compare the connection ID with zero.
* @param[in] rtID1 Reference to the first ID.
* @param[in] nVal The value to use for comparison (only 0 is allowed).
* @return Returns whether the ID is not zero.
*/
bool operator!=(const sdv::com::TConnectionID& rtID1, size_t nVal);
/**
* @brief Compare the connection ID with zero.
* @param[in] nVal The value to use for comparison (only 0 is allowed).
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the ID is not zero.
*/
bool operator!=(size_t nVal, const sdv::com::TConnectionID& rtID2);
/**
* @brief Compare two connection IDs.
* @param[in] rtID1 Reference to the first ID.
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the first ID is smaller than the second ID.
*/
bool operator<(const sdv::com::TConnectionID& rtID1, const sdv::com::TConnectionID& rtID2);
/**
* @brief Compare two connection IDs.
* @param[in] rtID1 Reference to the first ID.
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the first ID is smaller or equal the than second ID.
*/
bool operator<=(const sdv::com::TConnectionID& rtID1, const sdv::com::TConnectionID& rtID2);
/**
* @brief Compare two connection IDs.
* @param[in] rtID1 Reference to the first ID.
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the first ID is larger than the second ID.
*/
bool operator>(const sdv::com::TConnectionID& rtID1, const sdv::com::TConnectionID& rtID2);
/**
* @brief Compare two connection IDs.
* @param[in] rtID1 Reference to the first ID.
* @param[in] rtID2 Reference to the second ID.
* @return Returns whether the first ID is larger or equal than the second ID.
*/
bool operator>=(const sdv::com::TConnectionID& rtID1, const sdv::com::TConnectionID& rtID2);
/**
* @brief Check for validity of the connection ID.
* @param[in] rtID Reference to the ID.
* @return Returns whether the ID is valid.
*/
bool operator!(const sdv::com::TConnectionID& rtID);
#ifndef DOXYGEN_IGNORE
/**
* @brief Specialization of std::less for sdv::com::TConnectionID.
*/
template <>
struct std::less<sdv::com::TConnectionID>
{
/// The result type
using result_type = bool;
/// The first argument type.
using first_argument_type = sdv::com::TConnectionID;
/// The second argument type.
using second_argument_type = sdv::com::TConnectionID;
/**
* @brief Compare ID1 < ID2.
* @param[in] rtID1 Reference to the first ID.
* @param[in] rtID2 Reference to the second ID.
* @return Result of the comparison.
*/
bool operator()(const sdv::com::TConnectionID& rtID1, const sdv::com::TConnectionID& rtID2) const { return ::operator<(rtID1, rtID2); }
};
#endif // !defined DOXYGEN_IGNORE
#include "sequence.h"
#include "pointer.h"
#include "crc.h"
#include "component_impl.h"
#include <cassert>
#include <thread>
#include <condition_variable>
#include <map>
#include <functional>
#include <chrono>
#include <queue>
namespace sdv
{
namespace ps
{
/**
* Local SMarshall structure to handle specific CRC calculations
*/
struct SMarshallLocal : SMarshall
{};
/**
* @brief Bypass class available during a function call. This class uses thread local storage to allow the storage of
* raw data bypassing the serialization.
*/
class CRawDataBypass
{
public:
/**
* @brief Constructor
*/
CRawDataBypass();
/**
* @brief Add raw data to the raw data queue.
* @param[in] rptrData Reference to the smart pointer holding the data.
*/
void push(const pointer<uint8_t>& rptrData);
/**
* @brief Prop the data from the raw data queue.
* @return The data to pop.
*/
pointer<uint8_t> pop();
/**
* @brief Is the raw data queue empty?
* @return Returns whether the queue is empty.
*/
bool empty() const;
/**
* @brief Clear the raw data queue.
*/
void clear();
private:
std::queue<pointer<uint8_t>> m_queueBypassData; ///< Additional buffers not being serialized.
};
/**
* @brief Global access function for the raw data bypass.
* @return Reference to the bypass.
*/
CRawDataBypass& GetRawDataBypass();
/**
* @brief Result enumeration of the call function.
*/
enum class ECallResult : uint32_t
{
result_ok = 0, ///< Normal processing. The return buffer contains the return values.
result_exception = 1, ///< Exception occurred. The return buffer contains the serialized exception.
};
/**
* @brief Proxy class managing the function calls and incoming calls containing the response.
* @tparam TInterface The interface the deriving class is deriving from as well.
*/
template <typename TInterface>
class CProxyHandler : public sdv::CSdvObject, public IMarshallObjectIdent, public IMarshallLink
{
public:
// Ensure that the EEndian structure is 8 bits (to prevent byte swapping during detection).
static_assert(sizeof(EEndian) == 1);
/**
* @brief Constructor
*/
CProxyHandler();
/**
* @brief Constructor
*/
virtual ~CProxyHandler() override;
// Interface map
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_CHAIN_BASE(sdv::CSdvObject)
SDV_INTERFACE_ENTRY(IMarshallObjectIdent)
SDV_INTERFACE_ENTRY(IMarshallLink)
END_SDV_INTERFACE_MAP()
// Object class type
DECLARE_OBJECT_CLASS_TYPE(sdv::EObjectType::Proxy)
/**
* @brief Set the identification. Overload of IMarshallObjectIdent::SetIdentification.
* @param[in] tMarshallID Reference to the marshall object ID. For a proxy object, this is the proxy ID. For a stub object
* this is a stub ID.
*/
virtual void SetIdentification(/*in*/ const TMarshallID& tMarshallID) override;
/**
* @brief Link the communication interface to the object. Overload of IMarshallLink::Link.
* @remarks Only one link can exists at the time.
* @param[in] pMarshall Interface to be linked.
*/
virtual void Link(/*in*/ IMarshall* pMarshall) override;
/**
* @brief Unlink the linked interface. Overload of IMarshallLink::Unlink.
*/
virtual void Unlink() override;
/**
* @brief Schedule a call.
* @param[in] uiFuncIndex Operation/attribute index.
* @param[in] rserInput Serializer containing the input parameters.
* @param[in] rdesOutput Deserializer containing the return value and output parameters or the exception.
* @return The call result value.
*/
ECallResult DoCall(uint32_t uiFuncIndex, const serializer<GetPlatformEndianess()>& rserInput,
deserializer<GetPlatformEndianess()>& rdesOutput);
private:
IMarshall* m_pRequest = nullptr; ///< Marshall interface for call requests.
TMarshallID m_tProxyID = {}; ///< Proxy handler ID.
TMarshallID m_tStubID = {}; ///< Stub handler ID.
};
/**
* @brief Stub class managing incoming calls containing the request and dispatching them to the functions.
* @tparam TInterface The interface this stub is dispatching to.
*/
template <typename TInterface>
class CStubHandler : public sdv::CSdvObject, public IMarshallObjectIdent, public IMarshall
{
// Ensure that the EEndian structure is 8 bits (to prevent byte swapping during detection).
static_assert(sizeof(EEndian) == 1);
public:
/**
* @brief Constructor
*/
CStubHandler();
/**
* @brief Destructor
*/
virtual ~CStubHandler() override;
// Interface map
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_CHAIN_BASE(sdv::CSdvObject)
SDV_INTERFACE_ENTRY(IMarshallObjectIdent)
SDV_INTERFACE_ENTRY(IMarshall)
END_SDV_INTERFACE_MAP()
// Object class type
DECLARE_OBJECT_CLASS_TYPE(sdv::EObjectType::Stub)
protected:
/**
* @brief Dispatch function type. Function arguments are endianness, input parameters and output
* parameters/return value/exception information. Function returns the dispact result.
*/
typedef std::function<ECallResult(EEndian, const pointer<uint8_t>&, pointer<uint8_t>&)> FNDispatch;
/**
* @brief Register dispatch function.
* @remarks This dispatch functions must be registered in the correct order.
* @attention Registering dispatch functions should happen during construction. No protection of the vector is
* available during data dispatching.
* @param[in] fnDispatch Dispatch function to call for this interface.
*/
void RegisterDispatchFunc(FNDispatch fnDispatch);
/**
* @brief Serialize exception helper function.
* @tparam TExcept The exception type to serialize.
* @param[in] eEndian The endianness of the serialization.
* @param[in] rexcept Reference to the exception.
* @return The serialized exception.
*/
template <typename TExcept>
pointer<uint8_t> SerializeException(EEndian eEndian, const TExcept& rexcept);
/**
* @brief Set the identification. Overload of IMarshallObjectIdent::SetIdentification.
* @param[in] tMarshallID Reference to The marshall object ID. For a proxy object, this is the proxy ID. For a stub object
* this is a stub ID.
*/
virtual void SetIdentification(/*in*/ const TMarshallID& tMarshallID) override;
/**
* @brief Marshall a function call. Overload of IMarshall::Call.
* @remarks This function call is synchronous and does not return until the call has been finalized or a timeout
* exception has occurred.
* @remarks The sequence contains all data to make the call. It is important that the data in the sequence is
* complete and in the correct order.
* @param[inout] seqInputData Reference to sequence of input data pointers. The first data pointer contains the
* marshalling header. The second contains the parameters (if available) and the others contain raw data pointers
* (if available). The call is allowed to change the sequence to be able to add additional information during the
* communication without having to copy the existing data.
* @return Sequence of output data pointers. The first data pointer contains the marshalling header. The second
* contains the return value and parameters (if available) and the others contain raw data pointers (if available).
*/
virtual sequence<pointer<uint8_t>> Call(/*inout*/ sequence<pointer<uint8_t>>& seqInputData) override;
private:
std::vector<FNDispatch> m_vecDispatch; ///< Vector containing the dispatch functions.
TMarshallID m_tStubID{}; ///< Stub handler ID.
};
} // namespace ps
} // namespace sdv
#include "pssup.inl"
#endif // !defined(SDV_PS_SUPPORT_H)

999
export/support/pssup.inl Normal file
View File

@@ -0,0 +1,999 @@
#ifndef SDV_PS_SUPPORT_INL
#define SDV_PS_SUPPORT_INL
#ifndef SDV_PS_SUPPORT_H
#error Do not include "pssup.inl" directly. Include "pssup.h" instead!
#endif //!defined SDV_PS_SUPPORT_H
#include "../interfaces/core_ps.h"
#include "../interfaces/serdes/core_ps_serdes.h"
#include "../interfaces/serdes/core_types_serdes.h"
#include "sequence.h"
#include "pointer.h"
#include "crc.h"
#include "component_impl.h"
#include <cassert>
#include <thread>
#include <condition_variable>
#include <map>
#include <functional>
#include <chrono>
#include <queue>
namespace serdes
{
/**
* @brief Specialization of serializer/deserializer class for sdv::interface_t.
*/
template <>
class CSerdes<sdv::interface_t>
{
public:
/**
* @brief Calculate the size of the value in serialized form.
* @remarks Dependable on the size value, padding is added to align data.
* @param[in] rifc Reference to the interface variable.
* @param[in, out] rnSize Reference to the variable containing the current size and increased by the size of the value.
*/
static void CalcSize(const sdv::interface_t& rifc, size_t& rnSize)
{
sdv::ser_size(rifc.id(), rnSize);
sdv::ser_size(sdv::ps::TMarshallID(), rnSize);
}
/**
* @brief Stream the variable into the serializer.
* @tparam eTargetEndianess The target endianess detemines whether to swap the bytes before storing them into the buffer.
* @param[in] rSerializer Reference to the serializer.
* @param[in] rifc Reference to the variable.
* @return Reference to the serializer.
*/
template <sdv::EEndian eTargetEndianess>
static sdv::serializer<eTargetEndianess>& Serialize(sdv::serializer<eTargetEndianess>& rSerializer,
const sdv::interface_t& rifc)
{
// Get interface to the component isolation service.
auto ptrComControl = sdv::core::GetObject("CommunicationControl");
if (!ptrComControl) throw sdv::ps::XMarshallNotInitialized{};
sdv::ps::IMarshallAccess* pMarshallAccess = ptrComControl.GetInterface<sdv::ps::IMarshallAccess>();
if (!pMarshallAccess) throw sdv::ps::XMarshallNotInitialized{};
// Serialize the interface ID first
rSerializer << rifc.id();
// Create and serialize a stub object for the interface.
sdv::ps::TMarshallID tStubID = pMarshallAccess->GetStub(rifc);
rSerializer << tStubID;
return rSerializer;
}
/**
* @brief Stream a variable from the deserializer.
* @tparam eSourceEndianess The target endianess detemines whether to swap the bytes before storing them into the buffer.
* @param[in] rDeserializer Reference to the deserializer.
* @param[out] rifc Reference to the variable to be filled.
* @return Reference to the deserializer.
*/
template <sdv::EEndian eSourceEndianess>
static sdv::deserializer<eSourceEndianess>& Deserialize(sdv::deserializer<eSourceEndianess>& rDeserializer,
sdv::interface_t& rifc)
{
// Get interface to the component isolation service.
auto ptrComControl = sdv::core::GetObject("CommunicationControl");
if (!ptrComControl) throw sdv::ps::XMarshallNotInitialized{};
sdv::ps::IMarshallAccess* pMarshallAccess = ptrComControl.GetInterface<sdv::ps::IMarshallAccess>();
if (!pMarshallAccess) throw sdv::ps::XMarshallNotInitialized{};
// Get the interface ID
sdv::interface_id id = 0;
rDeserializer >> id;
// Get the stub ID
sdv::ps::TMarshallID tStubID{};
rDeserializer >> tStubID;
// Create the proxy
if (!tStubID && !id) // In case the ID is zero, an NULL interface was sent.
rifc = {};
else
rifc = pMarshallAccess->GetProxy(tStubID, id);
return rDeserializer;
}
};
/**
* @brief Specialization of serializer/deserializer class for sdv::any_t.
*/
template <>
class CSerdes<sdv::any_t>
{
public:
/**
* @brief Calculate the size of the value in serialized form.
* @remarks Dependable on the size value, padding is added to align data.
* @param[in] rany Reference to the variable.
* @param[in, out] rnSize Reference to the variable containing the current size and increased by the size of the value.
*/
static void CalcSize(const sdv::any_t& rany, size_t& rnSize)
{
// The size of the type
sdv::ser_size(rany.eValType, rnSize);
// Added with the size of the variable.
switch (rany.eValType)
{
case sdv::any_t::EValType::val_type_bool: sdv::ser_size(rany.bVal, rnSize); break;
case sdv::any_t::EValType::val_type_int8: sdv::ser_size(rany.i8Val, rnSize); break;
case sdv::any_t::EValType::val_type_uint8: sdv::ser_size(rany.ui8Val, rnSize); break;
case sdv::any_t::EValType::val_type_int16: sdv::ser_size(rany.i16Val, rnSize); break;
case sdv::any_t::EValType::val_type_uint16: sdv::ser_size(rany.ui16Val, rnSize); break;
case sdv::any_t::EValType::val_type_int32: sdv::ser_size(rany.i32Val, rnSize); break;
case sdv::any_t::EValType::val_type_uint32: sdv::ser_size(rany.ui32Val, rnSize); break;
case sdv::any_t::EValType::val_type_int64: sdv::ser_size(rany.i64Val, rnSize); break;
case sdv::any_t::EValType::val_type_uint64: sdv::ser_size(rany.ui64Val, rnSize); break;
case sdv::any_t::EValType::val_type_char: sdv::ser_size(rany.cVal, rnSize); break;
case sdv::any_t::EValType::val_type_char16: sdv::ser_size(rany.c16Val, rnSize); break;
case sdv::any_t::EValType::val_type_char32: sdv::ser_size(rany.c32Val, rnSize); break;
case sdv::any_t::EValType::val_type_wchar: sdv::ser_size(rany.cwVal, rnSize); break;
case sdv::any_t::EValType::val_type_float: sdv::ser_size(rany.fVal, rnSize); break;
case sdv::any_t::EValType::val_type_double: sdv::ser_size(rany.dVal, rnSize); break;
case sdv::any_t::EValType::val_type_long_double: sdv::ser_size(rany.ldVal, rnSize); break;
//case sdv::any_t::EValType::val_type_fixed: sdv::ser_size(rany.fixVal, rnSize); break;
case sdv::any_t::EValType::val_type_string: sdv::ser_size(rany.ssVal, rnSize); break;
case sdv::any_t::EValType::val_type_u8string: sdv::ser_size(rany.ss8Val, rnSize); break;
case sdv::any_t::EValType::val_type_u16string: sdv::ser_size(rany.ss16Val, rnSize); break;
case sdv::any_t::EValType::val_type_u32string: sdv::ser_size(rany.ss32Val, rnSize); break;
case sdv::any_t::EValType::val_type_wstring: sdv::ser_size(rany.sswVal, rnSize); break;
case sdv::any_t::EValType::val_type_interface: sdv::ser_size(rany.ifcVal, rnSize); break;
case sdv::any_t::EValType::val_type_interface_id: sdv::ser_size(rany.idIfcVal, rnSize); break;
case sdv::any_t::EValType::val_type_exception_id: sdv::ser_size(rany.idExceptVal, rnSize); break;
default: break;
}
}
/**
* @brief Stream the variable into the serializer.
* @tparam eTargetEndianess The target endianess detemines whether to swap the bytes before storing them into the buffer.
* @param[in] rSerializer Reference to the serializer.
* @param[in] rany Reference to the variable.
* @return Reference to the serializer.
*/
template <sdv::EEndian eTargetEndianess>
static sdv::serializer<eTargetEndianess>& Serialize(sdv::serializer<eTargetEndianess>& rSerializer, const sdv::any_t& rany)
{
// Serialize the type first
rSerializer << rany.eValType;
// Serialize the data
switch (rany.eValType)
{
case sdv::any_t::EValType::val_type_bool: rSerializer << rany.bVal; break;
case sdv::any_t::EValType::val_type_int8: rSerializer << rany.i8Val; break;
case sdv::any_t::EValType::val_type_uint8: rSerializer << rany.ui8Val; break;
case sdv::any_t::EValType::val_type_int16: rSerializer << rany.i16Val; break;
case sdv::any_t::EValType::val_type_uint16: rSerializer << rany.ui16Val; break;
case sdv::any_t::EValType::val_type_int32: rSerializer << rany.i32Val; break;
case sdv::any_t::EValType::val_type_uint32: rSerializer << rany.ui32Val; break;
case sdv::any_t::EValType::val_type_int64: rSerializer << rany.i64Val; break;
case sdv::any_t::EValType::val_type_uint64: rSerializer << rany.ui64Val; break;
case sdv::any_t::EValType::val_type_char: rSerializer << rany.cVal; break;
case sdv::any_t::EValType::val_type_char16: rSerializer << rany.c16Val; break;
case sdv::any_t::EValType::val_type_char32: rSerializer << rany.c32Val; break;
case sdv::any_t::EValType::val_type_wchar: rSerializer << rany.cwVal; break;
case sdv::any_t::EValType::val_type_float: rSerializer << rany.fVal; break;
case sdv::any_t::EValType::val_type_double: rSerializer << rany.dVal; break;
case sdv::any_t::EValType::val_type_long_double: rSerializer << rany.ldVal; break;
//case sdv::any_t::EValType::val_type_fixed: rSerializer << rany.fixVal; break;
case sdv::any_t::EValType::val_type_string: rSerializer << rany.ssVal; break;
case sdv::any_t::EValType::val_type_u8string: rSerializer << rany.ss8Val; break;
case sdv::any_t::EValType::val_type_u16string: rSerializer << rany.ss16Val; break;
case sdv::any_t::EValType::val_type_u32string: rSerializer << rany.ss32Val; break;
case sdv::any_t::EValType::val_type_wstring: rSerializer << rany.sswVal; break;
case sdv::any_t::EValType::val_type_interface: rSerializer << rany.ifcVal; break;
case sdv::any_t::EValType::val_type_interface_id: rSerializer << rany.idIfcVal; break;
case sdv::any_t::EValType::val_type_exception_id: rSerializer << rany.idExceptVal; break;
default: break;
}
return rSerializer;
}
/**
* @brief Stream a variable from the deserializer.
* @tparam eSourceEndianess The target endianess detemines whether to swap the bytes before storing them into the buffer.
* @param[in] rDeserializer Reference to the deserializer.
* @param[out] rany Reference to the variable to be filled.
* @return Reference to the deserializer.
*/
template <sdv::EEndian eSourceEndianess>
static sdv::deserializer<eSourceEndianess>& Deserialize(sdv::deserializer<eSourceEndianess>& rDeserializer, sdv::any_t& rany)
{
rany.clear();
// Deserialize the type first
rDeserializer >> rany.eValType;
// Serialize the data
switch (rany.eValType)
{
case sdv::any_t::EValType::val_type_bool: rDeserializer >> rany.bVal; break;
case sdv::any_t::EValType::val_type_int8: rDeserializer >> rany.i8Val; break;
case sdv::any_t::EValType::val_type_uint8: rDeserializer >> rany.ui8Val; break;
case sdv::any_t::EValType::val_type_int16: rDeserializer >> rany.i16Val; break;
case sdv::any_t::EValType::val_type_uint16: rDeserializer >> rany.ui16Val; break;
case sdv::any_t::EValType::val_type_int32: rDeserializer >> rany.i32Val; break;
case sdv::any_t::EValType::val_type_uint32: rDeserializer >> rany.ui32Val; break;
case sdv::any_t::EValType::val_type_int64: rDeserializer >> rany.i64Val; break;
case sdv::any_t::EValType::val_type_uint64: rDeserializer >> rany.ui64Val; break;
case sdv::any_t::EValType::val_type_char: rDeserializer >> rany.cVal; break;
case sdv::any_t::EValType::val_type_char16: rDeserializer >> rany.c16Val; break;
case sdv::any_t::EValType::val_type_char32: rDeserializer >> rany.c32Val; break;
case sdv::any_t::EValType::val_type_wchar: rDeserializer >> rany.cwVal; break;
case sdv::any_t::EValType::val_type_float: rDeserializer >> rany.fVal; break;
case sdv::any_t::EValType::val_type_double: rDeserializer >> rany.dVal; break;
case sdv::any_t::EValType::val_type_long_double: rDeserializer >> rany.ldVal; break;
//case sdv::any_t::EValType::val_type_fixed: new (&rany.fixVal) sdv::fixed; rDeserializer >> rany.fixVal; break;
case sdv::any_t::EValType::val_type_string: new (&rany.ssVal) sdv::string; rDeserializer >> rany.ssVal; break;
case sdv::any_t::EValType::val_type_u8string: new (&rany.ss8Val) sdv::u8string; rDeserializer >> rany.ss8Val; break;
case sdv::any_t::EValType::val_type_u16string: new (&rany.ss16Val) sdv::u16string; rDeserializer >> rany.ss16Val; break;
case sdv::any_t::EValType::val_type_u32string: new (&rany.ss32Val) sdv::u32string; rDeserializer >> rany.ss32Val; break;
case sdv::any_t::EValType::val_type_wstring: new (&rany.sswVal) sdv::wstring; rDeserializer >> rany.sswVal; break;
case sdv::any_t::EValType::val_type_interface: new (&rany.ifcVal) sdv::interface_t; rDeserializer >> rany.ifcVal; break;
case sdv::any_t::EValType::val_type_interface_id: rDeserializer >> rany.idIfcVal; break;
case sdv::any_t::EValType::val_type_exception_id: rDeserializer >> rany.idExceptVal; break;
default: rany.eValType = sdv::any_t::EValType::val_type_empty; break;
}
return rDeserializer;
}
};
/**
* @brief Specialization of serializer/deserializer class for sdv::ps::SMarshallLocal.
*/
template <>
class CSerdes<sdv::ps::SMarshallLocal>
{
public:
/**
* @brief Calculate the size of the value in serialized form.
* @remarks Dependable on the size value, padding is added to align data.
* @param[in] rsValue Reference to the variable.
* @param[in, out] rnSize Reference to the variable containing the current size and increased by the size of the value.
*/
static void CalcSize(const sdv::ps::SMarshallLocal& rsValue, size_t& rnSize)
{
sdv::ser_size(rsValue.eEndian, rnSize);
sdv::ser_size(rsValue.uiVersion, rnSize);
sdv::ser_size(rsValue.tIfcId, rnSize);
sdv::ser_size(rsValue.uiFuncIndex, rnSize);
sdv::ser_size(rsValue.uiFlags, rnSize);
sdv::ser_size(rsValue.seqChecksums, rnSize);
sdv::ser_size(rsValue.uiHdrChecksum, rnSize);
}
/**
* @brief Stream the variable into the serializer.
* @tparam eTargetEndianess The target endianess detemines whether to swap the bytes before storing them into the buffer.
* @param[in] rSerializer Reference to the serializer.
* @param[in] rsValue Reference to the variable.
* @return Reference to the serializer.
*/
template <sdv::EEndian eTargetEndianess>
static sdv::serializer<eTargetEndianess>& Serialize(sdv::serializer<eTargetEndianess>& rSerializer,
sdv::ps::SMarshallLocal& rsValue)
{
// Stream the initial parameters.
rSerializer << rsValue.eEndian;
rSerializer << rsValue.uiVersion;
rSerializer << rsValue.tIfcId;
rSerializer << rsValue.uiFuncIndex;
rSerializer << rsValue.uiFlags;
rSerializer << rsValue.seqChecksums;
// Get the currently calculated checksum and store the checksum.
rsValue.uiHdrChecksum = rSerializer.checksum();
// Stream the checksum.
rSerializer << rsValue.uiHdrChecksum;
return rSerializer;
}
/**
* @brief Stream a variable from the deserializer.
* @tparam eSourceEndianess The target endianess detemines whether to swap the bytes before storing them into the buffer.
* @param[in] rDeserializer Reference to the deserializer.
* @param[out] rsValue Reference to the variable to be filled.
* @return Reference to the deserializer.
*/
template <sdv::EEndian eSourceEndianess>
static sdv::deserializer<eSourceEndianess>& Deserialize(sdv::deserializer<eSourceEndianess>& rDeserializer,
sdv::ps::SMarshallLocal& rsValue)
{
// Stream the initial parameters.
rDeserializer >> rsValue.eEndian;
rDeserializer >> rsValue.uiVersion;
// Continue only when the version is corresponding with the interface version (otherwise the order might be
// mixed up).
if (rsValue.uiVersion == SDVFrameworkInterfaceVersion)
{
rDeserializer >> rsValue.tIfcId;
rDeserializer >> rsValue.uiFuncIndex;
rDeserializer >> rsValue.uiFlags;
rDeserializer >> rsValue.seqChecksums;
rDeserializer >> rsValue.uiHdrChecksum;
}
return rDeserializer;
}
};
} // namespace serdes
namespace sdv
{
namespace ps
{
inline CRawDataBypass::CRawDataBypass()
{}
inline void CRawDataBypass::push(const pointer<uint8_t>& rptrData)
{
m_queueBypassData.push(rptrData);
}
inline pointer<uint8_t> CRawDataBypass::pop()
{
pointer<uint8_t> ptrData = std::move(m_queueBypassData.front());
m_queueBypassData.pop();
return ptrData;
}
inline bool CRawDataBypass::empty() const
{
return m_queueBypassData.empty();
}
inline void CRawDataBypass::clear()
{
while (!m_queueBypassData.empty())
m_queueBypassData.pop();
}
inline CRawDataBypass& GetRawDataBypass()
{
thread_local static CRawDataBypass bypass;
return bypass;
}
template <typename TInterface>
inline CProxyHandler<TInterface>::CProxyHandler()
{}
template <typename TInterface>
inline CProxyHandler<TInterface>::~CProxyHandler()
{}
template <typename TInterface>
inline void CProxyHandler<TInterface>::SetIdentification(/*in*/ const TMarshallID& tMarshallID)
{
m_tProxyID = tMarshallID;
}
template <typename TInterface>
inline void CProxyHandler<TInterface>::Link(/*in*/ IMarshall* pMarshall)
{
assert(pMarshall);
m_pRequest = pMarshall;
}
template <typename TInterface>
inline void CProxyHandler<TInterface>::Unlink()
{
m_pRequest = nullptr;
}
template <typename TInterface>
inline ECallResult CProxyHandler<TInterface>::DoCall(uint32_t uiFuncIndex,
const serializer<GetPlatformEndianess()>& rserInput, deserializer<GetPlatformEndianess()>& rdesOutput)
{
// Needs a valid request interface
if (!m_pRequest) throw XMarshallNotInitialized{};
// The sequence holding the input data pointers
sequence<pointer<uint8_t>> seqInputData;
// Fill the marshall packet
SMarshallLocal sInputPacket{};
sInputPacket.eEndian = GetPlatformEndianess();
sInputPacket.uiVersion = SDVFrameworkInterfaceVersion;
sInputPacket.tIfcId = TInterface::_id;
sInputPacket.uiFuncIndex = uiFuncIndex;
// Are there any parameters?
if (rserInput.buffer())
{
// Add the serialized parameters to the marshall sequence
seqInputData.push_back(rserInput.buffer());
sInputPacket.seqChecksums.push_back(rserInput.checksum());
// Add additional raw data
while (!GetRawDataBypass().empty())
{
// Calculate the checksum
crcCCITT_FALSE crc;
pointer<uint8_t> ptrRawData = GetRawDataBypass().pop();
crcCCITT_FALSE crcBypass;
uint16_t uiChecksum = crcBypass.calc_checksum(ptrRawData.get(), ptrRawData.size());
// Add the raw data to the marshall sequence
seqInputData.push_back(ptrRawData);
sInputPacket.seqChecksums.push_back(uiChecksum);
}
}
// Create an additional stream for the marshall struct.
serializer serHdr;
serdes::CSerdes<SMarshallLocal>::Serialize(serHdr, sInputPacket);
// Add the packet to the top of the pointer sequence.
seqInputData.insert(seqInputData.begin(), serHdr.buffer());
// Call the request; this will update the sequence with result information
sequence<pointer<uint8_t>> seqOutputData = m_pRequest->Call(seqInputData);
if (seqOutputData.empty()) throw XMarshallMissingData{};
// The first data pointer in the sequence contains the marshall header
pointer<uint8_t> ptrHeader = seqOutputData[0];
if (!ptrHeader) throw ps::XMarshallMissingData{};
// And the first byte in the data pointer determines the endianess
EEndian eSourceEndianess = static_cast<EEndian>(ptrHeader[0]);
// Deserialize the packet
SMarshallLocal sOutputPacket{};
if (eSourceEndianess == EEndian::big_endian)
{
deserializer<EEndian::big_endian> deserializer;
deserializer.attach(ptrHeader, 0); // Do not check checksum...
serdes::CSerdes<SMarshallLocal>::Deserialize(deserializer, sOutputPacket);
} else
{
deserializer<EEndian::little_endian> deserializer;
deserializer.attach(ptrHeader, 0); // Do not check checksum...
serdes::CSerdes<SMarshallLocal>::Deserialize(deserializer, sOutputPacket);
}
// Check the packet version... must fit, otherwise data misalignment might occur.
if (sOutputPacket.uiVersion != SDVFrameworkInterfaceVersion) throw XMarshallVersion{};
// The checksum can be calculated by serializing the packet once more.
uint16_t uiHdrChecksum = sOutputPacket.uiHdrChecksum;
serializer serializer;
serdes::CSerdes<SMarshallLocal>::Serialize(serializer, sOutputPacket);
// Ignore cppcheck suppress warning is always false. The checksum is written into the packet again. If previously it
// was different, this causes an integrity exception.
// cppcheck-suppress knownConditionTrueFalse
if (sOutputPacket.uiHdrChecksum != uiHdrChecksum)
throw XMarshallIntegrity{};
// Check whether the result contains an exception
if (sOutputPacket.uiFlags & static_cast<uint32_t>(sdv::ps::EMarshallFlags::exception_triggered))
{
// Check the checksum of the data
if (seqOutputData.size() != 2) throw XMarshallIntegrity{};
if (sOutputPacket.seqChecksums.size() != 1) throw XMarshallIntegrity{};
crcCCITT_FALSE crc;
if (crc.calc_checksum(seqOutputData[1].get(), seqOutputData[1].size()) != sOutputPacket.seqChecksums[0])
throw XMarshallIntegrity{};
// Attach the data to the deserializer.
rdesOutput.attach(seqOutputData[1]);
// Check for system and/or proxy-stub exceptions
sdv::exception_id id = 0;
rdesOutput.peek_front(id);
switch(id)
{
case GetExceptionId<XNoInterface>():
{
XNoInterface exception;
serdes::CSerdes<XNoInterface>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<XIndexOutOfRange>():
{
XIndexOutOfRange exception;
serdes::CSerdes<XIndexOutOfRange>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<XInvalidIterator>():
{
XInvalidIterator exception;
serdes::CSerdes<XInvalidIterator>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<XNullPointer>():
{
XNullPointer exception;
serdes::CSerdes<XNullPointer>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<XInvalidRefCount>():
{
XInvalidRefCount exception;
serdes::CSerdes<XInvalidRefCount>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<XBufferTooSmall>():
{
XBufferTooSmall exception;
serdes::CSerdes<XBufferTooSmall>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<XHashNotMatching>():
{
XHashNotMatching exception;
serdes::CSerdes<XHashNotMatching>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<XOffsetPastBufferSize>():
{
XOffsetPastBufferSize exception;
serdes::CSerdes<XOffsetPastBufferSize>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<XUnknownException>():
{
XUnknownException exception;
serdes::CSerdes<XUnknownException>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<XUnhandledException>():
{
XUnhandledException exception;
serdes::CSerdes<XUnhandledException>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<core::XNoMemMgr>():
{
core::XNoMemMgr exception;
serdes::CSerdes<core::XNoMemMgr>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<core::XAllocFailed>():
{
core::XAllocFailed exception;
serdes::CSerdes<core::XAllocFailed>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<XMarshallNotInitialized>():
{
XMarshallNotInitialized exception;
serdes::CSerdes<XMarshallNotInitialized>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<XMarshallTimeout>():
{
XMarshallTimeout exception;
serdes::CSerdes<XMarshallTimeout>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<XMarshallMissingData>():
{
XMarshallMissingData exception;
serdes::CSerdes<XMarshallMissingData>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<XMarshallVersion>():
{
XMarshallVersion exception;
serdes::CSerdes<XMarshallVersion>::Deserialize(rdesOutput, exception);
throw exception;
}
case GetExceptionId<XMarshallIntegrity>():
{
XMarshallIntegrity exception;
serdes::CSerdes<XMarshallIntegrity>::Deserialize(rdesOutput, exception);
throw exception;
}
default:
break;
}
// No known exception, let the caller check whether it can handle the exception.
return ECallResult::result_exception;
}
// Check for packet integrity and add the raw data to the raw data bypass
if (sOutputPacket.seqChecksums.size() != seqOutputData.size() - 1) throw XMarshallIntegrity{};
size_t nChecksumIndex = 0;
pointer<uint8_t> ptrParams;
GetRawDataBypass().clear();
for (auto itData = seqOutputData.begin() + 1; itData != seqOutputData.end(); itData++)
{
crcCCITT_FALSE crc;
if (crc.calc_checksum(itData->get(), itData->size()) != sOutputPacket.seqChecksums[nChecksumIndex])
throw XMarshallIntegrity{};
if (nChecksumIndex)
GetRawDataBypass().push(*itData);
else
ptrParams = *itData;
nChecksumIndex++;
}
// Return the deserialization object.
if (ptrParams)
rdesOutput.attach(ptrParams);
return ECallResult::result_ok;
}
template <typename TInterface>
inline CStubHandler<TInterface>::CStubHandler()
{}
template <typename TInterface>
inline CStubHandler<TInterface>::~CStubHandler()
{}
template <typename TInterface>
inline void CStubHandler<TInterface>::RegisterDispatchFunc(FNDispatch fnDispatch)
{
m_vecDispatch.push_back(fnDispatch);
}
template <typename TInterface>
template <typename TExcept>
inline pointer<uint8_t> CStubHandler<TInterface>::SerializeException(EEndian eEndian, const TExcept& rexcept)
{
GetRawDataBypass().clear(); // just in case
if (eEndian == sdv::EEndian::big_endian)
{
sdv::serializer<sdv::EEndian::big_endian> serOutput;
serdes::CSerdes<TExcept>::Serialize(serOutput, rexcept);
return serOutput.buffer();
} else
{
sdv::serializer<sdv::EEndian::little_endian> serOutput;
serdes::CSerdes<TExcept>::Serialize(serOutput, rexcept);
return serOutput.buffer();
}
}
template <typename TInterface>
inline void CStubHandler<TInterface>::SetIdentification(/*in*/ const TMarshallID& tMarshallID)
{
m_tStubID = tMarshallID;
}
template <typename TInterface>
inline sequence<pointer<uint8_t>> CStubHandler<TInterface>::Call(/*inout*/ sequence<pointer<uint8_t>>& seqInputData)
{
if (seqInputData.empty()) throw XMarshallMissingData{};
// The first data pointer in the sequence contains the marshall header
pointer<uint8_t> ptrHeader = seqInputData[0];
if (!ptrHeader) throw ps::XMarshallMissingData{};
// And the first byte in the data pointer determines the endianess
EEndian eSourceEndianess = static_cast<EEndian>(ptrHeader[0]);
// Deserialize the packet
SMarshallLocal sInputPacket{};
if (eSourceEndianess == EEndian::big_endian)
{
deserializer<EEndian::big_endian> desInput;
desInput.attach(ptrHeader, 0); // Do not check checksum...
serdes::CSerdes<SMarshallLocal>::Deserialize(desInput, sInputPacket);
} else
{
deserializer<EEndian::little_endian> desInput;
desInput.attach(ptrHeader, 0); // Do not check checksum...
serdes::CSerdes<SMarshallLocal>::Deserialize(desInput, sInputPacket);
}
// Check the packet version... must fit, otherwise data misalignment might occur.
if (sInputPacket.uiVersion != SDVFrameworkInterfaceVersion) throw XMarshallVersion{};
// The checksum can be calculated by serializing the packet once more.
uint16_t uiHdrChecksum = sInputPacket.uiHdrChecksum;
serializer rserInput;
serdes::CSerdes<SMarshallLocal>::Serialize(rserInput, sInputPacket);
// Ignore cppcheck suppress warning is always false. The checksum is written into the packet again. If previously it
// was different, this causes an integrity exception.
// cppcheck-suppress knownConditionTrueFalse
if (sInputPacket.uiHdrChecksum != uiHdrChecksum) throw XMarshallIntegrity{};
// Check for packet integrity and add the raw data to the raw data bypass
if (sInputPacket.seqChecksums.size() != seqInputData.size() - 1) throw XMarshallIntegrity{};
size_t nChecksumIndex = 0;
pointer<uint8_t> ptrInputParams;
GetRawDataBypass().clear();
for (auto itData = seqInputData.begin() + 1; itData != seqInputData.end(); itData++)
{
crcCCITT_FALSE crc;
if (crc.calc_checksum(itData->get(), itData->size()) != sInputPacket.seqChecksums[nChecksumIndex])
throw XMarshallIntegrity{};
if (nChecksumIndex)
GetRawDataBypass().push(*itData);
else
ptrInputParams = *itData;
nChecksumIndex++;
}
// If any exception occured during the input processing, return the buffer without processing. This allows the
// caller to receive the exception.
if (sInputPacket.uiFlags & static_cast<uint32_t>(EMarshallFlags::exception_triggered))
return seqInputData;
// Call dispatch function
FNDispatch fnDispatch = m_vecDispatch[sInputPacket.uiFuncIndex];
if (!fnDispatch) throw XMarshallNotInitialized{};
pointer<uint8_t> ptrOutputParams;
ECallResult eResult = ECallResult::result_ok;
try
{
eResult = fnDispatch(eSourceEndianess, ptrInputParams, ptrOutputParams);
} catch (const XNoInterface& rexcept)
{
ptrOutputParams = SerializeException(eSourceEndianess, rexcept);
eResult = ECallResult::result_exception;
} catch (const XIndexOutOfRange& rexcept)
{
ptrOutputParams = SerializeException(eSourceEndianess, rexcept);
eResult = ECallResult::result_exception;
} catch (const XInvalidIterator& rexcept)
{
ptrOutputParams = SerializeException(eSourceEndianess, rexcept);
eResult = ECallResult::result_exception;
} catch (const XNullPointer& rexcept)
{
ptrOutputParams = SerializeException(eSourceEndianess, rexcept);
eResult = ECallResult::result_exception;
} catch (const XInvalidRefCount& rexcept)
{
ptrOutputParams = SerializeException(eSourceEndianess, rexcept);
eResult = ECallResult::result_exception;
} catch (const XBufferTooSmall& rexcept)
{
ptrOutputParams = SerializeException(eSourceEndianess, rexcept);
eResult = ECallResult::result_exception;
} catch (const XHashNotMatching& rexcept)
{
ptrOutputParams = SerializeException(eSourceEndianess, rexcept);
eResult = ECallResult::result_exception;
} catch (const XOffsetPastBufferSize& rexcept)
{
ptrOutputParams = SerializeException(eSourceEndianess, rexcept);
eResult = ECallResult::result_exception;
} catch (const XUnknownException& rexcept)
{
ptrOutputParams = SerializeException(eSourceEndianess, rexcept);
eResult = ECallResult::result_exception;
} catch (const XUnhandledException& rexcept)
{
ptrOutputParams = SerializeException(eSourceEndianess, rexcept);
eResult = ECallResult::result_exception;
} catch (const core::XNoMemMgr& rexcept)
{
ptrOutputParams = SerializeException(eSourceEndianess, rexcept);
eResult = ECallResult::result_exception;
} catch (const core::XAllocFailed& rexcept)
{
ptrOutputParams = SerializeException(eSourceEndianess, rexcept);
eResult = ECallResult::result_exception;
} catch (...)
{
XUnhandledException xUnhandled;
ptrOutputParams = SerializeException(eSourceEndianess, xUnhandled);
eResult = ECallResult::result_exception;
}
// The sequence holding the output data pointers
sequence<pointer<uint8_t>> seqOutputData;
// Fill the marshall packet
SMarshallLocal sOutputPacket{};
sOutputPacket.eEndian = eSourceEndianess;
sOutputPacket.uiVersion = SDVFrameworkInterfaceVersion;
sOutputPacket.tIfcId = TInterface::_id;
sOutputPacket.uiFuncIndex = sInputPacket.uiFuncIndex;
sOutputPacket.uiFlags = static_cast<uint32_t>(EMarshallFlags::direction_output);
if (eResult == ECallResult::result_exception)
sOutputPacket.uiFlags |= static_cast<uint32_t>(EMarshallFlags::exception_triggered);
// Are there any parameters?
if (ptrOutputParams)
{
// Calculate the checksum
crcCCITT_FALSE crc;
uint16_t uiChecksum = crc.calc_checksum(ptrOutputParams.get(), ptrOutputParams.size());
// Add the serialized parameters to the marshall sequence
seqOutputData.push_back(ptrOutputParams);
sOutputPacket.seqChecksums.push_back(uiChecksum);
// Add additional raw data
while (!GetRawDataBypass().empty())
{
// Calculate the checksum
pointer<uint8_t> ptrRawData = GetRawDataBypass().pop();
crcCCITT_FALSE crcBypass;
uiChecksum = crcBypass.calc_checksum(ptrRawData.get(), ptrRawData.size());
// Add the raw data to the marshall sequence
seqOutputData.push_back(ptrRawData);
sOutputPacket.seqChecksums.push_back(uiChecksum);
}
}
// Create an additional stream for the marshall struct.
serializer serHdr;
serdes::CSerdes<SMarshallLocal>::Serialize(serHdr, sOutputPacket);
// Add the packet to the top of the pointer sequence.
seqOutputData.insert(seqOutputData.begin(), serHdr.buffer());
return seqOutputData;
}
} // namespace ps
} // namespace sdv
inline bool operator==(const sdv::ps::TMarshallID& rtID1, const sdv::ps::TMarshallID& rtID2)
{
if (rtID1.uiHostID != rtID2.uiHostID) return false;
if (rtID1.tProcessID != rtID2.tProcessID) return false;
if (rtID1.uiIdent != rtID2.uiIdent) return false;
if (rtID1.uiControl != rtID2.uiControl) return false;
return true;
}
inline bool operator==(const sdv::ps::TMarshallID& rtID1, size_t nVal)
{
if (nVal) return false;
return operator==(rtID1, sdv::ps::TMarshallID{});
}
inline bool operator==(size_t nVal, const sdv::ps::TMarshallID& rtID2)
{
if (nVal) return false;
return operator==(sdv::ps::TMarshallID{}, rtID2);
}
inline bool operator!=(const sdv::ps::TMarshallID& rtID1, const sdv::ps::TMarshallID& rtID2)
{
return !operator==(rtID1, rtID2);
}
inline bool operator!=(const sdv::ps::TMarshallID& rtID1, size_t nVal)
{
if (nVal) return true;
return !operator==(rtID1, sdv::ps::TMarshallID{});
}
inline bool operator!=(size_t nVal, const sdv::ps::TMarshallID& rtID2)
{
if (nVal) return true;
return !operator==(sdv::ps::TMarshallID{}, rtID2);
}
inline bool operator<(const sdv::ps::TMarshallID& rtID1, const sdv::ps::TMarshallID& rtID2)
{
if (rtID1.uiHostID < rtID2.uiHostID) return true;
if (rtID1.uiHostID > rtID2.uiHostID) return false;
if (rtID1.tProcessID < rtID2.tProcessID) return true;
if (rtID1.tProcessID > rtID2.tProcessID) return false;
if (rtID1.uiIdent < rtID2.uiIdent) return true;
return false;
}
inline bool operator<=(const sdv::ps::TMarshallID& rtID1, const sdv::ps::TMarshallID& rtID2)
{
if (rtID1.uiHostID < rtID2.uiHostID) return true;
if (rtID1.uiHostID > rtID2.uiHostID) return false;
if (rtID1.tProcessID < rtID2.tProcessID) return true;
if (rtID1.tProcessID > rtID2.tProcessID) return false;
if (rtID1.uiIdent < rtID2.uiIdent) return true;
if (rtID1.uiControl == rtID2.uiControl) return true;
return false;
}
inline bool operator>(const sdv::ps::TMarshallID& rtID1, const sdv::ps::TMarshallID& rtID2)
{
if (rtID1.uiHostID > rtID2.uiHostID) return true;
if (rtID1.uiHostID < rtID2.uiHostID) return false;
if (rtID1.tProcessID > rtID2.tProcessID) return true;
if (rtID1.tProcessID < rtID2.tProcessID) return false;
if (rtID1.uiIdent > rtID2.uiIdent) return true;
return false;
}
inline bool operator>=(const sdv::ps::TMarshallID& rtID1, const sdv::ps::TMarshallID& rtID2)
{
if (rtID1.uiHostID > rtID2.uiHostID) return true;
if (rtID1.uiHostID < rtID2.uiHostID) return false;
if (rtID1.tProcessID > rtID2.tProcessID) return true;
if (rtID1.tProcessID < rtID2.tProcessID) return false;
if (rtID1.uiIdent > rtID2.uiIdent) return true;
if (rtID1.uiControl == rtID2.uiControl) return true;
return false;
}
inline bool operator!(const sdv::ps::TMarshallID& rtID)
{
// The control ID is the onl ID which is not allowed to be zero.
return rtID.uiControl ? false : true;
}
inline bool operator==(const sdv::com::TConnectionID& rtID1, const sdv::com::TConnectionID& rtID2)
{
if (rtID1.uiIdent != rtID2.uiIdent) return false;
if (rtID1.uiControl != rtID2.uiControl) return false;
return true;
}
inline bool operator==(const sdv::com::TConnectionID& rtID1, size_t nVal)
{
if (nVal) return false;
return operator==(rtID1, sdv::com::TConnectionID{});
}
inline bool operator==(size_t nVal, const sdv::com::TConnectionID& rtID2)
{
if (nVal) return false;
return operator==(sdv::com::TConnectionID{}, rtID2);
}
inline bool operator!=(const sdv::com::TConnectionID& rtID1, const sdv::com::TConnectionID& rtID2)
{
return !operator==(rtID1, rtID2);
}
inline bool operator!=(const sdv::com::TConnectionID& rtID1, size_t nVal)
{
if (nVal) return true;
return !operator==(rtID1, sdv::com::TConnectionID{});
}
inline bool operator!=(size_t nVal, const sdv::com::TConnectionID& rtID2)
{
if (nVal) return true;
return !operator==(sdv::com::TConnectionID{}, rtID2);
}
inline bool operator<(const sdv::com::TConnectionID& rtID1, const sdv::com::TConnectionID& rtID2)
{
if (rtID1.uiIdent < rtID2.uiIdent) return true;
return false;
}
inline bool operator<=(const sdv::com::TConnectionID& rtID1, const sdv::com::TConnectionID& rtID2)
{
if (rtID1.uiIdent < rtID2.uiIdent) return true;
if (rtID1.uiControl == rtID2.uiControl) return true;
return false;
}
inline bool operator>(const sdv::com::TConnectionID& rtID1, const sdv::com::TConnectionID& rtID2)
{
if (rtID1.uiIdent > rtID2.uiIdent) return true;
return false;
}
inline bool operator>=(const sdv::com::TConnectionID& rtID1, const sdv::com::TConnectionID& rtID2)
{
if (rtID1.uiIdent > rtID2.uiIdent) return true;
if (rtID1.uiControl == rtID2.uiControl) return true;
return false;
}
inline bool operator!(const sdv::com::TConnectionID& rtID)
{
// The control ID is the onl ID which is not allowed to be zero.
return rtID.uiControl ? false : true;
}
#endif // !defined(SDV_PS_SUPPORT_INL)

300
export/support/sdv_core.h Normal file
View File

@@ -0,0 +1,300 @@
#ifndef SDV_CORE_H
#define SDV_CORE_H
#ifndef DONT_LOAD_CORE_TYPES
#include "../interfaces/core.h"
#include "../interfaces/module.h"
#endif
#include "interface_ptr.h"
#include <fstream>
#include <filesystem>
#include <string>
#include <cctype>
#include <stdlib.h>
#include <functional>
#ifdef _WIN32
// Resolve conflict
#pragma push_macro("interface")
#pragma push_macro("GetObject")
#undef interface
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <WinSock2.h>
#include <Windows.h>
#include <objbase.h>
// Resolve conflict
#pragma pop_macro("interface")
#pragma pop_macro("GetObject")
#ifdef GetClassInfo
#undef GetClassInfo
#endif
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
#elif defined __unix__
#include <dlfcn.h>
#include <unistd.h>
#include <limits.h>
#else
#error OS is not supported!
#endif
namespace sdv
{
namespace core
{
namespace internal
{
/**
* @brief The SDV core loader
*/
class CSDVCoreLoader
{
public:
/**
* @brief Default constructor.
* @remarks The constructor doesn't load the library, since this could cause a deadlock during the initialization
* phase. Loading is done through the Load function.
*/
CSDVCoreLoader() = default;
/**
* @brief Destructor unloading the core
*/
~CSDVCoreLoader()
{
// Free the library
if (m_tModule)
#ifdef _WIN32
FreeLibrary(reinterpret_cast<HMODULE>(m_tModule));
#elif defined __unix__
dlclose(reinterpret_cast<void*>(m_tModule));
#else
#error OS not supported!
#endif
}
/**
* @brief Load the SDV core library.
* @details The function searches for the library core_services in different locations:
* First it searches in the directory of the executable for the library.
* Then it searches in the directory of the executable for a configuration file with the library location.
* The configuration file is called sdv_core_reloc.toml and should contain a section at least the line:
* directory=[path] whereas [path] represents the path to the core library. Other information in the file is
* ignored. Then it searches in the environment variable SDV_FRAMEWORK_RUNTIME for the location of the library.
* Last it searches in the path for the location of the library.
*/
void Load()
{
if (m_bInit) return; // Prevent trying to load again.
m_bInit = true;
// Check for the executable directory
std::filesystem::path pathCoreLib;
if (std::filesystem::exists(GetExecDirectory() / "core_services.sdv"))
pathCoreLib = GetExecDirectory() / "core_services.sdv";
// Check for the local config file
if (pathCoreLib.empty() && std::filesystem::exists(GetExecDirectory() / "sdv_core_reloc.toml"))
{
std::ifstream fstream(GetExecDirectory() / "sdv_core_reloc.toml");
std::string ssLine;
while (std::getline(fstream, ssLine))
{
size_t nPos = 0;
auto fnSkipWhitespace = [&]() { while (std::isspace(ssLine[nPos])) nPos++; };
fnSkipWhitespace();
if (ssLine[nPos] == '#') continue; // Rest of the line is comments
if (ssLine.substr(nPos, 9) != "directory") continue; // not the keq of interest: skip line
nPos += 9;
fnSkipWhitespace();
if (ssLine[nPos] != '=')
{
std::cout << "Error in \"sdv_core_reloc.toml\": expecting assignment character '=' following"
" keyword 'directory'." << std::endl;
break;
}
nPos++;
fnSkipWhitespace();
if (ssLine[nPos] != '\"')
{
std::cout << "Error in \"sdv_core_reloc.toml\": expecting double quote character '\"' indicating"
" a string begin'." << std::endl;
break;
}
nPos++;
size_t nStart = nPos;
while (nPos < ssLine.length() && ssLine[nPos] != '\"')
{
// Check for escape character
if (ssLine[nPos] == '\\') nPos++;
// Skip character
nPos++;
}
if (nPos >= ssLine.length() || ssLine[nPos] != '\"')
{
std::cout << "Error in \"sdv_core_reloc.toml\": expecting double quote character '\"' indicating"
" a string end'." << std::endl;
break;
}
std::string ssDirectory = ssLine.substr(nStart, nPos - nStart);
while (ssDirectory.empty())
{
std::cout << "Error in \"sdv_core_reloc.toml\": expecting a valid value following the assignment"
" of the 'directory' key." << std::endl;
break;
}
pathCoreLib = std::filesystem::path(ssDirectory) / "core_services.sdv";
if (pathCoreLib.is_relative())
pathCoreLib = (GetExecDirectory() / pathCoreLib).lexically_normal();
break;
}
}
// Check for the environment variable
#ifdef _WIN32
std::wstring ssPathCoreTemp(32768, '\0');
GetEnvironmentVariable(L"SDV_FRAMEWORK_RUNTIME", ssPathCoreTemp.data(), static_cast<DWORD>(ssPathCoreTemp.size()));
ssPathCoreTemp.resize(wcsnlen(ssPathCoreTemp.c_str(), ssPathCoreTemp.size()));
if (pathCoreLib.empty() && !ssPathCoreTemp.empty())
{
pathCoreLib = std::filesystem::path(ssPathCoreTemp) / "core_services.sdv";
#else
if (pathCoreLib.empty() && getenv("SDV_FRAMEWORK_RUNTIME"))
{
pathCoreLib = std::filesystem::path(getenv("SDV_FRAMEWORK_RUNTIME")) / "core_services.sdv";
#endif
if (pathCoreLib.is_relative())
pathCoreLib = (GetExecDirectory() / pathCoreLib).lexically_normal();
}
// Depend on system path to find the library
if (pathCoreLib.empty())
pathCoreLib = "core_services.sdv";
// Open the library
#ifdef _WIN32
SetErrorMode(SEM_FAILCRITICALERRORS);
m_tModule = reinterpret_cast<core::TModuleID>(LoadLibraryW(pathCoreLib.native().c_str()));
#elif defined __unix__
m_tModule = reinterpret_cast<core::TModuleID>(dlopen(pathCoreLib.native().c_str(), RTLD_LAZY));
#else
#error OS is not supported!
#endif
if (!m_tModule)
{
std::string ssError;
#ifdef _WIN32
ssError.resize(1024);
ssError.resize(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &ssError.front(), 1024, NULL));
while (!ssError.empty() && std::isspace(ssError.back())) ssError.pop_back();
#elif defined __unix__
const char* szError = dlerror();
if (szError) ssError = szError;
#else
#error OS is not supported!
#endif
std::cerr << "Could not load \"core_services.sdv\" library";
if (!ssError.empty()) std::cerr << ": " << ssError;
std::cerr << std::endl;
return;
}
// Get the SDVCore function pointer
using TFNSDVCore = IInterfaceAccess*();
#ifdef _WIN32
std::function<TFNSDVCore> fnSDVCore =
reinterpret_cast<TFNSDVCore*>(GetProcAddress(reinterpret_cast<HMODULE>(m_tModule), "SDVCore"));
#elif defined __unix__
std::function<TFNSDVCore> fnSDVCore =
reinterpret_cast<TFNSDVCore*>(dlsym(reinterpret_cast<void*>(m_tModule), "SDVCore"));
#else
#error OS is not supported!
#endif
if (!fnSDVCore)
{
std::cerr << "The library \"core_services.sdv\" doesn't expose the SDVCore function." << std::endl;
return;
}
// TODO: Add version check!
// Get the core interface
m_pCore = fnSDVCore();
if (!m_pCore)
{
std::cerr << "The library \"core_services.sdv\" doesn't provide a valid interface." << std::endl;
return;
}
}
/**
* @brief Return the core interface
*/
operator TInterfaceAccessPtr() const { return m_pCore; }
private:
/**
* @brief Get the directory of the executable.
* @return Path to the directory.
*/
static std::filesystem::path GetExecDirectory()
{
#ifdef _WIN32
// Windows specific
std::wstring ssPath(32768, '\0');
GetModuleFileNameW(NULL, ssPath.data(), static_cast<DWORD>(ssPath.size() - 1));
#elif defined __linux__
// Linux specific
std::string ssPath(PATH_MAX + 1, '\0');
const ssize_t nCount = readlink("/proc/self/exe", ssPath.data(), PATH_MAX);
if (nCount < 0 || nCount >= PATH_MAX)
return {}; // some error
ssPath.at(nCount) = '\0';
#else
#error OS is not supported!
#endif
return std::filesystem::path{ssPath.c_str()}.parent_path() / ""; // To finish the folder path with (back)slash
}
bool m_bInit = false; ///< Is the loader initialized?
core::TModuleID m_tModule = 0; ///< Module ID
IInterfaceAccess* m_pCore = nullptr; ///< Pointer to the core services.
};
} // namespace internal
#ifndef NO_SDV_CORE_FUNC
/**
* @brief Access to the core.
* @return Smart pointer to the core services interface.
*/
inline TInterfaceAccessPtr GetCore()
{
static internal::CSDVCoreLoader core;
core.Load();
return core;
}
/**
* @brief Access to specific interface of the core.
* @tparam TInterface Type of interface to return.
* @return Pointer to the interface or NULL when the interface was not exposed.
*/
template <typename TInterface>
inline TInterface* GetCore()
{
return GetCore().GetInterface<TInterface>();
}
#endif
}
}
#endif // !define SDV_CORE_H

View File

@@ -0,0 +1,250 @@
#ifndef SDV_TEST_MACRO_H
#define SDV_TEST_MACRO_H
/**
* @brief Software Defined Vehicle framework.
*/
namespace sdv
{
/**
* @brief Namespace TEST
*/
namespace TEST
{
/**
* @brief Enum for warning levels.
*/
enum WarningLevel
{
WARNING_ENABLED, //<! With this level Failed tests are reported as error as it is in GTEST normally.
WARNING_REDUCED, //<! With this level Failed tests are reported as warning.
WARNING_DISABLED //<! With this level no action is implemented at this moment.
};
/**
* @brief Function to report a warning when the expected condition is not met.
* @param[in] condition The condition that is being checked (should be true if valid).
* @param[in] warningLevel The level of warning to display.
* @param[in] message The warning message to display.
* @param[in] file The name of the file where the warning occurred.
* @param[in] line The line number where the warning occurred.
*/
inline void ReportWarning(bool condition, WarningLevel warningLevel, const std::string& message, const char* file, int line)
{
if (!condition)
{
switch (warningLevel)
{
case WARNING_ENABLED:
FAIL() << "[ FAILED ]: " << message << " in file " << file << " on line " << line << std::endl;
break;
case WARNING_DISABLED:
// No action
break;
case WARNING_REDUCED:
std::clog << "[[ WARNING ]] TEST FAILURE NOT EVALUATED: " << message << " in file " << file << " on line " << line << std::endl;
break;
default:
break;
}
}
}
/**
* @brief Function to detect whether tests are running with CMAKE build or locally manually.
* @return Returns true if it is running with CMAKE build, otherwise false.
*/
inline bool IsRunningTestsWithCmakeBuild()
{
auto envVar = std::getenv("TEST_EXECUTION_MODE");
if (envVar && std::string(envVar) == "CMake") return true;
else return false;
}
} // namespace TEST
} // namespace sdv
/**
* @brief Macro for checking whether tests are running with CMAKE build or locally manually.
* Returns true if it is running with CMAKE build, otherwise false.
*/
#define SDV_IS_RUNNING_TESTS_WITH_CMAKE_BUILD sdv::TEST::IsRunningTestsWithCmakeBuild()
/**
* @brief Helper macro to handle warning levels.
* @param[in] level The warning level.
* @param[in] statement The statement to execute.
* @param[in] val1 The first value for comparison.
* @param[in] val2 The second value for comparison.
* @param[in] condition The condition to check.
*/
#define HANDLE_WARNING_LEVEL(level, statement, val1, val2, condition) \
do \
{ \
switch (level) \
{ \
case sdv::TEST::WarningLevel::WARNING_ENABLED: \
statement; \
break; \
case sdv::TEST::WarningLevel::WARNING_REDUCED: \
if (val1 condition val2) statement; \
else \
{ \
std::ostringstream oss; \
oss << "[[ WARNING ]] TEST FAILURE NOT EVALUATED: Condition did not match for [" \
<< #val1 "] and [" #val2 << "] in file " << __FILE__ << " on line " << __LINE__; \
std::clog << oss.str() << std::endl; \
} \
break; \
case sdv::TEST::WarningLevel::WARNING_DISABLED: /* No action */ \
break; \
default: \
break; \
} \
} while (0)
/**
* @brief Redefine GTEST macros with warning level.
* @param[in] val1 The first value.
* @param[in] val2 The second value.
* @param[in] level The warning level.
*/
#define SDV_EXPECT_EQ(val1, val2, level) \
HANDLE_WARNING_LEVEL(level, EXPECT_EQ(val1, val2), val1, val2, ==)
#define SDV_ASSERT_EQ(val1, val2, level) \
HANDLE_WARNING_LEVEL(level, ASSERT_EQ(val1, val2), val1, val2, ==)
#define SDV_EXPECT_NE(val1, val2, level) \
HANDLE_WARNING_LEVEL(level, EXPECT_NE(val1, val2), val1, val2, !=)
#define SDV_ASSERT_NE(val1, val2, level) \
HANDLE_WARNING_LEVEL(level, ASSERT_NE(val1, val2), val1, val2, !=)
#define SDV_EXPECT_TRUE(condition, level) \
HANDLE_WARNING_LEVEL(level, EXPECT_TRUE(condition), condition, true, ==)
#define SDV_ASSERT_TRUE(condition, level) \
HANDLE_WARNING_LEVEL(level, ASSERT_TRUE(condition), condition, true, ==)
#define SDV_EXPECT_FALSE(condition, level) \
HANDLE_WARNING_LEVEL(level, EXPECT_FALSE(condition), condition, false, ==)
#define SDV_ASSERT_FALSE(condition, level) \
HANDLE_WARNING_LEVEL(level, ASSERT_FALSE(condition), condition, false, ==)
#define SDV_EXPECT_LT(val1, val2, level) \
HANDLE_WARNING_LEVEL(level, EXPECT_LT(val1, val2), val1, val2, <)
#define SDV_ASSERT_LT(val1, val2, level) \
HANDLE_WARNING_LEVEL(level, ASSERT_LT(val1, val2), val1, val2, <)
#define SDV_EXPECT_LE(val1, val2, level) \
HANDLE_WARNING_LEVEL(level, EXPECT_LE(val1, val2), val1, val2, <=)
#define SDV_ASSERT_LE(val1, val2, level) \
HANDLE_WARNING_LEVEL(level, ASSERT_LE(val1, val2), val1, val2, <=)
#define SDV_EXPECT_GT(val1, val2, level) \
HANDLE_WARNING_LEVEL(level, EXPECT_GT(val1, val2), val1, val2, >)
#define SDV_ASSERT_GT(val1, val2, level) \
HANDLE_WARNING_LEVEL(level, ASSERT_GT(val1, val2), val1, val2, >)
#define SDV_EXPECT_GE(val1, val2, level) \
HANDLE_WARNING_LEVEL(level, EXPECT_GE(val1, val2), val1, val2, >=)
#define SDV_ASSERT_GE(val1, val2, level) \
HANDLE_WARNING_LEVEL(level, ASSERT_GE(val1, val2), val1, val2, >=)
#define SDV_EXPECT_STREQ(str1, str2, level) \
HANDLE_WARNING_LEVEL(level, EXPECT_STREQ((str1).c_str(), (str2).c_str()), str1, str2, ==)
#define SDV_ASSERT_STREQ(str1, str2, level) \
HANDLE_WARNING_LEVEL(level, ASSERT_STREQ((str1).c_str(), (str2).c_str()), str1, str2, ==)
#define SDV_EXPECT_STRNE(str1, str2, level) \
HANDLE_WARNING_LEVEL(level, EXPECT_STRNE(str1.c_str(), str2.c_str()), str1, str2, !=)
#define SDV_ASSERT_STRNE(str1, str2, level) \
HANDLE_WARNING_LEVEL(level, ASSERT_STRNE(str1.c_str(), str2.c_str()), str1, str2, !=)
#define SDV_EXPECT_STRCASEEQ(str1, str2, level) \
HANDLE_WARNING_LEVEL(level, EXPECT_STRCASEEQ((str1).c_str(), (str2).c_str()), str1, str2, ==)
#define SDV_ASSERT_STRCASEEQ(str1, str2, level) \
HANDLE_WARNING_LEVEL(level, ASSERT_STRCASEEQ((str1).c_str(), (str2).c_str()), str1, str2, ==)
#define SDV_EXPECT_STRCASENE(str1, str2, level) \
HANDLE_WARNING_LEVEL(level, EXPECT_STRCASENE((str1).c_str(), (str2).c_str()), str1, str2, !=)
#define SDV_ASSERT_STRCASENE(str1, str2, level) \
HANDLE_WARNING_LEVEL(level, ASSERT_STRCASENE((str1).c_str(), (str2).c_str()), str1, str2, !=)
/**
* @brief Macro for equality check (==) with warning reporting for time critical tests.
* @param[in] val1 The first value.
* @param[in] val2 The second value.
* @param[in] warningLevel The level of warning to display.
*/
#define SDV_TIMING_EXPECT_EQ(val1, val2, warningLevel) \
sdv::TEST::ReportWarning((val1) == (val2), warningLevel, \
"Expected " #val1 " == " #val2 " (" #val1 "=" + std::to_string(val1) + ", " #val2 "=" + std::to_string(val2) + ")", \
__FILE__, __LINE__)
/**
* @brief Macro for inequality check (!=) with warning reporting for time critical tests.
* @param[in] val1 The first value.
* @param[in] val2 The second value.
* @param[in] warningLevel The level of warning to display.
*/
#define SDV_TIMING_EXPECT_NE(val1, val2, warningLevel) \
sdv::TEST::ReportWarning((val1) != (val2), warningLevel, \
"Expected " #val1 " != " #val2 " (" #val1 "=" + std::to_string(val1) + ", " #val2 "=" + std::to_string(val2) + ")", \
__FILE__, __LINE__)
/**
* @brief Macro for greater-than check (>) with warning reporting for time critical tests.
* @param[in] val1 The first value.
* @param[in] val2 The second value.
* @param[in] warningLevel The level of warning to display.
*/
#define SDV_TIMING_EXPECT_GT(val1, val2, warningLevel) \
sdv::TEST::ReportWarning((val1) > (val2), warningLevel, \
"Expected " #val1 " > " #val2 " (" #val1 "=" + std::to_string(val1) + ", " #val2 "=" + std::to_string(val2) + ")", \
__FILE__, __LINE__)
/**
* @brief Macro for less-than check (<) with warning reporting for time critical tests.
* @param[in] val1 The first value.
* @param[in] val2 The second value.
* @param[in] warningLevel The level of warning to display.
*/
#define SDV_TIMING_EXPECT_LT(val1, val2, warningLevel) \
sdv::TEST::ReportWarning((val1) < (val2), warningLevel, \
"Expected " #val1 " < " #val2 " (" #val1 "=" + std::to_string(val1) + ", " #val2 "=" + std::to_string(val2) + ")", \
__FILE__, __LINE__)
/**
* @brief Macro for greater-than-or-equal-to check (>=) with warning reporting for time critical tests.
* @param[in] val1 The first value.
* @param[in] val2 The second value.
* @param[in] warningLevel The level of warning to display.
*/
#define SDV_TIMING_EXPECT_GE(val1, val2, warningLevel) \
sdv::TEST::ReportWarning((val1) >= (val2), warningLevel, \
"Expected " #val1 " >= " #val2 " (" #val1 "=" + std::to_string(val1) + ", " #val2 "=" + std::to_string(val2) + ")", \
__FILE__, __LINE__)
/**
* @brief Macro for less-than-or-equal-to check (<=) with warning reporting for time critical tests.
* @param[in] val1 The first value.
* @param[in] val2 The second value.
* @param[in] warningLevel The level of warning to display.
*/
#define SDV_TIMING_EXPECT_LE(val1, val2, warningLevel) \
sdv::TEST::ReportWarning((val1) <= (val2), warningLevel, \
"Expected " #val1 " <= " #val2 " (" #val1 "=" + std::to_string(val1) + ", " #val2 "=" + std::to_string(val2) + ")", \
__FILE__, __LINE__)
#endif // SDV_TEST_MACRO_H

596
export/support/sequence.h Normal file
View File

@@ -0,0 +1,596 @@
#ifndef SDV_SEQUENCE_H
#define SDV_SEQUENCE_H
#include <vector>
#include <algorithm>
#include <limits>
#include "iterator.h"
#include "pointer.h"
namespace sdv
{
/**
* @brief Managed sequence class.
* @details Sequence management class. A sequence provides a dynamic vector based on a buffer implementation of the ptr-class.
* There are two versions of buffer management, fixed buffer management (nFixedSize template parameter larger than 0) and
* dynamic buffer management (nFixedSize template parameter is 0). The functions of this class are similar to the functions of
* the std::vector class.
* @tparam T Type to use for the buffer allocation.
* @tparam nFixedSize Size of the fixed size buffer or 0 for a dynamic sized buffer.
*/
template <class T, size_t nFixedSize = 0>
class sequence
{
public:
/**
* @brief Value type for this sequence class.
*/
using value_type = T;
/**
* @brief Forward iterator class used by this sequence class.
*/
using iterator = internal::index_iterator<sequence<T, nFixedSize>, false, false>;
/**
* @brief Backward iterator class used by this sequence class.
*/
using reverse_iterator = internal::index_iterator<sequence<T, nFixedSize>, false, true>;
/**
* @brief Const forward iterator class used by this sequence class.
*/
using const_iterator = internal::index_iterator<sequence<T, nFixedSize>, true, false>;
/**
* @brief Const backward iterator class used by this sequence class.
*/
using const_reverse_iterator = internal::index_iterator<sequence<T, nFixedSize>, true, true>;
/**
* @brief Reference type of the element.
*/
using reference = T&;
/**
* @brief Const reference type of the element.
*/
using const_reference = const T&;
/**
* @brief Default constructor
*/
sequence() noexcept;
/**
* @brief Destructor
*/
~sequence();
/**
* @brief Construct a sequence with a certain amount of values.
* @param[in] nCount The amount of values to create.
* @param[in] rtValue Reference to the value to use for the initialization.
*/
sequence(size_t nCount, const T& rtValue);
/**
* @brief Construct a sequence with a certain amount of values.
* @param[in] nCount The amount of values to create.
*/
explicit sequence(size_t nCount);
/**
* @brief Construct a sequence from a range of values accessible through iterators.
* @tparam TIterator Type of iterator.
* @param[in] itFirst The iterator pointing to the itFirst value.
* @param[in] itLast The iterator pointing to the value past the itLast value.
*/
template <class TIterator>
sequence(TIterator itFirst, TIterator itLast);
/**
* @brief Copy constructor of same sequence type.
* @param[in] rseq Reference to the sequence containing the values to copy.
*/
sequence(const sequence& rseq);
/**
* @brief Copy constructor of other sequence types.
* @tparam nFixedSize2 The fixed size of the provided sequence.
* @param[in] rseq Reference to the sequence containing the values to copy.
*/
template <size_t nFixedSize2>
sequence(const sequence<T, nFixedSize2>& rseq);
/**
* @brief Move constructor of same sequence type.
* @param[in] rseq Reference to the sequence to move the values from.
*/
sequence(sequence&& rseq) noexcept;
/**
* @brief Move constructor of other sequence types.
* @tparam nFixedSize2 The fixed size of the provided sequence.
* @param[in] rseq Reference to the sequence to move the values from.
*/
template <size_t nFixedSize2>
sequence(sequence<T, nFixedSize2>&& rseq) noexcept;
/**
* @brief Construct a sequence from a vector.
* @param[in] rvec Reference to the sequence.
*/
sequence(std::vector<T>& rvec);
/**
* @brief Construct a sequence from an initializer list.
* @param[in] ilist Initializer list.
*/
sequence(std::initializer_list<T> ilist);
/**
* @brief Assignment operator of same sequence type.
* @param[in] rseq Reference to the sequence.
* @return Reference to this sequence.
*/
sequence& operator=(const sequence& rseq);
/**
* @brief Assignment operator of other sequence types.
* @tparam nFixedSize2 The fixed size of the provided sequence.
* @param[in] rseq Reference to the sequence.
* @return Reference to this sequence.
*/
template <size_t nFixedSize2>
sequence& operator=(const sequence<T, nFixedSize2>& rseq);
/**
* @brief Move operator of same sequence type.
* @param[in] rseq Reference to the sequence.
* @return Reference to this sequence.
*/
sequence& operator=(sequence&& rseq) noexcept;
/**
* @brief Move operator of other sequence types.
* @tparam nFixedSize2 The fixed size of the provided sequence.
* @param[in] rseq Reference to the sequence.
* @return Reference to this sequence.
*/
template <size_t nFixedSize2>
sequence& operator=(sequence<T, nFixedSize2>&& rseq) noexcept;
/**
* @brief Assignment operator for vector.
* @param[in] rvec Reference to the vector.
* @return Reference to this sequence.
*/
sequence& operator=(const std::vector<T>& rvec);
/**
* @brief Assignment operator for initializer list.
* @param[in] ilist Initializer list.
* @return Reference to this sequence.
*/
sequence& operator=(std::initializer_list<T> ilist);
/**
* @brief Assign an amount of values to the sequence replacing the values existing before.
* @param[in] nCount Amount of values to assign.
* @param[in] rtValue Reference to the value to assign.
*/
void assign(size_t nCount, const T& rtValue);
/**
* @brief Assign an amount of values pointed to by itFirst and itLast iterators replacing the values existing before.
* @tparam TIterator Type of iterator.
* @param[in] itFirst The iterator pointing to the itFirst value.
* @param[in] itLast The iterator pointing to the value past the itLast value.
*/
template <class TIterator>
void assign(TIterator itFirst, TIterator itLast);
/**
* @brief Assign the values from an initializer list.
* @param[in] ilist Initializer list.
*/
void assign(std::initializer_list<T> ilist);
/**
* @brief Return a reference to the value at the specified position.
* @param[in] nPos The specified position.
* @return Reference to the value.
*/
reference at(size_t nPos);
/**
* @brief Return a reference to the value at the specified position.
* @param[in] nPos The specified position.
* @return Reference to the value.
*/
const_reference at(size_t nPos) const;
/**
* @brief Return a reference to the value at the specified position.
* @param[in] nPos The specified position.
* @return Reference to the value.
*/
reference operator[](size_t nPos);
/**
* @brief Return a reference to the value at the specified position.
* @param[in] nPos The specified position.
* @return Reference to the value.
*/
const_reference operator[](size_t nPos) const;
/**
* @brief Return a reference to the itFirst value.
* @return Reference to the value.
*/
T& front();
/**
* @brief Return a reference to the itFirst value.
* @return Reference to the value.
*/
const T& front() const;
/**
* @brief Return a reference to the itLast value.
* @return Reference to the value.
*/
T& back();
/**
* @brief Return a reference to the itLast value.
* @return Reference to the value.
*/
const T& back() const;
/**
* @brief Cast operator for C++ vector
* @return Returns a C++ vector object containing a copy of the sequence.
*/
operator std::vector<T>() const;
/**
* @brief Access to the underlying data.
* @return Pointer to the data.
*/
const T* data() const noexcept;
/**
* @brief Access to the buffer.
* @return Return a reference to the internal buffer.
*/
pointer<T, nFixedSize>& buffer() noexcept;
/**
* @brief Return an iterator to the itFirst value of the sequence.
* @return Iterator to the itFirst value of te sequence.
*/
iterator begin() noexcept;
/**
* @brief Return an iterator to the itFirst value of the sequence.
* @return Iterator to the itFirst value of te sequence.
*/
const_iterator begin() const noexcept;
/**
* @brief Return a const iterator to the itFirst value of the sequence.
* @return Const iterator to the itFirst value of te sequence.
*/
const_iterator cbegin() const noexcept;
/**
* @brief Return a reverse-iterator to the itLast value of the sequence.
* @return Reverse iterator to the itLast value of te sequence.
*/
reverse_iterator rbegin() noexcept;
/**
* @brief Return a reverse-iterator to the itLast value of the sequence.
* @return Reverse iterator to the itLast value of te sequence.
*/
const_reverse_iterator rbegin() const noexcept;
/**
* @brief Return a const reverse iterator to the itLast value of the sequence.
* @return Const reverse iterator to the itLast value of te sequence.
*/
const_reverse_iterator crbegin() const noexcept;
/**
* @brief Return an iterator beyond the itLast value of the sequence.
* @return Iterator beyond the itLast value of te sequence.
*/
iterator end() noexcept;
/**
* @brief Return an iterator beyond the itLast value of the sequence.
* @return Iterator beyond the itLast value of te sequence.
*/
const_iterator end() const noexcept;
/**
* @brief Return a const beyond the itLast value of the sequence.
* @return Const iterator beyond the itLast value of te sequence.
*/
const_iterator cend() const noexcept;
/**
* @brief Return a reverse iterator before the itFirst value of the sequence.
* @return Reverse iterator before the itLast value of te sequence.
*/
reverse_iterator rend() noexcept;
/**
* @brief Return a reverse iterator before the itFirst value of the sequence.
* @return Reverse iterator before the itLast value of te sequence.
*/
const_reverse_iterator rend() const noexcept;
/**
* @brief Return a const reverse iterator before the itFirst value of the sequence.
* @return Const reverse iterator before the itLast value of te sequence.
*/
const_reverse_iterator crend() const noexcept;
/**
* @brief Is the sequence empty?
* @return Returns 'true' when the sequence is empty; 'false' when not.
*/
bool empty() const;
/**
* @brief Get the size of the sequence.
* @remarks The length and the size for the sequence are equal.
* @return The size of the sequence buffer.
*/
size_t size() const;
/**
* @brief Get the length of the sequence.
* @remarks The length and the size for the sequence are equal.
* @return The length of the sequence.
*/
size_t length() const;
/**
* @brief Reserve capacity for the sequence buffer. Additional buffer will be filled with zeros.
* @remarks Reducing the capacity will have no effect.
* @param[in] nNewCap The new capacity.
*/
void reserve(size_t nNewCap = 0);
/**
* @brief Get the current sequence capacity.
* @remarks This will be the same as the length and size of the sequence.
* @return The capacity of the current sequence.
*/
size_t capacity() const noexcept;
/**
* @brief Reduce the buffer to fit the sequence.
* @remarks This function will have no effect.
*/
void shrink_to_fit();
/**
* @brief Clear the sequence.
*/
void clear();
/**
* @brief Insert a value rtValue at the position itPos.
* @param[in] itPos Iterator pointing to the position to insert the value.
* @param[in] rtValue Reference to the value to insert.
* @return The iterator pointing to the inserted value.
*/
iterator insert(const_iterator itPos, const T& rtValue);
/**
* @brief Insert a value rtValue at the position itPos.
* @param[in] itPos Iterator pointing to the position to insert the value.
* @param[in] rtValue Reference to the value to insert.
* @return The iterator pointing to the inserted value.
*/
iterator insert(const_iterator itPos, T&& rtValue);
/**
* @brief Insert an amount of values rtValue at the position itPos.
* @param[in] itPos Iterator pointing to the position to insert the value.
* @param[in] nCount The amount of values to insert.
* @param[in] rtValue Reference to the value to insert.
* @return The iterator pointing to the itFirst inserted value.
*/
iterator insert(const_iterator itPos, size_t nCount, const T& rtValue);
/**
* @brief Insert a range of vvalues identified by the supplied iterators.
* @tparam TIterator Iterator type to use.
* @param[in] itPos Iterator pointing to the position to insert the value.
* @param[in] itFirst The iterator pointing to the itFirst value.
* @param[in] itLast The iterator pointing to the value past the itLast value.
* @return The iterator pointing to the itFirst inserted value.
*/
template <class TIterator>
iterator insert(const_iterator itPos, TIterator itFirst, TIterator itLast);
/**
* @brief Insert an initializer list at the position itPos.
* @param[in] itPos Iterator pointing to the position to insert the value.
* @param[in] ilist Initializer list.
* @return The iterator pointing to the itFirst inserted value.
*/
iterator insert(const_iterator itPos, std::initializer_list<T> ilist);
/**
* @brief Remove a value at the provided position.
* @remarks The iterator must point to this sequence.
* @param[in] itPos Iterator pointing to the position to erase the value from.
* @return Iterator to the value following the erase value or end() when no more values are available.
*/
iterator erase(iterator itPos);
/**
* @brief Remove a value at the provided position.
* @remarks The iterator must point to this sequence.
* @param[in] itPos Iterator pointing to the position to erase the value from.
* @return Iterator to the value following the erase value or end() when no more values are available.
*/
iterator erase(const_iterator itPos);
/**
* @brief Remove al values starting at itFirst until but not including itLast.
* @remarks Both iterators must point to this sequence.
* @param[in] itFirst The iterator pointing to the itFirst value.
* @param[in] itLast The iterator pointing to the value past the itLast value.
* @return Iterator to the value following the erased values or end() when no more values are available.
*/
iterator erase(iterator itFirst, iterator itLast);
/**
* @brief Remove al values starting at itFirst until but not including itLast.
* @remarks Both iterators must point to this sequence.
* @param[in] itFirst The iterator pointing to the itFirst value.
* @param[in] itLast The iterator pointing to the value past the itLast value.
* @return Iterator to the value following the erased values or end() when no more values are available.
*/
iterator erase(const_iterator itFirst, const_iterator itLast);
/**
* @brief Appends the given value to the end of the sequence.
* @param[in] rtValue Reference to the value to append.
*/
void push_back(const T& rtValue);
/**
* @brief Appends the given value to the end of the sequence.
* @param[in] rtValue Reference to the value to append.
*/
void push_back(T&& rtValue);
/**
* @brief Removes the itLast value from the sequence.
*/
void pop_back();
/**
* @brief Set the new size of the sequence.
* @param[in] nCount The size of the sequence buffer.
*/
void resize(size_t nCount);
/**
* @brief Set the new size of the sequence. Additional values will be filled with rtValue.
* @param[in] nCount The size of the sequence buffer.
* @param[in] rtValue Reference to the value to use for initialization.
*/
void resize(size_t nCount, const value_type& rtValue);
/**
* @brief Exchange the content of provided sequence with this sequence.
* @tparam nFixedSize2 The fixed size of the provided sequence.
* @param[in] rseq Reference to the sequence to swap with.
*/
template <size_t nFixedSize2>
void swap(sequence<T, nFixedSize2>& rseq) noexcept;
private:
pointer<T, nFixedSize> m_ptrData; ///< Smart pointer to the data.
};
/**
* @brief Swap two sequences.
* @tparam T Type to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left sequence.
* @tparam nFixedSizeRight The fixed size of the right sequence.
* @param[in] rseqLeft Reference to the first sequence.
* @param[in] rseqRight Reference to the second sequence.
*/
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
void swap(sequence<T, nFixedSizeLeft>& rseqLeft, sequence<T, nFixedSizeRight>& rseqRight) noexcept;
/**
* @brief Compare whether the content of both sequences is identical.
* @tparam T Type to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left sequence.
* @tparam nFixedSizeRight The fixed size of the right sequence.
* @param[in] rseqLeft Reference to the first sequence.
* @param[in] rseqRight Reference to the second sequence.
* @return Returns whether the comparison was successful.
*/
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
bool operator==(const sequence<T, nFixedSizeLeft>& rseqLeft, const sequence<T, nFixedSizeRight>& rseqRight);
/**
* @brief Compare whether the content of both sequences is not identical.
* @tparam T Type to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left sequence.
* @tparam nFixedSizeRight The fixed size of the right sequence.
* @param[in] rseqLeft Reference to the first sequence.
* @param[in] rseqRight Reference to the second sequence.
* @return Returns whether the comparison was successful.
*/
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
bool operator!=(const sequence<T, nFixedSizeLeft>& rseqLeft, const sequence<T, nFixedSizeRight>& rseqRight);
/**
* @brief Compare whether the left sequence has a lower content than the right sequence or if equal, has a smaller size.
* @tparam T Type to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left sequence.
* @tparam nFixedSizeRight The fixed size of the right sequence.
* @param[in] rseqLeft Reference to the left sequence.
* @param[in] rseqRight Reference to the right sequence.
* @return Returns whether the comparison was successful.
*/
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
bool operator<(const sequence<T, nFixedSizeLeft>& rseqLeft, const sequence<T, nFixedSizeRight>& rseqRight);
/**
* @brief Compare whether the left sequence has a lower or equal content than the right sequence or if equal, has a smaller
* or equal size.
* @tparam T Type to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left sequence.
* @tparam nFixedSizeRight The fixed size of the right sequence.
* @param[in] rseqLeft Reference to the left sequence.
* @param[in] rseqRight Reference to the right sequence.
* @return Returns whether the comparison was successful.
*/
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
bool operator<=(const sequence<T, nFixedSizeLeft>& rseqLeft, const sequence<T, nFixedSizeRight>& rseqRight);
/**
* @brief Compare whether the left sequence has a higher content than the right sequence or if equal, has a larger size.
* @tparam T Type to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left sequence.
* @tparam nFixedSizeRight The fixed size of the right sequence.
* @param[in] rseqLeft Reference to the left sequence.
* @param[in] rseqRight Reference to the right sequence.
* @return Returns whether the comparison was successful.
*/
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
bool operator>(const sequence<T, nFixedSizeLeft>& rseqLeft, const sequence<T, nFixedSizeRight>& rseqRight);
/**
* @brief Compare whether the left sequence has a higher or equal content than the right sequence or if equal, has a larger
* or equal size.
* @tparam T Type to use as a base.
* @tparam nFixedSizeLeft The fixed size of the left sequence.
* @tparam nFixedSizeRight The fixed size of the right sequence.
* @param[in] rseqLeft Reference to the left sequence.
* @param[in] rseqRight Reference to the right sequence.
* @return Returns whether the comparison was successful.
*/
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
bool operator>=(const sequence<T, nFixedSizeLeft>& rseqLeft, const sequence<T, nFixedSizeRight>& rseqRight);
} // namespace sdv
#include "sequence.inl"
#endif // !defined SDV_SEQUENCE_H

713
export/support/sequence.inl Normal file
View File

@@ -0,0 +1,713 @@
#ifndef SDV_SEQUENCE_INL
#define SDV_SEQUENCE_INL
#ifndef SDV_SEQUENCE_H
#error Do not include "sequence.inl" directly. Include "sequence.h" instead!
#endif //!defined SDV_SEQUENCE_H
namespace sdv
{
template <class T, size_t nFixedSize>
inline sequence<T, nFixedSize>::sequence() noexcept
{}
template <class T, size_t nFixedSize>
sequence<T, nFixedSize>::~sequence()
{
clear();
}
template <class T, size_t nFixedSize>
inline sequence<T, nFixedSize>::sequence(size_t nCount, const T& rtValue) : sequence()
{
insert(begin(), nCount, rtValue);
}
template <class T, size_t nFixedSize>
inline sequence<T, nFixedSize>::sequence(size_t nCount) : sequence()
{
T t{};
insert(begin(), nCount, t);
}
template <class T, size_t nFixedSize>
template <class TIterator>
inline sequence<T, nFixedSize>::sequence(TIterator itFirst, TIterator itLast) : sequence()
{
insert(begin(), itFirst, itLast);
}
template <class T, size_t nFixedSize>
inline sequence<T, nFixedSize>::sequence(const sequence& rseq) : sequence()
{
if (!rseq.empty())
{
resize(rseq.size());
if (m_ptrData)
std::copy_n(rseq.data(), std::min(rseq.size(), size()), m_ptrData.get());
}
}
/// @cond DOXYGEN_IGNORE
template <class T, size_t nFixedSize>
template <size_t nFixedSize2>
inline sequence<T, nFixedSize>::sequence(const sequence<T, nFixedSize2>& rseq) : sequence()
{
if (!rseq.empty())
{
resize(rseq.size());
if (m_ptrData)
std::copy_n(rseq.data(), std::min(rseq.size(), size()), m_ptrData.get());
}
}
/// @endcond
template <class T, size_t nFixedSize>
inline sequence<T, nFixedSize>::sequence(sequence&& rseq) noexcept : sequence()
{
m_ptrData = std::move(rseq.m_ptrData);
}
/// @cond DOXYGEN_IGNORE
template <class T, size_t nFixedSize>
template <size_t nFixedSize2>
inline sequence<T, nFixedSize>::sequence(sequence<T, nFixedSize2>&& rseq) noexcept : sequence()
{
m_ptrData = std::move(rseq.buffer());
}
/// @endcond
template <class T, size_t nFixedSize>
inline sequence<T, nFixedSize>::sequence(std::vector<T>& rvec) : sequence()
{
if (!rvec.empty())
{
resize(rvec.size());
if (m_ptrData)
std::copy_n(rvec.data(), std::min(rvec.size(), size()), m_ptrData.get());
}
}
template <class T, size_t nFixedSize>
inline sequence<T, nFixedSize>::sequence(std::initializer_list<T> ilist) : sequence()
{
insert(begin(), ilist);
}
template <class T, size_t nFixedSize>
inline sequence<T, nFixedSize>& sequence<T, nFixedSize>::operator=(const sequence& rseq)
{
clear();
if (!rseq.empty())
{
resize(rseq.size());
if (m_ptrData)
std::copy_n(rseq.data(), std::min(rseq.size(), size()), m_ptrData.get());
}
return *this;
}
/// @cond DOXYGEN_IGNORE
template <class T, size_t nFixedSize>
template <size_t nFixedSize2>
inline sequence<T, nFixedSize>& sequence<T, nFixedSize>::operator=(const sequence<T, nFixedSize2>& rseq)
{
clear();
if (!rseq.empty())
{
resize(rseq.size());
if (m_ptrData)
std::copy_n(rseq.data(), std::min(rseq.size(), size()), m_ptrData.get());
}
return *this;
}
/// @endcond
/// @cond DOXYGEN_IGNORE
template <class T, size_t nFixedSize>
template <size_t nFixedSize2>
inline sequence<T, nFixedSize>& sequence<T, nFixedSize>::operator=(sequence<T, nFixedSize2>&& rseq) noexcept
{
clear();
m_ptrData = std::move(rseq.buffer());
return *this;
}
/// @endcond
template <class T, size_t nFixedSize>
inline sequence<T, nFixedSize>& sequence<T, nFixedSize>::operator=(sequence&& rseq) noexcept
{
clear();
m_ptrData = std::move(rseq.m_ptrData);
return *this;
}
template <class T, size_t nFixedSize>
inline sequence<T, nFixedSize>& sequence<T, nFixedSize>::operator=(const std::vector<T>& rvec)
{
clear();
if (!rvec.empty())
{
resize(rvec.size());
if (m_ptrData)
std::copy_n(rvec.data(), std::min(rvec.size(), size()), m_ptrData.get());
}
return *this;
}
template <class T, size_t nFixedSize>
inline sequence<T, nFixedSize>& sequence<T, nFixedSize>::operator=(std::initializer_list<T> ilist)
{
clear();
insert(begin(), ilist);
return *this;
}
template <class T, size_t nFixedSize>
inline void sequence<T, nFixedSize>::assign(size_t nCount, const T& rtValue)
{
clear();
insert(begin(), nCount, rtValue);
}
template <class T, size_t nFixedSize>
template <class TIterator>
inline void sequence<T, nFixedSize>::assign(TIterator itFirst, TIterator itLast)
{
clear();
insert(begin(), itFirst, itLast);
}
template <class T, size_t nFixedSize>
inline void sequence<T, nFixedSize>::assign(std::initializer_list<T> ilist)
{
clear();
insert(begin(), ilist);
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::reference sequence<T, nFixedSize>::at(size_t nPos)
{
if (nPos >= size())
{
XIndexOutOfRange exception;
exception.uiIndex = static_cast<uint32_t>(nPos);
exception.uiSize = static_cast<uint32_t>(size());
throw exception;
}
return m_ptrData[nPos];
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::const_reference sequence<T, nFixedSize>::at(size_t nPos) const
{
if (nPos >= size())
{
XIndexOutOfRange exception;
exception.uiIndex = static_cast<uint32_t>(nPos);
exception.uiSize = static_cast<uint32_t>(size());
throw exception;
}
return m_ptrData[nPos];
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::reference sequence<T, nFixedSize>::operator[](size_t nPos)
{
if (nPos >= size())
{
XIndexOutOfRange exception;
exception.uiIndex = static_cast<uint32_t>(nPos);
exception.uiSize = static_cast<uint32_t>(size());
throw exception;
}
return m_ptrData[nPos];
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::const_reference sequence<T, nFixedSize>::operator[](size_t nPos) const
{
if (nPos >= size())
{
XIndexOutOfRange exception;
exception.uiIndex = static_cast<uint32_t>(nPos);
exception.uiSize = static_cast<uint32_t>(size());
throw exception;
}
return m_ptrData[nPos];
}
template <class T, size_t nFixedSize>
inline T& sequence<T, nFixedSize>::front()
{
if (!size())
{
XIndexOutOfRange exception;
exception.uiIndex = static_cast<uint32_t>(0);
exception.uiSize = static_cast<uint32_t>(size());
throw exception;
}
return m_ptrData[0];
}
template <class T, size_t nFixedSize>
inline const T& sequence<T, nFixedSize>::front() const
{
if (!size())
{
XIndexOutOfRange exception;
exception.uiIndex = static_cast<uint32_t>(0);
exception.uiSize = static_cast<uint32_t>(size());
throw exception;
}
return m_ptrData[0];
}
template <class T, size_t nFixedSize>
inline T& sequence<T, nFixedSize>::back()
{
if (!size())
{
XIndexOutOfRange exception;
exception.uiIndex = static_cast<uint32_t>(0);
exception.uiSize = static_cast<uint32_t>(size());
throw exception;
}
return m_ptrData[size() - 1];
}
template <class T, size_t nFixedSize>
inline const T& sequence<T, nFixedSize>::back() const
{
if (!size())
{
XIndexOutOfRange exception;
exception.uiIndex = static_cast<uint32_t>(0);
exception.uiSize = static_cast<uint32_t>(size());
throw exception;
}
return m_ptrData[size() - 1];
}
template <class T, size_t nFixedSize>
inline sequence<T, nFixedSize>::operator std::vector<T>() const
{
std::vector<T> vec;
if (size())
{
try
{
vec.resize(size());
}
catch (const std::bad_alloc&)
{
core::XAllocFailed exception;
exception.uiSize = static_cast<uint32_t>(size() * sizeof(T));
throw exception;
}
std::copy_n(data(), std::min(size(), vec.size()), &vec.front());
}
return vec;
}
template <class T, size_t nFixedSize>
inline const T* sequence<T, nFixedSize>::data() const noexcept
{
return m_ptrData.get();
}
template <class T, size_t nFixedSize>
inline pointer<T, nFixedSize>& sequence<T, nFixedSize>::buffer() noexcept
{
return m_ptrData;
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::iterator sequence<T, nFixedSize>::begin() noexcept
{
return iterator(this);
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::const_iterator sequence<T, nFixedSize>::begin() const noexcept
{
return iterator(this);
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::const_iterator sequence<T, nFixedSize>::cbegin() const noexcept
{
return const_iterator(this);
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::reverse_iterator sequence<T, nFixedSize>::rbegin() noexcept
{
return reverse_iterator(this);
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::const_reverse_iterator sequence<T, nFixedSize>::rbegin() const noexcept
{
return reverse_iterator(this);
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::const_reverse_iterator sequence<T, nFixedSize>::crbegin() const noexcept
{
return const_reverse_iterator(this);
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::iterator sequence<T, nFixedSize>::end() noexcept
{
iterator it(this);
it += std::numeric_limits<size_t>::max();
return it;
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::const_iterator sequence<T, nFixedSize>::end() const noexcept
{
iterator it(this);
it += std::numeric_limits<size_t>::max();
return it;
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::const_iterator sequence<T, nFixedSize>::cend() const noexcept
{
const_iterator it(this);
it += std::numeric_limits<size_t>::max();
return it;
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::reverse_iterator sequence<T, nFixedSize>::rend() noexcept
{
reverse_iterator it(this);
it += std::numeric_limits<size_t>::max();
return it;
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::const_reverse_iterator sequence<T, nFixedSize>::rend() const noexcept
{
reverse_iterator it(this);
it += std::numeric_limits<size_t>::max();
return it;
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::const_reverse_iterator sequence<T, nFixedSize>::crend() const noexcept
{
const_reverse_iterator it(this);
it += std::numeric_limits<size_t>::max();
return it;
}
template <class T, size_t nFixedSize>
inline bool sequence<T, nFixedSize>::empty() const
{
return !size();
}
template <class T, size_t nFixedSize>
inline size_t sequence<T, nFixedSize>::size() const
{
return m_ptrData.size();
}
template <class T, size_t nFixedSize>
inline size_t sequence<T, nFixedSize>::length() const
{
return m_ptrData.size();
}
template <class T, size_t nFixedSize>
inline void sequence<T, nFixedSize>::reserve(size_t nNewCap /*= 0*/)
{
if (nNewCap > size())
resize(nNewCap);
}
template <class T, size_t nFixedSize>
inline size_t sequence<T, nFixedSize>::capacity() const noexcept
{
return m_ptrData.capacity();
}
template <class T, size_t nFixedSize>
inline void sequence<T, nFixedSize>::shrink_to_fit()
{
// Do nothing...
}
template <class T, size_t nFixedSize>
inline void sequence<T, nFixedSize>::clear()
{
m_ptrData.reset();
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::iterator sequence<T, nFixedSize>::insert(const_iterator itPos, const T& rtValue)
{
return insert(itPos, static_cast<size_t>(1), rtValue);
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::iterator sequence<T, nFixedSize>::insert(const_iterator itPos, T&& rtValue)
{
T t{};
insert(itPos, static_cast<size_t>(1), t);
iterator it = itPos;
*it = std::move(rtValue);
return it;
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::iterator sequence<T, nFixedSize>::insert(const_iterator itPos, size_t nCount, const T& rtValue)
{
if (!itPos.is_valid(*this)) throw XInvalidIterator();
// Determine location
size_t nIndex = 0;
if (itPos == cend())
nIndex = size();
else if (!empty())
nIndex = &itPos[0] - data();
// Calculate count
size_t nCountTemp = nCount;
size_t nCurrentLen = size();
if (nFixedSize && nCurrentLen + nCountTemp > nFixedSize)
nCountTemp = nFixedSize - nCurrentLen;
if (!nCountTemp) return iterator(itPos);;
// Allocate space for a new sequence.
m_ptrData.resize(nCurrentLen + nCountTemp);
// Copy the part following the index.
if (nIndex < nCurrentLen)
std::copy_backward(data() + nIndex, data() + nCurrentLen, m_ptrData.get() + nCurrentLen + nCountTemp);
// Insert the values
if (nCountTemp) std::fill_n(m_ptrData.get() + std::min(nIndex, nCurrentLen), nCountTemp, rtValue);
return iterator(itPos);
}
template <class T, size_t nFixedSize>
template <class TIterator>
inline typename sequence<T, nFixedSize>::iterator sequence<T, nFixedSize>::insert(const_iterator itPos, TIterator itFirst, TIterator itLast)
{
if (!itPos.is_valid(*this)) throw XInvalidIterator();
// Count the amount of entries to insert
size_t nCount = 0;
for (TIterator itIndex = itFirst; itIndex != itLast; itIndex++)
nCount++;
// Determine location
size_t nIndex = 0;
if (itPos == cend())
nIndex = size();
else if (!empty())
nIndex = &itPos[0] - data();
// Calculate count
size_t nCountTemp = nCount;
size_t nCurrentLen = size();
if (nFixedSize && nCurrentLen + nCountTemp > nFixedSize)
nCountTemp = nFixedSize - nCurrentLen;
if (!nCountTemp) return iterator(itPos);;
// Allocate space for a new sequence.
m_ptrData.resize(nCurrentLen + nCountTemp);
// Copy the part following the index.
if (nIndex < nCurrentLen)
std::copy_backward(data() + nIndex, data() + nCurrentLen, m_ptrData.get() + nCurrentLen + nCountTemp);
// Copy the data
for (TIterator itIndex = itFirst; itIndex != itLast; itIndex++)
at(nIndex++) = *itIndex;
return iterator(itPos);
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::iterator sequence<T, nFixedSize>::insert(const_iterator itPos, std::initializer_list<T> ilist)
{
if (!itPos.is_valid(*this)) throw XInvalidIterator();
return insert(itPos, ilist.begin(), ilist.end());
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::iterator sequence<T, nFixedSize>::erase(iterator itPos)
{
erase(itPos, itPos + 1);
return itPos;
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::iterator sequence<T, nFixedSize>::erase(const_iterator itPos)
{
erase(itPos, itPos + 1);
return itPos;
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::iterator sequence<T, nFixedSize>::erase(iterator itFirst, iterator itLast)
{
erase(const_iterator(itFirst), const_iterator(itLast));
return itFirst;
}
template <class T, size_t nFixedSize>
inline typename sequence<T, nFixedSize>::iterator sequence<T, nFixedSize>::erase(const_iterator itFirst, const_iterator itLast)
{
if (!itFirst.is_valid(*this)) throw XInvalidIterator();
if (!itLast.is_valid(*this)) throw XInvalidIterator();
if (empty()) return cbegin(); // Nothing to do
if (itFirst == cend()) return cbegin(); // Nothing to do
if (itFirst == itLast) return itFirst; // Nothing to do
// Determine location
size_t nIndex = &itFirst[0] - data();
size_t nCount = itLast == cend() ? (size() - nIndex) : (&itLast[0] - &itFirst[0]);
// Copy any leftover characters
if (nCount < size() && nIndex + nCount < size())
{
std::copy_n(m_ptrData.get() + nIndex + nCount, size() - nIndex - nCount, m_ptrData.get() + nIndex);
resize(size() - nCount);
}
else
resize(nIndex);
return itFirst;
}
template <class T, size_t nFixedSize>
inline void sequence<T, nFixedSize>::push_back(const T& rtValue)
{
insert(end(), rtValue);
}
template <class T, size_t nFixedSize>
inline void sequence<T, nFixedSize>::push_back(T&& rtValue)
{
insert(end(), std::move(rtValue));
}
template <class T, size_t nFixedSize>
inline void sequence<T, nFixedSize>::pop_back()
{
if (empty()) return; // Nothing to do
erase(cend() - 1);
}
template <class T, size_t nFixedSize>
inline void sequence<T, nFixedSize>::resize(size_t nCount)
{
T t{};
resize(nCount, t);
}
template <class T, size_t nFixedSize>
inline void sequence<T, nFixedSize>::resize(size_t nCount, const value_type& rtValue)
{
if (!nCount)
clear();
else
{
size_t nCurrentLen = size();
m_ptrData.resize(nCount);
// False positive of CppCheck - condition is not always true. Suppress warning.
// cppcheck-suppress knownConditionTrueFalse
if (size() > nCurrentLen)
std::fill_n(m_ptrData.get() + nCurrentLen, size() - nCurrentLen, rtValue);
}
}
/// @cond DOXYGEN_IGNORE
template <class T, size_t nFixedSize>
template <size_t nFixedSize2>
inline void sequence<T, nFixedSize>::swap(sequence<T, nFixedSize2>& rseq) noexcept
{
sequence seqTemp = std::move(rseq);
rseq = std::move(*this);
operator=(std::move(seqTemp));
}
/// @endcond
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
inline void swap(sequence<T, nFixedSizeLeft>& rseqLeft, sequence<T, nFixedSizeRight>& rseqRight) noexcept
{
rseqLeft.swap(rseqRight);
}
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
inline bool operator==(const sequence<T, nFixedSizeLeft>& rseqLeft, const sequence<T, nFixedSizeRight>& rseqRight)
{
if (rseqLeft.size() != rseqRight.size()) return false;
for (size_t nIndex = 0; nIndex < rseqLeft.size(); nIndex++)
if (rseqLeft[nIndex] != rseqRight[nIndex]) return false;
return true;
}
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
inline bool operator!=(const sequence<T, nFixedSizeLeft>& rseqLeft, const sequence<T, nFixedSizeRight>& rseqRight)
{
return !operator==(rseqLeft, rseqRight);
}
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
inline bool operator<(const sequence<T, nFixedSizeLeft>& rseqLeft, const sequence<T, nFixedSizeRight>& rseqRight)
{
for (size_t nIndex = 0; nIndex < std::min(rseqLeft.size(), rseqRight.size()); nIndex++)
{
if (rseqLeft[nIndex] < rseqRight[nIndex]) return true;
if (rseqLeft[nIndex] > rseqRight[nIndex]) return false;
}
return rseqLeft.size() < rseqRight.size();
}
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
inline bool operator<=(const sequence<T, nFixedSizeLeft>& rseqLeft, const sequence<T, nFixedSizeRight>& rseqRight)
{
for (size_t nIndex = 0; nIndex < std::min(rseqLeft.size(), rseqRight.size()); nIndex++)
{
if (rseqLeft[nIndex] < rseqRight[nIndex]) return true;
if (rseqLeft[nIndex] > rseqRight[nIndex]) return false;
}
return rseqLeft.size() <= rseqRight.size();
}
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
inline bool operator>(const sequence<T, nFixedSizeLeft>& rseqLeft, const sequence<T, nFixedSizeRight>& rseqRight)
{
for (size_t nIndex = 0; nIndex < std::min(rseqLeft.size(), rseqRight.size()); nIndex++)
{
if (rseqLeft[nIndex] < rseqRight[nIndex]) return false;
if (rseqLeft[nIndex] > rseqRight[nIndex]) return true;
}
return rseqLeft.size() > rseqRight.size();
}
template <class T, size_t nFixedSizeLeft, size_t nFixedSizeRight>
inline bool operator>=(const sequence<T, nFixedSizeLeft>& rseqLeft, const sequence<T, nFixedSizeRight>& rseqRight)
{
for (size_t nIndex = 0; nIndex < std::min(rseqLeft.size(), rseqRight.size()); nIndex++)
{
if (rseqLeft[nIndex] < rseqRight[nIndex]) return false;
if (rseqLeft[nIndex] > rseqRight[nIndex]) return true;
}
return rseqLeft.size() >= rseqRight.size();
}
} // namespace sdv
#endif // !defined SDV_SEQUENCE_INL

297
export/support/serdes.h Normal file
View File

@@ -0,0 +1,297 @@
#ifndef SDV_SERDES_H
#define SDV_SERDES_H
#include <cstdint>
#include "pointer.h"
#include "sequence.h"
#include "string.h"
#include "any.h"
#include "crc.h"
namespace sdv
{
/**
* @brief Return the endianness for this platform.
* @return The platform endianness enum value.
*/
inline constexpr EEndian GetPlatformEndianess()
{
// Since C++11 there is no programmatic way to test for endianness in a constexpr function. During runtime this is possible
// using a union or a casting pointers. C++20 adds platform endian support and the implementation is likely done using
// compiler constants.
#if defined _MSC_VER
return EEndian::little_endian;
#elif defined __GNUC__
return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? EEndian::big_endian : EEndian::little_endian;
#endif
}
/**
* @brief Serializer class implementing the serialization of basic types and memory management.
* @details The serialization into the buffer is aligned to the size of the value to store. For example, bytes can be stored at
* any position. 16-bit words can be stored at 2 bytes boundary. 32-bits can be stored at 4 bytes boundary and 64-bits can be
* stored at 8 bytes boundary.
* The buffer allocation occurs in 1024 bytes at the time. The buffer is readjusted to the correct size just before detaching
* the buffer.
* @tparam eTargetEndianess The targeendiannessss determines whether to swap the bytes before storing them into the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
*/
template <sdv::EEndian eTargetEndianess = GetPlatformEndianess(), typename TCRC = crcCCITT_FALSE>
class serializer
{
public:
/**
* @brief Constructor
*/
serializer() noexcept;
/**
* @brief Push value into the serializer.
* @tparam T Type of the value. Only arithmic and boolean types can be added. All other types need to be decomposed before
* they can be added.
* @param[in] tValue The value to add.
*/
template <typename T>
void push_back(T tValue);
/**
* @brief Attach a buffer to serialize into.
* @param[in] rptrBuffer Reference to the buffer.
* @param[in] nOffset Offset to start serializing.
* @param[in] uiChecksum Current checksum value to continue with in the CRC calculation.
*/
void attach(pointer<uint8_t>&& rptrBuffer, size_t nOffset = 0, typename TCRC::TCRCType uiChecksum = 0u);
/**
* @brief Detach the internal buffer and assign this buffer to the supplied pointer.
* @param[out] rptrBuffer Reference to the pointer to assign this buffer to.
*/
void detach(pointer<uint8_t>& rptrBuffer);
/**
* @brief Reserve space for a large amount of data.
* @details Reserving space for data is done automatically, but only in small chunks. If large data is serialized, it is
* more efficient to reserve the space at once before the serialization process takes place. This will prevent many smaller
* reallocations taking place.
* @param[in] nSize The size of new data to reserve space for.
*/
void reserve(size_t nSize);
/**
* @brief Get a copy of the buffer pointer.
* @return Smart pointer to the contained buffer.
*/
pointer<uint8_t> buffer() const;
/**
* @brief Return the calculated checksum value of the serialized data.
* @return Checksum value.
*/
typename TCRC::TCRCType checksum() const noexcept;
/**
* @brief Return the current offset.
* @return The offset from the start of the stream.
*/
size_t offset() const;
private:
/**
* @brief Extend the buffer and align to the size of the variable.
* @tparam T The type of the variable to use the size from.
*/
template <typename T>
void extend_and_align();
pointer<uint8_t> m_ptrBuffer; ///< Buffer smart pointer.
size_t m_nOffset = 0; ///< Current offset in the buffer.
TCRC m_crcChecksum; ///< Calculated checksum value.
};
/**
* @brief Deserializer class implementing the deserialization of basic types.
* @details The deserialization from the buffer is aligned to the size of the value that was stored. For example, bytes are
* stored at any position. 16-bit words are stored at 2 bytes aligned. 32-bits can be stored at 4 bytes aligned and 64-bits are
* stored at 8 bytes aligned.
* @tparam eSourceEndianess The source endianness determines whether to swap the bytes after retrieving them from the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
*/
template <sdv::EEndian eSourceEndianess = GetPlatformEndianess(), typename TCRC = crcCCITT_FALSE>
class deserializer
{
public:
/**
* @brief Constructor
*/
deserializer();
/**
* @brief Pull the value from the deserializer.
* @tparam T Type of the value. Only arithmic and boolean types can be deserialized. All other types need to be composed
* by deserialized arithmic and boolean types.
* @param[out] rtValue Reference to the value to get.
*/
template <typename T>
void pop_front(T& rtValue);
/**
* @brief Peek for the value from the deserializer without popping the value from the deserializer.
* @tparam T Type of the value. Only arithmic and boolean types can be deserialized.
* @param[out] rtValue Reference to the value to get.
*/
template <typename T>
void peek_front(T& rtValue);
/**
* @brief Assign a buffer.
* @param[in] pData Pointer to the data.
* @param[in] nSize Data size;
* @param[in] uiChecksum The checksum value that was calculated or 0 when no checksum checking should occur before
* deserialization.
*/
void assign(const uint8_t* pData, size_t nSize, typename TCRC::TCRCType uiChecksum = 0);
/**
* @brief Attach a buffer.
* @remarks Providing the checksum will result a check through the data in the supplied buffer for the fitting checksum.
* @param[in] rptrData Reference to the data pointer.
* @param[in] uiChecksum The checksum value that was calculated or 0 when no checksum checking should occur.
*/
void attach(const pointer<uint8_t>& rptrData, typename TCRC::TCRCType uiChecksum = 0);
/**
* @brief Return the calculated checksum value of the deserialized data.
* @return Checksum value.
*/
typename TCRC::TCRCType checksum() const noexcept;
/**
* @brief Return the size of the contained buffer.
* @return The size of the buffer.
*/
size_t size() const;
/**
* @brief Return the current offset.
* @return The offset from the start of the stream.
*/
size_t offset() const;
/**
* @brief Return the leftover space within the buffer (size - offset).
* @return The leftover space of the buffer.
*/
size_t remaining() const;
/**
* @brief Skip to the supplied offset and start calculating the rest of the checksum with the supplied checksum.
* @details This function allows navigating through the buffer or chunkwise deserialization. By supplying an offset, the
* deserialization can start from the supplied offset using the supplied checksum to check any further. It is also possible
* to do chunkwise deserialization, providing a small buffer covering only part of the large serialized package. Jumping to
* the beginning of the buffer (offset 0), but explicitly setting the checksum, allows processing the package as if part of
* a larger buffer.
* @param[in] nOffset New offset to start processing from. Must be smaller than the buffer size.
* @param[in] uiChecksum Checksum to start calculating the checksum value over the following data with.
*/
void jump(size_t nOffset, typename TCRC::TCRCType uiChecksum = 0);
private:
/**
* @brief Align the offset to the size of the variable.
* @tparam T The type of the variable to use the size from.
*/
template <typename T>
void align();
pointer<uint8_t> m_ptrBuffer; ///< Buffer smart pointer (might not be used).
const uint8_t* m_pData = nullptr; ///< Pointer to the data.
size_t m_nSize = 0; ///< Current buffer length.
size_t m_nOffset = 0; ///< Current offset in the buffer.
TCRC m_crcChecksum; ///< Calculated checksum value.
};
/**
* @brief Return the size of type T in serialized form.
* @remarks Dependable on the size value, padding is added to align data.
* @tparam T Type of the variable.
* @param[in] rtValue Reference to the variable.
* @param[in, out] rnSize Reference to the variable containing the current size and increased by the size of the value.
*/
template <typename T>
void ser_size(const T& rtValue, size_t& rnSize);
} // namespace sdv
/**
* @brief Serializer/deserializer namespace.
*/
namespace serdes
{
/**
* @brief Serializer/deserializer class.
* @tparam T Type of the variable.
*/
template <typename T>
class CSerdes
{
public:
/**
* @brief Calculate the size of the value in serialized form.
* @remarks Dependable on the size value, padding is added to align data.
* @param[in] rtValue Reference to the variable.
* @param[in, out] rnSize Reference to the variable containing the current size and increased by the size of the value.
*/
static void CalcSize(const T& rtValue, size_t& rnSize);
/**
* @brief Stream the variable into the serializer.
* @tparam eTargetEndianess The target endianness determines whether to swap the bytes before storing them into the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
* @param[in] rSerializer Reference to the serializer.
* @param[in] rtValue Reference to the variable.
* @return Reference to the serializer.
*/
template <sdv::EEndian eTargetEndianess, typename TCRC>
static sdv::serializer<eTargetEndianess, TCRC>& Serialize(sdv::serializer<eTargetEndianess, TCRC>& rSerializer, const T& rtValue);
/**
* @brief Stream a variable from the deserializer.
* @tparam eSourceEndianess The target endianness determines whether to swap the bytes before storing them into the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
* @param[in] rDeserializer Reference to the deserializer.
* @param[out] rtValue Reference to the variable to be filled.
* @return Reference to the deserializer.
*/
template <sdv::EEndian eSourceEndianess, typename TCRC>
static sdv::deserializer<eSourceEndianess, TCRC>& Deserialize(sdv::deserializer<eSourceEndianess, TCRC>& rDeserializer, T& rtValue);
};
} // namespace serdes
/**
* @brief Stream the variable into the serializer.
* @tparam T Type of the variable.
* @tparam eTargetEndianess The target endianness determines whether to swap the bytes before storing them into the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
* @param[in] rSerializer Reference to the serializer.
* @param[in] rtValue Reference to the variable.
* @return Reference to the serializer.
*/
template <typename T, sdv::EEndian eTargetEndianess, typename TCRC>
sdv::serializer<eTargetEndianess, TCRC>& operator<<(sdv::serializer<eTargetEndianess, TCRC>& rSerializer, const T& rtValue);
/**
* @brief Stream a variable from the deserializer.
* @tparam T Type of the variable.
* @tparam eSourceEndianess The target endianness determines whether to swap the bytes before storing them into the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
* @param[in] rDeserializer Reference to the deserializer.
* @param[out] rtValue Reference to the variable to be filled.
* @return Reference to the deserializer.
*/
template <typename T, sdv::EEndian eSourceEndianess, typename TCRC>
sdv::deserializer<eSourceEndianess, TCRC>& operator>>(sdv::deserializer<eSourceEndianess, TCRC>& rDeserializer, T& rtValue);
#include "serdes.inl"
#endif // !defined SDV_SERDES_H

651
export/support/serdes.inl Normal file
View File

@@ -0,0 +1,651 @@
#ifndef SDV_SERDES_INL
#define SDV_SERDES_INL
#ifndef SDV_SERDES_H
#error Do not include "serdes.inl" directly. Include "serdes.h" instead!
#endif //!defined SDV_SERDES_H
#include <type_traits>
namespace sdv
{
template <sdv::EEndian eTargetEndianess, typename TCRC>
inline serializer<eTargetEndianess, TCRC>::serializer() noexcept
{}
template <sdv::EEndian eTargetEndianess, typename TCRC>
template <typename T>
inline void serializer<eTargetEndianess, TCRC>::push_back(T tValue)
{
static_assert(std::is_arithmetic_v<T> || std::is_same_v<T, bool> || std::is_enum_v<T>);
// Make certain the data fits and align to the proper address.
extend_and_align<T>();
// Without buffer there is no serialization.
if (!m_ptrBuffer) return;
if constexpr (eTargetEndianess == GetPlatformEndianess()) // No swapping
*reinterpret_cast<T*>(m_ptrBuffer.get() + m_nOffset) = tValue;
else // Swap bytes
{
uint8_t* pData = m_ptrBuffer.get() + m_nOffset;
for (size_t nIndex = 0; nIndex < sizeof(T); nIndex++)
pData[nIndex] = reinterpret_cast<uint8_t*>(&tValue)[sizeof(T) - nIndex - 1];
}
// Calculate CRC
for (size_t nIndex = m_nOffset; nIndex < m_nOffset + sizeof(T); nIndex++)
m_crcChecksum.add(m_ptrBuffer[nIndex]);
// Increase offset
m_nOffset += sizeof(T);
}
template <sdv::EEndian eTargetEndianess, typename TCRC>
inline void serializer<eTargetEndianess, TCRC>::attach(pointer<uint8_t>&& rptrBuffer, size_t nOffset /*= 0*/, typename TCRC::TCRCType uiChecksum /*= 0u*/)
{
if (nOffset > rptrBuffer.size())
{
XOffsetPastBufferSize exception;
exception.uiOffset = static_cast<uint32_t>(nOffset);
exception.uiSize = static_cast<uint32_t>(rptrBuffer.size());
throw exception;
}
m_ptrBuffer = std::move(rptrBuffer);
m_nOffset = nOffset;
m_crcChecksum.set_checksum(uiChecksum);
}
template <sdv::EEndian eTargetEndianess, typename TCRC>
inline void serializer<eTargetEndianess, TCRC>::detach(pointer<uint8_t>& rptrBuffer)
{
// Reduce the buffer to the currently calculated offset.
if (m_ptrBuffer)
m_ptrBuffer.resize(m_nOffset);
// Assign the buffer
rptrBuffer = std::move(m_ptrBuffer);
// Clear the offset
m_nOffset = 0;
}
template <sdv::EEndian eTargetEndianess, typename TCRC>
inline void serializer<eTargetEndianess, TCRC>::reserve(size_t nSize)
{
// Check whether reservation is required.
if (m_ptrBuffer.size() < m_nOffset + nSize)
m_ptrBuffer.resize(m_ptrBuffer.size() + nSize);
}
template <sdv::EEndian eTargetEndianess, typename TCRC>
inline pointer<uint8_t> serializer<eTargetEndianess, TCRC>::buffer() const
{
pointer<uint8_t> ptrLocal = m_ptrBuffer;
// Reduce the buffer to the currently calculated offset.
if (ptrLocal)
ptrLocal.resize(m_nOffset);
// Return a copy of the smart pointer to the internal buffer.
return ptrLocal;
}
template <sdv::EEndian eTargetEndianess, typename TCRC>
inline typename TCRC::TCRCType serializer<eTargetEndianess, TCRC>::checksum() const noexcept
{
return m_crcChecksum.get_checksum();
}
template <EEndian eTargetEndianess, typename TCRC>
inline size_t serializer<eTargetEndianess, TCRC>::offset() const
{
return m_nOffset;
}
template <sdv::EEndian eTargetEndianess, typename TCRC>
template <typename T>
inline void serializer<eTargetEndianess, TCRC>::extend_and_align()
{
// Align the offset position dependable on the size of the variable to add.
size_t nOffsetNew = m_nOffset;
if ((nOffsetNew & (sizeof(T) - 1)) != 0)
nOffsetNew = (nOffsetNew | (sizeof(T) - 1)) + 1;
// Check if the buffer size is large enough to hold the alignment and the type.
// If not, extend with 1024 bytes.
if ((nOffsetNew + sizeof(T)) > m_ptrBuffer.size())
m_ptrBuffer.resize(m_ptrBuffer.size() + 1024);
// Fill the buffer with padding and add the padding to the checksum value calculation.
for (size_t nIndex = m_nOffset; nIndex != nOffsetNew; nIndex++)
{
m_ptrBuffer[m_nOffset] = 0x00;
m_crcChecksum.add(static_cast<uint8_t>(0x00));
}
// Set the new offset
m_nOffset = nOffsetNew;
}
template <EEndian eSourceEndianess, typename TCRC>
inline deserializer<eSourceEndianess, TCRC>::deserializer()
{}
template <EEndian eSourceEndianess, typename TCRC>
template <typename T>
inline void deserializer<eSourceEndianess, TCRC>::pop_front(T& rtValue)
{
static_assert(std::is_arithmetic_v<T> || std::is_same_v<T, bool> || std::is_enum_v<T>);
// Without buffer there is no deserialization.
if (!m_ptrBuffer) return;
// Align to the proper address.
align<T>();
// Check whether the buffer contains the data requested
if (m_ptrBuffer.size() < m_nOffset + sizeof(T))
{
sdv::XBufferTooSmall exception;
exception.uiSize = m_nOffset + sizeof(T);
exception.uiCapacity = m_ptrBuffer.size();
throw exception;
}
// Calculate CRC
for (size_t nIndex = m_nOffset; nIndex < m_nOffset + sizeof(T); nIndex++)
m_crcChecksum.add(m_ptrBuffer[nIndex]);
// Copy data
if constexpr (eSourceEndianess == GetPlatformEndianess()) // No swapping
rtValue = *reinterpret_cast<T*>(m_ptrBuffer.get() + m_nOffset);
else // Swap bytes
{
const uint8_t* pData = m_ptrBuffer.get() + m_nOffset;
for (size_t nIndex = 0; nIndex < sizeof(T); nIndex++)
reinterpret_cast<uint8_t*>(&rtValue)[nIndex] = pData[sizeof(T) - nIndex - 1];
}
// Increase offset
m_nOffset += sizeof(T);
}
template <EEndian eSourceEndianess, typename TCRC>
template <typename T>
inline void deserializer<eSourceEndianess, TCRC>::peek_front(T& rtValue)
{
static_assert(std::is_arithmetic_v<T> || std::is_same_v<T, bool> || std::is_enum_v<T>);
// Without buffer there is no deserialization.
if (!m_ptrBuffer) return;
// Store the offset and checksum
size_t nOffsetTemp = m_nOffset;
auto nChecksum = m_crcChecksum.get_checksum();
// Make certain the data fits and align to the proper address.
align<T>();
// Check whether the buffer contains the data requested
if (m_ptrBuffer.size() < m_nOffset + sizeof(T))
{
sdv::XBufferTooSmall exception;
exception.uiSize = m_nOffset + sizeof(T);
exception.uiCapacity = m_ptrBuffer.size();
throw exception;
}
// Copy data
if constexpr (eSourceEndianess == GetPlatformEndianess()) // No swapping
rtValue = *reinterpret_cast<T*>(m_ptrBuffer.get() + m_nOffset);
else // Swap bytes
{
const uint8_t* pData = m_ptrBuffer.get() + m_nOffset;
for (size_t nIndex = 0; nIndex < sizeof(T); nIndex++)
reinterpret_cast<uint8_t*>(&rtValue)[nIndex] = pData[sizeof(T) - nIndex - 1];
}
// Reset the offset and checksum
m_nOffset = nOffsetTemp;
m_crcChecksum.set_checksum(nChecksum);
}
template <EEndian eSourceEndianess, typename TCRC>
inline void deserializer<eSourceEndianess, TCRC>::assign(const uint8_t* pData, size_t nSize, typename TCRC::TCRCType uiChecksum /*= 0*/)
{
if (!pData) throw XNullPointer();
// Check the checksum value
if (uiChecksum)
{
crcCCITT_FALSE crcChecksum;
for (size_t nIndex = 0; nIndex < nSize; nIndex++)
crcChecksum.add(pData[nIndex]);
if (crcChecksum.get_checksum() != uiChecksum)
{
XHashNotMatching exception;
exception.uiCalculated = crcChecksum.get_checksum();
exception.uiProvided = uiChecksum;
throw exception;
}
}
m_pData = pData;
m_nSize = nSize;
}
template <EEndian eSourceEndianess, typename TCRC>
inline void deserializer<eSourceEndianess, TCRC>::attach(const pointer<uint8_t>& rptrData, typename TCRC::TCRCType uiChecksum /*= 0*/)
{
m_ptrBuffer = rptrData;
assign(rptrData.get(), rptrData.size(), uiChecksum);
}
template <EEndian eSourceEndianess, typename TCRC>
inline typename TCRC::TCRCType deserializer<eSourceEndianess, TCRC>::checksum() const noexcept
{
return m_crcChecksum.get_checksum();
}
template <EEndian eSourceEndianess, typename TCRC>
template <typename T>
inline void deserializer<eSourceEndianess, TCRC>::align()
{
// Align the offset position dependable on the size of the variable to get.
if ((m_nOffset & (sizeof(T) - 1)) != 0)
{
size_t nOffsetNew = (m_nOffset | (sizeof(T) - 1)) + 1;
// Add the padding to the checksum value calculation.
for (size_t nIndex = m_nOffset; nIndex != nOffsetNew; nIndex++)
m_crcChecksum.add(m_ptrBuffer[nIndex]);
m_nOffset = nOffsetNew;
}
}
template <EEndian eSourceEndianess, typename TCRC>
inline size_t deserializer<eSourceEndianess, TCRC>::size() const
{
return m_nSize;
}
template <EEndian eSourceEndianess, typename TCRC>
inline size_t deserializer<eSourceEndianess, TCRC>::offset() const
{
return m_nOffset;
}
template <EEndian eSourceEndianess, typename TCRC>
inline size_t deserializer<eSourceEndianess, TCRC>::remaining() const
{
return m_nSize - std::min(m_nOffset, m_nSize);
}
template <EEndian eSourceEndianess, typename TCRC>
void deserializer<eSourceEndianess, TCRC>::jump(size_t nOffset, typename TCRC::TCRCType uiChecksum /*= 0*/)
{
if (nOffset > m_ptrBuffer.size())
{
XOffsetPastBufferSize exception;
exception.uiOffset = static_cast<uint32_t>(nOffset);
exception.uiSize = static_cast<uint32_t>(m_ptrBuffer.size());
throw exception;
}
m_nOffset = nOffset;
m_crcChecksum.set_checksum(uiChecksum);
}
template <typename T>
inline void ser_size(const T& rtValue, size_t& rnSize)
{
serdes::CSerdes<T>::CalcSize(rtValue, rnSize);
}
} // namespace sdv
namespace serdes
{
template <typename T>
inline void CSerdes<T>::CalcSize([[maybe_unused]] const T& rtValue, size_t& rnSize)
{
static_assert(std::is_fundamental_v<T> || std::is_enum_v<T>);
// Add alignment if necessary
size_t nBytes = rnSize % sizeof(T);
if (nBytes) rnSize += sizeof(T) - nBytes;
// Increase the size
rnSize += sizeof(T);
}
template <typename T>
template <sdv::EEndian eTargetEndianess, typename TCRC>
inline sdv::serializer<eTargetEndianess, TCRC>& CSerdes<T>::Serialize(sdv::serializer<eTargetEndianess, TCRC>& rSerializer, const T& rtValue)
{
rSerializer.push_back(rtValue);
return rSerializer;
}
template <typename T>
template <sdv::EEndian eSourceEndianess, typename TCRC>
inline sdv::deserializer<eSourceEndianess, TCRC>& CSerdes<T>::Deserialize(sdv::deserializer<eSourceEndianess, TCRC>& rDeserializer, T& rtValue)
{
rDeserializer.pop_front(rtValue);
return rDeserializer;
}
/**
* @brief Specialization of serializer/deserializer class.
* @tparam T Type of the variable.
* @tparam nSize The size of the provided array.
*/
template <typename T, size_t nSize>
class CSerdes<T[nSize]>
{
public:
/**
* @brief Calculate the size of the value in serialized form.
* @remarks Dependable on the size value, padding is added to align data.
* @param[in] rrgtValue Reference to an array with variables.
* @param[in, out] rnSize Reference to the variable containing the current size and increased by the size of the value.
*/
static void CalcSize([[maybe_unused]] const T(&rrgtValue)[nSize], size_t& rnSize)
{
for (const T& rtValue : rrgtValue)
sdv::ser_size(rtValue, rnSize);
}
/**
* @brief Stream the variable into the serializer.
* @tparam eTargetEndianess The target endianess detemines whether to swap the bytes before storing them into the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
* @param[in] rSerializer Reference to the serializer.
* @param[in] rrgtValue Reference to an array with variables.
* @return Reference to the serializer.
*/
template <sdv::EEndian eTargetEndianess, typename TCRC>
static sdv::serializer<eTargetEndianess, TCRC>& Serialize(sdv::serializer<eTargetEndianess, TCRC>& rSerializer, const T(&rrgtValue)[nSize])
{
// Reserve the space in the serializer (this speeds up the serialization process).
rSerializer.reserve(nSize * sizeof(T));
// Serialize all entries
for (const T& rtValue : rrgtValue)
CSerdes<T>::Serialize(rSerializer, rtValue);
return rSerializer;
}
/**
* @brief Stream a variable from the deserializer.
* @tparam eSourceEndianess The source endianess detemines whether to swap the bytes after retrieving them from the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
* @param[in] rDeserializer Reference to the deserializer.
* @param[out] rrgtValue Reference to an array with variables to be filled.
* @return Reference to the deserializer.
*/
template <sdv::EEndian eSourceEndianess, typename TCRC>
static sdv::deserializer<eSourceEndianess, TCRC>& Deserialize(sdv::deserializer<eSourceEndianess, TCRC>& rDeserializer, T(&rrgtValue)[nSize])
{
for (T& rtValue : rrgtValue)
CSerdes<T>::Deserialize(rDeserializer, rtValue);
return rDeserializer;
}
};
/**
* @brief Specialization of serializer/deserializer class.
* @tparam T Type of the variable.
* @tparam nFixedSize The fixed size of the pointer or 0 when the pointer is dynamic.
*/
template <typename T, size_t nFixedSize>
class CSerdes<sdv::pointer<T, nFixedSize>>
{
public:
/**
* @brief Calculate the size of the value in serialized form.
* @remarks Dependable on the size value, padding is added to align data.
* @param[in] rptrValue Reference to the pointer.
* @param[in, out] rnSize Reference to the variable containing the current size and increased by the size of the value.
*/
static void CalcSize(const sdv::pointer<T, nFixedSize>& rptrValue, size_t& rnSize)
{
sdv::ser_size(static_cast<uint64_t>(rptrValue.size()), rnSize);
if constexpr (std::is_fundamental_v<T>)
rnSize += rptrValue.size() * sizeof(T);
else
{
for (size_t n = 0; n < rptrValue.size(); n++)
sdv::ser_size(rptrValue.get()[n], rnSize);
}
}
/**
* @brief Stream the pointer variable into the serializer.
* @tparam eTargetEndianess The target endianess detemines whether to swap the bytes before storing them into the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
* @param[in] rSerializer Reference to the serializer.
* @param[in] rptrValue Reference to the pointer.
* @return Reference to the serializer.
*/
template <sdv::EEndian eTargetEndianess, typename TCRC>
static sdv::serializer<eTargetEndianess, TCRC>& Serialize(sdv::serializer<eTargetEndianess, TCRC>& rSerializer, const sdv::pointer<T, nFixedSize>& rptrValue)
{
rSerializer << static_cast<uint64_t>(rptrValue.size());
if (rptrValue)
{
// Reserve the space in the serializer (this speeds up the serialization process).
rSerializer.reserve(rptrValue.size() * sizeof(T));
// Serialize all entries
const T* ptValue = rptrValue.get();
for (size_t nIndex = 0; nIndex < rptrValue.size(); nIndex++)
CSerdes<T>::Serialize(rSerializer, ptValue[nIndex]);
}
return rSerializer;
}
/**
* @brief Stream the pointer variable from the deserializer.
* @tparam eSourceEndianess The source endianess detemines whether to swap the bytes after retrieving them from the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
* @param[in] rDeserializer Reference to the deserializer.
* @param[in] rptrValue Reference to the pointer.
* @return Reference to the deserializer.
*/
template <sdv::EEndian eSourceEndianess, typename TCRC>
static sdv::deserializer<eSourceEndianess, TCRC>& Deserialize(sdv::deserializer<eSourceEndianess, TCRC>& rDeserializer, sdv::pointer<T, nFixedSize>& rptrValue)
{
uint64_t nSize = 0;
rDeserializer >> nSize;
if (nSize * sizeof(T) > rDeserializer.remaining())
{
sdv::XOffsetPastBufferSize exception;
exception.uiSize = rDeserializer.size();
exception.uiOffset = rDeserializer.offset() + nSize * sizeof(T);
throw exception;
}
rptrValue.resize(nSize);
if (nSize && rptrValue)
{
T* ptValue = rptrValue.get();
for (size_t nIndex = 0; nIndex < nSize; nIndex++)
CSerdes<T>::Deserialize(rDeserializer, ptValue[nIndex]);
}
return rDeserializer;
}
};
/**
* @brief Specialization of serializer/deserializer class.
* @tparam T Type of the variable.
* @tparam nFixedSize The fixed size of the sequence or 0 when the sequence is dynamic.
*/
template <typename T, size_t nFixedSize>
class CSerdes<sdv::sequence<T, nFixedSize>>
{
public:
/**
* @brief Calculate the size of the value in serialized form.
* @remarks Dependable on the size value, padding is added to align data.
* @param[in] rseqValue Reference to the sequence.
* @param[in, out] rnSize Reference to the variable containing the current size and increased by the size of the value.
*/
static void CalcSize(const sdv::sequence<T, nFixedSize>& rseqValue, size_t& rnSize)
{
sdv::ser_size(static_cast<uint64_t>(rseqValue.size()), rnSize);
if constexpr (std::is_fundamental_v<T>)
rnSize += rseqValue.size() * sizeof(T);
else
{
for (const T& rValue: rseqValue)
sdv::ser_size(rValue, rnSize);
}
}
/**
* @brief Stream the sequence variable into the serializer.
* @tparam eTargetEndianess The target endianess detemines whether to swap the bytes before storing them into the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
* @param[in] rSerializer Reference to the serializer.
* @param[in] rseqValue Reference to the sequence.
* @return Reference to the serializer.
*/
template <sdv::EEndian eTargetEndianess, typename TCRC>
static sdv::serializer<eTargetEndianess, TCRC>& Serialize(sdv::serializer<eTargetEndianess, TCRC>& rSerializer, const sdv::sequence<T, nFixedSize>& rseqValue)
{
rSerializer << static_cast<uint64_t>(rseqValue.size());
// Reserve the space in the serializer (this speeds up the serialization process).
rSerializer.reserve(rseqValue.size() * sizeof(T));
// Serialize all entries
for (const T& rtValue : rseqValue)
CSerdes<T>::Serialize(rSerializer, rtValue);
return rSerializer;
}
/**
* @brief Stream the sequence variable from the deserializer.
* @tparam eSourceEndianess The source endianess detemines whether to swap the bytes after retrieving them from the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
* @param[in] rDeserializer Reference to the deserializer.
* @param[in] rseqValue Reference to the sequence.
* @return Reference to the deserializer.
*/
template <sdv::EEndian eSourceEndianess, typename TCRC>
static sdv::deserializer<eSourceEndianess, TCRC>& Deserialize(sdv::deserializer<eSourceEndianess, TCRC>& rDeserializer, sdv::sequence<T, nFixedSize>& rseqValue)
{
uint64_t nSize = 0;
rDeserializer >> nSize;
if (nSize * sizeof(T) > rDeserializer.remaining())
{
sdv::XOffsetPastBufferSize exception;
exception.uiSize = rDeserializer.size();
exception.uiOffset = rDeserializer.offset() + nSize * sizeof(T);
throw exception;
}
rseqValue.resize(nSize);
if (nSize)
{
for (T& rtValue : rseqValue)
CSerdes<T>::Deserialize(rDeserializer, rtValue);
}
return rDeserializer;
}
};
/**
* @brief Specialization of serializer/deserializer class.
* @tparam TCharType Type of the string.
* @tparam eTargetEndianess The target endianess detemines whether to swap the bytes before storing them into the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
* @tparam bUnicode When set, the string is a unicode string.
* @tparam nFixedSize The fixed size of the string or 0 when the string is dynamic.
*/
template <typename TCharType, bool bUnicode, size_t nFixedSize>
class CSerdes<sdv::string_base<TCharType, bUnicode, nFixedSize>>
{
public:
/**
* @brief Calculate the size of the value in serialized form.
* @remarks Dependable on the size value, padding is added to align data.
* @param[in] rssValue Reference to the string.
* @param[in, out] rnSize Reference to the variable containing the current size and increased by the size of the value.
*/
static void CalcSize(const sdv::string_base<TCharType, bUnicode, nFixedSize>& rssValue, size_t& rnSize)
{
sdv::ser_size(static_cast<uint64_t>(rssValue.size()), rnSize);
rnSize += rssValue.size() * sizeof(TCharType);
}
/**
* @brief Stream the string variable into the serializer.
* @tparam eTargetEndianess The target endianess detemines whether to swap the bytes before storing them into the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
* @param[in] rSerializer Reference to the serializer.
* @param[in] rssValue Reference to the string.
* @return Reference to the serializer.
*/
template <sdv::EEndian eTargetEndianess, typename TCRC>
static sdv::serializer<eTargetEndianess, TCRC>& Serialize(sdv::serializer<eTargetEndianess, TCRC>& rSerializer, const sdv::string_base<TCharType, bUnicode, nFixedSize>& rssValue)
{
rSerializer << static_cast<uint64_t>(rssValue.size());
// Reserve the space in the serializer (this speeds up the serialization process).
rSerializer.reserve(rssValue.size() * sizeof(TCharType));
// Serialize all entries
for (TCharType tValue : rssValue)
CSerdes<TCharType>::Serialize(rSerializer, tValue);
return rSerializer;
}
/**
* @brief Stream the string variable from the deserializer.
* @tparam eSourceEndianess The source endianess detemines whether to swap the bytes after retrieving them from the buffer.
* @tparam TCRC The CRC type to use for the checksum calculation.
* @param[in] rDeserializer Reference to the deserializer.
* @param[in] rssValue Reference to the string.
* @return Reference to the deserializer.
*/
template <sdv::EEndian eSourceEndianess, typename TCRC>
static sdv::deserializer<eSourceEndianess, TCRC>& Deserialize(sdv::deserializer<eSourceEndianess, TCRC>& rDeserializer, sdv::string_base<TCharType, bUnicode, nFixedSize>& rssValue)
{
uint64_t nSize = 0;
rDeserializer >> nSize;
if (nSize * sizeof(TCharType) > rDeserializer.remaining())
{
sdv::XOffsetPastBufferSize exception;
exception.uiSize = rDeserializer.size();
exception.uiOffset = rDeserializer.offset() + nSize * sizeof(TCharType);
throw exception;
}
rssValue.resize(nSize);
if (nSize)
{
for (TCharType& rtValue : rssValue)
CSerdes<TCharType>::Deserialize(rDeserializer, rtValue);
}
return rDeserializer;
}
};
} // namespace serdes
template <typename T, sdv::EEndian eTargetEndianess, typename TCRC>
inline sdv::serializer<eTargetEndianess, TCRC>& operator<<(sdv::serializer<eTargetEndianess, TCRC>& rSerializer, const T& rtValue)
{
serdes::CSerdes<T>::Serialize(rSerializer, rtValue);
return rSerializer;
}
template <typename T, sdv::EEndian eSourceEndianess, typename TCRC>
inline sdv::deserializer<eSourceEndianess, TCRC>& operator>>(sdv::deserializer<eSourceEndianess, TCRC>& rDeserializer, T& rtValue)
{
serdes::CSerdes<T>::Deserialize(rDeserializer, rtValue);
return rDeserializer;
}
#endif // !defined SDV_SERDES_INL

View File

@@ -0,0 +1,832 @@
/**
*
* @file signal_support.h
* @brief This file provides base-implementations and helpers for signals and signal handling.
* @version 0.1
* @date 2022.11.14
* @author Thomas.pfleiderer@zf.com
* @copyright Copyright ZF Friedrichshaven AG (c) 2022
*
*/
#ifndef SIGNAL_SUPPORT_H
#define SIGNAL_SUPPORT_H
#include <functional>
#include <mutex>
#include <vector>
#include "../interfaces/dispatch.h"
#include "local_service_access.h"
/**
* @brief Software Defined Vehicle framework.
*/
namespace sdv
{
/**
* @brief Core features.
*/
namespace core
{
// Forward declaration
class CSignal;
class CTrigger;
class CTransaction;
/**
* @brief Dispatch service convenience class.
*/
class CDispatchService
{
public:
/**
* @brief Constructor. The constructor will automatically try to connect to the Data Dispatch Service.
*/
CDispatchService();
/**
* @brief Destructor
*/
~CDispatchService();
/**
* @brief Register a signal for sending over the network; reading from the dispatch service. Data is provided by the
* signal publisher and dependable on the requested behavior stored until it is sent.
* @param[in] rssSignalName Reference to the name of the signal. To guarantee uniqueness, it is preferred to add the group
* hierarchy to the signal name separated by a dot. E.g. with CAN: MAB.BcmChas1Fr03.SteerReCtrlReqAgReq
* @param[in] tDefVal The default value of the signal.
* @return Returns the initialized signal class or an empty signal when the signal already existed or the dispatch
* service could not be reached.
*/
template <typename TType>
CSignal RegisterTxSignal(const u8string& rssSignalName, TType tDefVal);
/**
* @brief Register a signal for reception over the network; providing to the dispatch service.
* @param[in] rssSignalName Name of the signal. To guarantee uniqueness, it is preferred to add the group hierarchy to
* the signal name separated by a dot. E.g. with CAN: MAB.BcmChas1Fr03.SteerReCtrlReqAgReq
* @return Returns the initialized signal class or an empty signal when the signal already existed or the dispatch
* service could not be reached.
*/
CSignal RegisterRxSignal(const u8string& rssSignalName);
/**
* @brief Add a publisher of signal data.
* @param[in] rssSignalName Reference to the name of the signal to publish data for.
* @return Returns the initialized signal class or an empty signal when the signal was nor registered before or the
* dispatch service could not be reached.
*/
CSignal AddPublisher(const u8string& rssSignalName);
/**
* @brief Subscribe to a signal event.
* @param[in] rssSignalName Reference to the name of the signal to publish data for.
* @param[in] func Function to call when data is received.
* @return Returns the initialized signal class or an empty signal when the signal was nor registered before or the
* dispatch service could not be reached.
*/
CSignal Subscribe(const u8string& rssSignalName, std::function<void(any_t)> func);
/**
* @brief Subscribe to a signal event and allow updating the signal value automatically.
* @tparam TType Type of the signal data.
* @param[in] rssSignalName Reference to the name of the signal to publish data for.
* @param[in] rtVal Reference to the value to be filled automatically.
* @return Returns the initialized signal class or an empty signal when the signal was nor registered before or the
* dispatch service could not be reached.
*/
template <typename TType>
CSignal Subscribe(const u8string& rssSignalName, std::atomic<TType>& rtVal);
/**
* @brief Get a list of registered signals.
* @return List of registration functions.
*/
sequence<SSignalRegistration> GetRegisteredSignals() const;
/**
* @brief Create a transaction.
* @return Returns the transaction object. Returns an empty transaction object when the limit of transactions has been
* exhausted.
*/
CTransaction CreateTransaction();
/**
* @brief Finish a transaction.
* @param[in] rTransaction Reference to the transaction to finish.
*/
void FinishTransaction(CTransaction& rTransaction);
/**
* @brief Create a trigger object for the TX interface.
* @param[in] fnExecute Callback function that is triggered.
* @param[in] bSpontaneous When set, will be triggered on signal changes.
* @param[in] uiDelayTime The minimal time between two triggers.
* @param[in] uiPeriod When not 0, triggers periodically (time in ms).
* @param[in] bOnlyWhenActive When set, periodic trigger will only occur once if the signal value equals the default
* value.
* @return If successful, returns the initialized trigger object or an empty trigger object when not successful.
*/
CTrigger CreateTxTrigger(std::function<void()> fnExecute, bool bSpontaneous = true, uint32_t uiDelayTime = 0,
uint32_t uiPeriod = 0ul, bool bOnlyWhenActive = false);
};
/**
* @brief Transaction wrapping class
*/
class CTransaction
{
/// Dispatch service friend class.
friend CDispatchService;
public:
/**
* @brief Default constructor
*/
CTransaction() = default;
protected:
/**
* @brief Constructor for transaction.
* @param[in] rDispatch Reference to the dispatch class.
* @param[in] pTransaction Pointer to the interface of the transaction object.
*/
CTransaction(CDispatchService& rDispatch, IInterfaceAccess* pTransaction) :
m_pDispatch(&rDispatch), m_pTransaction(pTransaction)
{}
public:
/**
* @brief Copy constructor (deleted)
* @param[in] rTransaction Reference to the transaction to copy from.
*/
CTransaction(const CTransaction& rTransaction) = delete;
/**
* @brief Move constructor
* @param[in] rTransaction Reference to the transaction to move from.
*/
CTransaction(CTransaction&& rTransaction) :
m_pDispatch(rTransaction.m_pDispatch), m_pTransaction(rTransaction.m_pTransaction)
{
rTransaction.m_pDispatch = nullptr;
rTransaction.m_pTransaction = nullptr;
}
/**
* @brief Destructor
*/
~CTransaction()
{
Finish();
}
/**
* @brief Assignment operator (deleted)
* @param[in] rTransaction Reference to the transaction to copy from.
* @return Reference to this class.
*/
CTransaction& operator=(const CTransaction& rTransaction) = delete;
/**
* @brief Move operator
* @param[in] rTransaction Reference to the transaction to move from.
* @return Reference to this class.
*/
CTransaction& operator=(CTransaction&& rTransaction)
{
Finish();
m_pDispatch = rTransaction.m_pDispatch;
m_pTransaction = rTransaction.m_pTransaction;
rTransaction.m_pDispatch = nullptr;
rTransaction.m_pTransaction = nullptr;
return *this;
}
/**
* @brief Valid transaction?
*/
operator bool() const { return m_pTransaction ? true : false; }
/**
* @brief Finish the transaction.
*/
void Finish()
{
if (m_pDispatch && m_pTransaction)
{
IObjectDestroy* pDestroy = m_pTransaction->GetInterface<IObjectDestroy>();
pDestroy->DestroyObject();
}
m_pDispatch = nullptr;
m_pTransaction = nullptr;
}
/**
* @brief Get the transaction interface.
* @return The transaction interface that was used for this transaction or nullptr when the transaction was started yet
* or had finished before.
*/
IInterfaceAccess* GetTransaction() const
{
return m_pTransaction;
}
private:
CDispatchService* m_pDispatch = nullptr; ///< Pointer to the dispatch class.
IInterfaceAccess* m_pTransaction = nullptr; ///< Transaction object
};
/**
* @brief Signal class wrapping the signal access functions.
*/
class CSignal
{
friend CDispatchService;
public:
/**
* @brief Default constructor
*/
CSignal() = default;
protected:
/**
* @brief Constructor for signal interface received by a call to RegisterTxSignal, RegisterRxSignal or
* RequestSignalPublisher.
* @param[in] rDispatch Reference to the dispatch class.
* @param[in] rssName Reference to the string holding the name of the signal.
* @param[in] pSignal The signal interface access allowing access to the ISignalWrite interface.
* @param[in] bRegistering Boolean indicating that the signal was created using a registration function rather than an
* access function.
*/
CSignal(CDispatchService& rDispatch, const u8string& rssName, IInterfaceAccess* pSignal, bool bRegistering) :
m_pDispatch(&rDispatch), m_ssName(rssName), m_pSignal(pSignal), m_bRegistering(bRegistering)
{
if (pSignal)
{
m_pSignalWrite = pSignal->GetInterface<ISignalWrite>();
m_pSignalRead = pSignal->GetInterface<ISignalRead>();
}
}
/**
* @brief Constructor for signal receiving callback.
* @param[in] rDispatch Reference to the dispatch class.
* @param[in] rssName Reference to the string holding the name of the signal.
* @param[in] func Callback function being called on receiving data.
*/
CSignal(CDispatchService& rDispatch, const u8string& rssName, std::function<void(any_t)> func) :
m_pDispatch(&rDispatch), m_ssName(rssName),
m_ptrSubscriptionHandler(std::make_unique<CReceiveEventHandler>(rDispatch, func))
{}
/**
* @brief Constructor for signal receiving callback.
* @tparam TType Type of the variable to update automatically on an event call.
* @param[in] rDispatch Reference to the dispatch class.
* @param[in] rssName Reference to the string holding the name of the signal.
* @param[in] rtVal Reference to the variable to update automatically on an event call.
*/
template <typename TType>
CSignal(CDispatchService& rDispatch, const u8string& rssName, std::atomic<TType>& rtVal) :
m_pDispatch(&rDispatch), m_ssName(rssName),
m_ptrSubscriptionHandler(std::make_unique<CReceiveEventHandler>(rDispatch, rtVal))
{}
/**
* @brief Get the subscription event handler, if existing.
* @return Interface to the subscription handler or NULL when no handler is available.
*/
IInterfaceAccess* GetSubscriptionEventHandler()
{
return m_ptrSubscriptionHandler.get();
}
/**
* @brief Assign subscription object returned by the dispatch service.
* @param[in] pSubscription The interface to the subscription object.
*/
void Assign(IInterfaceAccess* pSubscription)
{
// The subscription object is managed through the signal int
if (m_ptrSubscriptionHandler && !m_pSignal) m_pSignal = pSubscription;
}
public:
/**
* @brief Copy constructor (not available).
* @param[in] rSignal Reference to the signal class to copy from.
*/
CSignal(const CSignal& rSignal) = delete;
/**
* @brief Move constructor.
* @param[in] rSignal Reference to the signal class to move from.
*/
CSignal(CSignal&& rSignal) : m_pDispatch(rSignal.m_pDispatch), m_ssName(std::move(rSignal.m_ssName)),
m_pSignal(rSignal.m_pSignal), m_pSignalWrite(rSignal.m_pSignalWrite), m_pSignalRead(rSignal.m_pSignalRead),
m_ptrSubscriptionHandler(std::move(rSignal.m_ptrSubscriptionHandler)), m_bRegistering(rSignal.m_bRegistering)
{
rSignal.m_pSignal = nullptr;
rSignal.m_pSignalWrite = nullptr;
rSignal.m_pSignalRead = nullptr;
rSignal.m_bRegistering = false;
}
/**
* @brief Assignment operator (not available).
* @param[in] rSignal Reference to the signal class to copy from.
* @return Reference to this class.
*/
CSignal& operator=(const CSignal& rSignal) = delete;
/**
* @brief Move operator
* @param[in] rSignal Reference to the signal class to move from.
* @return Reference to this class.
*/
CSignal& operator=(CSignal&& rSignal)
{
Reset();
m_pDispatch = rSignal.m_pDispatch;
m_ssName = std::move(rSignal.m_ssName);
m_pSignal = rSignal.m_pSignal;
m_pSignalWrite = rSignal.m_pSignalWrite;
m_pSignalRead = rSignal.m_pSignalRead;
m_ptrSubscriptionHandler = std::move(rSignal.m_ptrSubscriptionHandler);
m_bRegistering = rSignal.m_bRegistering;
rSignal.m_pSignal = nullptr;
rSignal.m_pSignalWrite = nullptr;
rSignal.m_pSignalRead = nullptr;
rSignal.m_bRegistering = false;
return *this;
}
/**
* Destructor
*/
~CSignal()
{
Reset();
}
/**
* @brief Reset the signal
*/
void Reset()
{
// First destroy the signal object. This will also prevent events to arrive.
if (m_pSignal)
{
IObjectDestroy* pDestroy = m_pSignal->GetInterface<IObjectDestroy>();
if (pDestroy) pDestroy->DestroyObject();
}
m_ptrSubscriptionHandler.reset();
m_bRegistering = false;
m_ssName.clear();
m_pSignal = nullptr;
m_pSignalWrite = nullptr;
m_pSignalRead = nullptr;
m_pDispatch = nullptr;
}
/**
* @brief Operator testing for validity of this class.
*/
operator bool() const
{
return m_pSignal ? true : false;
}
/**
* @brief Update the signal value. This function is available for Rx signals (receiving data from the network) and for
* services of publishing signals.
* @param[in] tVal The value to update the signal with.
* @param[in] rTransaction Reference to the transaction to use for reading.
*/
template <typename TType>
void Write(TType tVal, const CTransaction& rTransaction = CTransaction())
{
if (m_pSignalWrite) m_pSignalWrite->Write(any_t(tVal), rTransaction.GetTransaction());
}
/**
* @brief Read the signal value. This function is available for Tx signals (sending data over the network).
* @param[in] rTransaction Reference to the transaction to use for reading.
* @return The signal value or empty when no value or interface is available.
*/
any_t Read(const CTransaction& rTransaction = CTransaction()) const
{
any_t anyVal;
if (m_pSignalRead) anyVal = m_pSignalRead->Read(rTransaction.GetTransaction());
return anyVal;
}
/**
* @brief Was this signal class used for registration of the signal.
* @return Set when this signal is used for registration.
*/
bool UsedForRegistration() const { return m_bRegistering; }
/**
* @brief Get the name of the signal.
* @return String containing the name of the string.
*/
u8string GetName() const { return m_ssName; }
private:
/**
* @brief Receive event handler
*/
class CReceiveEventHandler : public IInterfaceAccess, public ISignalReceiveEvent
{
public:
/**
* @brief Constructor for attaching a function.
* @param[in] rDispatch Reference to the dispatch class.
* @param[in] funcSignalReceive Callback function being called on receiving data.
*/
CReceiveEventHandler(CDispatchService& rDispatch, std::function<void(any_t)> funcSignalReceive) :
m_rDispatch(rDispatch), m_funcSignalReceive(funcSignalReceive)
{}
/**
* @brief Constructor for attaching a variable
* @tparam TType Type of the variable to update automatically on an event call.
* @param[in] rDispatch Reference to the dispatch class.
* @param[in] rtVal Reference to the variable to update automatically on an event call.
*/
template <typename TType>
CReceiveEventHandler(CDispatchService& rDispatch, std::atomic<TType>& rtVal) :
m_rDispatch(rDispatch), m_ptrValue(std::make_unique<CValueAssignmentHelperT<TType>>(rtVal))
{}
/**
* @brief Destructor
*/
~CReceiveEventHandler()
{
if (m_pSubscription)
{
IObjectDestroy* pDestroy = m_pSubscription->GetInterface<IObjectDestroy>();
if (pDestroy) pDestroy->DestroyObject();
}
}
/**
* @brief Helper class for the value assignment.
*/
class CValueAssignmentHelper : public ISignalReceiveEvent
{
public:
virtual ~CValueAssignmentHelper() = default;
};
/**
* @brief Type specific helper for the value assignment.
* @tparam TType The type of the value.
*/
template <typename TType>
class CValueAssignmentHelperT : public CValueAssignmentHelper
{
public:
/**
* @brief Constructor
* @param[in] rtVal Reference to the value to update at every receive event.
*/
CValueAssignmentHelperT(std::atomic<TType>& rtVal) : m_rtVal(rtVal)
{}
/**
* Destructor
*/
virtual ~CValueAssignmentHelperT() = default;
/**
* @brief A signal value was received. Overload function of ISignalReceiveEvent::Receive.
* @param[in] anyVal The signal value.
*/
virtual void Receive(any_t anyVal) override
{
m_rtVal = static_cast<TType>(anyVal);
}
private:
std::atomic<TType>& m_rtVal;
};
/**
* @brief Set the subscriber cookie. This allows automatically subscription removal.
* @param[in] pSubscription Subscription interface.
*/
void Assign(IInterfaceAccess* pSubscription)
{
m_pSubscription = pSubscription;
}
private:
// Interface map
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(IInterfaceAccess)
SDV_INTERFACE_ENTRY(ISignalReceiveEvent)
END_SDV_INTERFACE_MAP()
/**
* @brief A signal value was received. Overload function of ISignalReceiveEvent::Receive.
* @param[in] anyVal The signal value.
*/
virtual void Receive(any_t anyVal) override
{
if (m_funcSignalReceive) m_funcSignalReceive(anyVal);
if (m_ptrValue) m_ptrValue->Receive(anyVal);
}
CDispatchService& m_rDispatch; ///< Reference to the dispatch service.
std::function<void(any_t)> m_funcSignalReceive; ///< Receive signal data - callback function.
IInterfaceAccess* m_pSubscription = nullptr; ///< Cookie received by adding an receive subscription.
std::unique_ptr<CValueAssignmentHelper> m_ptrValue; ///< Value to update instead of a callback function.
};
/**
* @brief Receive event handler smart pointer.
*/
using CReceiveEventHandlerPtr = std::unique_ptr<CReceiveEventHandler>;
CDispatchService* m_pDispatch = nullptr; ///< Pointer to the dispatch service.
u8string m_ssName; ///< Signal name.
IInterfaceAccess* m_pSignal = nullptr; ///< The signal interface.
ISignalWrite* m_pSignalWrite = nullptr; ///< Write signal data interface.
ISignalRead* m_pSignalRead = nullptr; ///< Write signal data interface.
CReceiveEventHandlerPtr m_ptrSubscriptionHandler; ///< Receive event handler smart pointer.
bool m_bRegistering = false; ///< When set, the signal was created using the
///< registration function.
};
/**
* @brief Trigger class wrapping the trigger functionality.
*/
class CTrigger
{
friend CDispatchService;
public:
/**
* @brief Default constructor.
*/
CTrigger() = default;
protected:
/**
* @brief Constructor for trigger.
* @param[in] rDispatch Reference to the dispatch class.
* @param[in] fnExecute Function to the callback.
*/
CTrigger(CDispatchService& rDispatch, std::function<void()> fnExecute) :
m_pDispatch(&rDispatch), m_ptrCallback(std::make_unique<STriggerCallback>(fnExecute))
{}
public:
/**
* @brief Copy constructor (deleted)
* @param[in] rTrigger Reference to the trigger to copy from.
*/
CTrigger(const CTrigger& rTrigger) = delete;
/**
* @brief Move constructor
* @param[in] rTrigger Reference to the trigger to move from.
*/
CTrigger(CTrigger&& rTrigger) :
m_pDispatch(rTrigger.m_pDispatch), m_pTrigger(rTrigger.m_pTrigger),
m_ptrCallback(std::move(rTrigger.m_ptrCallback))
{
rTrigger.m_pDispatch = nullptr;
rTrigger.m_pTrigger = nullptr;
}
/**
* @brief Destructor
*/
~CTrigger()
{
Reset();
}
/**
* @brief Assignment operator (deleted)
* @param[in] rTrigger Reference to the trigger to copy from.
* @return Reference to this class.
*/
CTrigger& operator=(const CTrigger& rTrigger) = delete;
/**
* @brief Move operator
* @param[in] rTrigger Reference to the trigger to move from.
* @return Reference to this class.
*/
CTrigger& operator=(CTrigger&& rTrigger)
{
Reset();
m_pDispatch = rTrigger.m_pDispatch;
m_pTrigger = rTrigger.m_pTrigger;
m_ptrCallback = std::move(rTrigger.m_ptrCallback);
rTrigger.m_pDispatch = nullptr;
rTrigger.m_pTrigger = nullptr;
return *this;
}
/**
* @brief Valid trigger?
*/
operator bool() const { return m_pTrigger ? true : false; }
/**
* @brief Reset the trigger.
*/
void Reset()
{
if (m_pDispatch && m_pTrigger)
{
IObjectDestroy* pDestroy = m_pTrigger->GetInterface<IObjectDestroy>();
pDestroy->DestroyObject();
}
m_pDispatch = nullptr;
m_pTrigger = nullptr;
m_ptrCallback.reset();
}
/**
* @brief Add a signal that should trigger.
* @param[in] rSignal Reference to the signal.
*/
void AddSignal(const CSignal& rSignal)
{
if (!m_pTrigger) return;
ITxTrigger* pTrigger = m_pTrigger->GetInterface<ITxTrigger>();
if (!pTrigger) return;
pTrigger->AddSignal(rSignal.GetName());
}
/**
* @brief Remove a signal from the trigger.
* @param[in] rSignal Reference to the signal.
*/
void RemoveSignal(const CSignal& rSignal)
{
if (!m_pTrigger) return;
ITxTrigger* pTrigger = m_pTrigger->GetInterface<ITxTrigger>();
if (!pTrigger) return;
pTrigger->RemoveSignal(rSignal.GetName());
}
protected:
/**
* @brief Get the pointer of the callback object.
* @return Interface pointer to the callback.
*/
IInterfaceAccess* GetCallback()
{
return m_ptrCallback.get();
}
/**
* @brief Assign the trigger object.
* @param[in] pTrigger Pointer to the interface to the trigger object.
*/
void Assign(IInterfaceAccess* pTrigger)
{
m_pTrigger = pTrigger;
}
private:
/**
* @brief Trigger callback wrapper object.
*/
struct STriggerCallback : public IInterfaceAccess, public ITxTriggerCallback
{
STriggerCallback(std::function<void()> fnExecute) : m_fnExecute(fnExecute)
{}
protected:
// Interface map
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(ITxTriggerCallback)
END_SDV_INTERFACE_MAP()
/**
* @brief Execute the trigger. Overload of ITxTriggerCallback::Execute.
*/
virtual void Execute() override
{
if (m_fnExecute) m_fnExecute();
}
private:
std::function<void()> m_fnExecute; ///< Execution callback function.
};
CDispatchService* m_pDispatch = nullptr; ///< Pointer to the dispatch class.
IInterfaceAccess* m_pTrigger = nullptr; ///< Trigger object
std::unique_ptr<STriggerCallback> m_ptrCallback; ///< Callback object
};
inline CDispatchService::CDispatchService()
{}
inline CDispatchService::~CDispatchService()
{}
template <typename TType>
inline CSignal CDispatchService::RegisterTxSignal(const u8string& rssName, TType tDefVal)
{
ISignalTransmission* pRegister = GetObject<ISignalTransmission>("DataDispatchService");
CSignal signal;
if (pRegister)
signal = CSignal(*this, rssName,
pRegister->RegisterTxSignal(rssName, any_t(tDefVal)),
true);
return signal;
}
inline CSignal CDispatchService::RegisterRxSignal(const u8string& rssName)
{
ISignalTransmission* pRegister = GetObject<ISignalTransmission>("DataDispatchService");
CSignal signal;
if (pRegister)
signal = CSignal(*this, rssName, pRegister->RegisterRxSignal(rssName), true);
return signal;
}
inline CSignal CDispatchService::AddPublisher(const u8string& rssSignalName)
{
ISignalAccess* pAccess = GetObject<ISignalAccess>("DataDispatchService");
CSignal signal;
if (pAccess)
signal = CSignal(*this, rssSignalName, pAccess->RequestSignalPublisher(rssSignalName), false);
return signal;
}
inline CSignal CDispatchService::Subscribe(const u8string& rssSignalName, std::function<void(any_t)> func)
{
ISignalAccess* pAccess = GetObject<ISignalAccess>("DataDispatchService");
CSignal signal(*this, rssSignalName, func);
if (pAccess)
signal.Assign(pAccess->AddSignalSubscription(rssSignalName, signal.GetSubscriptionEventHandler()));
return signal;
}
template <typename TType>
inline CSignal CDispatchService::Subscribe(const u8string& rssSignalName, std::atomic<TType>& rtVal)
{
ISignalAccess* pAccess = GetObject<ISignalAccess>("DataDispatchService");
CSignal signal(*this, rssSignalName, rtVal);
if (pAccess)
signal.Assign(pAccess->AddSignalSubscription(rssSignalName, signal.GetSubscriptionEventHandler()));
return signal;
}
inline sequence<SSignalRegistration> CDispatchService::GetRegisteredSignals() const
{
ISignalAccess* pAccess = GetObject<ISignalAccess>("DataDispatchService");
sequence<SSignalRegistration> seqSignalNames;
if (pAccess) seqSignalNames = pAccess->GetRegisteredSignals();
return seqSignalNames;
}
inline CTransaction CDispatchService::CreateTransaction()
{
IDispatchTransaction* pTransaction = GetObject<IDispatchTransaction>("DataDispatchService");
CTransaction transaction;
if (pTransaction) transaction = CTransaction(*this, pTransaction->CreateTransaction());
return transaction;
}
inline void CDispatchService::FinishTransaction(CTransaction& rTransaction)
{
rTransaction.Finish();
}
inline CTrigger CDispatchService::CreateTxTrigger(std::function<void()> fnExecute, bool bSpontaneous /*= true*/,
uint32_t uiDelayTime /*= 0*/, uint32_t uiPeriod /*= 0ul*/, bool bOnlyWhenActive /*= false*/)
{
if (!fnExecute) return CTrigger();
if (!bSpontaneous && !uiPeriod) return CTrigger();
ISignalTransmission* pSignalTransmission = GetObject<ISignalTransmission>("DataDispatchService");
if (!pSignalTransmission) return CTrigger();
uint32_t uiFlags = 0;
if (bSpontaneous) uiFlags |= static_cast<uint32_t>(ISignalTransmission::ETxTriggerBehavior::spontaneous);
if (uiPeriod && bOnlyWhenActive) uiFlags |= static_cast<uint32_t>(ISignalTransmission::ETxTriggerBehavior::periodic_if_active);
CTrigger trigger(*this, fnExecute);
trigger.Assign(pSignalTransmission->CreateTxTrigger(uiPeriod, uiDelayTime, uiFlags, trigger.GetCallback()));
return trigger;
}
} // namespace core
} // namespace sdv
#endif // !defined SIGNAL_SUPPORT_H

2317
export/support/string.h Normal file

File diff suppressed because it is too large Load Diff

2939
export/support/string.inl Normal file

File diff suppressed because it is too large Load Diff

181
export/support/timer.h Normal file
View File

@@ -0,0 +1,181 @@
#ifndef VAPI_TASK_TIMER_H
#define VAPI_TASK_TIMER_H
#include "../interfaces/timer.h"
#include "interface_ptr.h"
#include "local_service_access.h"
#include <functional>
namespace sdv
{
namespace core
{
/**
* @brief Task timer class.
*/
class CTaskTimer
{
public:
/**
* @brief Dfault constructor
*/
CTaskTimer() = default;
/**
* @brief Constructor
* @param[in] uiPeriod The period to create a timer for.
* @param[in] fnCallback Callback function to be called on task execution.
*/
CTaskTimer(uint32_t uiPeriod, std::function<void()> fnCallback) :
m_ptrCallback(std::make_unique<STimerCallback>(fnCallback))
{
if (!m_ptrCallback) return;
if (!uiPeriod) return;
// Get the task timer service.
sdv::core::ITaskTimer* pTaskTimer = sdv::core::GetObject<sdv::core::ITaskTimer>("TaskTimerService");
if (!pTaskTimer)
{
pTaskTimer = sdv::core::GetObject<sdv::core::ITaskTimer>("SimulationTaskTimerService");
if (!pTaskTimer) return;
}
// Create the timer
m_pTimer = pTaskTimer->CreateTimer(uiPeriod, m_ptrCallback.get());
}
/**
* @brief Constructor
* @param[in] uiPeriod The period to create a timer for.
* @param[in] pTask Pointer to the interface of the task object to be called. The object must expose
* sdv::core::ITastExecute.
*/
CTaskTimer(uint32_t uiPeriod, sdv::IInterfaceAccess* pTask)
{
if (!uiPeriod) return;
// Get the task timer service.
sdv::core::ITaskTimer* pTaskTimer = sdv::core::GetObject<sdv::core::ITaskTimer>("TaskTimerService");
if (!pTaskTimer)
{
pTaskTimer = sdv::core::GetObject<sdv::core::ITaskTimer>("SimulationTaskTimerService");
if (!pTaskTimer) return;
}
// Create the timer
m_pTimer = pTaskTimer->CreateTimer(uiPeriod, pTask);
}
/**
* @brief Copy constructor is deleted.
*/
CTaskTimer(const CTaskTimer&) = delete;
/**
* @brief Move constructor
* @param[in] rtimer Reference to the timer to move from.
*/
CTaskTimer(CTaskTimer&& rtimer) noexcept :
m_pTimer(rtimer.m_pTimer), m_uiPeriod(rtimer.m_uiPeriod), m_ptrCallback(std::move(rtimer.m_ptrCallback))
{
rtimer.m_pTimer = nullptr;
rtimer.m_uiPeriod = 0;
}
/**
* @brief Destructor
*/
~CTaskTimer()
{
Reset();
}
/**
* @brief Assignment operator is deleted.
*/
CTaskTimer& operator=(const CTaskTimer&) = delete;
/**
* @brief Move operator
* @param[in] rtimer Reference to the timer to move from.
* @return Reference to this timer object.
*/
CTaskTimer& operator=(CTaskTimer&& rtimer) noexcept
{
Reset();
m_pTimer = rtimer.m_pTimer;
m_ptrCallback = std::move(rtimer.m_ptrCallback);
m_uiPeriod = rtimer.m_uiPeriod;
rtimer.m_pTimer = nullptr;
rtimer.m_uiPeriod = 0;
return *this;
}
/**
* @brief Returns whether the timer is valid.
*/
operator bool() const
{
return m_pTimer;
}
/**
* @brief Reset the timer. Releases the timer object.
*/
void Reset()
{
if (m_pTimer)
{
IObjectDestroy* pDestroy = m_pTimer->GetInterface<IObjectDestroy>();
if (pDestroy)
pDestroy->DestroyObject();
m_pTimer = nullptr;
}
m_ptrCallback.reset();
m_uiPeriod = 0ul;
}
/**
* @brief Get the task timer period.
* @return The period of the timer in ms.
*/
uint32_t GetPeriod() const
{
return m_uiPeriod;
}
private:
/**
* @brief Timer callback wrapper object.
*/
struct STimerCallback : public IInterfaceAccess, public core::ITaskExecute
{
STimerCallback(std::function<void()> fnCallback) : m_fnCallback(fnCallback)
{}
protected:
// Interface map
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(core::ITaskExecute)
END_SDV_INTERFACE_MAP()
/**
* @brief Execute the trigger. Overload of ITxTriggerCallback::Execute.
*/
virtual void Execute() override
{
if (m_fnCallback) m_fnCallback();
}
private:
std::function<void()> m_fnCallback; ///< Callback function
};
sdv::IInterfaceAccess* m_pTimer = nullptr; ///< Timer object
uint32_t m_uiPeriod = 0ul; ///< Task timer period
std::unique_ptr<STimerCallback> m_ptrCallback; ///< Callback object
};
}
}
#endif // !defined VAPI_TASK_TIMER_H

379
export/support/toml.h Normal file
View File

@@ -0,0 +1,379 @@
#ifndef SDV_CONFIG_H
#define SDV_CONFIG_H
#include "../interfaces/toml.h"
#include "interface_ptr.h"
#include "local_service_access.h"
namespace sdv::toml
{
/**
* @brief Node class allowing access to the type and value.
*/
class CNode
{
public:
/**
* @brief Default constructor.
*/
CNode() = default;
/**
* @brief Node assignment constructor.
* @param[in] rptrNode Reference to the node interface.
*/
CNode(const TInterfaceAccessPtr& rptrNode);
/**
* @brief Node assignment operator.
* @param[in] rptrNode Reference to the node interface.
* @return Reference to this class.
*/
CNode& operator=(const TInterfaceAccessPtr& rptrNode);
/**
* @brief Does the class contain a valid node?
* @return Returns 'true' if the class contains a valid node; 'false' otherwise.
*/
virtual bool IsValid() const;
/**
* @brief Does the class contain a valid node?
* @return Returns 'true' if the class contains a valid node; 'false' otherwise.
*/
virtual operator bool() const;
/**
* @brief Return the node name.
* @return String containing the node name.
*/
sdv::u8string GetName();
/**
* @brief Get the node type.
* @return The node type.
*/
ENodeType GetType();
/**
* @brief Get the node value if the node contains a value.
* @return The node value.
*/
sdv::any_t GetValue();
/**
* @brief Clear the node class.
*/
virtual void Clear();
/**
* @brief Get the TOML string from this node including all children.
* @return The TOMl string.
*/
sdv::u8string GetTOML() const;
protected:
TInterfaceAccessPtr m_ptrNode; ///< Pointer to the node interface.
INodeInfo* m_pNodeInfo = nullptr; ///< Node information interface.
};
/**
* @brief Node collection class representing a table or array node.
*/
class CNodeCollection : public CNode
{
public:
/**
* @brief Default constructor.
*/
CNodeCollection() = default;
/**
* @brief Node assignment constructor.
* @param[in] rptrNode Reference to the node interface.
*/
CNodeCollection(const TInterfaceAccessPtr& rptrNode);
/**
* @brief Node assignment constructor.
* @param[in] rNode Reference to the node class.
*/
CNodeCollection(const CNode& rNode);
/**
* @brief Node assignment operator.
* @param[in] rptrNode Reference to the node interface.
* @return Reference to this class.
*/
CNodeCollection& operator=(const TInterfaceAccessPtr& rptrNode);
/**
* @brief Node assignment operator.
* @param[in] rNode Reference to the node class.
* @return Reference to this class.
*/
CNodeCollection& operator=(const CNode& rNode);
/**
* @brief Does the class contain a valid node?
* @return Returns 'true' if the class contains a valid node; 'false' otherwise.
*/
virtual bool IsValid() const override;
/**
* @brief Does the class contain a valid node?
* @return Returns 'true' if the class contains a valid node; 'false' otherwise.
*/
virtual operator bool() const override;
/**
* @brief Return the amount of nodes in this collection.
* @return The amount of nodes.
*/
size_t GetCount() const;
/**
* @brief Get the node at the provided index.
* @param[in] nIndex The index number.
* @return Returns the node if available or an empty node when not.
*/
CNode Get(size_t nIndex) const;
/**
* @brief Get the node at the provided index.
* @param[in] nIndex The index number.
* @return Returns the node if available or an empty node when not.
*/
CNode operator[](size_t nIndex) const;
/**
* @brief Clear the node class.
*/
virtual void Clear() override;
/**
* @brief Get direct access to a node.
* @details Elements of tables can be accessed and traversed by using '.' to separated the parent name from child name.
* E.g. 'parent.child' would access the 'child' element of the 'parent' table. Elements of arrays can be accessed and
* traversed by using the index number in brackets. E.g. 'array[3]' would access the fourth element of the array 'array'.
* These access conventions can also be chained like 'table.array[2][1].subtable.integerElement'.
* @param[in] rssNode Reference to the node string.
* @return Returns the node when available or an empty node when not.
*/
CNode GetDirect(const sdv::u8string& rssNode) const;
private:
INodeCollection* m_pCollection = nullptr; ///< Pointer to the node collection interface.
};
/**
* @brief TOML parser class
*/
class CTOMLParser : public CNodeCollection
{
public:
/**
* @brief Default constructor.
*/
CTOMLParser() = default;
/**
* @brief Constructor providing automatic processing.
* @param[in] rssConfig Reference to the configuration.
*/
CTOMLParser(const std::string& rssConfig);
/**
* @brief Process a configuration. This will clear any previous configuration.
* @param[in] rssConfig Reference to the configuration.
* @return Returns 'true' when the processing was successful; 'false# when not.
*/
bool Process(const std::string& rssConfig);
/**
* @brief Returns whether a valid processed configuration is available.
* @return Returns 'true' when the configuration is valid; 'false' when not.
*/
virtual bool IsValid() const override;
/**
* @brief Returns whether a valid processed configuration is available.
* @return Returns 'true' when the configuration is valid; 'false' when not.
*/
virtual operator bool() const override;
// Ignore cppcheck warning for not using dynamic binding when being called through the destructor.
// cppcheck-suppress virtualCallInConstructor
/**
* @brief Clear the current configuration.
*/
virtual void Clear() override;
private:
TObjectPtr m_ptrParserUtil; ///< TOML parser utility
ITOMLParser* m_pParser = nullptr; ///< Pointer to the parser interface.
};
inline CNode::CNode(const TInterfaceAccessPtr& rptrNode)
{
m_pNodeInfo = rptrNode.GetInterface<INodeInfo>();
if (!m_pNodeInfo)
return;
m_ptrNode = rptrNode;
}
inline CNode& CNode::operator=(const TInterfaceAccessPtr& rptrNode)
{
CNode::Clear();
m_pNodeInfo = rptrNode.GetInterface<INodeInfo>();
if (!m_pNodeInfo)
return *this;
m_ptrNode = rptrNode;
return *this;
}
inline bool CNode::IsValid() const
{
return m_pNodeInfo ? true : false;
}
inline CNode::operator bool() const
{
return m_pNodeInfo ? true : false;
}
inline sdv::u8string CNode::GetName()
{
return m_pNodeInfo ? m_pNodeInfo->GetName() : sdv::u8string();
}
inline ENodeType CNode::GetType()
{
return m_pNodeInfo ? m_pNodeInfo->GetType() : ENodeType::node_invalid;
}
inline sdv::any_t CNode::GetValue()
{
return m_pNodeInfo ? m_pNodeInfo->GetValue() : sdv::any_t();
}
inline void CNode::Clear()
{
m_ptrNode = nullptr;
m_pNodeInfo = nullptr;
}
inline sdv::u8string CNode::GetTOML() const
{
return m_pNodeInfo ? m_pNodeInfo->GetTOML() : sdv::u8string();
}
inline CNodeCollection::CNodeCollection(const TInterfaceAccessPtr& rptrNode) : CNode(rptrNode)
{
m_pCollection = rptrNode.GetInterface<INodeCollection>();
if (!m_pCollection) CNode::Clear();
}
inline CNodeCollection::CNodeCollection(const CNode& rNode) : CNode(rNode)
{
m_pCollection = m_ptrNode.GetInterface<INodeCollection>();
if (!m_pCollection) CNode::Clear();
}
inline CNodeCollection& CNodeCollection::operator=(const TInterfaceAccessPtr& rptrNode)
{
CNode::operator=(rptrNode);
m_pCollection = rptrNode.GetInterface<INodeCollection>();
if (!m_pCollection) CNode::Clear();
return *this;
}
inline CNodeCollection& CNodeCollection::operator=(const CNode& rNode)
{
CNode::operator=(rNode);
m_pCollection = m_ptrNode.GetInterface<INodeCollection>();
if (!m_pCollection) CNode::Clear();
return *this;
}
inline bool CNodeCollection::IsValid() const
{
return m_pCollection ? true : false;
}
inline CNodeCollection::operator bool() const
{
return m_pCollection ? true : false;
}
inline size_t CNodeCollection::GetCount() const
{
return m_pCollection ? m_pCollection->GetCount() : 0;
}
inline CNode CNodeCollection::Get(size_t nIndex) const
{
return m_pCollection ? CNode(m_pCollection->GetNode(static_cast<uint32_t>(nIndex))) : CNode();
}
inline CNode CNodeCollection::operator[](size_t nIndex) const
{
return m_pCollection ? CNode(m_pCollection->GetNode(static_cast<uint32_t>(nIndex))) : CNode();
}
inline void CNodeCollection::Clear()
{
CNode::Clear();
m_pCollection = nullptr;
}
inline CNode CNodeCollection::GetDirect(const sdv::u8string& rssNode) const
{
return m_pCollection ? CNode(m_pCollection->GetNodeDirect(rssNode)) : CNode();
}
inline CTOMLParser::CTOMLParser(const std::string& rssConfig)
{
Process(rssConfig);
}
inline bool CTOMLParser::Process(const std::string& rssConfig)
{
Clear();
m_ptrParserUtil = sdv::core::CreateUtility("TOMLParserUtility");
m_pParser = m_ptrParserUtil.GetInterface<ITOMLParser>();
if (m_pParser)
{
try
{
m_pParser->Process(rssConfig);
CNodeCollection::operator=(m_ptrParserUtil);
}
catch (const sdv::toml::XTOMLParseException&)
{
Clear();
return false;
}
}
return IsValid();
}
inline bool CTOMLParser::IsValid() const
{
return m_pParser ? true : false;
}
inline CTOMLParser::operator bool() const
{
return m_pParser ? true : false;
}
inline void CTOMLParser::Clear()
{
m_pParser = nullptr;
m_ptrParserUtil.Clear();
}
}
#endif // !defined SDV_CONFIG_H