bug 284: cannot use config paths to get a handle on an object.
This commit is contained in:
@@ -30,6 +30,100 @@ NS_LOG_COMPONENT_DEFINE ("Config");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
namespace Config {
|
||||
|
||||
MatchContainer::MatchContainer ()
|
||||
{}
|
||||
MatchContainer::MatchContainer (const std::vector<Ptr<Object> > &objects,
|
||||
const std::vector<std::string> &contexts,
|
||||
std::string path)
|
||||
: m_objects (objects),
|
||||
m_contexts (contexts),
|
||||
m_path (path)
|
||||
{}
|
||||
MatchContainer::Iterator
|
||||
MatchContainer::Begin (void) const
|
||||
{
|
||||
return m_objects.begin ();
|
||||
}
|
||||
MatchContainer::Iterator
|
||||
MatchContainer::End (void) const
|
||||
{
|
||||
return m_objects.end ();
|
||||
}
|
||||
uint32_t
|
||||
MatchContainer::GetN (void) const
|
||||
{
|
||||
return m_objects.size ();
|
||||
}
|
||||
Ptr<Object>
|
||||
MatchContainer::Get (uint32_t i) const
|
||||
{
|
||||
return m_objects[i];
|
||||
}
|
||||
std::string
|
||||
MatchContainer::GetMatchedPath (uint32_t i) const
|
||||
{
|
||||
return m_contexts[i];
|
||||
}
|
||||
std::string
|
||||
MatchContainer::GetPath (void) const
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
||||
void
|
||||
MatchContainer::Set (std::string name, const AttributeValue &value)
|
||||
{
|
||||
for (Iterator tmp = Begin (); tmp != End (); ++tmp)
|
||||
{
|
||||
Ptr<Object> object = *tmp;
|
||||
object->SetAttribute (name, value);
|
||||
}
|
||||
}
|
||||
void
|
||||
MatchContainer::Connect (std::string name, const CallbackBase &cb)
|
||||
{
|
||||
NS_ASSERT (m_objects.size () == m_contexts.size ());
|
||||
for (uint32_t i = 0; i < m_objects.size (); ++i)
|
||||
{
|
||||
Ptr<Object> object = m_objects[i];
|
||||
std::string ctx = m_contexts[i] + name;
|
||||
object->TraceConnect (name, ctx, cb);
|
||||
}
|
||||
}
|
||||
void
|
||||
MatchContainer::ConnectWithoutContext (std::string name, const CallbackBase &cb)
|
||||
{
|
||||
for (Iterator tmp = Begin (); tmp != End (); ++tmp)
|
||||
{
|
||||
Ptr<Object> object = *tmp;
|
||||
object->TraceConnectWithoutContext (name, cb);
|
||||
}
|
||||
}
|
||||
void
|
||||
MatchContainer::Disconnect (std::string name, const CallbackBase &cb)
|
||||
{
|
||||
NS_ASSERT (m_objects.size () == m_contexts.size ());
|
||||
for (uint32_t i = 0; i < m_objects.size (); ++i)
|
||||
{
|
||||
Ptr<Object> object = m_objects[i];
|
||||
std::string ctx = m_contexts[i] + name;
|
||||
object->TraceDisconnect (name, ctx, cb);
|
||||
}
|
||||
}
|
||||
void
|
||||
MatchContainer::DisconnectWithoutContext (std::string name, const CallbackBase &cb)
|
||||
{
|
||||
for (Iterator tmp = Begin (); tmp != End (); ++tmp)
|
||||
{
|
||||
Ptr<Object> object = *tmp;
|
||||
object->TraceDisconnectWithoutContext (name, cb);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Config
|
||||
|
||||
class ArrayMatcher
|
||||
{
|
||||
public:
|
||||
@@ -125,20 +219,40 @@ public:
|
||||
|
||||
void Resolve (Ptr<Object> root);
|
||||
private:
|
||||
void Canonicalize (void);
|
||||
void DoResolve (std::string path, Ptr<Object> root);
|
||||
void DoArrayResolve (std::string path, const ObjectVectorValue &vector);
|
||||
void DoResolveOne (Ptr<Object> object, std::string name);
|
||||
std::string GetResolvedPath (std::string name) const;
|
||||
virtual void DoOne (Ptr<Object> object, std::string path, std::string name) = 0;
|
||||
void DoResolveOne (Ptr<Object> object);
|
||||
std::string GetResolvedPath (void) const;
|
||||
virtual void DoOne (Ptr<Object> object, std::string path) = 0;
|
||||
std::vector<std::string> m_workStack;
|
||||
std::string m_path;
|
||||
};
|
||||
|
||||
Resolver::Resolver (std::string path)
|
||||
: m_path (path)
|
||||
{}
|
||||
{
|
||||
Canonicalize ();
|
||||
}
|
||||
Resolver::~Resolver ()
|
||||
{}
|
||||
void
|
||||
Resolver::Canonicalize (void)
|
||||
{
|
||||
// ensure that we start and end with a '/'
|
||||
std::string::size_type tmp = m_path.find ("/");
|
||||
if (tmp != 0)
|
||||
{
|
||||
// no slash at start
|
||||
m_path = "/" + m_path;
|
||||
}
|
||||
tmp = m_path.find_last_of ("/");
|
||||
if (tmp != (m_path.size () - 1))
|
||||
{
|
||||
// no slash at end
|
||||
m_path = m_path + "/";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Resolver::Resolve (Ptr<Object> root)
|
||||
@@ -147,40 +261,34 @@ Resolver::Resolve (Ptr<Object> root)
|
||||
}
|
||||
|
||||
std::string
|
||||
Resolver::GetResolvedPath (std::string name) const
|
||||
Resolver::GetResolvedPath (void) const
|
||||
{
|
||||
std::string fullPath = "";
|
||||
std::string fullPath = "/";
|
||||
for (std::vector<std::string>::const_iterator i = m_workStack.begin (); i != m_workStack.end (); i++)
|
||||
{
|
||||
fullPath += "/" + *i;
|
||||
fullPath += *i + "/";
|
||||
}
|
||||
fullPath += "/" + name;
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
void
|
||||
Resolver::DoResolveOne (Ptr<Object> object, std::string name)
|
||||
Resolver::DoResolveOne (Ptr<Object> object)
|
||||
{
|
||||
NS_LOG_DEBUG ("resolved="<<GetResolvedPath (name));
|
||||
DoOne (object, GetResolvedPath (name), name);
|
||||
NS_LOG_DEBUG ("resolved="<<GetResolvedPath ());
|
||||
DoOne (object, GetResolvedPath ());
|
||||
}
|
||||
|
||||
void
|
||||
Resolver::DoResolve (std::string path, Ptr<Object> root)
|
||||
{
|
||||
NS_ASSERT (path != "");
|
||||
std::string::size_type pos = path.find ("/");
|
||||
if (pos != 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("path does not start with a \"/\": \""<<path<<"\"");
|
||||
return;
|
||||
}
|
||||
NS_LOG_FUNCTION (path << root);
|
||||
std::string::size_type tmp;
|
||||
tmp = path.find ("/");
|
||||
NS_ASSERT (tmp == 0);
|
||||
std::string::size_type next = path.find ("/", 1);
|
||||
if (next == std::string::npos)
|
||||
{
|
||||
std::string attributeName = path.substr (1, path.size ()-1);
|
||||
NS_LOG_DEBUG ("handle attr="<<attributeName);
|
||||
DoOne (root, GetResolvedPath (attributeName), attributeName);
|
||||
DoResolveOne (root);
|
||||
return;
|
||||
}
|
||||
std::string item = path.substr (1, next-1);
|
||||
@@ -191,12 +299,12 @@ Resolver::DoResolve (std::string path, Ptr<Object> root)
|
||||
{
|
||||
// This is a call to GetObject
|
||||
std::string tidString = item.substr (1, item.size () - 1);
|
||||
NS_LOG_DEBUG ("GetObject="<<tidString<<" on path="<<GetResolvedPath (""));
|
||||
NS_LOG_DEBUG ("GetObject="<<tidString<<" on path="<<GetResolvedPath ());
|
||||
TypeId tid = TypeId::LookupByName (tidString);
|
||||
Ptr<Object> object = root->GetObject<Object> (tid);
|
||||
if (object == 0)
|
||||
{
|
||||
NS_LOG_DEBUG ("GetObject ("<<tidString<<") failed on path="<<GetResolvedPath (""));
|
||||
NS_LOG_DEBUG ("GetObject ("<<tidString<<") failed on path="<<GetResolvedPath ());
|
||||
return;
|
||||
}
|
||||
m_workStack.push_back (item);
|
||||
@@ -210,21 +318,21 @@ Resolver::DoResolve (std::string path, Ptr<Object> root)
|
||||
struct TypeId::AttributeInfo info;
|
||||
if (!tid.LookupAttributeByName (item, &info))
|
||||
{
|
||||
NS_LOG_DEBUG ("Requested item="<<item<<" does not exist on path="<<GetResolvedPath (""));
|
||||
NS_LOG_DEBUG ("Requested item="<<item<<" does not exist on path="<<GetResolvedPath ());
|
||||
return;
|
||||
}
|
||||
// attempt to cast to a pointer checker.
|
||||
const PointerChecker *ptr = dynamic_cast<const PointerChecker *> (PeekPointer (info.checker));
|
||||
if (ptr != 0)
|
||||
{
|
||||
NS_LOG_DEBUG ("GetAttribute(ptr)="<<item<<" on path="<<GetResolvedPath (""));
|
||||
NS_LOG_DEBUG ("GetAttribute(ptr)="<<item<<" on path="<<GetResolvedPath ());
|
||||
PointerValue ptr;
|
||||
root->GetAttribute (item, ptr);
|
||||
Ptr<Object> object = ptr.Get<Object> ();
|
||||
if (object == 0)
|
||||
{
|
||||
NS_LOG_ERROR ("Requested object name=\""<<item<<
|
||||
"\" exists on path=\""<<GetResolvedPath ("")<<"\""
|
||||
"\" exists on path=\""<<GetResolvedPath ()<<"\""
|
||||
" but is null.");
|
||||
return;
|
||||
}
|
||||
@@ -236,7 +344,7 @@ Resolver::DoResolve (std::string path, Ptr<Object> root)
|
||||
const ObjectVectorChecker *vectorChecker = dynamic_cast<const ObjectVectorChecker *> (PeekPointer (info.checker));
|
||||
if (vectorChecker != 0)
|
||||
{
|
||||
NS_LOG_DEBUG ("GetAttribute(vector)="<<item<<" on path="<<GetResolvedPath (""));
|
||||
NS_LOG_DEBUG ("GetAttribute(vector)="<<item<<" on path="<<GetResolvedPath ());
|
||||
ObjectVectorValue vector;
|
||||
root->GetAttribute (item, vector);
|
||||
m_workStack.push_back (item);
|
||||
@@ -252,17 +360,13 @@ void
|
||||
Resolver::DoArrayResolve (std::string path, const ObjectVectorValue &vector)
|
||||
{
|
||||
NS_ASSERT (path != "");
|
||||
std::string::size_type pos = path.find ("/");
|
||||
if (pos != 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("path does not start with a \"/\": \""<<path<<"\"");
|
||||
return;
|
||||
}
|
||||
std::string::size_type tmp;
|
||||
tmp = path.find ("/");
|
||||
NS_ASSERT (tmp == 0);
|
||||
std::string::size_type next = path.find ("/", 1);
|
||||
if (next == std::string::npos)
|
||||
{
|
||||
NS_LOG_DEBUG ("vector path includes no index data on path=\""<<path<<"\"");
|
||||
return;
|
||||
NS_FATAL_ERROR ("vector path includes no index data on path=\""<<path<<"\"");
|
||||
}
|
||||
std::string item = path.substr (1, next-1);
|
||||
std::string pathLeft = path.substr (next, path.size ()-next);
|
||||
@@ -290,6 +394,7 @@ public:
|
||||
void Connect (std::string path, const CallbackBase &cb);
|
||||
void DisconnectWithoutContext (std::string path, const CallbackBase &cb);
|
||||
void Disconnect (std::string path, const CallbackBase &cb);
|
||||
Config::MatchContainer LookupMatches (std::string path);
|
||||
|
||||
void RegisterRootNamespaceObject (Ptr<Object> obj);
|
||||
void UnregisterRootNamespaceObject (Ptr<Object> obj);
|
||||
@@ -298,110 +403,86 @@ public:
|
||||
Ptr<Object> GetRootNamespaceObject (uint32_t i) const;
|
||||
|
||||
private:
|
||||
void ParsePath (std::string path, std::string *root, std::string *leaf) const;
|
||||
typedef std::vector<Ptr<Object> > Roots;
|
||||
Roots m_roots;
|
||||
};
|
||||
|
||||
void
|
||||
ConfigImpl::ParsePath (std::string path, std::string *root, std::string *leaf) const
|
||||
{
|
||||
std::string::size_type slash = path.find_last_of ("/");
|
||||
NS_ASSERT (slash != std::string::npos);
|
||||
*root = path.substr (0, slash);
|
||||
*leaf = path.substr (slash+1, path.size ()-(slash+1));
|
||||
NS_LOG_FUNCTION (path << *root << *leaf);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigImpl::Set (std::string path, const AttributeValue &value)
|
||||
{
|
||||
class SetResolver : public Resolver
|
||||
{
|
||||
public:
|
||||
SetResolver (std::string path, const AttributeValue &value)
|
||||
: Resolver (path),
|
||||
m_value (value.Copy ()) {}
|
||||
private:
|
||||
virtual void DoOne (Ptr<Object> object, std::string path, std::string name) {
|
||||
object->SetAttribute (name, *m_value);
|
||||
}
|
||||
Ptr<const AttributeValue> m_value;
|
||||
} resolver = SetResolver (path, value);
|
||||
for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
|
||||
{
|
||||
resolver.Resolve (*i);
|
||||
}
|
||||
std::string root, leaf;
|
||||
ParsePath (path, &root, &leaf);
|
||||
Config::MatchContainer container = LookupMatches (root);
|
||||
container.Set (leaf, value);
|
||||
}
|
||||
void
|
||||
ConfigImpl::ConnectWithoutContext (std::string path, const CallbackBase &cb)
|
||||
{
|
||||
class ConnectResolver : public Resolver
|
||||
{
|
||||
public:
|
||||
ConnectResolver (std::string path, const CallbackBase &cb)
|
||||
: Resolver (path),
|
||||
m_cb (cb) {}
|
||||
private:
|
||||
virtual void DoOne (Ptr<Object> object, std::string path, std::string name) {
|
||||
object->TraceConnectWithoutContext (name, m_cb);
|
||||
}
|
||||
CallbackBase m_cb;
|
||||
} resolver = ConnectResolver (path, cb);
|
||||
for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
|
||||
{
|
||||
resolver.Resolve (*i);
|
||||
}
|
||||
std::string root, leaf;
|
||||
ParsePath (path, &root, &leaf);
|
||||
Config::MatchContainer container = LookupMatches (root);
|
||||
container.ConnectWithoutContext (leaf, cb);
|
||||
}
|
||||
void
|
||||
ConfigImpl::DisconnectWithoutContext (std::string path, const CallbackBase &cb)
|
||||
{
|
||||
class DisconnectResolver : public Resolver
|
||||
{
|
||||
public:
|
||||
DisconnectResolver (std::string path, const CallbackBase &cb)
|
||||
: Resolver (path),
|
||||
m_cb (cb) {}
|
||||
private:
|
||||
virtual void DoOne (Ptr<Object> object, std::string path, std::string name) {
|
||||
object->TraceDisconnectWithoutContext (name, m_cb);
|
||||
}
|
||||
CallbackBase m_cb;
|
||||
} resolver = DisconnectResolver (path, cb);
|
||||
for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
|
||||
{
|
||||
resolver.Resolve (*i);
|
||||
}
|
||||
std::string root, leaf;
|
||||
ParsePath (path, &root, &leaf);
|
||||
Config::MatchContainer container = LookupMatches (root);
|
||||
container.DisconnectWithoutContext (leaf, cb);
|
||||
}
|
||||
void
|
||||
ConfigImpl::Connect (std::string path, const CallbackBase &cb)
|
||||
{
|
||||
class ConnectWithContextResolver : public Resolver
|
||||
{
|
||||
public:
|
||||
ConnectWithContextResolver (std::string path, const CallbackBase &cb)
|
||||
: Resolver (path),
|
||||
m_cb (cb) {}
|
||||
private:
|
||||
virtual void DoOne (Ptr<Object> object, std::string path, std::string name) {
|
||||
object->TraceConnect (name, path, m_cb);
|
||||
}
|
||||
CallbackBase m_cb;
|
||||
} resolver = ConnectWithContextResolver (path, cb);
|
||||
for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
|
||||
{
|
||||
resolver.Resolve (*i);
|
||||
}
|
||||
std::string root, leaf;
|
||||
ParsePath (path, &root, &leaf);
|
||||
Config::MatchContainer container = LookupMatches (root);
|
||||
container.Connect (leaf, cb);
|
||||
}
|
||||
void
|
||||
ConfigImpl::Disconnect (std::string path, const CallbackBase &cb)
|
||||
{
|
||||
class DisconnectWithContextResolver : public Resolver
|
||||
std::string root, leaf;
|
||||
ParsePath (path, &root, &leaf);
|
||||
Config::MatchContainer container = LookupMatches (root);
|
||||
container.Disconnect (leaf, cb);
|
||||
}
|
||||
|
||||
Config::MatchContainer
|
||||
ConfigImpl::LookupMatches (std::string path)
|
||||
{
|
||||
NS_LOG_FUNCTION (path);
|
||||
class LookupMatchesResolver : public Resolver
|
||||
{
|
||||
public:
|
||||
DisconnectWithContextResolver (std::string path, const CallbackBase &cb)
|
||||
: Resolver (path),
|
||||
m_cb (cb) {}
|
||||
private:
|
||||
virtual void DoOne (Ptr<Object> object, std::string path, std::string name) {
|
||||
object->TraceDisconnect (name, path, m_cb);
|
||||
LookupMatchesResolver (std::string path)
|
||||
: Resolver (path)
|
||||
{}
|
||||
virtual void DoOne (Ptr<Object> object, std::string path) {
|
||||
m_objects.push_back (object);
|
||||
m_contexts.push_back (path);
|
||||
}
|
||||
CallbackBase m_cb;
|
||||
} resolver = DisconnectWithContextResolver (path, cb);
|
||||
std::vector<Ptr<Object> > m_objects;
|
||||
std::vector<std::string> m_contexts;
|
||||
} resolver = LookupMatchesResolver (path);
|
||||
for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
|
||||
{
|
||||
resolver.Resolve (*i);
|
||||
}
|
||||
return Config::MatchContainer (resolver.m_objects, resolver.m_contexts, path);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigImpl::RegisterRootNamespaceObject (Ptr<Object> obj)
|
||||
{
|
||||
@@ -472,6 +553,10 @@ Disconnect (std::string path, const CallbackBase &cb)
|
||||
{
|
||||
Singleton<ConfigImpl>::Get ()->Disconnect (path, cb);
|
||||
}
|
||||
Config::MatchContainer LookupMatches (std::string path)
|
||||
{
|
||||
return Singleton<ConfigImpl>::Get ()->LookupMatches (path);
|
||||
}
|
||||
|
||||
void RegisterRootNamespaceObject (Ptr<Object> obj)
|
||||
{
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "ptr.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -110,6 +111,35 @@ void Connect (std::string path, const CallbackBase &cb);
|
||||
*/
|
||||
void Disconnect (std::string path, const CallbackBase &cb);
|
||||
|
||||
class MatchContainer
|
||||
{
|
||||
public:
|
||||
typedef std::vector<Ptr<Object> >::const_iterator Iterator;
|
||||
MatchContainer ();
|
||||
MatchContainer (const std::vector<Ptr<Object> > &objects,
|
||||
const std::vector<std::string> &contexts,
|
||||
std::string path);
|
||||
|
||||
MatchContainer::Iterator Begin (void) const;
|
||||
MatchContainer::Iterator End (void) const;
|
||||
uint32_t GetN (void) const;
|
||||
Ptr<Object> Get (uint32_t i) const;
|
||||
std::string GetMatchedPath (uint32_t i) const;
|
||||
std::string GetPath (void) const;
|
||||
|
||||
void Set (std::string name, const AttributeValue &value);
|
||||
void Connect (std::string name, const CallbackBase &cb);
|
||||
void ConnectWithoutContext (std::string name, const CallbackBase &cb);
|
||||
void Disconnect (std::string name, const CallbackBase &cb);
|
||||
void DisconnectWithoutContext (std::string name, const CallbackBase &cb);
|
||||
private:
|
||||
std::vector<Ptr<Object> > m_objects;
|
||||
std::vector<std::string> m_contexts;
|
||||
std::string m_path;
|
||||
};
|
||||
|
||||
MatchContainer LookupMatches (std::string path);
|
||||
|
||||
/**
|
||||
* \param obj a new root object
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user