/* * 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 */ #ifndef ATTRIBUTE_CONTAINER_H #define ATTRIBUTE_CONTAINER_H #include #include #include #include #include #include #include #include #include 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 C = std::list> class AttributeContainerValue : public AttributeValue { public: /** AttributeValue (element) type. */ typedef A attribute_type; /** Type actually stored within the container. */ typedef Ptr value_type; /** Internal container type. */ typedef std::list 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 item_type; /** Type of container returned. */ typedef C 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 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 AttributeContainerValue(const ITER begin, const ITER end); /** Destructor. */ ~AttributeContainerValue() override; // Inherited Ptr Copy() const override; bool DeserializeFromString(std::string value, Ptr checker) override; std::string SerializeToString(Ptr 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 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 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 Ptr> 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 itemchecker) = 0; /** * Get the item checker * \return The item checker */ virtual Ptr 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 C> Ptr MakeAttributeContainerChecker(const AttributeContainerValue& 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 C = std::list> Ptr MakeAttributeContainerChecker(Ptr itemchecker); /** * Make uninitialized AttributeContainerChecker using explicit types. * @tparam A AttributeValue type in container. * @tparam C Container type returned by Get. * \return AttributeContainerChecker. */ template class C = std::list> Ptr 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 class C = std::list, typename T1> Ptr 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 class C = std::list, typename T1, typename T2> Ptr 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 C> class AttributeContainerChecker : public ns3::AttributeContainerChecker { public: AttributeContainerChecker(); /** * Explicit constructor * \param itemchecker The AttributeChecker. */ explicit AttributeContainerChecker(Ptr itemchecker); void SetItemChecker(Ptr itemchecker) override; Ptr GetItemChecker() const override; private: Ptr m_itemchecker; //!< The AttributeChecker }; template class C> AttributeContainerChecker::AttributeContainerChecker() : m_itemchecker(nullptr) { } template class C> AttributeContainerChecker::AttributeContainerChecker(Ptr itemchecker) : m_itemchecker(itemchecker) { } template class C> void AttributeContainerChecker::SetItemChecker(Ptr itemchecker) { m_itemchecker = itemchecker; } template class C> Ptr AttributeContainerChecker::GetItemChecker() const { return m_itemchecker; } } // namespace internal template class C> Ptr MakeAttributeContainerChecker(const AttributeContainerValue& value) { return MakeAttributeContainerChecker(); } template class C> Ptr MakeAttributeContainerChecker(Ptr itemchecker) { auto checker = MakeAttributeContainerChecker(); auto acchecker = DynamicCast(checker); acchecker->SetItemChecker(itemchecker); return checker; } template class C> Ptr MakeAttributeContainerChecker() { std::string containerType; std::string underlyingType; typedef AttributeContainerValue 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>(containerType, underlyingType); } template class C> AttributeContainerValue::AttributeContainerValue(char sep) : m_sep(sep) { } template class C> template AttributeContainerValue::AttributeContainerValue(const CONTAINER& c) : AttributeContainerValue(c.begin(), c.end()) { } template class C> template AttributeContainerValue::AttributeContainerValue(const ITER begin, const ITER end) : AttributeContainerValue() { CopyFrom(begin, end); } template class C> AttributeContainerValue::~AttributeContainerValue() { m_container.clear(); } template class C> Ptr AttributeContainerValue::Copy() const { auto c = Create>(); c->m_sep = m_sep; c->m_container = m_container; return c; } template class C> bool AttributeContainerValue::DeserializeFromString(std::string value, Ptr checker) { auto acchecker = DynamicCast(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(avalue); if (!attr) { return false; } // TODO(jared): make insertion more generic? m_container.push_back(attr); } return true; } template class C> std::string AttributeContainerValue::SerializeToString(Ptr 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 C> typename AttributeContainerValue::result_type AttributeContainerValue::Get() const { result_type c; for (const value_type& a : *this) { c.insert(c.end(), a->Get()); } return c; } template class C> template bool AttributeContainerValue::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 C> template void AttributeContainerValue::Set(const T& c) { m_container.clear(); CopyFrom(c.begin(), c.end()); } template class C> typename AttributeContainerValue::size_type AttributeContainerValue::GetN() const { return size(); } template class C> typename AttributeContainerValue::Iterator AttributeContainerValue::Begin() { return begin(); } template class C> typename AttributeContainerValue::Iterator AttributeContainerValue::End() { return end(); } template class C> typename AttributeContainerValue::size_type AttributeContainerValue::size() const { return m_container.size(); } template class C> typename AttributeContainerValue::iterator AttributeContainerValue::begin() { return m_container.begin(); } template class C> typename AttributeContainerValue::iterator AttributeContainerValue::end() { return m_container.end(); } template class C> typename AttributeContainerValue::const_iterator AttributeContainerValue::begin() const { return m_container.cbegin(); } template class C> typename AttributeContainerValue::const_iterator AttributeContainerValue::end() const { return m_container.cend(); } template class C> template Ptr> AttributeContainerValue::CopyFrom(const ITER begin, const ITER end) { for (ITER iter = begin; iter != end; ++iter) { m_container.push_back(Create(*iter)); } return this; } template class C, typename T1> Ptr MakeAttributeContainerAccessor(T1 a1) { return MakeAccessorHelper>(a1); } template class C, typename T1, typename T2> Ptr MakeAttributeContainerAccessor(T1 a1, T2 a2) { return MakeAccessorHelper>(a1, a2); } } // namespace ns3 #endif // ATTRIBUTE_CONTAINER_H