/******************************************************************************** * Copyright (c) 2025-2026 Contributors to the Eclipse Foundation * * This program and the accompanying materials are made available under the * terms of the Apache License Version 2.0 which is available at * https://www.apache.org/licenses/LICENSE-2.0 * * SPDX-License-Identifier: Apache-2.0 * * Contributors: * Erik Verhoeven - initial API and implementation ********************************************************************************/ #ifndef PARAM_IMPL_H #define PARAM_IMPL_H #include "../interfaces/param.h" #include "interface_ptr.h" #include #include #include #include #include #include /** * @brief Software Defined Vehicle framework. */ namespace sdv { // Forward declaration class CSdvParamMap; /** * @brief Parameter information helper class; used for filling the parameter definition. */ class CSdvParamInfo : private SParamInfo { public: /** * @brief Constructor for automatic parameter type detection. * @tparam TVar Type of the variable determining the type of information. * @tparam TDefaultType Type of the variable of the default value. * @param[in] rtVar Reference to the variable to extract the type from. * @param[in] rssName Reference to the string containing the name of the parameter. * @param[in] tDefaultVal The default value assigned to the parameter. * @param[in] rssUnit Reference to the string containing the unit description. * @param[in] rssCategory Reference to the string containing the name of the group. Can be empty when no group * is provided. * @param[in] rssDescription Reference to the string containing the description of the parameter. * @param[in] uiFlags The flags to use with this parameter (extended with read-only for 'const' types). */ template CSdvParamInfo(TVar& rtVar, const std::string& rssName, TDefaultType tDefaultVal, const std::string& rssUnit, const std::string& rssCategory, const std::string& rssDescription, uint32_t uiFlags); /** * @brief Constructor for numeric values. The parameter type is extracted from the variable type. * @tparam TVar Type of the variable determining the type of information. * @param[in] rtVar Reference to the variable to extract the type from. * @param[in] rssName Reference to the string containing the name of the parameter. * @param[in] tDefaultVal The default value assigned to the parameter. * @param[in] ranyLimitLow Reference to the lower limit value or no limit if set to empty. * @param[in] bIncludeLow If there is a lower limit set, the boolean defines how to interpret the limit: when set * limit <= value, when not set limit < value. * @param[in] ranyLimitHigh Reference to the higher limit value or no limit if set to empty. * @param[in] bIncludeHigh If there is a higher limit set, the boolean defines how to interpret the limit: when set * limit >= value, when not set limit > value. * @param[in] rssUnit Reference to the string containing the unit description. * @param[in] rssCategory Reference to the string containing the name of the group. Can be empty when no group * is provided. * @param[in] rssDescription Reference to the string containing the description of the parameter. * @param[in] uiFlags The flags to use with this parameter (extended with read-only for 'const' types). */ template CSdvParamInfo(TVar& rtVar, const std::string& rssName, TDefaultType tDefaultVal, const any_t& ranyLimitLow, bool bIncludeLow, const any_t& ranyLimitHigh, bool bIncludeHigh, const std::string& rssUnit, const std::string& rssCategory, const std::string& rssDescription, uint32_t uiFlags); /** * @brief Construct function for string values. The numeric type is extracted from the variable type. * @tparam TVar Type of the variable determining the type of information. * @tparam TDefaultType Type of the variable of the default value. * @param[in] rtVar Reference to the variable to extract the type from. * @param[in] rssName Reference to the string containing the name of the parameter. * @param[in] tDefaultVal The default value assigned to the parameter. * @param[in] rssPattern Reference to the string containing the regular expression describing the pattern the value is * allowed to have. * @param[in] rssUnit Reference to the string containing the unit description. * @param[in] rssCategory Reference to the string containing the name of the group. Can be empty when no group * is provided. * @param[in] rssDescription Reference to the string containing the description of the parameter. * @param[in] uiFlags The flags to use with this parameter (extended with read-only for 'const' types). */ template CSdvParamInfo(TVar& rtVar, const std::string& rssName, TDefaultType tDefaultVal, const std::string& rssPattern, const std::string& rssUnit, const std::string& rssCategory, const std::string& rssDescription, uint32_t uiFlags); /** * @brief Constructor function for enumerator and bitmask parameters. The parameter type is extracted from the variable * type. * @tparam TVar Type of the variable determining the type of information. * @tparam TDefaultType Type of the variable of the default value. * @param[in] rtVar Reference to the variable to extract the type from. * @param[in] rssName Reference to the string containing the name of the parameter. * @param[in] tDefaultVal The default value assigned to the parameter. * @param[in] rseqLabels Reference to the sequence of labels available for the enumerator or bitmask. * @param[in] rssCategory Reference to the string containing the name of the group. Can be empty when no group * is provided. * @param[in] rssDescription Reference to the string containing the description of the parameter. * @param[in] uiFlags The flags to use with this parameter (extended with read-only for 'const' types). */ template CSdvParamInfo(TVar& rtVar, const std::string& rssName, TDefaultType tDefaultVal, const sequence& rseqLabels, const std::string& rssCategory, const std::string& rssDescription, uint32_t uiFlags); /** * @brief Assignment constructor for parameter information structure. * @param rInfo Reference to the parameter information structure. */ CSdvParamInfo(const SParamInfo& rInfo); /** * @brief Move constructor for the parameter information structure. * @param rInfo Reference to the parameter information structure. */ CSdvParamInfo(SParamInfo&& rInfo); /** * @brief Default destructor. */ virtual ~CSdvParamInfo() = default; /** * @brief Assignment operator for parameter information. * @param rsInfo Reference to the information structure. * @return Reference to this class. */ CSdvParamInfo& operator=(const SParamInfo& rsInfo); /** * @brief Move operator for parameter information. * @param rsInfo Reference to the information structure. * @return Reference to this class. */ CSdvParamInfo& operator=(SParamInfo&& rsInfo); /** * @brief Get the parameter information structure. * @return Reference to the parameter information structure. */ virtual SParamInfo InfoStruct() const; /** * @brief Get the name of the parameter. * @return Reference to the parameter name. */ const u8string& Name() const; /** * @brief Get the path of the parameter (name and grops together). * @return Path to the parameter. */ u8string Path() const; /** * @brief Get the default value of the parameter. * @return Reference to the default value. */ const any_t& DefaultVal() const; /** * @brief Get the group of the parameter. * @return Reference to the parameter group. */ const u8string& Group() const; /** * @brief Get the description of the parameter. * @return Reference to the parameter description. */ const u8string& Description() const; /** * @brief Get the unit for the parameter. * @return Reference to the parameter unit. */ const u8string& Unit() const; /** * @brief Get the parameter flags. * @return The parameter flags. */ virtual uint32_t Flags() const; /** * @brief Is this a read-only parameter? * @return Returns whether the parameter has a read-only flag. */ bool ReadOnly() const; /** * @brief Is this a Temporary parameter? * @return Returns whether the parameter has a temporary flag. */ bool Temporary() const; /** * @brief Is the parameter dirty (state value, not available in static param info)? * @return Returns whether the parameter has a dirty flag set. */ virtual bool Dirty() const; /** * @brief Is this parameter locked (state value, not available in static param info)? * @return Returns whether the parameter has a locked flag set. */ virtual bool Locked() const; /** * @brief Is the paratemer a boolean parameter. * @return Returns whether the parameter is boolean. */ bool Boolean() const; /** * @brief Is the paratemer a numeric parameter. * @return Returns whether the parameter is numeric. */ bool Numeric() const; /** * @brief Is the parameter a string parameter. * @return Returns whether the parameter is a string. */ bool String() const; /** * @brief Is the parameter an enum parameter. * @return Returns whether the parameter is an enum. */ bool Enum() const; /** * @brief Is the parameter a bitmask parameter. * @return Returns whether the parameter is a bitmask. */ bool Bitmask() const; /** * @brief Get the lower limit for a numeric parameter. * @return Return a pair with the lower limit and a boolean whether the lower limit can be used as a value. The lower limit * will be set to empty if the parameter is not numeric or if there is no lower limit set for the parameter. */ std::pair NumericLimitLow() const; /** * @brief Get the higher limit for a numeric parameter. * @return Return a pair with the upper limit and a boolean whether the upper limit can be used as a value. The upper limit * will be set to empty if the parameter is not numeric or if there is no upper limit set for the parameter. */ std::pair NumericLimitHigh() const; /** * @brief Get the string pattern for a string parameter. * @return Return the string pattern or an empty string. */ std::string StringPattern() const; /** * @brief Get the labels for an enumerator or bitmask parameter. * @return Returns a sequence with the labels or an empty sequence when the parameter is not an enumerator or a bitmask or * there are no labels defined. */ sequence EnumBitmaskLabels() const; protected: /** * @brief Check the type for being a string (standard C++ string, SDV string, character array, character pointer). * @tparam TType Type to check for. * @return Returns whether the type is a string. */ template static constexpr bool TypeIsString(); /** * @brief Check the type for being read only. * @remarks Character arrays and character pointers are also identified as read only. * @tparam TType Type to check for. * @return Returns whether the type is read only. */ template static constexpr bool TypeIsReadOnly(); private: /** * @brief Initialization function called by constructors. * @param[in] eType The type of the parameter. * @param[in] rssName Reference to the string containing the name of the parameter. * @param[in] ranyDefaultVal Reference to the default value assigned to the parameter. Could be empty if no value was * assigned. * @param[in] rssUnit Reference to the string containing the unit description. * @param[in] rssCategory Reference to the string containing the name of the group. Can be empty when no group * is provided. * @param[in] rssDescription Reference to the string containing the description of the parameter. * @param[in] uiFlags The flags to use with this parameter (extended with read-only for 'const' types). */ void Init(EParamType eType, const std::string& rssName, const any_t& ranyDefaultVal, const std::string& rssUnit, const std::string& rssCategory, const std::string& rssDescription, uint32_t uiFlags); }; /** Internal namespace */ namespace internal { /** * @brief The parameter guardian class limits manages the parameter states and allows access to the parameter infos and * values. */ class CParamGuardian : public CSdvParamInfo { public: /** * @brief Constructor. * @tparam TInfoConstruct The type of the variables that are provided to the constructor function of the parameter * information. * @param[in] bLockable When set, the parameter is lockable. Only use with writable parameters. * @param[in] bAutoDirty When set, the parameter dirty flag is detected automatically. Only use with writable parameters. * @param[in] tConstruct The construct function arguments. */ template CParamGuardian(bool bLockable, bool bAutoDirty, TInfoConstruct... tConstruct); /** * @brief Get the parameter information structure. Overload of sdv::CSdvParamInfo::InfoStruct. * @return Reference to the parameter information structure. */ virtual sdv::SParamInfo InfoStruct() const override; /** * @brief Get the parameter flags. Overload of sdv::CSdvParamInfo::Flags. * @return The parameter flags. */ virtual uint32_t Flags() const override; /** * @brief Mark the parameter as dirty if the value has changed. This implies the automatic dirty detection to be * enabled. * @param ranyValue Reference to the value to be used to to check. * @return Returns 'true' if the dirty flag has changed. */ bool UpdateDirty(const sdv::any_t& ranyValue); /** * @brief Explicitly set the parameter to dirty. * @return Returns 'true' if the dirty flag has changed. */ bool SetDirty(); /** * @brief Reset the parameter dirty flag. * @return Returns 'true' if the dirty flag has changed. */ bool ResetDirty(); /** * @brief Is the parameter marked dirty? Overload of sdv::CSdvParamInfo::Dirty. * @return Returns the dirty flag of the parameter. */ virtual bool Dirty() const override; /** * @brief Is the parameter lockable? * @return Returns whether the parameter can be locked. */ bool Lockable() const; /** * @brief Lock the parameter. * @return Returns 'true' if the lock flag has changed. */ bool Lock(); /** * @brief Unlock the parameter. * @return Returns 'true' if the lock flag has changed. */ bool Unlock(); /** * @brief Is the parameter currently locked? Overload of sdv::CSdvParamInfo::Locked. * @return Returns the lock flag for the parameter. */ virtual bool Locked() const override; /** * @brief Set a value. * @param[in] ranyValue Reference to the value. * @return Returns whether the parameter is writable and can be set. */ virtual bool Set(const any_t& ranyValue) = 0; /** * @brief Get a value. * @return Returns the value. */ virtual any_t Get() const = 0; protected: /** * @brief Check the variable for compatibility the restrictions. * @param[in] ranyValue Reference to the value. * @return Returns whether the variable passes the restrictions. */ bool CheckRestrictions(const any_t& ranyValue); private: bool m_bLockable = false; ///< When set, the parameter is lockable (only for writable parameters). bool m_bLocked = false; ///< When set, the parameter is locked against writing (only for lockable parameters). bool m_bAutoDirty = false; ///< When set, automatic dirty flag detection is enabled (only for writable parameters). bool m_bDirty = false; ///< When set, the parameter is marked as dirty. any_t m_anyStored; ///< Value of the parameter to detect for dirtiness. }; /** * @brief Parameter value class * @tparam TVar Type of the parameter variable. */ template class CParamValue : public CParamGuardian { public: /** * @brief Constructor. * @tparam TInfoConstruct The type of the variables that are provided to the constructor function of the parameter * information. * @param[in] rtVar Reference to the parameter variable. * @param[in] bLockable When set, the parameter is lockable. Only use with writable parameters. * @param[in] bAutoDirty When set, the parameter dirty flag is detected automatically. Only use with writable parameters. * @param[in] tConstruct The construct function arguments. */ template CParamValue(TVar& rtVar, bool bLockable, bool bAutoDirty, TInfoConstruct... tConstruct); /** * @brief Set a value. Overload of CParamGuardian::Set. * @param[in] ranyValue Reference to the value. * @return Returns whether the parameter is writable and can be set. */ virtual bool Set(const any_t& ranyValue) override; /** * @brief Get a value. Overload of CParamGuardian::Get. * @return Returns the value. */ virtual any_t Get() const override; private: TVar& m_rtVar; ///< Reference to the parameter }; /** * @brief Label map helper class. This helper class collects the labels of each defined map. */ class CLabelMapHelper { public: /** * @brief Explicit clearing of the label map might be needed when a local memory manager is used. * @remarks Call this function before the destruction of the memory manager. */ void Clear() { m_mapLabelCollections.clear(); } /** * @brief Local version of SLabel. */ struct SLabelLocal { sdv::any_t anyValue; ///< Label value (must be an integral number) std::string ssLabel; ///< Label text }; /** * @brief Store a collection of labels for an enum type. * @attention Since this function is called before the execution of main(), there is no SDV memory manager available * yet. Use the C++ allocation instead (this means conversion needs to be done at a later stage). * @tparam TEnum The enum type this label collection is describing. * @param rseqLabels Reference to the sequence containing the label-value-pairs. * @return Return 'true' to allow an assignment to a static variable during startup. */ template bool StoreLabelMap(const std::vector& rseqLabels) { m_mapLabelCollections[typeid(TEnum).name()] = rseqLabels; return true; } /** * @brief Get a previously stored label collection for an enum type. * @tparam TEnum The enum type to get the labels for. * @return Reference to a sequence containing the label-value-pairs or an empty sequence when no labels were stored for * this enum type. */ template sequence GetLabelMap() const { using TEnumLocal = std::remove_reference_t; static const sequence seqEmpty; auto itEnum = m_mapLabelCollections.find(typeid(TEnumLocal).name()); if (itEnum == m_mapLabelCollections.end()) return seqEmpty; // Create a copy pf the data using the SDV memory manager. sequence seqLabels; for (const SLabelLocal& rsLabel : itEnum->second) seqLabels.push_back(SLabelInfo::SLabel{rsLabel.anyValue, rsLabel.ssLabel}); return seqLabels; } private: std::map> m_mapLabelCollections; ///< Map with label collections. }; /** * @brief Get access to the one instance of the label map helper class. * @return Reference to the label map helper class instance. */ inline CLabelMapHelper& GetLabelMapHelper() { static CLabelMapHelper helper; return helper; } /** Limit type to use */ enum class ELimitType { up_to_limit, up_to_and_include_limit, no_limit }; /** * @brief Determine the lower limit of the numeric value. * @details The lower limit is defined by the operators > and >=. When no limit is required, the operator != is used * (defined by the macro NO_LIMIT). */ struct SLowerLimit { /** * @brief Operator larger than. * @tparam TType Type to use for the comparison. * @param[in] tLimit The limit value. * @return A pair defining the limit. First the type, second the limit type. */ template std::pair operator>(TType tLimit) const { return std::make_pair(tLimit, ELimitType::up_to_limit); } /** * @brief Operator larger than or equal. * @tparam TType Type to use for the comparison. * @param[in] tLimit The limit value. * @return A pair defining the limit. First the type, second the limit type. */ template std::pair operator>=(TType tLimit) const { return std::make_pair(tLimit, ELimitType::up_to_and_include_limit); } /** * @brief No limit operator. * @param[in] n The value that was supplied. This is typically 0. * @return A pair containing the value and the limit type, being no limit. */ std::pair operator!=(size_t n) const { return std::make_pair(n, ELimitType::no_limit); } }; /** * @brief Determine the upper limit of the numeric value. * @details The upper limit is defined by the operators < and <=. When no limit is required, the operator != is used * (defined by the macro NO_LIMIT). */ struct SUpperLimit { /** * @brief Operator smaller than. * @tparam TType Type to use for the comparison. * @param[in] tLimit The limit value. * @return A pair defining the limit. First the type, second the limit type. */ template std::pair operator<(TType tLimit) const { return std::make_pair(tLimit, ELimitType::up_to_limit); } /** * @brief Operator smaller than or equal. * @tparam TType Type to use for the comparison. * @param[in] tLimit The limit value. * @return A pair defining the limit. First the type, second the limit type. */ template std::pair operator<=(TType tLimit) const { return std::make_pair(tLimit, ELimitType::up_to_and_include_limit); } /** * @brief No limit operator. * @param[in] n The value that was supplied. This is typically 0. * @return A pair containing the value and the limit type, being no limit. */ std::pair operator!=(size_t n) const { return std::make_pair(n, ELimitType::no_limit); } }; /** * @brief Helper structure to determine if the type is a shared pointer. * @tparam T Type to test for. */ template struct is_shared_ptr : std::false_type {}; /** * @brief Specialization of std::shared_ptr. */ template struct is_shared_ptr> : std::true_type {}; /** * @brief Helper variable for is_shared_ptr. */ template inline constexpr bool is_shared_ptr_v = is_shared_ptr::value; /** * @brief Member access class. */ struct SMemberMapAccess { /** * @brief Find the parameter object with the supplied name. * @param[in] rssName Reference to the name of the parameter. * @return Returns a smart pointer to the parameter object. */ virtual std::shared_ptr FindParamObject(const sdv::u8string& rssName) = 0; /** * @{ * @brief Get CSdvParamMap access. * @return The parameter map pointer or a NULL pointer if there is no associated parameter map. */ virtual CSdvParamMap* Access() = 0; virtual const CSdvParamMap* Access() const = 0; /** * @} */ }; /** * @brief Struct to give access to a member map. * @tparam TMember The member variable type. */ template struct SMemberMap : SMemberMapAccess { static_assert(std::is_base_of_v, "The member type must derive from sdv::CSdvParamMap."); /// The type definition. using TType = TMember; /** * @brief Constructor * @param[in] rMember Reference to the member. * @param[in] pEventObject Pointer to the object receiving the parameter change notifications. */ SMemberMap(TMember& rMember, sdv::CSdvParamMap* pEventObject) : m_pEventObject(pEventObject), refMember(rMember) {} /** * @brief Default destructor. */ virtual ~SMemberMap() = default; /** * @brief Build the parameter map (static build). * @return Vector with parameter info classes. */ static std::vector> BuildStatic() { return TMember::BuildParamMap(nullptr, nullptr); } /** * @brief Build the parameter map. */ void BuildMap() { refMember.get().BuildParamMap(&refMember.get(), m_pEventObject); } /** * @brief Find the parameter object with the supplied name. Overload of SMemberMapAccess::FindParamObject. * @param[in] rssName Reference to the name of the parameter. * @return Returns a smart pointer to the parameter object. */ virtual std::shared_ptr FindParamObject(const sdv::u8string& rssName) override { return refMember.get().FindParamObject(rssName); } /** * @{ * @brief Get CSdvParamMap access. Overload of SMemberMapAccess::Interface. * @return The parameter map pointer or a NULL pointer if there is no associated parameter map. */ virtual CSdvParamMap* Access() override { return &refMember.get(); } virtual const CSdvParamMap* Access() const override { return &refMember.get(); } /** * @} */ private: sdv::CSdvParamMap* m_pEventObject; ///< Pointer to the object to receive notifications. std::reference_wrapper refMember; ///< Reference to the member map. }; /** * @brief Specialization for a pointer to the member. * @tparam TMember The member variable type. Must derive from sdv::CSdvParamMap. */ template struct SMemberMap : SMemberMapAccess { static_assert(std::is_base_of_v, "The member type must derive from sdv::CSdvParamMap."); /// The type definition. using TType = TMember; /** * @brief Constructor * @param[in] rpMember Reference to the pointer to the member. * @param[in] pEventObject Pointer to the object receiving the parameter change notifications. */ SMemberMap(TMember*& rpMember, sdv::CSdvParamMap* pEventObject) : m_pEventObject(pEventObject), refpMember(rpMember) {} /** * @brief Default destructor. */ virtual ~SMemberMap() = default; /** * @brief Build the parameter map (static build). * @return Vector with parameter info classes. */ static std::vector> BuildStatic() { return TMember::BuildParamMap(nullptr, nullptr); } /** * @brief Build the parameter map. */ void BuildMap() { if (refpMember.get()) refpMember.get()->BuildParamMap(refpMember.get(), m_pEventObject); } /** * @brief Find the parameter object with the supplied name. Overload of SMemberMapAccess::FindParamObject. * @param[in] rssName Reference to the name of the parameter. * @return Returns a smart pointer to the parameter object. */ virtual std::shared_ptr FindParamObject(const sdv::u8string& rssName) override { if (!refpMember.get()) return {}; return refpMember.get()->FindParamObject(rssName); } /** * @{ * @brief Get the IParameters interface. Overload of SMemberMapAccess::Interface. * @return The parameter map pointer or a NULL pointer if there is no associated parameter map. */ virtual CSdvParamMap* Access() override { // In case a change has happened, or the member was not build previously... if (refpMember.get()) refpMember.get()->BuildParamMap(refpMember.get(), m_pEventObject); return refpMember.get(); } virtual const CSdvParamMap* Access() const override { if (!refpMember.get()) return nullptr; // In case a change has happened, or the member was not build previously... if (refpMember.get()) refpMember.get()->BuildParamMap(refpMember.get(), m_pEventObject); return refpMember; } /** * @} */ private: sdv::CSdvParamMap* m_pEventObject; ///< Pointer to the object to receive notifications. mutable std::reference_wrapper refpMember; ///< Reference to the pointer to the member map. }; /** * @brief Specialization for a shared pointer to the member. * @tparam TMember The member variable type. Must derive from sdv::CSdvParamMap. */ template struct SMemberMap> : SMemberMapAccess { static_assert(std::is_base_of_v, "The member type must derive from sdv::CSdvParamMap."); /// The type definition. using TType = TMember; /** * @brief Constructor * @param[in] rptrMember Reference to the smart pointer holding the member. * @param[in] pEventObject Pointer to the object receiving the parameter change notifications. */ // Warning of cppcheck 2.7 for missing m_pEventObject member variable instantiation. Suppress warning. // cppcheck-suppress uninitMemberVar SMemberMap(std::shared_ptr& rptrMember, sdv::CSdvParamMap* pEventObject) : m_pEventObject(pEventObject), refptrMember(rptrMember) {} /** * @brief Default destructor. */ virtual ~SMemberMap() = default; /** * @brief Build the parameter map (static build). * @return Vector with parameter info classes. */ static std::vector> BuildStatic() { return TMember::BuildParamMap(nullptr, nullptr); } /** * @brief Build the parameter map. */ void BuildMap() { if (refptrMember.get()) refptrMember.get()->BuildParamMap(refptrMember.get().get(), m_pEventObject); } /** * @brief Find the parameter object with the supplied name. Overload of SMemberMapAccess::FindParamObject. * @param[in] rssName Reference to the name of the parameter. * @return Returns a smart pointer to the parameter object. */ virtual std::shared_ptr FindParamObject(const sdv::u8string& rssName) override { if (!refptrMember.get()) return {}; return refptrMember.get()->FindParamObject(rssName); } /** * @{ * @brief Get the IParameters interface. Overload of SMemberMapAccess::Interface. * @return The parameter map pointer or a NULL pointer if there is no associated parameter map. */ virtual CSdvParamMap* Access() override { if (!refptrMember.get()) return nullptr; // In case a change has happened, or the member was not build previously... if (refptrMember.get()) refptrMember.get()->BuildParamMap(refptrMember.get().get(), m_pEventObject); return refptrMember.get().get(); } virtual const CSdvParamMap* Access() const override { if (!refptrMember.get()) return nullptr; // In case a change has happened, or the member was not build previously... if (refptrMember.get()) refptrMember.get()->BuildParamMap(refptrMember.get().get(), m_pEventObject); return refptrMember.get().get(); } /** * @} */ private: sdv::CSdvParamMap* m_pEventObject; ///< Pointer to the object to receive notifications. mutable std::reference_wrapper> refptrMember; ///< Reference to the smart pointer to the ///< member map. }; } // namespace internal /** * @brief Concatenate two variables together. * @param a First variable * @param b Second variable */ #define SDV_CONCAT_IMPL(a, b) a##b /** * @brief Concatenate two variables together with additional indirection. * @param a First variable * @param b Second variable */ #define SDV_CONCAT(a, b) SDV_CONCAT_IMPL(a, b) /** * @brief Create a unique variable by using the __COUNTER__ macro concatenated to a provided prefix. * @param prefix The prefix to use for the unique variable. */ #define SDV_UNIQUE_VAR(prefix) SDV_CONCAT(prefix, __COUNTER__) /** * @brief Begin an label map. * @param enum_type The name of the enumeration declaration. */ #define BEGIN_SDV_LABEL_MAP(enum_type) \ /** Global variable initialized at the beginning triggering the label map storage. */ \ [[maybe_unused]] static inline bool SDV_UNIQUE_VAR(_bLabelMap) = sdv::internal::GetLabelMapHelper().StoreLabelMap({ /** * @brief Label element entry. Associates the value to the label. * @param enum_element The enumerator element. * @param name_string The name of the element as a string. */ #define SDV_LABEL_ENTRY(enum_element, name_string) \ { static_cast>(enum_element), name_string }, /** * @brief End of enumerator description map. */ #define END_SDV_LABEL_MAP() \ }); /** * @brief Begin a parameter map. */ #define BEGIN_SDV_PARAM_MAP() \ /** \ * @brief Build the parameter map. If a pointer is supplied, registers the parameters in the map. \ * @tparam TClass Type of the class containing the parameter map. This class must derive from sdv::CSdvParamMap or \ * std::nullptr_t. \ * @param[in] pObject Pointer to the class instance holding the parameter map. Can be NULL if only initial parameter \ * information is requested. \ * @param[in] pEventObject Pointer to the object receiving the parameter change notifications. \ * @return Returns a vector with the parameter information structures. \ */ \ template \ static std::vector> BuildParamMap([[maybe_unused]] TClassPtr pObject, \ [[maybe_unused]] sdv::CSdvParamMap* pEventObject) \ { \ bool constexpr bStatic = std::is_same_v; \ static_assert(bStatic || (std::is_pointer_v && \ std::is_base_of_v>), \ "The class needs to derive from sdv::CSdvParamMap."); \ if constexpr (!bStatic) \ { \ /* Build only if necessary */ \ if (!pObject->BuildNecessary()) return {}; \ } \ std::vector> vecParamInfo; \ [[maybe_unused]] uint32_t uiFlags = 0; \ [[maybe_unused]] std::string ssGroup; \ [[maybe_unused]] bool bLockable = false; /** * @brief End the parameter map. */ #define END_SDV_PARAM_MAP() \ return vecParamInfo; \ } \ \ /** \ * @brief Return a vector with parameter information structures. \ * @attention Only parameters that are statically available are available here. The returned list can differ from the list \ * after instantiation. \ * @return Vector containing parameter information structures. \ */ \ static std::vector> GetParamMapInfoStatic() \ { \ std::vector> vecParamInfo = BuildParamMap(nullptr, nullptr); \ return vecParamInfo; \ } \ \ /** \ * @brief Initialize the parameter map. This function is called only once for initial map creation. Overload of \ * sdv::CSdvParamMap::InitParamMap. \ */ \ virtual void InitParamMap() override \ { \ BuildParamMap(this, this); \ } /** * @brief The following parameters belong to the defined group. * @details Parameters cabn be grouped together. Within a group, they need to be unique. A group can have sub-groups, separated * with a dot '.'. For example: "Sensor.ADAS.Radar". Each (sub-)group represents its own TOML table in the configuration. For * the example this would be: * @code * [Sensor] * [Sensor.ADAS] * [Sensor.Radar] * @endcode * @param group_string Name of the group and sub-groups separated by dots. Group names are case-sensitive. */ #define SDV_PARAM_GROUP(group_string) \ ssGroup = group_string; \ /** * @brief The following parameters belong to the top level group again (not having any group name assigned to them). */ #define SDV_PARAM_NO_GROUP() \ ssGroup.clear(); /** * @brief Reset all attributes for all following parameters. */ #define SDV_PARAM_RESET_ATTRIBUTES() \ uiFlags = 0; \ bLockable = false; /** * @brief Following parameters are not writable. */ #define SDV_PARAM_SET_READONLY() \ uiFlags |= static_cast(::sdv::EParamFlags::read_only); /** * @brief Following parameters can be written (if not defined as const). */ #define SDV_PARAM_RESET_READONLY() \ uiFlags &= ~static_cast(::sdv::EParamFlags::read_only); /** * @brief Following parameters will be protected against writing when locked (e.g. after initialization). */ #define SDV_PARAM_ENABLE_LOCKING() \ bLockable = true; /** * @brief Following parameters will not be protected against writing. */ #define SDV_PARAM_DISABLE_LOCKING() \ bLockable = false; /** * @brief Following parameters are marked temporary (will not be stored in the configuration). */ #define SDV_PARAM_SET_TEMPORARY() \ uiFlags |= static_cast(::sdv::EParamFlags::temporary); /** * @brief Following parameters are not marked temporary. */ #define SDV_PARAM_RESET_TEMPORARY() \ uiFlags &= ~static_cast(::sdv::EParamFlags::temporary); /** * @brief Define a parameter. * @param var The member variable of the class containing this parameter map. * @param name_string The name of the parameter. The name must be unique within the group. * @param default_val The default value for the parameter. * @param unit_string The unit of the parameter. * @param description_string The description of the parameter. */ #define SDV_PARAM_ENTRY(var, name_string, default_val, unit_string, description_string) \ if constexpr (bStatic) \ { \ decltype(var) temp{}; \ std::shared_ptr ptrParamInfo = std::make_shared(temp, name_string, default_val, \ unit_string, ssGroup, description_string, uiFlags); \ if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \ } \ else \ { \ std::shared_ptr ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, name_string, \ default_val, unit_string, ssGroup, description_string, uiFlags); \ if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \ } /** No limit for the SDV_PARAM_NUMBER_ENTRY limitation definition. */ #define NO_LIMIT != 0 /** * @brief Define a number parameter with restriction. * @param var The member variable of the class containing this parameter map. * @param name_string The name of the parameter. The name must be unique within the group. * @param default_val The default value for the parameter. * @param low_limit The minimal value limit. Can be '> val' or '>= val' or NO_LIMIT for no limitation. * @param high_limit The maximal value limit. Can be '< val' or '<= val' or NO_LIMIT for no limitation. * @param unit_string The unit of the parameter. * @param description_string The description of the parameter. */ #define SDV_PARAM_NUMBER_ENTRY(var, name_string, default_val, low_limit, high_limit, unit_string, description_string) \ { \ auto prLowLimit = sdv::internal::SLowerLimit() low_limit; \ sdv::any_t anyLower; \ if (prLowLimit.second != sdv::internal::ELimitType::no_limit) anyLower = prLowLimit.first; \ auto prHighLimit = sdv::internal::SUpperLimit() high_limit; \ sdv::any_t anyUpper; \ if (prHighLimit.second != sdv::internal::ELimitType::no_limit) anyUpper = prHighLimit.first; \ if constexpr (bStatic) \ { \ decltype(var) temp{}; \ std::shared_ptr ptrParamInfo = std::make_shared(temp, name_string, \ default_val, anyLower, prLowLimit.second != sdv::internal::ELimitType::up_to_limit, anyUpper, \ prHighLimit.second != sdv::internal::ELimitType::up_to_limit, unit_string, ssGroup, description_string, \ uiFlags); \ if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \ } \ else \ { \ std::shared_ptr ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, \ name_string, default_val, anyLower, prLowLimit.second != sdv::internal::ELimitType::up_to_limit, anyUpper, \ prHighLimit.second != sdv::internal::ELimitType::up_to_limit, unit_string, ssGroup, description_string, \ uiFlags); \ if (ptrParamInfo)vecParamInfo.push_back(std::move(ptrParamInfo)); \ } \ } /** * @brief Define an enum parameter. * @param var The member variable of the class containing this parameter map. * @param name_string The name of the parameter. The name must be unique within the group. * @param default_val The default value for the parameter. * @param description_string The description of the parameter. */ #define SDV_PARAM_ENUM_ENTRY(var, name_string, default_val, description_string) \ SDV_PARAM_ENTRY(var, name_string, default_val, "", description_string) /** * @brief Define a string parameter. * @param var The member variable of the class containing this parameter map. * @param name_string The name of the parameter. The name must be unique within the group. * @param default_val The default value for the parameter. * @param pattern_string The pattern the parameter should fit to. This is a regular expression. * @param unit_string The unit of the parameter. * @param description_string The description of the parameter. */ #define SDV_PARAM_STRING_ENTRY(var, name_string, default_val, pattern_string, unit_string, description_string) \ if constexpr (bStatic) \ { \ decltype(var) temp{}; \ std::shared_ptr ptrParamInfo = std::make_shared(temp, name_string, default_val, \ pattern_string, unit_string, ssGroup, description_string, uiFlags); \ if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \ } \ else \ { \ std::shared_ptr ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, name_string, \ default_val, pattern_string, unit_string, ssGroup, description_string, uiFlags); \ if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \ } /** * @brief Define a path parameter. * @param var The member variable of the class containing this parameter map. * @param name_string The name of the parameter. The name must be unique within the group. * @param default_val The default value for the parameter. * @param description_string The description of the parameter. */ #define SDV_PARAM_PATH_ENTRY(var, name_string, default_val, description_string) \ SDV_PARAM_ENTRY(var, name_string, default_val, "", description_string) /** * @brief Define a bitmask parameter. * @param TEnum Name of the enum definition defining the bits through BEGIN_SDV_ENUM_DEF_MAP macro. * @param var The member variable of the class containing this parameter map. * @param name_string The name of the parameter. The name must be unique within the group. * @param description_string The description of the parameter. */ #define SDV_PARAM_BITMASK_ENTRY(TEnum, var, name_string, default_val, description_string) \ if constexpr (bStatic) \ { \ decltype(var) temp{}; \ std::shared_ptr ptrParamInfo = std::make_shared(temp, name_string, default_val, \ sdv::internal::GetLabelMapHelper().GetLabelMap(), ssGroup, description_string, uiFlags); \ if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \ } \ else \ { \ std::shared_ptr ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, name_string, \ default_val, sdv::internal::GetLabelMapHelper().GetLabelMap(), ssGroup, description_string, uiFlags); \ if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \ } /** * @brief Chain the parameter map of a base class. * @param base_class Name of the base class. */ #define SDV_PARAM_CHAIN_BASE(base_class) \ { \ auto vecBaseParamInfo = base_class::BuildParamMap(pObject, pEventObject); \ vecParamInfo.insert(vecParamInfo.end(), vecBaseParamInfo.begin(), vecBaseParamInfo.end()); \ } /** * @brief Call the parameter map a member variable containing a parameter map. * @param member Name of the member variable containing a parameter map. This can be a member instance, a pointer or a smart * pointer to the instance. */ #define SDV_PARAM_CHAIN_MEMBER(member) \ { \ std::vector> vecParamInfoMember; \ if constexpr (bStatic) \ { \ vecParamInfoMember = sdv::internal::SMemberMap::BuildStatic(); \ } \ else \ { \ auto ptrMemberMap = std::make_shared>(pObject->member, pObject); \ if (ptrMemberMap) \ { \ ptrMemberMap->BuildMap(); \ pObject->RegisterMemberMap(ptrMemberMap); \ } \ } \ vecParamInfo.insert(vecParamInfo.end(), vecParamInfoMember.begin(), vecParamInfoMember.end()); \ } /** * @brief Parameter map base class implementing parameter support using the parameter map macros. * @details The parameter map base class implements the support for the parameter map macros as well as parameter state * management. A class using parameters can derive from this class and overload the following events to control its behavior: * - OnParamChanged - parameter has changed * - OnParamFlagChanged - parameter flag has changed */ class CSdvParamMap : public IParameters { public: /** * @brief Default destructor. */ virtual ~CSdvParamMap() = default; /** * @{ * @brief Find a parameter object by name. * @param[in] rssName Reference to the name of the parameter. * @return Smart pointer to the parameter guardian object or an empty pointer when the parameter was not found. */ std::shared_ptr FindParamObject(const sdv::u8string& rssName); std::shared_ptr FindParamObject(const sdv::u8string& rssName) const; /** * @} */ /** * Return a sequence with parameter paths. Each path is unique and can be used to get and set the parameter value. Overload * of sdv::IParameters::GetParamPaths. * @return Sequence containing parameter paths. Parameter paths are composed from group/sub-groups and the parameter name, * separated by a dot. */ virtual sequence GetParamPaths() const override; /** * @brief Returns the parameter value. Overload of sdv::IParameters::GetParam. * @param[in] ssPath Path of the parameter. The parameter path is composed from group/sub-groups and the parameter name, * separated by a dot. * @return Returns the parameter value. Returns an 'empty' parameter value when not successful or the parameter is not set. */ virtual any_t GetParam(/*in*/ const u8string& ssPath) const override; /** * @brief Set the parameter value. Overload of sdv::IParameters::SetParam. * @param[in] ssPath Path of the parameter. The parameter path is composed from group/sub-groups and the parameter name, * separated by a dot. * @param[in] anyValue Reference to the parameter value to set. * @return Returns 'true' on success or 'false' when parameter could not be set (e.g. the parameter is read-only) or the * index is larger than the amount of parameters being available. */ virtual bool SetParam(/*in*/ const u8string& ssPath, /*in*/ any_t anyValue) override; /** * @brief Get parameter information.Overload of sdv::IParameters::GetParamInfo. * @param[in] ssPath Path of the parameter. The parameter path is composed from group/sub-groups and the parameter name, * separated by a dot. * @return Return the parameter information for the requested parameter or an empty structure when no parameter information * is available or the parameter is not available. */ virtual SParamInfo GetParamInfo(/*in*/ const u8string& ssPath) const override; /** * @brief Is the parameter dirty (was it changed)? Checks the parameter dirty flag. Overload of sdv::IParameters::IsDirty. * @param[in] ssPath Path of the parameter. The parameter path is composed from group/sub-groups and the parameter name, * separated by a dot. * @return Returns whether the parameter was changed either by an explicit call to the SetParam function or internally by * the object itself. */ virtual bool IsParamDirty(/*in*/ const u8string& ssPath) const override; /** * @brief Set dirty flag for one parameter (or all properties for the function without parameters). * @param[in] rssPath Reference to the path of the parameter. */ void SetParamDirtyFlag(const std::string& rssPath); /** * @brief Reset the dirty flag. Overload of sdv::IParameters::ResetParamDirtyFlag. * @param[in] ssPath Path of the parameter. The parameter path is composed from group/sub-groups and the parameter name, * separated by a dot. */ virtual void ResetParamDirtyFlag(/*in*/ const u8string& ssPath) override; /** * @brief Is the parameter map dirty? Overload of sdv::IParameters::IsParamMapDirty. * @return Returns true when any one of the parameters is flagged as dirty. */ virtual bool IsParamMapDirty() const override; /** * @brief Reset the dirty flag for all parameters. Overload of sdv::IParameters::ResetParamMapDirtyFlags. */ virtual void ResetParamMapDirtyFlags() override; /** * @brief Lock the parameter map. */ void LockParamMap(); /** * @brief Unlock the parameter map. */ void UnlockParamMap(); /** * @brief Parameter changed event. Overload this function to implement parameter event handling. * @param[in] rssPath Reference to the string containing the path of the parameter that changed. * @param[in] rvarOld Reference to the any holding the value of the parameter. * @param[in] rvarNew Reference to the any holding the value of the parameter. * @param[in] rptrParamInfo Reference to the smart pointer to the parameter information object. */ virtual void OnParamChanged([[maybe_unused]] const std::string& rssPath, [[maybe_unused]] const any_t& rvarOld, [[maybe_unused]] const any_t& rvarNew, [[maybe_unused]] const std::shared_ptr& rptrParamInfo) {} /** * @brief Parameter dirty flag changed event. Overload this function to implement parameter dirty flag event * handling. * @param[in] rssPath Reference to the string containing the path of the parameter that changed. * @param[in] uiOldFlags The old value of the flags. * @param[in] uiNewFlags The new value of the flags. * @param[in] uiMask The mask of the flags that are changed by the new value. * @param[in] rvar Reference to the any holding the value of the parameter. * @param[in] rptrParamInfo Reference to the smart pointer to the parameter information object. */ virtual void OnParamFlagChanged([[maybe_unused]] const std::string& rssPath, [[maybe_unused]] uint32_t uiOldFlags, [[maybe_unused]] uint32_t uiNewFlags, [[maybe_unused]] uint32_t uiMask, [[maybe_unused]] const any_t& rvar, [[maybe_unused]] const std::shared_ptr& rptrParamInfo) {} protected: /** * @brief Register the parameter in the parameter map. * @tparam TVar Type of the variable. * @tparam TConstruct The arguments for the parameter info construct function. * @param[in] rtVar Reference to the parameter. * @param[in] bLockable When set, the parameter is lockable. Only use with writable parameters. * @param[in] bAutoDirty When set, the parameter dirty flag is detected automatically. Only use with writable parameters. * @param[in] tConstruct The construct function arguments. * @return Smart pointer to the parameter information structure. */ template std::shared_ptr RegisterParameter(TVar& rtVar, bool bLockable, bool bAutoDirty, TConstruct... tConstruct); /** * @brief Register a member parameter map into this parameter map. * @param[in] rptrMember Reference to the smart pointer pointing to the member map. */ void RegisterMemberMap(const std::shared_ptr& rptrMember); /** * @brief Initialize the parameter map. This function is called only once for initial map creation. This implementation * doesn't do anything. The parameter map macros overload this function to allow map building. */ virtual void InitParamMap(); /** * @brief Is a parameter map build necessary? * @return Returns whether parameter map building is required. */ bool BuildNecessary() const; public: /** * @brief Return a vector with parameter information structures. Empty function called when the derived class doesn't * implement its own parameter map. * @return Vector containing parameter information structures. */ static std::vector> GetParamMapInfoStatic() { return {}; } private: /** * @brief Member registration. */ struct SParamRegistration { /** * @brief Constructor for a parameter. * @tparam TVar Type of the variable. * @param[in] rptrParameter Reference to the smart pointer containing the parameter. */ template SParamRegistration(const std::shared_ptr>& rptrParameter) : eType(EType::parameter), ptrParameter(rptrParameter) {} /** * @brief Constructor for a member parameter map * @param[in] rptrMember Reference to the smart pointer pointing to the member map. */ SParamRegistration(const std::shared_ptr& rptrMember) : eType(EType::member_map), ptrMemberMap(rptrMember) {} /** * @brief Copy constructor */ SParamRegistration(const SParamRegistration& rRegistration) { eType = rRegistration.eType; switch (rRegistration.eType) { case EType::parameter: new (&ptrParameter) std::shared_ptr(rRegistration.ptrParameter); break; case EType::member_map: new (&ptrMemberMap) std::shared_ptr(rRegistration.ptrMemberMap); break; } } /** * @brief Move constructor */ SParamRegistration(SParamRegistration&& rRegistration) { eType = rRegistration.eType; switch (rRegistration.eType) { case EType::parameter: new (&ptrParameter) std::shared_ptr(std::move(rRegistration.ptrParameter)); break; case EType::member_map: new (&ptrMemberMap) std::shared_ptr(std::move(rRegistration.ptrMemberMap)); break; } } /** * @brief Destructor */ ~SParamRegistration() { switch (eType) { case EType::parameter: ptrParameter.~shared_ptr(); break; case EType::member_map: ptrMemberMap.~shared_ptr(); break; } } /** * @brief Get the parameter if this structure is defined as parameter. * @return Smart pointer to the parameter or empty when there is no parameter. */ std::shared_ptr Parameter() const { if (eType == EType::parameter) return ptrParameter; return {}; } /** * @brief Get the member parameter map if this structure is defined as member parameter map. * @return Smart pointer to the member map or empty when there is no member map. */ std::shared_ptr MemberMap() const { if (eType == EType::member_map) return ptrMemberMap; return {}; } private: enum class EType {parameter, member_map} eType; ///< Type of registration union { std::shared_ptr ptrParameter; ///< Smart pointer to parameter of this map. std::shared_ptr ptrMemberMap; ///< Smart pointer to a member containing another ///< parameter map. }; }; mutable std::vector m_vecParamMapRegistration; ///< Vector with parameters. }; }; // namespace sdv #include "param_impl.inl" #endif // !defined PARAM_IMPL_H