mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-02-05 15:18:45 +00:00
491
export/support/any.h
Normal file
491
export/support/any.h
Normal 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
1460
export/support/any.inl
Normal file
File diff suppressed because it is too large
Load Diff
476
export/support/app_control.h
Normal file
476
export/support/app_control.h
Normal 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
|
||||
954
export/support/component_impl.h
Normal file
954
export/support/component_impl.h
Normal 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
207
export/support/crc.h
Normal 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
31
export/support/except.h
Normal 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
279
export/support/interface.h
Normal 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
|
||||
208
export/support/interface.inl
Normal file
208
export/support/interface.inl
Normal 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
|
||||
835
export/support/interface_ptr.h
Normal file
835
export/support/interface_ptr.h
Normal 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
355
export/support/iterator.h
Normal 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
|
||||
310
export/support/local_service_access.h
Normal file
310
export/support/local_service_access.h
Normal 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
|
||||
85
export/support/mem_access.h
Normal file
85
export/support/mem_access.h
Normal 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
665
export/support/pointer.h
Normal 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
877
export/support/pointer.inl
Normal 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
464
export/support/pssup.h
Normal 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
999
export/support/pssup.inl
Normal 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
300
export/support/sdv_core.h
Normal 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
|
||||
250
export/support/sdv_test_macro.h
Normal file
250
export/support/sdv_test_macro.h
Normal 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
596
export/support/sequence.h
Normal 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
713
export/support/sequence.inl
Normal 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
297
export/support/serdes.h
Normal 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
651
export/support/serdes.inl
Normal 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
|
||||
832
export/support/signal_support.h
Normal file
832
export/support/signal_support.h
Normal 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
2317
export/support/string.h
Normal file
File diff suppressed because it is too large
Load Diff
2939
export/support/string.inl
Normal file
2939
export/support/string.inl
Normal file
File diff suppressed because it is too large
Load Diff
181
export/support/timer.h
Normal file
181
export/support/timer.h
Normal 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
379
export/support/toml.h
Normal 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
|
||||
Reference in New Issue
Block a user