src/core/config.cc
changeset 3787 985324e2caaa
parent 3033 5daf048843a6
child 4139 d45e62c78504
--- a/src/core/config.cc	Fri Oct 24 12:31:57 2008 +0200
+++ b/src/core/config.cc	Fri Oct 24 12:35:28 2008 +0200
@@ -30,6 +30,100 @@
 
 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 @@
 
   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 @@
 }
 
 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 @@
     {
       // 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 @@
       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 @@
       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 @@
 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 @@
   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 @@
   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 
+  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)
+{
+  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:
-    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);
+    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 = ConnectWithContextResolver (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::Disconnect (std::string path, const CallbackBase &cb)
-{
-  class DisconnectWithContextResolver : 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);
-    }
-    CallbackBase m_cb;
-  } resolver = DisconnectWithContextResolver (path, cb);
-  for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
-    {
-      resolver.Resolve (*i);
-    }
-}
+
 void 
 ConfigImpl::RegisterRootNamespaceObject (Ptr<Object> obj)
 {
@@ -472,6 +553,10 @@
 {
   Singleton<ConfigImpl>::Get ()->Disconnect (path, cb);
 }
+Config::MatchContainer LookupMatches (std::string path)
+{
+  return Singleton<ConfigImpl>::Get ()->LookupMatches (path);
+}
 
 void RegisterRootNamespaceObject (Ptr<Object> obj)
 {