STL container and pair attributes
This commit adds the ability to read / write attributes corresponding to STL containers or pair structures. Testcases are included and demonstrate how to add container or pair member variables as attributes to your class.
This commit is contained in:
committed by
Tom Henderson
parent
d1d0423f4c
commit
4f4c893e52
101
src/core/model/attribute-container-accessor-helper.h
Normal file
101
src/core/model/attribute-container-accessor-helper.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2018 WPL, Inc.
|
||||
*
|
||||
* 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@wpli.net>
|
||||
*/
|
||||
|
||||
#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 {
|
||||
|
||||
/**
|
||||
* \ingroup attributeimpl
|
||||
*
|
||||
* DoMakeAccessorHelperOne specialization for member containers
|
||||
*
|
||||
* The template parameter list contains an extra parameter that disambiguates
|
||||
* the templated Ptr type from container types by taking advantage of the fact
|
||||
* that container types have multiple template arguments and Ptr has only one.
|
||||
* This disambiguation works but is not sufficiently robust as a long term solution.
|
||||
*
|
||||
* \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< (sizeof...(I) > 1), 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
|
||||
27
src/core/model/attribute-container.cc
Normal file
27
src/core/model/attribute-container.cc
Normal file
@@ -0,0 +1,27 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2018 WPL, Inc.
|
||||
*
|
||||
* 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@wpli.net>
|
||||
* Note: Need this file for library to be built
|
||||
*/
|
||||
|
||||
#include "attribute-container.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
384
src/core/model/attribute-container.h
Normal file
384
src/core/model/attribute-container.h
Normal file
@@ -0,0 +1,384 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2018 WPL, Inc.
|
||||
*
|
||||
* 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@wpli.net>
|
||||
*/
|
||||
|
||||
#ifndef ATTRIBUTE_CONTAINER_H
|
||||
#define ATTRIBUTE_CONTAINER_H
|
||||
|
||||
#include <ns3/ptr.h>
|
||||
#include <ns3/string.h>
|
||||
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class AttributeChecker;
|
||||
|
||||
// A = attribute value type, C = container type to return
|
||||
template <class A, template<class...> class C=std::list>
|
||||
class AttributeContainerValue : public AttributeValue
|
||||
{
|
||||
public:
|
||||
typedef A attribute_type;
|
||||
typedef Ptr<A> value_type;
|
||||
typedef std::list<value_type> container_type;
|
||||
typedef typename container_type::const_iterator const_iterator;
|
||||
typedef typename container_type::iterator iterator;
|
||||
typedef typename container_type::size_type size_type;
|
||||
typedef typename AttributeContainerValue::const_iterator Iterator; // NS3 type
|
||||
|
||||
// use underlying AttributeValue to get return element type
|
||||
typedef typename std::result_of<decltype(&A::Get)(A)>::type item_type;
|
||||
typedef C<item_type> result_type;
|
||||
|
||||
AttributeContainerValue (char sep = ',');
|
||||
|
||||
template <class CONTAINER>
|
||||
AttributeContainerValue (const CONTAINER &c);
|
||||
|
||||
template <class ITER>
|
||||
AttributeContainerValue (const ITER begin, const ITER end);
|
||||
|
||||
~AttributeContainerValue ();
|
||||
|
||||
Ptr<AttributeValue> Copy (void) const;
|
||||
|
||||
bool DeserializeFromString (std::string value, Ptr<const AttributeChecker > checker);
|
||||
std::string SerializeToString (Ptr<const AttributeChecker> checker) const;
|
||||
|
||||
// defacto pure virtuals to integrate with built-in accessor code
|
||||
result_type Get (void) const;
|
||||
template <class T>
|
||||
void Set (const T &c);
|
||||
|
||||
// NS3 interface
|
||||
size_type GetN (void) const;
|
||||
Iterator Begin (void);
|
||||
Iterator End (void);
|
||||
|
||||
size_type size (void) const;
|
||||
iterator begin (void);
|
||||
iterator end (void);
|
||||
const_iterator begin (void) const;
|
||||
const_iterator end (void) const;
|
||||
|
||||
private:
|
||||
template <class ITER>
|
||||
Ptr<AttributeContainerValue<A, C> > CopyFrom (const ITER begin, const ITER end);
|
||||
|
||||
char m_sep;
|
||||
container_type m_container;
|
||||
};
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
class AttributeContainerChecker : public AttributeChecker
|
||||
{
|
||||
public:
|
||||
virtual void SetItemChecker (Ptr<const AttributeChecker> itemchecker) = 0;
|
||||
virtual Ptr<const AttributeChecker> GetItemChecker (void) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return checker using attribute value to provide types
|
||||
*/
|
||||
template <class A, template <class...> class C>
|
||||
Ptr<AttributeContainerChecker<A, C> >
|
||||
MakeAttributeContainerChecker (const AttributeContainerValue<A, C> &value);
|
||||
|
||||
/**
|
||||
* Return checker give types explicitly, defaults same
|
||||
* as AttributeContainerValue defaults
|
||||
*/
|
||||
template <class A, template <class...> class C=std::list>
|
||||
Ptr<AttributeContainerChecker<A, C> >
|
||||
MakeAttributeContainerChecker (Ptr<const AttributeChecker> itemchecker);
|
||||
|
||||
template <class A, template <class...> class C=std::list>
|
||||
Ptr<AttributeContainerChecker<A, C> > MakeAttributeContainerChecker (void);
|
||||
|
||||
template <typename A, template <typename...> class C=std::list, typename T1>
|
||||
Ptr<const AttributeAccessor> MakeAttributeContainerAccessor (T1 a1);
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
/*****************************************************************************
|
||||
* Implementation below
|
||||
*****************************************************************************/
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
class AttributeContainerChecker : public ns3::AttributeContainerChecker<A, C>
|
||||
{
|
||||
public:
|
||||
AttributeContainerChecker (void);
|
||||
explicit AttributeContainerChecker (Ptr<const AttributeChecker> itemchecker);
|
||||
void SetItemChecker (Ptr<const AttributeChecker> itemchecker);
|
||||
Ptr<const AttributeChecker> GetItemChecker (void) const;
|
||||
|
||||
private:
|
||||
Ptr<const AttributeChecker> m_itemchecker;
|
||||
};
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
AttributeContainerChecker<A, C>::AttributeContainerChecker (void)
|
||||
: m_itemchecker (0)
|
||||
{}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
AttributeContainerChecker<A, C>::AttributeContainerChecker (Ptr<const AttributeChecker> itemchecker)
|
||||
: m_itemchecker (itemchecker)
|
||||
{}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
void
|
||||
AttributeContainerChecker<A, C>::SetItemChecker (Ptr<const AttributeChecker> itemchecker)
|
||||
{
|
||||
m_itemchecker = itemchecker;
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
Ptr<const AttributeChecker>
|
||||
AttributeContainerChecker<A, C>::GetItemChecker (void) const
|
||||
{
|
||||
return m_itemchecker;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
Ptr<AttributeContainerChecker<A, C> >
|
||||
MakeAttributeContainerChecker (const AttributeContainerValue<A, C> &value)
|
||||
{
|
||||
return MakeAttributeContainerChecker <A, C> ();
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
Ptr<AttributeContainerChecker<A, C> >
|
||||
MakeAttributeContainerChecker (Ptr<const AttributeChecker> itemchecker)
|
||||
{
|
||||
auto checker = MakeAttributeContainerChecker <A, C> ();
|
||||
checker->SetItemChecker (itemchecker);
|
||||
return checker;
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
Ptr<AttributeContainerChecker<A, C> >
|
||||
MakeAttributeContainerChecker (void)
|
||||
{
|
||||
std::string typeName, underlyingType;
|
||||
typedef AttributeContainerValue<A, C> T;
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "ns3::AttributeContainerValue<" << typeid (typename T::attribute_type).name ()
|
||||
<< ", " << typeid (typename T::container_type).name () << ">";
|
||||
typeName = oss.str ();
|
||||
}
|
||||
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "ns3::Ptr<" << typeid (typename T::attribute_type).name () << ">";
|
||||
underlyingType = oss.str ();
|
||||
}
|
||||
|
||||
return DynamicCast<AttributeContainerChecker<A, C> > (
|
||||
MakeSimpleAttributeChecker<T, internal::AttributeContainerChecker<A, C> > (typeName, underlyingType)
|
||||
);
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
AttributeContainerValue<A, C>::AttributeContainerValue (char sep)
|
||||
: m_sep (sep)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
template <class CONTAINER>
|
||||
AttributeContainerValue<A, C>::AttributeContainerValue (const CONTAINER &c)
|
||||
: AttributeContainerValue<A, C> (c.begin (), c.end ())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
template <class ITER>
|
||||
AttributeContainerValue<A, C>::AttributeContainerValue (const ITER begin, const ITER end)
|
||||
: AttributeContainerValue ()
|
||||
{
|
||||
CopyFrom (begin, end);
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
AttributeContainerValue<A, C>::~AttributeContainerValue ()
|
||||
{
|
||||
m_container.clear ();
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
Ptr<AttributeValue>
|
||||
AttributeContainerValue<A, C>::Copy (void) const
|
||||
{
|
||||
auto c = Create<AttributeContainerValue<A, C> > ();
|
||||
c->m_sep = m_sep;
|
||||
c->m_container = m_container;
|
||||
return c;
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
bool
|
||||
AttributeContainerValue<A, C>::DeserializeFromString (std::string value, Ptr<const AttributeChecker> checker)
|
||||
{
|
||||
auto acchecker = DynamicCast<const AttributeContainerChecker<A, C> > (checker);
|
||||
if (!acchecker) return false;
|
||||
|
||||
std::istringstream iss (value); // copies value
|
||||
while (std::getline (iss, value, m_sep))
|
||||
{
|
||||
auto avalue = acchecker->GetItemChecker ()->CreateValidValue (StringValue (value));
|
||||
if (!avalue) return false;
|
||||
|
||||
auto attr = DynamicCast <A> (avalue);
|
||||
if (!attr) return false;
|
||||
|
||||
// TODO(jared): make insertion more generic?
|
||||
m_container.push_back (attr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
std::string
|
||||
AttributeContainerValue<A, C>::SerializeToString (Ptr<const AttributeChecker> checker) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
bool first = true;
|
||||
for (auto attr: *this)
|
||||
{
|
||||
if (!first) oss << m_sep;
|
||||
oss << attr->SerializeToString (checker);
|
||||
first = false;
|
||||
}
|
||||
return oss.str ();
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
typename AttributeContainerValue<A, C>::result_type
|
||||
AttributeContainerValue<A, C>::Get (void) const
|
||||
{
|
||||
result_type c;
|
||||
for (const value_type a: *this)
|
||||
c.insert (c.end (), a->Get ());
|
||||
return c;
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
template <class T>
|
||||
void
|
||||
AttributeContainerValue<A, C>::Set (const T &c)
|
||||
{
|
||||
m_container.clear ();
|
||||
CopyFrom (c.begin (), c.end ());
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
typename AttributeContainerValue<A, C>::size_type
|
||||
AttributeContainerValue<A, C>::GetN (void) const
|
||||
{
|
||||
return size ();
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
typename AttributeContainerValue<A, C>::Iterator
|
||||
AttributeContainerValue<A, C>::Begin (void)
|
||||
{
|
||||
return begin ();
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
typename AttributeContainerValue<A, C>::Iterator
|
||||
AttributeContainerValue<A, C>::End (void)
|
||||
{
|
||||
return end ();
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
typename AttributeContainerValue<A, C>::size_type
|
||||
AttributeContainerValue<A, C>::size (void) const
|
||||
{
|
||||
return m_container.size ();
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
typename AttributeContainerValue<A, C>::iterator
|
||||
AttributeContainerValue<A, C>::begin (void)
|
||||
{
|
||||
return m_container.begin ();
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
typename AttributeContainerValue<A, C>::iterator
|
||||
AttributeContainerValue<A, C>::end (void)
|
||||
{
|
||||
return m_container.end ();
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
typename AttributeContainerValue<A, C>::const_iterator
|
||||
AttributeContainerValue<A, C>::begin (void) const
|
||||
{
|
||||
return m_container.cbegin ();
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
typename AttributeContainerValue<A, C>::const_iterator
|
||||
AttributeContainerValue<A, C>::end (void) const
|
||||
{
|
||||
return m_container.cend ();
|
||||
}
|
||||
|
||||
template <class A, template <class...> class C>
|
||||
template <class ITER>
|
||||
Ptr<AttributeContainerValue<A, C> >
|
||||
AttributeContainerValue<A, C>::CopyFrom (const ITER begin, const ITER end)
|
||||
{
|
||||
for (ITER iter = begin; iter != end; ++iter)
|
||||
{
|
||||
m_container.push_back (Create<A> (*iter));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
template <typename A, template <typename...> class C, typename T1>
|
||||
Ptr<const AttributeAccessor> MakeAttributeContainerAccessor (T1 a1)
|
||||
{
|
||||
return MakeAccessorHelper<AttributeContainerValue<A, C> > (a1);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif // ATTRIBUTE_CONTAINER_H
|
||||
346
src/core/model/extended-attribute-helper.h
Normal file
346
src/core/model/extended-attribute-helper.h
Normal file
@@ -0,0 +1,346 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2018 WPL, Inc.
|
||||
*
|
||||
* 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@wpli.net>
|
||||
*/
|
||||
|
||||
#ifndef EXTENDED_ATTRIBUTE_HELPER_H
|
||||
#define EXTENDED_ATTRIBUTE_HELPER_H
|
||||
|
||||
#include "ns3/attribute-accessor-helper.h"
|
||||
|
||||
namespace ns3 {
|
||||
/**
|
||||
* \ingroup attributeimpl
|
||||
*
|
||||
* MakeAccessorHelper implementation for a plain ole get functor.
|
||||
*
|
||||
* \tparam V \explicit The specific AttributeValue type to use to represent
|
||||
* the Attribute.
|
||||
* \tparam T \deduced The class whose object pointer will be passed to the get functor.
|
||||
* \tparam U \deduced The return type of the get functor.
|
||||
* \param [in] getter The address of the get functor.
|
||||
* \returns The AttributeAccessor.
|
||||
*/
|
||||
template <typename V, typename T, typename U>
|
||||
inline
|
||||
Ptr<const AttributeAccessor>
|
||||
DoMakeAccessorHelperOne (U (*getter)(const T*))
|
||||
{
|
||||
/* AttributeAccessor implementation with a plain ole functor method. */
|
||||
class POFunction : public AccessorHelper<T,V>
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Construct from a class get functor method.
|
||||
* \param [in] getter The class get functor method pointer.
|
||||
*/
|
||||
POFunction (U (*getter)(const T*))
|
||||
: AccessorHelper<T,V> (),
|
||||
m_getter (getter)
|
||||
{}
|
||||
private:
|
||||
virtual bool DoSet (T *object, const V *v) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool DoGet (const T *object, V *v) const {
|
||||
v->Set ((*m_getter)(object));
|
||||
return true;
|
||||
}
|
||||
virtual bool HasGetter (void) const {
|
||||
return true;
|
||||
}
|
||||
virtual bool HasSetter (void) const {
|
||||
return false;
|
||||
}
|
||||
U (*m_getter)(const T*); // The class get functor method pointer.
|
||||
};
|
||||
return Ptr<const AttributeAccessor> (new POFunction (getter), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup attributeimpl
|
||||
*
|
||||
* MakeAccessorHelper implementation for a plain ole function returning void.
|
||||
*
|
||||
* \tparam V \explicit The specific AttributeValue type to use to represent
|
||||
* the Attribute.
|
||||
* \tparam T \deduced The class whose object pointer will be passed to the set functor.
|
||||
* \tparam U \deduced The argument type of the set functor.
|
||||
* \param [in] setter The address of the set functor, returning void.
|
||||
* \returns The AttributeAccessor.
|
||||
*/
|
||||
template <typename V, typename T, typename U>
|
||||
inline
|
||||
Ptr<const AttributeAccessor>
|
||||
DoMakeAccessorHelperOne (void (*setter)(T*, U))
|
||||
{
|
||||
/* AttributeAccessor implementation with a plain ole function returning void. */
|
||||
class POFunction : public AccessorHelper<T,V>
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Construct from a class set method.
|
||||
* \param [in] setter The class set method pointer.
|
||||
*/
|
||||
POFunction (void (*setter)(T*, U))
|
||||
: AccessorHelper<T,V> (),
|
||||
m_setter (setter)
|
||||
{}
|
||||
private:
|
||||
virtual bool DoSet (T *object, const V *v) const {
|
||||
typename AccessorTrait<U>::Result tmp;
|
||||
bool ok = v->GetAccessor (tmp);
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
(*m_setter)(object, tmp);
|
||||
return true;
|
||||
}
|
||||
virtual bool DoGet (const T *object, V *v) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool HasGetter (void) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool HasSetter (void) const {
|
||||
return true;
|
||||
}
|
||||
void (*m_setter)(T*, U); // The class set method pointer, returning void.
|
||||
};
|
||||
return Ptr<const AttributeAccessor> (new POFunction (setter), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup attributeimpl
|
||||
*
|
||||
* MakeAccessorHelper implementation for a ns3::Callback argument
|
||||
*
|
||||
* Using ns3::Callback functors gives the option of binding arguments
|
||||
* \tparam V \explicit The specific AttributeValue type to use to represent
|
||||
* the Attribute.
|
||||
* \tparam T \deduced The class whose object pointer will be passed to the set functor.
|
||||
* \tparam U \deduced The argument type of the set functor.
|
||||
* \param [in] setter The set functor (type ns3::Callback), returning void.
|
||||
* \returns The AttributeAccessor.
|
||||
*/
|
||||
template <typename V, typename T, typename U>
|
||||
inline
|
||||
Ptr<const AttributeAccessor>
|
||||
DoMakeAccessorHelperOne (Callback <void, T*, U> setter)
|
||||
{
|
||||
/* AttributeAccessor implementation with a plain ole function returning void. */
|
||||
class POFunction : public AccessorHelper<T,V>
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Construct from a class set method.
|
||||
* \param [in] setter The class set method pointer.
|
||||
*/
|
||||
POFunction (Callback<void, T*, U> setter)
|
||||
: AccessorHelper<T,V> (),
|
||||
m_setter (setter)
|
||||
{}
|
||||
private:
|
||||
virtual bool DoSet (T *object, const V *v) const {
|
||||
typename AccessorTrait<U>::Result tmp;
|
||||
bool ok = v->GetAccessor (tmp);
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_setter(object, tmp);
|
||||
return true;
|
||||
}
|
||||
virtual bool DoGet (const T *object, V *v) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool HasGetter (void) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool HasSetter (void) const {
|
||||
return true;
|
||||
}
|
||||
Callback<void, T*, U> m_setter; // The class set method pointer, returning void.
|
||||
};
|
||||
return Ptr<const AttributeAccessor> (new POFunction (setter), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup attributeimpl
|
||||
*
|
||||
* MakeAccessorHelper implementation with a get functor
|
||||
* and a set functor returning 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 whose object pointer is passed to the functors.
|
||||
* \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 set functor, returning void.
|
||||
* \param [in] getter The address of the get functor.
|
||||
* \returns The AttributeAccessor.
|
||||
*/
|
||||
template <typename W, typename T, typename U, typename V>
|
||||
inline
|
||||
Ptr<const AttributeAccessor>
|
||||
DoMakeAccessorHelperTwo (void (*setter)(T*, U), V (*getter)(T*))
|
||||
{
|
||||
/*
|
||||
* AttributeAccessor implementation with plain ole get functor and set functor,
|
||||
* returning void.
|
||||
*/
|
||||
class POFunction : public AccessorHelper<T,W>
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Construct from get and set functors.
|
||||
* \param [in] setter The set functor pointer, returning void.
|
||||
* \param [in] getter The get functor pointer.
|
||||
*/
|
||||
POFunction (void (*setter)(T*, U), V (*getter)(T*))
|
||||
: AccessorHelper<T,W> (),
|
||||
m_setter (setter),
|
||||
m_getter (getter)
|
||||
{}
|
||||
private:
|
||||
virtual bool DoSet (T *object, const W *v) const {
|
||||
typename AccessorTrait<U>::Result tmp;
|
||||
bool ok = v->GetAccessor (tmp);
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
(*m_setter)(object, tmp);
|
||||
return true;
|
||||
}
|
||||
virtual bool DoGet (const T *object, W *v) const {
|
||||
v->Set ((*m_getter)(object));
|
||||
return true;
|
||||
}
|
||||
virtual bool HasGetter (void) const {
|
||||
return true;
|
||||
}
|
||||
virtual bool HasSetter (void) const {
|
||||
return true;
|
||||
}
|
||||
void (*m_setter)(T*, U); // The class set method pointer, returning void.
|
||||
V (*m_getter)(T*); // The class get functor method pointer.
|
||||
};
|
||||
return Ptr<const AttributeAccessor> (new POFunction (setter, getter), false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup attributeimpl
|
||||
* \copydoc DoMakeAccessorHelperTwo(void(*)(T*, U),V(*)(T*))
|
||||
*/
|
||||
template <typename W, typename T, typename U, typename V>
|
||||
inline
|
||||
Ptr<const AttributeAccessor>
|
||||
DoMakeAccessorHelperTwo (V (*getter)(T*), void (*setter)(T*, U))
|
||||
{
|
||||
return DoMakeAccessorHelperTwo<W> (setter, getter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup attributeimpl
|
||||
*
|
||||
* MakeAccessorHelper implementation with a get functor
|
||||
* and a set functor returning \p 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 whose object pointer is passed to the functors.
|
||||
* \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 set functor, returning bool.
|
||||
* \param [in] getter The address of the get functor.
|
||||
* \returns The AttributeAccessor.
|
||||
*/
|
||||
template <typename W, typename T, typename U, typename V>
|
||||
inline
|
||||
Ptr<const AttributeAccessor>
|
||||
DoMakeAccessorHelperTwo (bool (*setter)(T*, U), V (*getter)(T*))
|
||||
{
|
||||
/*
|
||||
* AttributeAccessor implementation with plain ole get functor and
|
||||
* set functor, returning bool.
|
||||
*/
|
||||
class POFunction : 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.
|
||||
*/
|
||||
POFunction (bool (*setter)(T*, U), V (*getter)(T**))
|
||||
: AccessorHelper<T,W> (),
|
||||
m_setter (setter),
|
||||
m_getter (getter)
|
||||
{}
|
||||
private:
|
||||
virtual bool DoSet (T *object, const W *v) const {
|
||||
typename AccessorTrait<U>::Result tmp;
|
||||
bool ok = v->GetAccessor (tmp);
|
||||
if (!ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ok = (*m_setter)(object, tmp);
|
||||
return ok;
|
||||
}
|
||||
virtual bool DoGet (const T *object, W *v) const {
|
||||
v->Set ((*m_getter)(object));
|
||||
return true;
|
||||
}
|
||||
virtual bool HasGetter (void) const {
|
||||
return true;
|
||||
}
|
||||
virtual bool HasSetter (void) const {
|
||||
return true;
|
||||
}
|
||||
bool (*m_setter)(T*, U); // The set method pointer, returning bool.
|
||||
V (*m_getter)(T*); // The get functor method pointer.
|
||||
};
|
||||
return Ptr<const AttributeAccessor> (new POFunction (setter, getter), false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup attributeimpl
|
||||
* \copydoc ns3::DoMakeAccessorHelperTwo(bool(*)(T*, U),V(*)(T*))
|
||||
*/
|
||||
template <typename W, typename T, typename U, typename V>
|
||||
inline
|
||||
Ptr<const AttributeAccessor>
|
||||
DoMakeAccessorHelperTwo (V (*getter)(T*), bool (*setter)(T*, U))
|
||||
{
|
||||
return DoMakeAccessorHelperTwo<W> (setter, getter);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
#endif // EXTENDED_ATTRIBUTE_HELPER_H
|
||||
27
src/core/model/pair.cc
Normal file
27
src/core/model/pair.cc
Normal file
@@ -0,0 +1,27 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2018 WPL, Inc.
|
||||
*
|
||||
* 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@wpli.net>
|
||||
* Note: Need this file for library to be built
|
||||
*/
|
||||
|
||||
#include "pair.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
292
src/core/model/pair.h
Normal file
292
src/core/model/pair.h
Normal file
@@ -0,0 +1,292 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2018 WPL, Inc.
|
||||
*
|
||||
* 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@wpli.net>
|
||||
*/
|
||||
|
||||
#ifndef PAIR_H
|
||||
#define PAIR_H
|
||||
|
||||
#include <ns3/attribute.h>
|
||||
#include <ns3/ptr.h>
|
||||
#include <ns3/string.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class AttributeChecker;
|
||||
|
||||
// TODO(jared): useful to maybe define global to be the pair separator
|
||||
// for serialization / deserialization?
|
||||
template <class A, class B>
|
||||
std::ostream &
|
||||
operator << (std::ostream &os, const std::pair<A, B> &p)
|
||||
{
|
||||
os << p.first << " " << p.second;
|
||||
return os;
|
||||
}
|
||||
|
||||
// A = attribute value type, C = container type to return
|
||||
template <class A, class B>
|
||||
class PairValue : public AttributeValue
|
||||
{
|
||||
public:
|
||||
typedef std::pair<Ptr<A>, Ptr<B> > value_type;
|
||||
typedef typename std::result_of<decltype(&A::Get)(A)>::type first_type;
|
||||
typedef typename std::result_of<decltype(&B::Get)(B)>::type second_type;
|
||||
typedef typename std::pair<first_type, second_type> result_type;
|
||||
typedef typename std::pair<const first_type, second_type> map_value_type;
|
||||
|
||||
PairValue ();
|
||||
PairValue (const result_type &value); // "import" constructor
|
||||
|
||||
Ptr<AttributeValue> Copy (void) const;
|
||||
|
||||
bool DeserializeFromString (std::string value, Ptr<const AttributeChecker> checker);
|
||||
std::string SerializeToString (Ptr<const AttributeChecker> checker) const;
|
||||
|
||||
result_type Get (void) const;
|
||||
void Set (const result_type &value);
|
||||
|
||||
template <typename T>
|
||||
bool GetAccessor (T &value) const;
|
||||
|
||||
private:
|
||||
value_type m_value;
|
||||
};
|
||||
|
||||
template <class A, class B>
|
||||
class PairChecker : public AttributeChecker
|
||||
{
|
||||
public:
|
||||
typedef std::pair<Ptr<const AttributeChecker>, Ptr<const AttributeChecker> > checker_pair_type;
|
||||
|
||||
virtual void SetCheckers (Ptr<const AttributeChecker> firstchecker, Ptr<const AttributeChecker> secondchecker) = 0;
|
||||
virtual checker_pair_type GetCheckers (void) const = 0;
|
||||
};
|
||||
|
||||
template <class A, class B>
|
||||
Ptr<PairChecker<A, B> >
|
||||
MakePairChecker (const PairValue<A, B> &value);
|
||||
|
||||
template <class A, class B>
|
||||
Ptr<PairChecker<A, B> >
|
||||
MakePairChecker (Ptr<const AttributeChecker> firstchecker, Ptr<const AttributeChecker> secondchecker);
|
||||
|
||||
template <class A, class B>
|
||||
Ptr<PairChecker<A, B> > MakePairChecker (void);
|
||||
|
||||
template <typename A, typename B, typename T1>
|
||||
Ptr<const AttributeAccessor> MakePairAccessor (T1 a1);
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
/*****************************************************************************
|
||||
* Implementation below
|
||||
*****************************************************************************/
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <class A, class B>
|
||||
class PairChecker : public ns3::PairChecker<A, B>
|
||||
{
|
||||
public:
|
||||
PairChecker (void);
|
||||
explicit PairChecker (Ptr<const AttributeChecker> firstchecker, Ptr<const AttributeChecker> secondchecker);
|
||||
void SetCheckers (Ptr<const AttributeChecker> firstchecker, Ptr<const AttributeChecker> secondchecker);
|
||||
typename ns3::PairChecker<A, B>::checker_pair_type GetCheckers (void) const;
|
||||
|
||||
private:
|
||||
Ptr<const AttributeChecker> m_firstchecker;
|
||||
Ptr<const AttributeChecker> m_secondchecker;
|
||||
};
|
||||
|
||||
template <class A, class B>
|
||||
PairChecker<A, B>::PairChecker (void)
|
||||
: m_firstchecker (0)
|
||||
, m_secondchecker (0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
PairChecker<A, B>::PairChecker (Ptr<const AttributeChecker> firstchecker, Ptr<const AttributeChecker> secondchecker)
|
||||
: m_firstchecker (firstchecker)
|
||||
, m_secondchecker (secondchecker)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void
|
||||
PairChecker<A, B>::SetCheckers (Ptr<const AttributeChecker> firstchecker, Ptr<const AttributeChecker> secondchecker)
|
||||
{
|
||||
m_firstchecker = firstchecker;
|
||||
m_secondchecker = secondchecker;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
typename ns3::PairChecker<A, B>::checker_pair_type
|
||||
PairChecker<A, B>::GetCheckers (void) const
|
||||
{
|
||||
return std::make_pair (m_firstchecker, m_secondchecker);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <class A, class B>
|
||||
Ptr<PairChecker<A, B> >
|
||||
MakePairChecker (const PairValue<A, B> &value)
|
||||
{
|
||||
return MakePairChecker <A, B> ();
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
Ptr<PairChecker<A, B> >
|
||||
MakePairChecker (Ptr<const AttributeChecker> firstchecker, Ptr<const AttributeChecker> secondchecker)
|
||||
{
|
||||
auto checker = MakePairChecker <A, B> ();
|
||||
checker->SetCheckers (firstchecker, secondchecker);
|
||||
return checker;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
Ptr<PairChecker<A, B> >
|
||||
MakePairChecker (void)
|
||||
{
|
||||
std::string typeName, underlyingType;
|
||||
typedef PairValue<A, B> T;
|
||||
std::string first_type_name = typeid (typename T::value_type::first_type).name ();
|
||||
std::string second_type_name = typeid (typename T::value_type::second_type).name ();
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "ns3::PairValue<" << first_type_name << ", " << second_type_name << ">";
|
||||
typeName = oss.str ();
|
||||
}
|
||||
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << typeid (typename T::value_type).name ();
|
||||
underlyingType = oss.str ();
|
||||
}
|
||||
|
||||
return DynamicCast<PairChecker<A, B> > (
|
||||
MakeSimpleAttributeChecker<T, internal::PairChecker<A, B> > (typeName, underlyingType)
|
||||
);
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
PairValue<A, B>::PairValue ()
|
||||
: m_value (std::make_pair (Create <A> (), Create <B> ()))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
PairValue<A, B>::PairValue (const typename PairValue<A, B>::result_type &value)
|
||||
{
|
||||
Set (value);
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
Ptr<AttributeValue>
|
||||
PairValue<A, B>::Copy (void) const
|
||||
{
|
||||
auto p = Create <PairValue <A, B> > ();
|
||||
// deep copy if non-null
|
||||
if (m_value.first)
|
||||
p->m_value = std::make_pair (DynamicCast<A> (m_value.first->Copy ()),
|
||||
DynamicCast<B> (m_value.second->Copy ()));
|
||||
return p;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
bool
|
||||
PairValue<A, B>::DeserializeFromString (std::string value, Ptr<const AttributeChecker> checker)
|
||||
{
|
||||
auto pchecker = DynamicCast<const PairChecker<A, B> > (checker);
|
||||
if (!pchecker) return false;
|
||||
|
||||
std::istringstream iss (value); // copies value
|
||||
iss >> value;
|
||||
auto first = pchecker->GetCheckers ().first->CreateValidValue (StringValue (value));
|
||||
if (!first) return false;
|
||||
|
||||
auto firstattr = DynamicCast <A> (first);
|
||||
if (!firstattr) return false;
|
||||
|
||||
iss >> value;
|
||||
auto second = pchecker->GetCheckers ().second->CreateValidValue (StringValue (value));
|
||||
if (!second) return false;
|
||||
|
||||
auto secondattr = DynamicCast <B> (second);
|
||||
if (!secondattr) return false;
|
||||
|
||||
m_value = std::make_pair (firstattr, secondattr);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
std::string
|
||||
PairValue<A, B>::SerializeToString (Ptr<const AttributeChecker> checker) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << m_value.first->SerializeToString (checker);
|
||||
oss << " ";
|
||||
oss << m_value.second->SerializeToString (checker);
|
||||
|
||||
return oss.str ();
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
typename PairValue<A, B>::result_type
|
||||
PairValue<A, B>::Get (void) const
|
||||
{
|
||||
return std::make_pair (m_value.first->Get (), m_value.second->Get ());
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void
|
||||
PairValue<A, B>::Set (const typename PairValue<A, B>::result_type &value)
|
||||
{
|
||||
m_value = std::make_pair (Create <A> (value.first), Create <B> (value.second));
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
template <typename T>
|
||||
bool
|
||||
PairValue<A, B>::GetAccessor (T &value) const
|
||||
{
|
||||
value = T (Get ());
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename A, typename B, typename T1>
|
||||
Ptr<const AttributeAccessor> MakePairAccessor (T1 a1)
|
||||
{
|
||||
return MakeAccessorHelper<PairValue<A, B> > (a1);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif // PAIR_H
|
||||
430
src/core/test/attribute-container-test-suite.cc
Normal file
430
src/core/test/attribute-container-test-suite.cc
Normal file
@@ -0,0 +1,430 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2018 WPL, Inc.
|
||||
*
|
||||
* 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@wpli.net>
|
||||
*/
|
||||
|
||||
#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>
|
||||
#include <ns3/string.h>
|
||||
#include <ns3/ptr.h>
|
||||
#include <ns3/object.h>
|
||||
#include <ns3/type-id.h>
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("AttributeContainerTestSuite");
|
||||
|
||||
class AttributeContainerObject : public Object
|
||||
{
|
||||
public:
|
||||
AttributeContainerObject ();
|
||||
virtual ~AttributeContainerObject ();
|
||||
|
||||
void ReverseList ();
|
||||
|
||||
static
|
||||
TypeId GetTypeId ();
|
||||
|
||||
friend std::ostream &operator <<(std::ostream &os, const AttributeContainerObject &obj);
|
||||
|
||||
private:
|
||||
std::list<double> m_doublelist;
|
||||
std::vector<int> m_intvec;
|
||||
// TODO(jared): need PairValue attributevalue to handle std::pair elements
|
||||
std::map<std::string, int> m_map;
|
||||
};
|
||||
|
||||
AttributeContainerObject::AttributeContainerObject ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AttributeContainerObject::~AttributeContainerObject ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TypeId
|
||||
AttributeContainerObject::GetTypeId ()
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::AttributeContainerObject")
|
||||
.SetParent<Object> ()
|
||||
.SetGroupName("Test")
|
||||
.AddConstructor<AttributeContainerObject> ()
|
||||
.AddAttribute ("DoubleList", "List of doubles",
|
||||
AttributeContainerValue <DoubleValue> (),
|
||||
MakeAttributeContainerAccessor <DoubleValue> (&AttributeContainerObject::m_doublelist),
|
||||
MakeAttributeContainerChecker<DoubleValue> (MakeDoubleChecker<double> ()))
|
||||
.AddAttribute ("IntegerVector", "Vector of integers",
|
||||
// the container value container differs from the underlying object
|
||||
AttributeContainerValue <IntegerValue> (),
|
||||
MakeAttributeContainerAccessor <IntegerValue> (&AttributeContainerObject::m_intvec),
|
||||
MakeAttributeContainerChecker<IntegerValue> (MakeIntegerChecker<int> ()))
|
||||
.AddAttribute ("MapStringInt", "Map of strings to ints",
|
||||
// the container value container differs from the underlying object
|
||||
AttributeContainerValue <PairValue <StringValue, IntegerValue> > (),
|
||||
MakeAttributeContainerAccessor <PairValue <StringValue, IntegerValue> > (&AttributeContainerObject::m_map),
|
||||
MakeAttributeContainerChecker<PairValue <StringValue, IntegerValue> > (
|
||||
MakePairChecker<StringValue, IntegerValue> (MakeStringChecker (), MakeIntegerChecker<int> ())))
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
void
|
||||
AttributeContainerObject::ReverseList ()
|
||||
{
|
||||
m_doublelist.reverse ();
|
||||
std::vector<int> tmp;
|
||||
std::copy_backward (m_intvec.begin (), m_intvec.end (), tmp.begin ());
|
||||
m_intvec = tmp;
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
operator << (std::ostream &os, const AttributeContainerObject &obj)
|
||||
{
|
||||
os << "AttributeContainerObject: ";
|
||||
bool first = true;
|
||||
for (auto d: obj.m_doublelist)
|
||||
{
|
||||
if (!first) os << ", ";
|
||||
os << d;
|
||||
first = false;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
// this handles mixed constness and compatible, yet
|
||||
// distinct numerical classes (like int and long)
|
||||
template <class A, class B, class C, class D>
|
||||
bool
|
||||
operator ==(const std::pair<A, B> &x, const std::pair<C, D> &y)
|
||||
{
|
||||
return x.first == y.first && x.second == y.second;
|
||||
}
|
||||
|
||||
/* Test instantiation, initialization, access */
|
||||
class AttributeContainerTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
AttributeContainerTestCase ();
|
||||
virtual ~AttributeContainerTestCase () {}
|
||||
|
||||
private:
|
||||
virtual void DoRun ();
|
||||
};
|
||||
|
||||
AttributeContainerTestCase::AttributeContainerTestCase ()
|
||||
: TestCase ("test instantiation, initialization, access")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
AttributeContainerTestCase::DoRun ()
|
||||
{
|
||||
{
|
||||
std::list<double> ref = {1.0, 2.1, 3.145269};
|
||||
|
||||
AttributeContainerValue<DoubleValue> ac (ref);
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (ref.size (), ac.GetN (), "Container size mismatch");
|
||||
auto aciter = ac.Begin ();
|
||||
for (auto rend = ref.end (),
|
||||
riter= ref.begin (); riter != rend; ++riter)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
|
||||
NS_TEST_ASSERT_MSG_EQ (*riter, (*aciter)->Get (), "Incorrect value");
|
||||
++aciter;
|
||||
}
|
||||
NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> ref = {-2, 3, 10, -1042};
|
||||
|
||||
AttributeContainerValue<IntegerValue> ac (ref.begin (), ref.end ());
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (ref.size (), ac.GetN (), "Container size mismatch");
|
||||
auto aciter = ac.Begin ();
|
||||
for (auto rend = ref.end (),
|
||||
riter= ref.begin (); riter != rend; ++riter)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
|
||||
NS_TEST_ASSERT_MSG_EQ (*riter, (*aciter)->Get (), "Incorrect value");
|
||||
++aciter;
|
||||
}
|
||||
NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
|
||||
}
|
||||
|
||||
{
|
||||
auto ref = {"one", "two", "three"};
|
||||
AttributeContainerValue<StringValue> ac (ref.begin (), ref.end ());
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (3, ac.GetN (), "Container size mismatch");
|
||||
auto aciter = ac.Begin ();
|
||||
for (auto v: ref)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
|
||||
NS_TEST_ASSERT_MSG_EQ (v, (*aciter)->Get (), "Incorrect value");
|
||||
++aciter;
|
||||
}
|
||||
NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
|
||||
}
|
||||
|
||||
{
|
||||
auto ref = {"one", "two", "three"};
|
||||
AttributeContainerValue<StringValue, std::vector> ac (ref);
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (3, ac.GetN (), "Container size mismatch");
|
||||
auto aciter = ac.Begin ();
|
||||
for (auto v: ref)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
|
||||
NS_TEST_ASSERT_MSG_EQ (v, (*aciter)->Get (), "Incorrect value");
|
||||
++aciter;
|
||||
}
|
||||
NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
|
||||
}
|
||||
|
||||
{
|
||||
// use int64_t which is default for IntegerValue
|
||||
std::map<std::string, int64_t> ref = { {"one", 1}, {"two", 2}, {"three", 3}};
|
||||
AttributeContainerValue<PairValue <StringValue, IntegerValue> > ac (ref);
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (3, ac.GetN (), "Container size mismatch");
|
||||
auto aciter = ac.Begin ();
|
||||
for (auto v: ref)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
|
||||
NS_TEST_ASSERT_MSG_EQ (v, (*aciter)->Get (), "Incorrect value");
|
||||
++aciter;
|
||||
}
|
||||
NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// test serdes functions
|
||||
class AttributeContainerSerializationTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
AttributeContainerSerializationTestCase ();
|
||||
virtual ~AttributeContainerSerializationTestCase () {}
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
};
|
||||
|
||||
AttributeContainerSerializationTestCase::AttributeContainerSerializationTestCase ()
|
||||
: TestCase ("test serialization and deserialization")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
AttributeContainerSerializationTestCase::DoRun (void)
|
||||
{
|
||||
{
|
||||
// notice embedded spaces
|
||||
std::string doubles = "1.0001, 20.53, -102.3";
|
||||
|
||||
AttributeContainerValue<DoubleValue> attr;
|
||||
auto checker = MakeAttributeContainerChecker (attr);
|
||||
//auto acchecker = DynamicCast<AttributeContainerChecker <DoubleValue, std::list> > (checker);
|
||||
checker->SetItemChecker (MakeDoubleChecker<double> ());
|
||||
NS_TEST_ASSERT_MSG_EQ (attr.DeserializeFromString (doubles, checker), true, "Deserialize failed");
|
||||
NS_TEST_ASSERT_MSG_EQ (attr.GetN (), 3, "Incorrect container size");
|
||||
|
||||
std::string reserialized = attr.SerializeToString (checker);
|
||||
std::string canonical = doubles;
|
||||
canonical.erase (std::remove (canonical.begin (), canonical.end (), ' '), canonical.end ());
|
||||
NS_TEST_ASSERT_MSG_EQ (reserialized, canonical, "Reserialization failed");
|
||||
}
|
||||
|
||||
{
|
||||
// notice embedded spaces
|
||||
std::string ints = "1, 2, -3, -4";
|
||||
|
||||
AttributeContainerValue<IntegerValue> attr;
|
||||
auto checker = MakeAttributeContainerChecker (attr);
|
||||
checker->SetItemChecker (MakeIntegerChecker<int> ());
|
||||
NS_TEST_ASSERT_MSG_EQ (attr.DeserializeFromString (ints, checker), true, "Deserialize failed");
|
||||
NS_TEST_ASSERT_MSG_EQ (attr.GetN (), 4, "Incorrect container size");
|
||||
|
||||
std::string reserialized = attr.SerializeToString (checker);
|
||||
std::string canonical = ints;
|
||||
canonical.erase (std::remove (canonical.begin (), canonical.end (), ' '), canonical.end ());
|
||||
NS_TEST_ASSERT_MSG_EQ (reserialized, canonical, "Reserialization failed");
|
||||
}
|
||||
|
||||
{
|
||||
std::string strings = "this is a sentence with words";
|
||||
|
||||
AttributeContainerValue<StringValue> attr (' ');
|
||||
auto checker = MakeAttributeContainerChecker (attr);
|
||||
checker->SetItemChecker (MakeStringChecker ());
|
||||
NS_TEST_ASSERT_MSG_EQ (attr.DeserializeFromString (strings, checker), true, "Deserialize failed");
|
||||
NS_TEST_ASSERT_MSG_EQ (attr.GetN (), 6, "Incorrect container size");
|
||||
|
||||
std::string reserialized = attr.SerializeToString (checker);
|
||||
std::string canonical = strings;
|
||||
NS_TEST_ASSERT_MSG_EQ (reserialized, canonical, "Reserialization failed");
|
||||
}
|
||||
|
||||
{
|
||||
std::string pairs = "one 1,two 2,three 3";
|
||||
AttributeContainerValue<PairValue<StringValue, IntegerValue> > attr;
|
||||
auto checker = MakeAttributeContainerChecker (attr);
|
||||
checker->SetItemChecker (MakePairChecker <StringValue, IntegerValue> (
|
||||
MakeStringChecker (), MakeIntegerChecker<int> ()));
|
||||
NS_TEST_ASSERT_MSG_EQ (attr.DeserializeFromString (pairs, checker), true, "Deserialization failed");
|
||||
NS_TEST_ASSERT_MSG_EQ (attr.GetN (), 3, "Incorrect container size");
|
||||
|
||||
std::string reserialized = attr.SerializeToString (checker);
|
||||
std::string canonical = pairs;
|
||||
NS_TEST_ASSERT_MSG_EQ (reserialized, canonical, "Reserealization failed");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class AttributeContainerSetGetTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
AttributeContainerSetGetTestCase ();
|
||||
virtual ~AttributeContainerSetGetTestCase () {}
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
};
|
||||
|
||||
AttributeContainerSetGetTestCase::AttributeContainerSetGetTestCase ()
|
||||
: TestCase ("test attribute set and get")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
AttributeContainerSetGetTestCase::DoRun (void)
|
||||
{
|
||||
Ptr<AttributeContainerObject> obj = CreateObject<AttributeContainerObject> ();
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << *obj;
|
||||
NS_TEST_ASSERT_MSG_EQ (oss.str (), "AttributeContainerObject: ", "DoubleList initialized incorrectly");
|
||||
}
|
||||
|
||||
std::list<double> doubles = {1.1, 2.22, 3.333};
|
||||
obj->SetAttribute ("DoubleList", AttributeContainerValue<DoubleValue> (doubles));
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << *obj;
|
||||
NS_TEST_ASSERT_MSG_EQ (oss.str (), "AttributeContainerObject: 1.1, 2.22, 3.333", "DoubleList incorrectly set");
|
||||
}
|
||||
|
||||
obj->ReverseList ();
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << *obj;
|
||||
NS_TEST_ASSERT_MSG_EQ (oss.str (), "AttributeContainerObject: 3.333, 2.22, 1.1", "DoubleList incorrectly reversed");
|
||||
|
||||
// NOTE: changing the return container here too!
|
||||
AttributeContainerValue<DoubleValue> value;
|
||||
obj->GetAttribute ("DoubleList", value);
|
||||
NS_TEST_ASSERT_MSG_EQ (doubles.size (), value.GetN (), "AttributeContainerValue wrong size");
|
||||
|
||||
AttributeContainerValue<DoubleValue>::result_type doublevec = value.Get ();
|
||||
NS_TEST_ASSERT_MSG_EQ (doubles.size (), doublevec.size (), "DoublesVec wrong size");
|
||||
auto iter = doubles.rbegin ();
|
||||
for (auto d: doublevec)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ (d, *iter, "Incorrect value in doublesvec");
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> ints = {-1, 0, 1, 2, 3};
|
||||
// NOTE: here the underlying attribute container type differs from the actual container
|
||||
obj->SetAttribute ("IntegerVector", AttributeContainerValue<IntegerValue> (ints));
|
||||
|
||||
{
|
||||
// NOTE: changing the container here too!
|
||||
AttributeContainerValue<IntegerValue> value;
|
||||
obj->GetAttribute ("IntegerVector", value);
|
||||
NS_TEST_ASSERT_MSG_EQ (ints.size (), value.GetN (), "AttributeContainerValue wrong size");
|
||||
|
||||
AttributeContainerValue<IntegerValue>::result_type intlist = value.Get ();
|
||||
NS_TEST_ASSERT_MSG_EQ (ints.size (), intlist.size (), "Intvec wrong size");
|
||||
auto iter = ints.begin ();
|
||||
for (auto d: intlist)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ (d, *iter, "Incorrect value in intvec");
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, int> map = { {"one", 1}, {"two", 2}, {"three", 3}};
|
||||
obj->SetAttribute ("MapStringInt", AttributeContainerValue<PairValue <StringValue, IntegerValue> > (map));
|
||||
|
||||
{
|
||||
AttributeContainerValue<PairValue<StringValue, IntegerValue> > value;
|
||||
obj->GetAttribute ("MapStringInt", value);
|
||||
NS_TEST_ASSERT_MSG_EQ (map.size (), value.GetN (), "AttributeContainerValue wrong size");
|
||||
|
||||
// could possibly make custom assignment operator to make assignment statement work
|
||||
std::map<std::string, int> mapstrint;
|
||||
auto lst = value.Get ();
|
||||
for (auto l: lst) mapstrint[l.first] = l.second;
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (map.size (), mapstrint.size (), "mapstrint wrong size");
|
||||
auto iter = map.begin ();
|
||||
for (auto v: mapstrint)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ (v, *iter, "Incorrect value in mapstrint");
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AttributeContainerTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
AttributeContainerTestSuite ();
|
||||
};
|
||||
|
||||
AttributeContainerTestSuite::AttributeContainerTestSuite ()
|
||||
: TestSuite ("attribute-container-test-suite", UNIT)
|
||||
{
|
||||
AddTestCase (new AttributeContainerTestCase (), TestCase::QUICK);
|
||||
AddTestCase (new AttributeContainerSerializationTestCase (), TestCase::QUICK);
|
||||
AddTestCase (new AttributeContainerSetGetTestCase (), TestCase::QUICK);
|
||||
}
|
||||
|
||||
static AttributeContainerTestSuite AttributeContainerTestSuite; //!< Static variable for test initialization
|
||||
179
src/core/test/pair-value-test-suite.cc
Normal file
179
src/core/test/pair-value-test-suite.cc
Normal file
@@ -0,0 +1,179 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2018 WPL, Inc.
|
||||
*
|
||||
* 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@wpli.net>
|
||||
*/
|
||||
|
||||
#include <ns3/test.h>
|
||||
#include <ns3/log.h>
|
||||
#include <ns3/pair.h>
|
||||
#include <ns3/double.h>
|
||||
#include <ns3/integer.h>
|
||||
#include <ns3/string.h>
|
||||
#include <ns3/ptr.h>
|
||||
#include <ns3/object.h>
|
||||
#include <ns3/type-id.h>
|
||||
#include <ns3/address.h>
|
||||
#include <ns3/mac48-address.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("PairTestSuite");
|
||||
|
||||
class PairObject : public Object
|
||||
{
|
||||
public:
|
||||
PairObject ();
|
||||
virtual ~PairObject ();
|
||||
|
||||
static
|
||||
TypeId GetTypeId ();
|
||||
|
||||
friend std::ostream &operator <<(std::ostream &os, const PairObject &obj);
|
||||
|
||||
private:
|
||||
std::pair <std::string, std::string> m_stringpair;
|
||||
std::pair <Address, int> m_addresspair;
|
||||
};
|
||||
|
||||
PairObject::PairObject ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PairObject::~PairObject ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TypeId
|
||||
PairObject::GetTypeId ()
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::PairObject")
|
||||
.SetParent<Object> ()
|
||||
.SetGroupName("Test")
|
||||
.AddConstructor<PairObject> ()
|
||||
.AddAttribute ("StringPair", "Pair: string, string",
|
||||
PairValue <StringValue, StringValue> (),
|
||||
MakePairAccessor <StringValue, StringValue> (&PairObject::m_stringpair),
|
||||
MakePairChecker<StringValue, StringValue> (MakeStringChecker (), MakeStringChecker ()))
|
||||
.AddAttribute ("AddressPair", "Pair: address int",
|
||||
// the container value container differs from the underlying object
|
||||
PairValue <AddressValue, IntegerValue> (),
|
||||
MakePairAccessor <AddressValue, IntegerValue> (&PairObject::m_addresspair),
|
||||
MakePairChecker<AddressValue, IntegerValue> (MakeAddressChecker (), MakeIntegerChecker<int> ()))
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
operator << (std::ostream &os, const PairObject &obj)
|
||||
{
|
||||
os << "StringPair = { " << obj.m_stringpair << " } ";
|
||||
os << "AddressPair = { " << obj.m_addresspair << " }";
|
||||
return os;
|
||||
}
|
||||
|
||||
/* Test instantiation, initialization, access */
|
||||
class PairValueTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
PairValueTestCase ();
|
||||
virtual ~PairValueTestCase () {}
|
||||
|
||||
private:
|
||||
virtual void DoRun ();
|
||||
};
|
||||
|
||||
PairValueTestCase::PairValueTestCase ()
|
||||
: TestCase ("test instantiation, initialization, access")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
PairValueTestCase::DoRun ()
|
||||
{
|
||||
{
|
||||
std::pair<const int, double> ref = {1, 2.4};
|
||||
|
||||
PairValue<IntegerValue, DoubleValue> ac (ref);
|
||||
|
||||
std::pair<const int, double> rv = ac.Get ();
|
||||
NS_TEST_ASSERT_MSG_EQ (rv, ref, "Attribute value does not equal original");
|
||||
}
|
||||
|
||||
{
|
||||
std::pair<const std::string, Mac48Address> ref = {"hello", Mac48Address::Allocate ()};
|
||||
|
||||
PairValue<StringValue, Mac48AddressValue> ac;
|
||||
ac.Set (ref);
|
||||
std::pair<const std::string, Mac48Address> rv = ac.Get ();
|
||||
NS_TEST_ASSERT_MSG_EQ (rv, ref, "Attribute value does not equal original");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PairValueSettingsTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
PairValueSettingsTestCase ();
|
||||
|
||||
void DoRun ();
|
||||
};
|
||||
|
||||
PairValueSettingsTestCase::PairValueSettingsTestCase ()
|
||||
: TestCase ("test setting through attribute interface")
|
||||
{}
|
||||
|
||||
void
|
||||
PairValueSettingsTestCase::DoRun ()
|
||||
{
|
||||
Address addr = Mac48Address::Allocate ();
|
||||
|
||||
auto p = CreateObject <PairObject> ();
|
||||
p->SetAttribute ("StringPair", PairValue<StringValue, StringValue> (std::make_pair ("hello", "world")));
|
||||
p->SetAttribute ("AddressPair", PairValue<AddressValue, IntegerValue> (std::make_pair (addr, 31)));
|
||||
|
||||
std::ostringstream oss, ref;
|
||||
oss << *p;
|
||||
|
||||
ref << "StringPair = { hello world } AddressPair = { " << addr << " 31 }";
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ ((oss.str ()), (ref.str ()), "Pairs not correctly set");
|
||||
}
|
||||
|
||||
class PairValueTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
PairValueTestSuite ();
|
||||
};
|
||||
|
||||
PairValueTestSuite::PairValueTestSuite ()
|
||||
: TestSuite ("pair-value-test-suite", UNIT)
|
||||
{
|
||||
AddTestCase (new PairValueTestCase (), TestCase::QUICK);
|
||||
AddTestCase (new PairValueSettingsTestCase (), TestCase::QUICK);
|
||||
}
|
||||
|
||||
static PairValueTestSuite pairValueTestSuite; //!< Static variable for test initialization
|
||||
@@ -101,6 +101,10 @@ def configure(conf):
|
||||
conf.check_nonfatal(header_name='sys/stat.h', define_name='HAVE_SYS_STAT_H')
|
||||
conf.check_nonfatal(header_name='dirent.h', define_name='HAVE_DIRENT_H')
|
||||
|
||||
if conf.check_nonfatal(header_name='stdlib.h'):
|
||||
conf.define('HAVE_STDLIB_H', 1)
|
||||
conf.define('HAVE_GETENV', 1)
|
||||
|
||||
conf.check_nonfatal(header_name='signal.h', define_name='HAVE_SIGNAL_H')
|
||||
|
||||
# Check for POSIX threads
|
||||
@@ -240,6 +244,8 @@ def build(bld):
|
||||
'model/show-progress.cc',
|
||||
'model/system-wall-clock-timestamp.cc',
|
||||
'model/version.cc',
|
||||
'model/attribute-container.cc',
|
||||
'model/pair.cc',
|
||||
]
|
||||
|
||||
if (bld.env['ENABLE_EXAMPLES']):
|
||||
@@ -271,11 +277,6 @@ def build(bld):
|
||||
'test/type-id-test-suite.cc',
|
||||
]
|
||||
|
||||
if (bld.env['ENABLE_EXAMPLES']):
|
||||
core_test.source.extend([
|
||||
'test/examples-as-tests-test-suite.cc',
|
||||
])
|
||||
|
||||
headers = bld(features='ns3header')
|
||||
headers.module = 'core'
|
||||
headers.source = [
|
||||
@@ -290,7 +291,6 @@ def build(bld):
|
||||
'model/map-scheduler.h',
|
||||
'model/heap-scheduler.h',
|
||||
'model/calendar-scheduler.h',
|
||||
'model/priority-queue-scheduler.h',
|
||||
'model/simulation-singleton.h',
|
||||
'model/singleton.h',
|
||||
'model/timer.h',
|
||||
@@ -299,7 +299,6 @@ def build(bld):
|
||||
'model/synchronizer.h',
|
||||
'model/make-event.h',
|
||||
'model/system-wall-clock-ms.h',
|
||||
'model/system-wall-clock-timestamp.h',
|
||||
'model/empty.h',
|
||||
'model/callback.h',
|
||||
'model/object-base.h',
|
||||
@@ -369,6 +368,10 @@ def build(bld):
|
||||
'model/time-printer.h',
|
||||
'model/show-progress.h',
|
||||
'model/version.h',
|
||||
'model/pair.h',
|
||||
'model/attribute-container-accessor-helper.h',
|
||||
'model/attribute-container.h',
|
||||
'model/extended-attribute-helper.h',
|
||||
]
|
||||
|
||||
if (bld.env['ENABLE_EXAMPLES']):
|
||||
|
||||
Reference in New Issue
Block a user