Files
unison/src/core/model/attribute-accessor-helper.h

612 lines
18 KiB
C++

/*
* Copyright (c) 2008 INRIA
*
* SPDX-License-Identifier: GPL-2.0-only
*
* Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#ifndef ATTRIBUTE_ACCESSOR_HELPER_H
#define ATTRIBUTE_ACCESSOR_HELPER_H
#include "attribute.h"
/**
* @file
* @ingroup attributeimpl
* ns3::MakeAccessorHelper declarations and template implementations.
*/
namespace ns3
{
/**
* @ingroup attributeimpl
*
* Create an AttributeAccessor for a class data member,
* or a lone class get functor or set method.
*
* The get functor method should have a signature like
* @code
* typedef U (T::*getter)() const
* @endcode
* where \pname{T} is the class and \pname{U} is the type of
* the return value.
*
* The set method should have one of these signatures:
* @code
* typedef void (T::*setter)(U)
* typedef bool (T::*setter)(U)
* @endcode
* where \pname{T} is the class and \pname{U} is the type of the value to set
* the attribute to, which should be compatible with the
* specific AttributeValue type \pname{V} which holds the value
* (or the type implied by the name \c Make<V>Accessor of this function.)
* In the case of a \pname{setter} returning \pname{bool,} the return value
* should be \c true if the value could be set successfully.
*
* @tparam V \explicit (If present) The specific AttributeValue type
* to use to represent the Attribute. (If not present,
* the type \pname{V} is implicit in the name of this function,
* as "Make<V>Accessor"
* @tparam T1 \deduced The type of the class data member,
* or the type of the class get functor or set method.
* @param [in] a1 The address of the data member,
* or the get or set method.
* @returns The AttributeAccessor
*/
template <typename V, typename T1>
inline Ptr<const AttributeAccessor> MakeAccessorHelper(T1 a1);
/**
* @ingroup attributeimpl
*
* Create an AttributeAccessor using a pair of get functor
* and set methods from a class.
*
* The get functor method should have a signature like
* @code
* typedef U (T::*getter)() const
* @endcode
* where \pname{T} is the class and \pname{U} is the type of
* the return value.
*
* The set method should have one of these signatures:
* @code
* typedef void (T::*setter)(U)
* typedef bool (T::*setter)(U)
* @endcode
* where \pname{T} is the class and \pname{U} is the type of the value to set
* the attribute to, which should be compatible with the
* specific AttributeValue type \pname{V} which holds the value
* (or the type implied by the name \c Make<V>Accessor of this function.)
* In the case of a \pname{setter} returning \pname{bool,} the return value
* should be true if the value could be set successfully.
*
* In practice the setter and getter arguments can appear in either order,
* but setter first is preferred.
*
* @tparam V \explicit (If present) The specific AttributeValue type to use to represent
* the Attribute. (If not present, the type \pname{V} is implicit
* in the name of this function as "Make<V>Accessor"
* @tparam T1 \deduced The type of the class data member,
* or the type of the class get functor or set method.
*
* @tparam T2 \deduced The type of the getter class functor method.
* @param [in] a2 The address of the class method to set the attribute.
* @param [in] a1 The address of the data member,
* or the get or set method.
* @returns The AttributeAccessor
*/
template <typename V, typename T1, typename T2>
inline Ptr<const AttributeAccessor> MakeAccessorHelper(T1 a1, T2 a2);
} // namespace ns3
/***************************************************************
* Implementation of the templates declared above.
***************************************************************/
#include <type_traits>
namespace ns3
{
/**
* @ingroup attributeimpl
*
* The non-const and non-reference type equivalent to \pname{T}.
*
* @tparam T \explicit The original (possibly qualified) type.
*/
template <typename T>
struct AccessorTrait
{
/** The non-const, non reference type. */
using Result = std::remove_cvref_t<T>;
};
/**
* @ingroup attributeimpl
*
* Basic functionality for accessing class attributes via
* class data members, or get functor/set methods.
*
* @tparam T \explicit Class of object holding the attribute.
* @tparam U \explicit AttributeValue type for the underlying class member
* which is an attribute.
*/
template <typename T, typename U>
class AccessorHelper : public AttributeAccessor
{
public:
/** Constructor */
AccessorHelper()
{
}
/**
* Set the underlying member to the argument AttributeValue.
*
* Handle dynamic casting from generic ObjectBase and AttributeValue
* up to desired object class and specific AttributeValue.
*
* Forwards to DoSet method.
*
* @param [in] object Generic object pointer, to upcast to \pname{T}.
* @param [in] val Generic AttributeValue, to upcast to \pname{U}.
* @returns true if the member was set successfully.
*/
bool Set(ObjectBase* object, const AttributeValue& val) const override
{
const U* value = dynamic_cast<const U*>(&val);
if (value == nullptr)
{
return false;
}
T* obj = dynamic_cast<T*>(object);
if (obj == nullptr)
{
return false;
}
return DoSet(obj, value);
}
/**
* Get the value of the underlying member into the AttributeValue.
*
* Handle dynamic casting from generic ObjectBase and AttributeValue
* up to desired object class and specific AttributeValue.
*
* Forwards to DoGet method.
*
* @param [out] object Generic object pointer, to upcast to \pname{T}.
* @param [out] val Generic AttributeValue, to upcast to \pname{U}.
* @returns true if the member value could be retrieved successfully
*/
bool Get(const ObjectBase* object, AttributeValue& val) const override
{
U* value = dynamic_cast<U*>(&val);
if (value == nullptr)
{
return false;
}
const T* obj = dynamic_cast<const T*>(object);
if (obj == nullptr)
{
return false;
}
return DoGet(obj, value);
}
private:
/**
* Setter implementation.
*
* @see Set()
* @param [in] object The parent object holding the attribute.
* @param [in] v The specific AttributeValue to set.
* @returns true if the member was set successfully.
*/
virtual bool DoSet(T* object, const U* v) const = 0;
/**
* Getter implementation.
*
* @see Get()
* @param [out] object The parent object holding the attribute.
* @param [out] v The specific AttributeValue to set.
* @returns true if the member value could be retrieved successfully
*/
virtual bool DoGet(const T* object, U* v) const = 0;
// end of class AccessorHelper
};
/**
* @ingroup attributeimpl
*
* MakeAccessorHelper implementation for a class data member.
*
* @tparam V \explicit The specific AttributeValue type to use to represent
* the Attribute.
* @tparam T \deduced The class holding the data member.
* @tparam U \deduced The type of the data member.
* @param [in] memberVariable The address of the data member.
* @returns The AttributeAccessor.
*/
// clang-format off
// Clang-format guard needed for versions <= 18
template <typename V, typename T, typename U>
inline Ptr<const AttributeAccessor>
DoMakeAccessorHelperOne(U T::* memberVariable)
// clang-format on
{
/* AttributeAccessor implementation for a class member variable. */
class MemberVariable : public AccessorHelper<T, V>
{
public:
/*
* Construct from a class data member address.
* @param [in] memberVariable The class data member address.
*/
// clang-format off
// Clang-format guard needed for versions <= 18
MemberVariable(U T::* memberVariable)
// clang-format on
: AccessorHelper<T, V>(),
m_memberVariable(memberVariable)
{
}
private:
bool DoSet(T* object, const V* v) const override
{
typename AccessorTrait<U>::Result tmp;
bool ok = v->GetAccessor(tmp);
if (!ok)
{
return false;
}
(object->*m_memberVariable) = tmp;
return true;
}
bool DoGet(const T* object, V* v) const override
{
v->Set(object->*m_memberVariable);
return true;
}
bool HasGetter() const override
{
return true;
}
bool HasSetter() const override
{
return true;
}
// clang-format off
// Clang-format guard needed for versions <= 18
U T::* m_memberVariable; // Address of the class data member.
// clang-format on
};
return Ptr<const AttributeAccessor>(new MemberVariable(memberVariable), false);
}
/**
* @ingroup attributeimpl
*
* MakeAccessorHelper implementation for a class get functor method.
*
* @tparam V \explicit The specific AttributeValue type to use to represent
* the Attribute.
* @tparam T \deduced The class holding the get functor method.
* @tparam U \deduced The return type of the get functor method.
* @param [in] getter The address of the class get functor method.
* @returns The AttributeAccessor.
*/
template <typename V, typename T, typename U>
inline Ptr<const AttributeAccessor>
DoMakeAccessorHelperOne(U (T::*getter)() const)
{
/* AttributeAccessor implementation with a class get functor method. */
class MemberMethod : public AccessorHelper<T, V>
{
public:
/*
* Construct from a class get functor method.
* @param [in] getter The class get functor method pointer.
*/
MemberMethod(U (T::*getter)() const)
: AccessorHelper<T, V>(),
m_getter(getter)
{
}
private:
bool DoSet(T* /* object */, const V* /* v */) const override
{
return false;
}
bool DoGet(const T* object, V* v) const override
{
v->Set((object->*m_getter)());
return true;
}
bool HasGetter() const override
{
return true;
}
bool HasSetter() const override
{
return false;
}
U (T::*m_getter)() const; // The class get functor method pointer.
};
return Ptr<const AttributeAccessor>(new MemberMethod(getter), false);
}
/**
* @ingroup attributeimpl
*
* MakeAccessorHelper implementation for a class set method
* returning void.
*
* @tparam V \explicit The specific AttributeValue type to use to represent
* the Attribute.
* @tparam T \deduced The class holding the set method.
* @tparam U \deduced The argument type of the set method.
* @param [in] setter The address of the class set method, returning void.
* @returns The AttributeAccessor.
*/
template <typename V, typename T, typename U>
inline Ptr<const AttributeAccessor>
DoMakeAccessorHelperOne(void (T::*setter)(U))
{
/* AttributeAccessor implementation with a class set method returning void. */
class MemberMethod : public AccessorHelper<T, V>
{
public:
/*
* Construct from a class set method.
* @param [in] setter The class set method pointer.
*/
MemberMethod(void (T::*setter)(U))
: AccessorHelper<T, V>(),
m_setter(setter)
{
}
private:
bool DoSet(T* object, const V* v) const override
{
typename AccessorTrait<U>::Result tmp;
bool ok = v->GetAccessor(tmp);
if (!ok)
{
return false;
}
(object->*m_setter)(tmp);
return true;
}
bool DoGet(const T* /* object */, V* /* v */) const override
{
return false;
}
bool HasGetter() const override
{
return false;
}
bool HasSetter() const override
{
return true;
}
void (T::*m_setter)(U); // The class set method pointer, returning void.
};
return Ptr<const AttributeAccessor>(new MemberMethod(setter), false);
}
/**
* @ingroup attributeimpl
*
* MakeAccessorHelper implementation with a class get functor method
* and a class set method returning \pname{void}.
*
* The two versions of this function differ only in argument order.
*
* @tparam W \explicit The specific AttributeValue type to use to represent
* the Attribute.
* @tparam T \deduced The class holding the functor methods.
* @tparam U \deduced The argument type of the set method.
* @tparam V \deduced The return type of the get functor method.
* @param [in] setter The address of the class set method, returning void.
* @param [in] getter The address of the class get functor method.
* @returns The AttributeAccessor.
*/
template <typename W, typename T, typename U, typename V>
inline Ptr<const AttributeAccessor>
DoMakeAccessorHelperTwo(void (T::*setter)(U), V (T::*getter)() const)
{
/*
* AttributeAccessor implementation with class get functor and set method,
* returning void.
*/
class MemberMethod : public AccessorHelper<T, W>
{
public:
/*
* Construct from class get functor and set methods.
* @param [in] setter The class set method pointer, returning void.
* @param [in] getter The class get functor method pointer.
*/
MemberMethod(void (T::*setter)(U), V (T::*getter)() const)
: AccessorHelper<T, W>(),
m_setter(setter),
m_getter(getter)
{
}
private:
bool DoSet(T* object, const W* v) const override
{
typename AccessorTrait<U>::Result tmp;
bool ok = v->GetAccessor(tmp);
if (!ok)
{
return false;
}
(object->*m_setter)(tmp);
return true;
}
bool DoGet(const T* object, W* v) const override
{
v->Set((object->*m_getter)());
return true;
}
bool HasGetter() const override
{
return true;
}
bool HasSetter() const override
{
return true;
}
void (T::*m_setter)(U); // The class set method pointer, returning void.
V (T::*m_getter)() const; // The class get functor method pointer.
};
return Ptr<const AttributeAccessor>(new MemberMethod(setter, getter), false);
}
/**
* @ingroup attributeimpl
* @copydoc DoMakeAccessorHelperTwo(void(T::*)(U),V(T::*)()const)
*/
template <typename W, typename T, typename U, typename V>
inline Ptr<const AttributeAccessor>
DoMakeAccessorHelperTwo(V (T::*getter)() const, void (T::*setter)(U))
{
return DoMakeAccessorHelperTwo<W>(setter, getter);
}
/**
* @ingroup attributeimpl
*
* MakeAccessorHelper implementation with a class get functor method
* and a class set method returning \pname{bool}.
*
* The two versions of this function differ only in argument order.
*
* @tparam W \explicit The specific AttributeValue type to use to represent
* the Attribute.
* @tparam T \deduced The class holding the functor methods.
* @tparam U \deduced The argument type of the set method.
* @tparam V \deduced The return type of the get functor method.
* @param [in] setter The address of the class set method, returning bool.
* @param [in] getter The address of the class get functor method.
* @returns The AttributeAccessor.
*/
template <typename W, typename T, typename U, typename V>
inline Ptr<const AttributeAccessor>
DoMakeAccessorHelperTwo(bool (T::*setter)(U), V (T::*getter)() const)
{
/*
* AttributeAccessor implementation with class get functor and
* set method, returning bool.
*/
class MemberMethod : public AccessorHelper<T, W>
{
public:
/*
* Construct from class get functor and set method, returning bool.
* @param [in] setter The class set method pointer, returning bool.
* @param [in] getter The class get functor method pointer.
*/
MemberMethod(bool (T::*setter)(U), V (T::*getter)() const)
: AccessorHelper<T, W>(),
m_setter(setter),
m_getter(getter)
{
}
private:
bool DoSet(T* object, const W* v) const override
{
typename AccessorTrait<U>::Result tmp;
bool ok = v->GetAccessor(tmp);
if (!ok)
{
return false;
}
ok = (object->*m_setter)(tmp);
return ok;
}
bool DoGet(const T* object, W* v) const override
{
v->Set((object->*m_getter)());
return true;
}
bool HasGetter() const override
{
return true;
}
bool HasSetter() const override
{
return true;
}
bool (T::*m_setter)(U); // The class set method pointer, returning bool.
V (T::*m_getter)() const; // The class get functor method pointer.
};
return Ptr<const AttributeAccessor>(new MemberMethod(setter, getter), false);
}
/**
* @ingroup attributeimpl
* @copydoc ns3::DoMakeAccessorHelperTwo(bool(T::*)(U),V(T::*)()const)
*/
template <typename W, typename T, typename U, typename V>
inline Ptr<const AttributeAccessor>
DoMakeAccessorHelperTwo(V (T::*getter)() const, bool (T::*setter)(U))
{
return DoMakeAccessorHelperTwo<W>(setter, getter);
}
template <typename V, typename T1>
inline Ptr<const AttributeAccessor>
MakeAccessorHelper(T1 a1)
{
return DoMakeAccessorHelperOne<V>(a1);
}
template <typename V, typename T1, typename T2>
inline Ptr<const AttributeAccessor>
MakeAccessorHelper(T1 a1, T2 a2)
{
return DoMakeAccessorHelperTwo<V>(a1, a2);
}
} // namespace ns3
#endif /* ATTRIBUTE_ACCESSOR_HELPER_H */