Fixed bug 1352 (Object attribute map / vector issue)
This commit is contained in:
@@ -51,6 +51,8 @@ Bugs fixed
|
||||
- bug 1391 - .ns3rc does not allow comments as expected
|
||||
- bug 1392 - Modules built report does not clarify C++ or Python
|
||||
- bug 1395 - AODV DeferredRouteOutputTag missing constructor
|
||||
- bug 1352 - Fixed MapAttributes, previously was mapped to a vector in ObjectPtrContainer
|
||||
and (and key information was dropped). Now the container is a map.
|
||||
|
||||
Known issues
|
||||
------------
|
||||
|
||||
@@ -222,18 +222,20 @@ AttributeIterator::DoIterate (Ptr<Object> object)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// attempt to cast to an object vector.
|
||||
// attempt to cast to an object container
|
||||
const ObjectPtrContainerChecker *vectorChecker = dynamic_cast<const ObjectPtrContainerChecker *> (PeekPointer (info.checker));
|
||||
if (vectorChecker != 0)
|
||||
{
|
||||
NS_LOG_DEBUG ("vector attribute " << info.name);
|
||||
NS_LOG_DEBUG ("ObjectPtrContainer attribute " << info.name);
|
||||
ObjectPtrContainerValue vector;
|
||||
object->GetAttribute (info.name, vector);
|
||||
StartVisitArrayAttribute (object, info.name, vector);
|
||||
for (uint32_t j = 0; j < vector.GetN (); ++j)
|
||||
ObjectPtrContainerValue::Iterator it;
|
||||
for (it = vector.Begin (); it != vector.End (); ++it)
|
||||
{
|
||||
NS_LOG_DEBUG ("vector attribute item " << j);
|
||||
Ptr<Object> tmp = vector.Get (j);
|
||||
uint32_t j = (*it).first;
|
||||
NS_LOG_DEBUG ("ObjectPtrContainer attribute item " << j);
|
||||
Ptr<Object> tmp = (*it).second;
|
||||
StartVisitArrayItem (vector, j, tmp);
|
||||
m_examined.push_back (object);
|
||||
DoIterate (tmp);
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#ifndef OBJECT_MAP_H
|
||||
#define OBJECT_MAP_H
|
||||
|
||||
#include <vector>
|
||||
#include "object.h"
|
||||
#include "ptr.h"
|
||||
#include "attribute.h"
|
||||
@@ -39,17 +38,13 @@ Ptr<const AttributeChecker> MakeObjectMapChecker (void);
|
||||
|
||||
template <typename T, typename U, typename INDEX>
|
||||
Ptr<const AttributeAccessor>
|
||||
MakeObjectVectorAccessor (Ptr<U> (T::*get)(INDEX) const,
|
||||
MakeObjectMapAccessor (Ptr<U> (T::*get)(INDEX) const,
|
||||
INDEX (T::*getN)(void) const);
|
||||
|
||||
template <typename T, typename U, typename INDEX>
|
||||
Ptr<const AttributeAccessor>
|
||||
MakeObjectVectorAccessor (INDEX (T::*getN)(void) const,
|
||||
Ptr<U> (T::*get)(INDEX) const);
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
namespace ns3 {
|
||||
MakeObjectMapAccessor (INDEX (T::*getN)(void) const,
|
||||
Ptr<U> (T::*get)(INDEX) const);
|
||||
|
||||
template <typename T, typename U>
|
||||
Ptr<const AttributeAccessor>
|
||||
@@ -66,7 +61,7 @@ MakeObjectMapAccessor (U T::*memberVector)
|
||||
*n = (obj->*m_memberVector).size ();
|
||||
return true;
|
||||
}
|
||||
virtual Ptr<Object> DoGet (const ObjectBase *object, uint32_t i) const {
|
||||
virtual Ptr<Object> DoGet (const ObjectBase *object, uint32_t i, uint32_t *index) const {
|
||||
const T *obj = static_cast<const T *> (object);
|
||||
typename U::const_iterator begin = (obj->*m_memberVector).begin ();
|
||||
typename U::const_iterator end = (obj->*m_memberVector).end ();
|
||||
@@ -75,6 +70,7 @@ MakeObjectMapAccessor (U T::*memberVector)
|
||||
{
|
||||
if (k == i)
|
||||
{
|
||||
*index = (*j).first;
|
||||
return (*j).second;
|
||||
break;
|
||||
}
|
||||
@@ -111,8 +107,6 @@ MakeObjectMapAccessor (INDEX (T::*getN)(void) const,
|
||||
return MakeObjectPtrContainerAccessor<T,U,INDEX>(get, getN);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* OBJECT_MAP_H */
|
||||
|
||||
@@ -43,7 +43,7 @@ ObjectPtrContainerValue::GetN (void) const
|
||||
Ptr<Object>
|
||||
ObjectPtrContainerValue::Get (uint32_t i) const
|
||||
{
|
||||
return m_objects[i];
|
||||
return m_objects.find (i)->second;
|
||||
}
|
||||
|
||||
Ptr<AttributeValue>
|
||||
@@ -55,10 +55,11 @@ std::string
|
||||
ObjectPtrContainerValue::SerializeToString (Ptr<const AttributeChecker> checker) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
for (uint32_t i = 0; i < m_objects.size (); ++i)
|
||||
Iterator it;
|
||||
for (it = Begin (); it != End (); ++it)
|
||||
{
|
||||
oss << m_objects[i];
|
||||
if (i != m_objects.size () - 1)
|
||||
oss << (*it).second;
|
||||
if (it != End ())
|
||||
{
|
||||
oss << " ";
|
||||
}
|
||||
@@ -68,7 +69,7 @@ ObjectPtrContainerValue::SerializeToString (Ptr<const AttributeChecker> checker)
|
||||
bool
|
||||
ObjectPtrContainerValue::DeserializeFromString (std::string value, Ptr<const AttributeChecker> checker)
|
||||
{
|
||||
NS_FATAL_ERROR ("cannot deserialize a vector of object pointers.");
|
||||
NS_FATAL_ERROR ("cannot deserialize a set of object pointers.");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -95,8 +96,9 @@ ObjectPtrContainerAccessor::Get (const ObjectBase * object, AttributeValue &valu
|
||||
}
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
Ptr<Object> o = DoGet (object, i);
|
||||
v->m_objects.push_back (o);
|
||||
uint32_t index;
|
||||
Ptr<Object> o = DoGet (object, i, &index);
|
||||
v->m_objects.insert (std::pair <uint32_t, Ptr<Object> > (index, o));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef OBJECT_PTR_CONTAINER_H
|
||||
#define OBJECT_PTR_CONTAINER_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "object.h"
|
||||
#include "ptr.h"
|
||||
#include "attribute.h"
|
||||
@@ -30,7 +30,7 @@ namespace ns3 {
|
||||
/**
|
||||
* \ingroup object
|
||||
*
|
||||
* \brief contain a vector of ns3::Object pointers.
|
||||
* \brief contain a set of ns3::Object pointers.
|
||||
*
|
||||
* This class it used to get attribute access to an array of
|
||||
* ns3::Object pointers.
|
||||
@@ -38,20 +38,20 @@ namespace ns3 {
|
||||
class ObjectPtrContainerValue : public AttributeValue
|
||||
{
|
||||
public:
|
||||
typedef std::vector<Ptr<Object> >::const_iterator Iterator;
|
||||
typedef std::map<uint32_t, Ptr<Object> >::const_iterator Iterator;
|
||||
|
||||
ObjectPtrContainerValue ();
|
||||
|
||||
/**
|
||||
* \returns an iterator to the first object contained in this vector
|
||||
* \returns an iterator to the first object contained in this set
|
||||
*/
|
||||
Iterator Begin (void) const;
|
||||
/**
|
||||
* \returns an iterator to the last object contained in this vector
|
||||
* \returns an iterator to the last object contained in this set
|
||||
*/
|
||||
Iterator End (void) const;
|
||||
/**
|
||||
* \returns the number of objects contained in this vector.
|
||||
* \returns the number of objects contained in this set.
|
||||
*/
|
||||
uint32_t GetN (void) const;
|
||||
/**
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
|
||||
private:
|
||||
friend class ObjectPtrContainerAccessor;
|
||||
std::vector<Ptr<Object> > m_objects;
|
||||
std::map<uint32_t, Ptr<Object> > m_objects;
|
||||
};
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
virtual bool HasSetter (void) const;
|
||||
private:
|
||||
virtual bool DoGetN (const ObjectBase *object, uint32_t *n) const = 0;
|
||||
virtual Ptr<Object> DoGet (const ObjectBase *object, uint32_t i) const = 0;
|
||||
virtual Ptr<Object> DoGet (const ObjectBase *object, uint32_t i, uint32_t *index) const = 0;
|
||||
};
|
||||
|
||||
template <typename T, typename U, typename INDEX>
|
||||
@@ -160,8 +160,9 @@ MakeObjectPtrContainerAccessor (Ptr<U> (T::*get)(INDEX) const,
|
||||
*n = (obj->*m_getN)();
|
||||
return true;
|
||||
}
|
||||
virtual Ptr<Object> DoGet (const ObjectBase *object, uint32_t i) const {
|
||||
virtual Ptr<Object> DoGet (const ObjectBase *object, uint32_t i, uint32_t *index) const {
|
||||
const T *obj = static_cast<const T *> (object);
|
||||
*index = i;
|
||||
return (obj->*m_get)(i);
|
||||
}
|
||||
Ptr<U> (T::*m_get)(INDEX) const;
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#ifndef OBJECT_VECTOR_H
|
||||
#define OBJECT_VECTOR_H
|
||||
|
||||
#include <vector>
|
||||
#include "object.h"
|
||||
#include "ptr.h"
|
||||
#include "attribute.h"
|
||||
@@ -47,10 +46,6 @@ Ptr<const AttributeAccessor>
|
||||
MakeObjectVectorAccessor (INDEX (T::*getN)(void) const,
|
||||
Ptr<U> (T::*get)(INDEX) const);
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <typename T, typename U>
|
||||
Ptr<const AttributeAccessor>
|
||||
MakeObjectVectorAccessor (U T::*memberVector)
|
||||
@@ -66,7 +61,7 @@ MakeObjectVectorAccessor (U T::*memberVector)
|
||||
*n = (obj->*m_memberVector).size ();
|
||||
return true;
|
||||
}
|
||||
virtual Ptr<Object> DoGet (const ObjectBase *object, uint32_t i) const {
|
||||
virtual Ptr<Object> DoGet (const ObjectBase *object, uint32_t i, uint32_t *index) const {
|
||||
const T *obj = static_cast<const T *> (object);
|
||||
typename U::const_iterator begin = (obj->*m_memberVector).begin ();
|
||||
typename U::const_iterator end = (obj->*m_memberVector).end ();
|
||||
@@ -75,6 +70,7 @@ MakeObjectVectorAccessor (U T::*memberVector)
|
||||
{
|
||||
if (k == i)
|
||||
{
|
||||
*index = k;
|
||||
return *j;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/double.h"
|
||||
#include "ns3/object-vector.h"
|
||||
#include "ns3/object-map.h"
|
||||
#include "ns3/traced-value.h"
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
@@ -134,6 +135,10 @@ public:
|
||||
MakeObjectVectorAccessor (&AttributeObjectTest::DoGetVectorN,
|
||||
&AttributeObjectTest::DoGetVector),
|
||||
MakeObjectVectorChecker<Derived> ())
|
||||
.AddAttribute ("TestMap1", "help text",
|
||||
ObjectMapValue (),
|
||||
MakeObjectMapAccessor (&AttributeObjectTest::m_map1),
|
||||
MakeObjectMapChecker<Derived> ())
|
||||
.AddAttribute ("IntegerTraceSource1", "help text",
|
||||
IntegerValue (-2),
|
||||
MakeIntegerAccessor (&AttributeObjectTest::m_intSrc1),
|
||||
@@ -192,6 +197,9 @@ public:
|
||||
|
||||
void AddToVector1 (void) { m_vector1.push_back (CreateObject<Derived> ()); }
|
||||
void AddToVector2 (void) { m_vector2.push_back (CreateObject<Derived> ()); }
|
||||
|
||||
void AddToMap1 (uint32_t i) { m_map1.insert (std::pair <uint32_t, Ptr<Derived> > (i, CreateObject<Derived> ())); }
|
||||
|
||||
void InvokeCb (double a, int b, float c) { m_cb (a,b,c); }
|
||||
|
||||
void InvokeCbValue (int8_t a)
|
||||
@@ -222,6 +230,7 @@ private:
|
||||
RandomVariable m_random;
|
||||
std::vector<Ptr<Derived> > m_vector1;
|
||||
std::vector<Ptr<Derived> > m_vector2;
|
||||
std::map <uint32_t, Ptr<Derived> > m_map1;
|
||||
Callback<void,int8_t> m_cbValue;
|
||||
TracedValue<int8_t> m_intSrc1;
|
||||
TracedValue<int8_t> m_intSrc2;
|
||||
@@ -722,6 +731,71 @@ ObjectVectorAttributeTestCase::DoRun (void)
|
||||
NS_TEST_ASSERT_MSG_EQ (vector.GetN (), 2, "ObjectVectorValue \"TestVector1\" should be incremented");
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Test case for Object Map Attributes.
|
||||
// ===========================================================================
|
||||
class ObjectMapAttributeTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
ObjectMapAttributeTestCase (std::string description);
|
||||
virtual ~ObjectMapAttributeTestCase () {}
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
};
|
||||
|
||||
ObjectMapAttributeTestCase::ObjectMapAttributeTestCase (std::string description)
|
||||
: TestCase (description)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ObjectMapAttributeTestCase::DoRun (void)
|
||||
{
|
||||
Ptr<AttributeObjectTest> p;
|
||||
ObjectMapValue map;
|
||||
|
||||
p = CreateObject<AttributeObjectTest> ();
|
||||
NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject");
|
||||
|
||||
//
|
||||
// When the object is first created, the Attribute should have no items in
|
||||
// the vector.
|
||||
//
|
||||
p->GetAttribute ("TestMap1", map);
|
||||
NS_TEST_ASSERT_MSG_EQ (map.GetN (), 0, "Initial count of ObjectVectorValue \"TestMap1\" should be zero");
|
||||
|
||||
//
|
||||
// Adding to the attribute shouldn't affect the value we already have.
|
||||
//
|
||||
p->AddToMap1 (1);
|
||||
NS_TEST_ASSERT_MSG_EQ (map.GetN (), 0, "Initial count of ObjectVectorValue \"TestMap1\" should still be zero");
|
||||
|
||||
//
|
||||
// Getting the attribute again should update the value.
|
||||
//
|
||||
p->GetAttribute ("TestMap1", map);
|
||||
NS_TEST_ASSERT_MSG_EQ (map.GetN (), 1, "ObjectVectorValue \"TestMap1\" should be incremented");
|
||||
|
||||
//
|
||||
// Get the Object pointer from the value.
|
||||
//
|
||||
Ptr<Object> a = map.Get (0);
|
||||
NS_TEST_ASSERT_MSG_NE (a, 0, "Ptr<Object> from VectorValue \"TestMap1\" is zero");
|
||||
|
||||
//
|
||||
// Adding to the attribute shouldn't affect the value we already have.
|
||||
//
|
||||
p->AddToMap1 (2);
|
||||
NS_TEST_ASSERT_MSG_EQ (map.GetN (), 1, "Count of ObjectVectorValue \"TestMap1\" should still be one");
|
||||
|
||||
//
|
||||
// Getting the attribute again should update the value.
|
||||
//
|
||||
p->GetAttribute ("TestMap1", map);
|
||||
NS_TEST_ASSERT_MSG_EQ (map.GetN (), 2, "ObjectVectorValue \"TestMap1\" should be incremented");
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Trace sources with value semantics can be used like Attributes. Make sure
|
||||
// we can use them that way.
|
||||
@@ -1172,6 +1246,7 @@ AttributesTestSuite::AttributesTestSuite ()
|
||||
AddTestCase (new AttributeTestCase<EnumValue> ("Check Attributes of type EnumValue"));
|
||||
AddTestCase (new AttributeTestCase<RandomVariableValue> ("Check Attributes of type RandomVariableValue"));
|
||||
AddTestCase (new ObjectVectorAttributeTestCase ("Check Attributes of type ObjectVectorValue"));
|
||||
AddTestCase (new ObjectMapAttributeTestCase ("Check Attributes of type ObjectMapValue"));
|
||||
AddTestCase (new IntegerTraceSourceAttributeTestCase ("Ensure TracedValue<uint8_t> can be set like IntegerValue"));
|
||||
AddTestCase (new IntegerTraceSourceTestCase ("Ensure TracedValue<uint8_t> also works as trace source"));
|
||||
AddTestCase (new TracedCallbackTestCase ("Ensure TracedCallback<double, int, float> works as trace source"));
|
||||
|
||||
Reference in New Issue
Block a user