core: Make all usual accessors available to AttributeContainerValue

This commit is contained in:
Stefano Avallone
2022-03-05 17:40:00 +01:00
committed by Stefano Avallone
parent 6a9a3b1f51
commit ceb714e175
4 changed files with 87 additions and 202 deletions

View File

@@ -231,7 +231,6 @@ set(header_files
model/assert.h
model/attribute-accessor-helper.h
model/attribute-construction-list.h
model/attribute-container-accessor-helper.h
model/attribute-container.h
model/attribute-helper.h
model/attribute.h

View File

@@ -1,187 +0,0 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2018 Caliola Engineering, LLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Jared Dulmage <jared.dulmage@caliola.com>
*/
#ifndef ATTRIBUTE_CONTAINER_ACCESSOR_HELPER_H
#define ATTRIBUTE_CONTAINER_ACCESSOR_HELPER_H
#include "attribute-container.h"
#include <ns3/attribute-helper.h>
#include <type_traits>
#include <list>
namespace ns3 {
/**
* SFINAE compile time check if type T has const iterator.
*/
template <typename T>
struct has_const_iterator
{
private:
/// positive result
typedef char yes;
/// negative result
typedef struct
{
char array[2]; //!< Check value, its size must be different than the "yes" size
} no;
/**
* Test function, compiled if type has a const_iterator
* \return A value indicating that this specialization has been compiled.
*/
template <typename C> static yes test (typename C::const_iterator *);
/**
* Test function, compiled if type does not have a const_iterator
* \return A value indicating that this specialization has been compiled.
*/
template <typename C> static no test (...);
public:
/// Value of the test - true if type has a const_iterator
static const bool value = sizeof (test<T> (0)) == sizeof (yes);
/// Equivalent name of the type T
typedef T type;
};
/**
* SFINAE compile time check if type T has begin() and end() methods.
*/
template <typename T>
struct has_begin_end
{
/**
* Compiled if type T has a begin() method.
* \return A value indicating that this specialization has been compiled.
*/
template <typename C> static char (&f (typename std::enable_if<
std::is_same<decltype (static_cast<typename C::const_iterator (C::*) () const> (&C::begin)),
typename C::const_iterator (C::*) () const>::value, void>::type *))[1];
/**
* Compiled if type T does not have a begin() method.
* \return A value indicating that this specialization has been compiled.
*/
template <typename C> static char (&f (...))[2];
/**
* Compiled if type T has an end() method.
* \return A value indicating that this specialization has been compiled.
*/
template <typename C> static char (&g (typename std::enable_if<
std::is_same<decltype (static_cast<typename C::const_iterator (C::*) () const> (&C::end)),
typename C::const_iterator (C::*) () const>::value, void>::type *))[1];
/**
* Compiled if type T does not have an end() method.
* \return A value indicating that this specialization has been compiled.
*/
template <typename C> static char (&g (...))[2];
/// True if type T has a begin() method.
static bool const beg_value = sizeof (f<T> (0)) == 1;
/// True if type T has an end() method.
static bool const end_value = sizeof (g<T> (0)) == 1;
};
/**
* Compile time check if type T is a container.
*
* Container here means has an iterator and supports begin() and end()
* methods.
*
* Can be used when defining specializations when a type T is an STL
* like container.
*/
template<typename T>
struct is_container : std::integral_constant<bool, has_const_iterator<T>::value && has_begin_end<T>::beg_value && has_begin_end<T>::end_value>
{ };
/**
* \ingroup attributeimpl
*
* DoMakeAccessorHelperOne specialization for member containers
*
* The template parameter list contains an extra parameter that is
* intended to disambiguate an attribute container from any other
* templated attribute, e.g Ptr or Callback. Disambiguation is based
* on begin/end and iterator.
*
* \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 container.
* \tparam I \deduced The type of item (s) within the container.
* \param [in] memberContainer The address of the data member.
* \returns The AttributeAccessor.
*/
template <typename V, typename T, template <typename...> class U, typename ...I,
typename = typename std::enable_if< ( is_container< U<I...> >::value ), void>::type >
inline
Ptr<const AttributeAccessor>
DoMakeAccessorHelperOne (U<I...> T::*memberContainer)
{
/* AttributeAcessor implementation for a class member variable. */
class MemberContainer : public AccessorHelper<T,V>
{
public:
/*
* Construct from a class data member address.
* \param [in] memberContainer The class data member address.
*/
MemberContainer (U<I...> T::*memberContainer)
: AccessorHelper<T,V> (),
m_memberContainer (memberContainer)
{}
private:
virtual bool DoSet (T *object, const V *v) const {
// typename AccessorTrait<U<I>::value_type>::Result tmp;
// bool ok = v->GetAccessor (tmp);
// if (!ok)
// {
// return false;
// }
auto src = v->Get ();
(object->*m_memberContainer).clear ();
std::copy (src.begin (), src.end (), std::inserter ((object->*m_memberContainer), (object->*m_memberContainer).end ()));
return true;
}
virtual bool DoGet (const T *object, V *v) const {
v->Set (object->*m_memberContainer);
return true;
}
virtual bool HasGetter (void) const {
return true;
}
virtual bool HasSetter (void) const {
return true;
}
U<I...> T::*m_memberContainer; // Address of the class data member.
};
return Ptr<const AttributeAccessor> (new MemberContainer (memberContainer), false);
}
} // namespace ns3
#endif // ATTRIBUTE_CONTAINER_ACCESSOR_HELPER_H

View File

@@ -39,11 +39,11 @@ class AttributeChecker;
// A = attribute value type, C = container type to return
/**
* A container for one type of attribute.
*
*
* The container uses \p A to parse items into elements.
* Internally the container is always a list but an instance
* can return the items in a container specified by \p C.
*
*
* @tparam A AttributeValue type to be contained.
* @tparam C Possibly templated container class returned by Get.
*/
@@ -111,7 +111,7 @@ public:
result_type Get (void) const;
/**
* Copy items from container c.
*
*
* This method assumes \p c has stl-style begin and end methods.
* The AttributeContainerValue value is cleared before copying from \p c.
* @tparam T type of container.
@@ -119,6 +119,17 @@ public:
*/
template <class T>
void Set (const T &c);
/**
* Set the given variable to the values stored by this TupleValue object.
*
* \tparam T \deduced the type of the given variable (normally, the argument type
* of a set method or the type of a data member)
* \param value the given variable
* \return true if the given variable was set
*/
template <typename T>
bool GetAccessor (T &value) const;
// NS3 interface
/**
@@ -166,8 +177,8 @@ public:
private:
/**
* Copy items from \ref begin to \ref end.
*
* Copy items from \ref begin to \ref end.
*
* The internal container is cleared before values are copied
* using the push_back method.
* @tparam ITER \deduced iterator type
@@ -232,12 +243,31 @@ Ptr<AttributeChecker> MakeAttributeContainerChecker (void);
* Make AttributeContainerAccessor using explicit types.
* @tparam A AttributeValue type in container.
* @tparam C Container type returned by Get.
* \param[in] a1 AttributeContainer to be used.
* \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.
* \return AttributeContainerAccessor.
*/
template <typename A, template <typename...> class C=std::list, typename T1>
Ptr<const AttributeAccessor> MakeAttributeContainerAccessor (T1 a1);
/**
* Make AttributeContainerAccessor using explicit types.
* @tparam A AttributeValue type in container.
* @tparam C Container type returned by Get.
* \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.
* \return AttributeContainerAccessor.
*/
template <typename A, template <typename...> class C=std::list, typename T1, typename T2>
Ptr<const AttributeAccessor> MakeAttributeContainerAccessor (T1 a1, T2 a2);
} // namespace ns3
/*****************************************************************************
@@ -423,6 +453,17 @@ AttributeContainerValue<A, C>::Get (void) const
return c;
}
template <class A, template <class...> class C>
template <typename T>
bool
AttributeContainerValue<A, C>::GetAccessor (T &value) const
{
result_type src = Get ();
value.clear ();
std::copy (src.begin (), src.end (), std::inserter (value, value.end ()));
return true;
}
template <class A, template <class...> class C>
template <class T>
void
@@ -506,6 +547,12 @@ Ptr<const AttributeAccessor> MakeAttributeContainerAccessor (T1 a1)
return MakeAccessorHelper<AttributeContainerValue<A, C> > (a1);
}
template <typename A, template <typename...> class C, typename T1, typename T2>
Ptr<const AttributeAccessor> MakeAttributeContainerAccessor (T1 a1, T2 a2)
{
return MakeAccessorHelper<AttributeContainerValue<A, C> > (a1, a2);
}
} // namespace ns3
#endif // ATTRIBUTE_CONTAINER_H

View File

@@ -21,7 +21,6 @@
#include <ns3/test.h>
#include <ns3/log.h>
#include <ns3/attribute-container.h>
#include <ns3/attribute-container-accessor-helper.h>
#include <ns3/pair.h>
#include <ns3/double.h>
#include <ns3/integer.h>
@@ -66,10 +65,23 @@ public:
/**
* \brief Get the type ID.
* \return The object TypeId.
*/
*/
static
TypeId GetTypeId ();
/**
* Set the vector of ints to the given vector
*
* \param vec the given vector
*/
void SetIntVec (std::vector<int> vec);
/**
* Get the vector of ints
*
* \return the vector of ints
*/
std::vector<int> GetIntVec (void) const;
/**
* \brief Stream insertion operator.
*
@@ -110,7 +122,9 @@ AttributeContainerObject::GetTypeId ()
.AddAttribute ("IntegerVector", "Vector of integers",
// the container value container differs from the underlying object
AttributeContainerValue <IntegerValue> (),
MakeAttributeContainerAccessor <IntegerValue> (&AttributeContainerObject::m_intvec),
// the type of the underlying container cannot be deduced
MakeAttributeContainerAccessor <IntegerValue, std::list> (&AttributeContainerObject::SetIntVec,
&AttributeContainerObject::GetIntVec),
MakeAttributeContainerChecker<IntegerValue> (MakeIntegerChecker<int> ()))
.AddAttribute ("MapStringInt", "Map of strings to ints",
// the container value container differs from the underlying object
@@ -131,6 +145,18 @@ AttributeContainerObject::ReverseList ()
m_intvec = tmp;
}
void
AttributeContainerObject::SetIntVec (std::vector<int> vec)
{
m_intvec = vec;
}
std::vector<int>
AttributeContainerObject::GetIntVec (void) const
{
return m_intvec;
}
std::ostream &
operator << (std::ostream &os, const AttributeContainerObject &obj)
{
@@ -147,7 +173,7 @@ operator << (std::ostream &os, const AttributeContainerObject &obj)
/**
* \ingroup attribute-tests
*
*
* This function handles mixed constness and compatible, yet
* distinct numerical classes (like int and long)
* \param x The left operand.
@@ -163,7 +189,7 @@ operator ==(const std::pair<A, B> &x, const std::pair<C, D> &y)
/**
* \ingroup attribute-tests
*
*
* Test AttributeContainer instantiation, initialization, access
*/
class AttributeContainerTestCase : public TestCase
@@ -269,7 +295,7 @@ AttributeContainerTestCase::DoRun ()
/**
* \ingroup attribute-tests
*
*
* Attribute serialization and deserialization TestCase.
*/
class AttributeContainerSerializationTestCase : public TestCase
@@ -359,7 +385,7 @@ AttributeContainerSerializationTestCase::DoRun (void)
/**
* \ingroup attribute-tests
*
*
* Attribute set and get TestCase.
*/
class AttributeContainerSetGetTestCase : public TestCase
@@ -462,7 +488,7 @@ AttributeContainerSetGetTestCase::DoRun (void)
/**
* \ingroup attribute-tests
*
*
* Attribute attribute container TestCase.
*/
class AttributeContainerTestSuite : public TestSuite