Files
unison/src/core/model/attribute-container.h
Gabriel Ferreira 6f076416e7 Fix typos
2023-02-21 22:29:29 -03:00

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