576 lines
17 KiB
C++
576 lines
17 KiB
C++
/*
|
|
* 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_H
|
|
#define ATTRIBUTE_CONTAINER_H
|
|
|
|
#include <ns3/attribute-helper.h>
|
|
#include <ns3/string.h>
|
|
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
#include <list>
|
|
#include <sstream>
|
|
#include <type_traits>
|
|
#include <typeinfo>
|
|
#include <utility>
|
|
|
|
namespace ns3
|
|
{
|
|
|
|
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.
|
|
*/
|
|
template <class A, template <class...> class C = std::list>
|
|
class AttributeContainerValue : public AttributeValue
|
|
{
|
|
public:
|
|
/** AttributeValue (element) type. */
|
|
typedef A attribute_type;
|
|
/** Type actually stored within the container. */
|
|
typedef Ptr<A> value_type;
|
|
/** Internal container type. */
|
|
typedef std::list<value_type> container_type;
|
|
/** stl-style Const iterator type. */
|
|
typedef typename container_type::const_iterator const_iterator;
|
|
/** stl-style Non-const iterator type. */
|
|
typedef typename container_type::iterator iterator;
|
|
/** Size type for container. */
|
|
typedef typename container_type::size_type size_type;
|
|
/** NS3 style iterator type. */
|
|
typedef typename AttributeContainerValue::const_iterator Iterator; // NS3 type
|
|
|
|
// use underlying AttributeValue to get return element type
|
|
/** Item type of container returned by Get. */
|
|
typedef typename std::invoke_result_t<decltype(&A::Get), A> item_type;
|
|
/** Type of container returned. */
|
|
typedef C<item_type> result_type;
|
|
|
|
/**
|
|
* Default constructor.
|
|
* \param[in] sep Character separator between elements for parsing.
|
|
*/
|
|
AttributeContainerValue(char sep = ',');
|
|
|
|
/**
|
|
* Construct from another container.
|
|
* @tparam CONTAINER \deduced type of container passed for initialization.
|
|
* \param c Instance of CONTAINER with which to initialize AttributeContainerValue.
|
|
*/
|
|
template <class CONTAINER>
|
|
AttributeContainerValue(const CONTAINER& c);
|
|
|
|
/**
|
|
* Construct from iterators.
|
|
* @tparam ITER \deduced type of iterator.
|
|
* \param[in] begin Iterator that points to first initialization item.
|
|
* \param[in] end Iterator that points ones past last initialization item.
|
|
*/
|
|
template <class ITER>
|
|
AttributeContainerValue(const ITER begin, const ITER end);
|
|
|
|
/** Destructor. */
|
|
~AttributeContainerValue() override;
|
|
|
|
// Inherited
|
|
Ptr<AttributeValue> Copy() const override;
|
|
bool DeserializeFromString(std::string value, Ptr<const AttributeChecker> checker) override;
|
|
std::string SerializeToString(Ptr<const AttributeChecker> checker) const override;
|
|
|
|
// defacto pure virtuals to integrate with built-in accessor code
|
|
/**
|
|
* Return a container of items.
|
|
* \return Container of items.
|
|
*/
|
|
result_type Get() 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.
|
|
* \param c Container from which to copy items.
|
|
*/
|
|
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
|
|
/**
|
|
* NS3-style Number of items.
|
|
* \return Number of items in container.
|
|
*/
|
|
size_type GetN() const;
|
|
/**
|
|
* NS3-style beginning of container.
|
|
* \return Iterator pointing to first time in container.
|
|
*/
|
|
Iterator Begin();
|
|
/**
|
|
* NS3-style ending of container.
|
|
* \return Iterator pointing one past last item of container.
|
|
*/
|
|
Iterator End();
|
|
|
|
// STL-interface
|
|
/**
|
|
* STL-style number of items in container
|
|
* \return number of items in container.
|
|
*/
|
|
size_type size() const;
|
|
/**
|
|
* STL-style beginning of container.
|
|
* \return Iterator pointing to first item in container.
|
|
*/
|
|
iterator begin();
|
|
/**
|
|
* STL-style end of container.
|
|
* \return Iterator pointing to one past last item in container.
|
|
*/
|
|
iterator end();
|
|
/**
|
|
* STL-style const beginning of container.
|
|
* \return Const iterator pointing to first item in container.
|
|
*/
|
|
const_iterator begin() const;
|
|
/**
|
|
* STL-style const end of container.
|
|
* \return Const iterator pointing to one past last item in container.
|
|
*/
|
|
const_iterator end() const;
|
|
|
|
private:
|
|
/**
|
|
* 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
|
|
* \param[in] begin Points to first item to copy
|
|
* \param[in] end Points to one after last item to copy
|
|
* \return This object with items copied.
|
|
*/
|
|
template <class ITER>
|
|
Ptr<AttributeContainerValue<A, C>> CopyFrom(const ITER begin, const ITER end);
|
|
|
|
char m_sep; //!< Item separator
|
|
container_type m_container; //!< Internal container
|
|
};
|
|
|
|
class AttributeContainerChecker : public AttributeChecker
|
|
{
|
|
public:
|
|
/**
|
|
* Set the item checker
|
|
* \param itemchecker The item checker
|
|
*/
|
|
virtual void SetItemChecker(Ptr<const AttributeChecker> itemchecker) = 0;
|
|
/**
|
|
* Get the item checker
|
|
* \return The item checker
|
|
*/
|
|
virtual Ptr<const AttributeChecker> GetItemChecker() const = 0;
|
|
};
|
|
|
|
/**
|
|
* Make AttributeContainerChecker from AttributeContainerValue.
|
|
* @tparam A \deduced AttributeValue type in container.
|
|
* @tparam C \deduced Container type returned by Get.
|
|
* \param[in] value AttributeContainerValue from which to deduce types.
|
|
* \return AttributeContainerChecker for value.
|
|
*/
|
|
template <class A, template <class...> class C>
|
|
Ptr<AttributeChecker> MakeAttributeContainerChecker(const AttributeContainerValue<A, C>& value);
|
|
|
|
/**
|
|
* Make AttributeContainerChecker using explicit types, initialize item checker.
|
|
* @tparam A AttributeValue type in container.
|
|
* @tparam C Container type returned by Get.
|
|
* \param[in] itemchecker AttributeChecker used for each item in the container.
|
|
* \return AttributeContainerChecker.
|
|
*/
|
|
template <class A, template <class...> class C = std::list>
|
|
Ptr<const AttributeChecker> MakeAttributeContainerChecker(Ptr<const AttributeChecker> itemchecker);
|
|
|
|
/**
|
|
* Make uninitialized AttributeContainerChecker using explicit types.
|
|
* @tparam A AttributeValue type in container.
|
|
* @tparam C Container type returned by Get.
|
|
* \return AttributeContainerChecker.
|
|
*/
|
|
template <class A, template <class...> class C = std::list>
|
|
Ptr<AttributeChecker> MakeAttributeContainerChecker();
|
|
|
|
/**
|
|
* 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.
|
|
* \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
|
|
|
|
/*****************************************************************************
|
|
* Implementation below
|
|
*****************************************************************************/
|
|
|
|
namespace ns3
|
|
{
|
|
|
|
namespace internal
|
|
{
|
|
|
|
/**
|
|
* \internal
|
|
* Templated AttributeContainerChecker class that is instantiated
|
|
* in MakeAttributeContainerChecker. The non-templated base ns3::AttributeContainerChecker
|
|
* is returned from that function. This is the same pattern as ObjectPtrContainer.
|
|
*/
|
|
template <class A, template <class...> class C>
|
|
class AttributeContainerChecker : public ns3::AttributeContainerChecker
|
|
{
|
|
public:
|
|
AttributeContainerChecker();
|
|
/**
|
|
* Explicit constructor
|
|
* \param itemchecker The AttributeChecker.
|
|
*/
|
|
explicit AttributeContainerChecker(Ptr<const AttributeChecker> itemchecker);
|
|
void SetItemChecker(Ptr<const AttributeChecker> itemchecker) override;
|
|
Ptr<const AttributeChecker> GetItemChecker() const override;
|
|
|
|
private:
|
|
Ptr<const AttributeChecker> m_itemchecker; //!< The AttributeChecker
|
|
};
|
|
|
|
template <class A, template <class...> class C>
|
|
AttributeContainerChecker<A, C>::AttributeContainerChecker()
|
|
: m_itemchecker(nullptr)
|
|
{
|
|
}
|
|
|
|
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() const
|
|
{
|
|
return m_itemchecker;
|
|
}
|
|
|
|
} // namespace internal
|
|
|
|
template <class A, template <class...> class C>
|
|
Ptr<AttributeChecker>
|
|
MakeAttributeContainerChecker(const AttributeContainerValue<A, C>& value)
|
|
{
|
|
return MakeAttributeContainerChecker<A, C>();
|
|
}
|
|
|
|
template <class A, template <class...> class C>
|
|
Ptr<const AttributeChecker>
|
|
MakeAttributeContainerChecker(Ptr<const AttributeChecker> itemchecker)
|
|
{
|
|
auto checker = MakeAttributeContainerChecker<A, C>();
|
|
auto acchecker = DynamicCast<AttributeContainerChecker>(checker);
|
|
acchecker->SetItemChecker(itemchecker);
|
|
return checker;
|
|
}
|
|
|
|
template <class A, template <class...> class C>
|
|
Ptr<AttributeChecker>
|
|
MakeAttributeContainerChecker()
|
|
{
|
|
std::string containerType;
|
|
std::string underlyingType;
|
|
typedef AttributeContainerValue<A, C> T;
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "ns3::AttributeContainerValue<" << typeid(typename T::attribute_type).name() << ", "
|
|
<< typeid(typename T::container_type).name() << ">";
|
|
containerType = oss.str();
|
|
}
|
|
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "ns3::Ptr<" << typeid(typename T::attribute_type).name() << ">";
|
|
underlyingType = oss.str();
|
|
}
|
|
|
|
return MakeSimpleAttributeChecker<T, internal::AttributeContainerChecker<A, C>>(containerType,
|
|
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() 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>(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() 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 <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
|
|
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() const
|
|
{
|
|
return size();
|
|
}
|
|
|
|
template <class A, template <class...> class C>
|
|
typename AttributeContainerValue<A, C>::Iterator
|
|
AttributeContainerValue<A, C>::Begin()
|
|
{
|
|
return begin();
|
|
}
|
|
|
|
template <class A, template <class...> class C>
|
|
typename AttributeContainerValue<A, C>::Iterator
|
|
AttributeContainerValue<A, C>::End()
|
|
{
|
|
return end();
|
|
}
|
|
|
|
template <class A, template <class...> class C>
|
|
typename AttributeContainerValue<A, C>::size_type
|
|
AttributeContainerValue<A, C>::size() const
|
|
{
|
|
return m_container.size();
|
|
}
|
|
|
|
template <class A, template <class...> class C>
|
|
typename AttributeContainerValue<A, C>::iterator
|
|
AttributeContainerValue<A, C>::begin()
|
|
{
|
|
return m_container.begin();
|
|
}
|
|
|
|
template <class A, template <class...> class C>
|
|
typename AttributeContainerValue<A, C>::iterator
|
|
AttributeContainerValue<A, C>::end()
|
|
{
|
|
return m_container.end();
|
|
}
|
|
|
|
template <class A, template <class...> class C>
|
|
typename AttributeContainerValue<A, C>::const_iterator
|
|
AttributeContainerValue<A, C>::begin() const
|
|
{
|
|
return m_container.cbegin();
|
|
}
|
|
|
|
template <class A, template <class...> class C>
|
|
typename AttributeContainerValue<A, C>::const_iterator
|
|
AttributeContainerValue<A, C>::end() 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);
|
|
}
|
|
|
|
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
|