872 lines
26 KiB
C++
872 lines
26 KiB
C++
/*
|
|
* Copyright (c) 2009 University of Washington
|
|
*
|
|
* 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
|
|
*/
|
|
|
|
#include "names.h"
|
|
|
|
#include "abort.h"
|
|
#include "assert.h"
|
|
#include "log.h"
|
|
#include "object.h"
|
|
#include "singleton.h"
|
|
|
|
#include <map>
|
|
|
|
/**
|
|
* \file
|
|
* \ingroup config
|
|
* ns3::Names, ns3::NamesNode and ns3::NamePriv implementations.
|
|
*/
|
|
|
|
namespace ns3
|
|
{
|
|
|
|
NS_LOG_COMPONENT_DEFINE("Names");
|
|
|
|
/**
|
|
* \ingroup config
|
|
* Node in the naming tree.
|
|
*/
|
|
class NameNode
|
|
{
|
|
public:
|
|
/** Default constructor. */
|
|
NameNode();
|
|
/**
|
|
* Copy constructor.
|
|
*
|
|
* \param [in] nameNode The NameNode to copy from.
|
|
*/
|
|
NameNode(const NameNode& nameNode);
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* \param [in] parent The parent NameNode.
|
|
* \param [in] name The name of this NameNode
|
|
* \param [in] object The object corresponding to this NameNode.
|
|
*/
|
|
NameNode(NameNode* parent, std::string name, Ptr<Object> object);
|
|
/**
|
|
* Assignment operator.
|
|
*
|
|
* \param [in] rhs The NameNode to copy from.
|
|
* \returns The lhs NameNode.
|
|
*/
|
|
NameNode& operator=(const NameNode& rhs);
|
|
|
|
/** Destructor. */
|
|
~NameNode();
|
|
|
|
/** The parent NameNode. */
|
|
NameNode* m_parent;
|
|
/** The name of this NameNode. */
|
|
std::string m_name;
|
|
/** The object corresponding to this NameNode. */
|
|
Ptr<Object> m_object;
|
|
|
|
/** Children of this NameNode. */
|
|
std::map<std::string, NameNode*> m_nameMap;
|
|
};
|
|
|
|
NameNode::NameNode()
|
|
: m_parent(nullptr),
|
|
m_name(""),
|
|
m_object(nullptr)
|
|
{
|
|
}
|
|
|
|
NameNode::NameNode(const NameNode& nameNode)
|
|
{
|
|
m_parent = nameNode.m_parent;
|
|
m_name = nameNode.m_name;
|
|
m_object = nameNode.m_object;
|
|
m_nameMap = nameNode.m_nameMap;
|
|
}
|
|
|
|
NameNode&
|
|
NameNode::operator=(const NameNode& rhs)
|
|
{
|
|
m_parent = rhs.m_parent;
|
|
m_name = rhs.m_name;
|
|
m_object = rhs.m_object;
|
|
m_nameMap = rhs.m_nameMap;
|
|
return *this;
|
|
}
|
|
|
|
NameNode::NameNode(NameNode* parent, std::string name, Ptr<Object> object)
|
|
: m_parent(parent),
|
|
m_name(name),
|
|
m_object(object)
|
|
{
|
|
NS_LOG_FUNCTION(this << parent << name << object);
|
|
}
|
|
|
|
NameNode::~NameNode()
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
}
|
|
|
|
/**
|
|
* \ingroup config
|
|
* The singleton root Names object.
|
|
*/
|
|
class NamesPriv : public Singleton<NamesPriv>
|
|
{
|
|
public:
|
|
/** Constructor. */
|
|
NamesPriv();
|
|
/** Destructor. */
|
|
~NamesPriv() override;
|
|
|
|
// Doxygen \copydoc bug: won't copy these docs, so we repeat them.
|
|
|
|
/**
|
|
* Internal implementation for Names::Add(std::string,Ptr<Object>)
|
|
*
|
|
* \param [in] name The name of the object you want to associate;
|
|
* which may be prepended with a path to that object.
|
|
* \param [in] object A smart pointer to the object itself.
|
|
* \return \c true if the object was named successfully.
|
|
*/
|
|
bool Add(std::string name, Ptr<Object> object);
|
|
/**
|
|
* Internal implementation for Names::Add(std::string,std::string,Ptr<Object>)
|
|
*
|
|
* \param [in] path A path name describing a previously named object
|
|
* under which you want this new name to be defined.
|
|
* \param [in] name The name of the object you want to associate.
|
|
* \param [in] object A smart pointer to the object itself.
|
|
* \return \c true if the object was named successfully.
|
|
*/
|
|
bool Add(std::string path, std::string name, Ptr<Object> object);
|
|
/**
|
|
* Internal implementation for Names::Add(Ptr<Object>,std::string,Ptr<Object>)
|
|
*
|
|
* \param [in] context A smart pointer to an object that is used
|
|
* in place of the path under which you want this new
|
|
* name to be defined.
|
|
* \param [in] name The name of the object you want to associate.
|
|
* \param [in] object A smart pointer to the object itself.
|
|
* \return \c true if the object was named successfully.
|
|
*/
|
|
bool Add(Ptr<Object> context, std::string name, Ptr<Object> object);
|
|
|
|
/**
|
|
* Internal implementation for Names::Rename(std::string,std::string)
|
|
*
|
|
* \param [in] oldpath The current path name to the object you want
|
|
* to change.
|
|
* \param [in] newname The new name of the object you want to change.
|
|
* \return \c true if the object was renamed successfully.
|
|
*/
|
|
bool Rename(std::string oldpath, std::string newname);
|
|
/**
|
|
* Internal implementation for
|
|
* Names::Rename(std::string,std::string,std::string)
|
|
*
|
|
* \param [in] path A path name describing a previously named object
|
|
* under which you want this name change to occur
|
|
* (cf. directory).
|
|
* \param [in] oldname The currently defined name of the object.
|
|
* \param [in] newname The new name you want the object to have.
|
|
* \return \c true if the object was renamed successfully.
|
|
*/
|
|
bool Rename(std::string path, std::string oldname, std::string newname);
|
|
/**
|
|
* Internal implementation for
|
|
* Names::Rename(Ptr<Object>,std::string,std::string)
|
|
*
|
|
* \param [in] context A smart pointer to an object that is used
|
|
* in place of the path under which you want this
|
|
* new name to be defined.
|
|
* \param [in] oldname The current shortname of the object you want
|
|
* to change.
|
|
* \param [in] newname The new shortname of the object you want
|
|
* to change.
|
|
* \return \c true if the object was renamed successfully.
|
|
*/
|
|
bool Rename(Ptr<Object> context, std::string oldname, std::string newname);
|
|
|
|
/**
|
|
* Internal implementation for Names::FindName()
|
|
*
|
|
* \param [in] object A smart pointer to an object for which you want
|
|
* to find its name.
|
|
* \returns A string containing the name of the object if found,
|
|
* otherwise the empty string.
|
|
*/
|
|
std::string FindName(Ptr<Object> object);
|
|
/**
|
|
* Internal implementation of Names::FindPath()
|
|
*
|
|
* \param [in] object A smart pointer to an object for which you
|
|
* want to find its fullname.
|
|
* \returns A string containing the name path of the object,
|
|
* otherwise the empty string.
|
|
*/
|
|
std::string FindPath(Ptr<Object> object);
|
|
|
|
/**
|
|
* Internal implementation for Names::Clear()
|
|
*/
|
|
void Clear();
|
|
|
|
/**
|
|
* Internal implementation for ns3::Names::Find(std::string)
|
|
*
|
|
* \param [in] path A string containing a name space path used
|
|
* to locate the object.
|
|
* \returns A smart pointer to the named object converted to
|
|
* the requested type.
|
|
*/
|
|
Ptr<Object> Find(std::string path);
|
|
/**
|
|
* Internal implementation for ns3::Names::Find(std::string,std::string)
|
|
*
|
|
* \param [in] path A path name describing a previously named object
|
|
* under which you want to look for the specified name.
|
|
* \param [in] name A string containing a name to search for.
|
|
* \returns A smart pointer to the named object converted to
|
|
* the requested type.
|
|
*/
|
|
Ptr<Object> Find(std::string path, std::string name);
|
|
/**
|
|
* Internal implementation for ns3::Names::Find(Ptr<Object>,std::string)
|
|
*
|
|
* \param [in] context A smart pointer to an object that is used
|
|
* in place of the path under which you want this
|
|
* new name to be defined.
|
|
* \param [in] name A string containing a name to search for.
|
|
* \returns A smart pointer to the named object converted to
|
|
* the requested type.
|
|
*/
|
|
Ptr<Object> Find(Ptr<Object> context, std::string name);
|
|
|
|
private:
|
|
/**
|
|
* Check if an object has a name.
|
|
*
|
|
* \param [in] object The object to check.
|
|
* \returns The corresponding NameNode, if it exists.
|
|
*/
|
|
NameNode* IsNamed(Ptr<Object> object);
|
|
/**
|
|
* Check if a name already exists as a child of a NameNode.
|
|
*
|
|
* \param [in] node The node to search.
|
|
* \param [in] name The name to search for.
|
|
* \returns \c true if \c name already exists as a child of \c node.
|
|
*/
|
|
bool IsDuplicateName(NameNode* node, std::string name);
|
|
|
|
/** The root NameNode. */
|
|
NameNode m_root;
|
|
|
|
/** Map from object pointers to their NameNodes. */
|
|
std::map<Ptr<Object>, NameNode*> m_objectMap;
|
|
};
|
|
|
|
NamesPriv::NamesPriv()
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
|
|
m_root.m_parent = nullptr;
|
|
m_root.m_name = "Names";
|
|
m_root.m_object = nullptr;
|
|
}
|
|
|
|
NamesPriv::~NamesPriv()
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
Clear();
|
|
m_root.m_name = "";
|
|
}
|
|
|
|
void
|
|
NamesPriv::Clear()
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
//
|
|
// Every name is associated with an object in the object map, so freeing the
|
|
// NameNodes in this map will free all of the memory allocated for the NameNodes
|
|
//
|
|
for (std::map<Ptr<Object>, NameNode*>::iterator i = m_objectMap.begin(); i != m_objectMap.end();
|
|
++i)
|
|
{
|
|
delete i->second;
|
|
i->second = nullptr;
|
|
}
|
|
|
|
m_objectMap.clear();
|
|
|
|
m_root.m_parent = nullptr;
|
|
m_root.m_name = "Names";
|
|
m_root.m_object = nullptr;
|
|
m_root.m_nameMap.clear();
|
|
}
|
|
|
|
bool
|
|
NamesPriv::Add(std::string name, Ptr<Object> object)
|
|
{
|
|
NS_LOG_FUNCTION(this << name << object);
|
|
//
|
|
// This is the simple, easy to use version of Add, so we want it to be flexible.
|
|
// We don't want to force a user to always type the fully qualified namespace
|
|
// name, so we allow the namespace name to be omitted. For example, calling
|
|
// Add ("Client/ath0", obj) should result in exactly the same behavior as
|
|
// Add ("/Names/Client/ath0", obj). Calling Add ("Client", obj) should have
|
|
// the same effect as Add ("Names/Client", obj)
|
|
//
|
|
// The first thing to do, then, is to "canonicalize" the input string to always
|
|
// be a fully qualified name.
|
|
//
|
|
// If we are given a name that begins with "/Names/" we assume that this is a
|
|
// fully qualified path name to the object we want to create. We split the name
|
|
// into a path string and a final segment (name) and then call the "Real" Add.
|
|
//
|
|
std::string namespaceName = "/Names";
|
|
std::string::size_type offset = name.find(namespaceName);
|
|
if (offset != 0)
|
|
{
|
|
//
|
|
// This must be a name that has the "/Names" namespace prefix omitted.
|
|
// Do some reasonableness checking on the rest of the name.
|
|
//
|
|
offset = name.find('/');
|
|
if (offset == 0)
|
|
{
|
|
NS_ASSERT_MSG(false, "NamesPriv::Add(): Name begins with '/' but not \"/Names\"");
|
|
return false;
|
|
}
|
|
|
|
name = "/Names/" + name;
|
|
}
|
|
|
|
//
|
|
// There must now be a fully qualified path in the string. All fully
|
|
// qualified names begin with "/Names". We have to split off the final
|
|
// segment which will become the name of the object. A '/' that
|
|
// separates the path from the final segment had better be there since
|
|
// we just made sure that at least the namespace name was there.
|
|
//
|
|
std::string::size_type i = name.rfind('/');
|
|
NS_ASSERT_MSG(i != std::string::npos,
|
|
"NamesPriv::Add(): Internal error. Can't find '/' in name");
|
|
|
|
//
|
|
// The slash we found cannot be the slash at the start of the namespaceName.
|
|
// This would indicate there is no name in the path at all. It can be
|
|
// any other index.
|
|
//
|
|
NS_ASSERT_MSG(i != 0, "NamesPriv::Add(): Can't find a name in the path string");
|
|
|
|
//
|
|
// We now know where the path string starts and ends, and where the
|
|
// name starts and ends. All we have to do is to call our available
|
|
// function for adding a name under a path string.
|
|
//
|
|
return Add(name.substr(0, i), name.substr(i + 1), object);
|
|
}
|
|
|
|
bool
|
|
NamesPriv::Add(std::string path, std::string name, Ptr<Object> object)
|
|
{
|
|
NS_LOG_FUNCTION(this << path << name << object);
|
|
if (path == "/Names")
|
|
{
|
|
return Add(Ptr<Object>(nullptr, false), name, object);
|
|
}
|
|
return Add(Find(path), name, object);
|
|
}
|
|
|
|
bool
|
|
NamesPriv::Add(Ptr<Object> context, std::string name, Ptr<Object> object)
|
|
{
|
|
NS_LOG_FUNCTION(this << context << name << object);
|
|
|
|
if (IsNamed(object))
|
|
{
|
|
NS_LOG_LOGIC("Object is already named");
|
|
return false;
|
|
}
|
|
|
|
NameNode* node = nullptr;
|
|
if (context)
|
|
{
|
|
node = IsNamed(context);
|
|
NS_ASSERT_MSG(node, "NamesPriv::Name(): context must point to a previously named node");
|
|
}
|
|
else
|
|
{
|
|
node = &m_root;
|
|
}
|
|
|
|
if (IsDuplicateName(node, name))
|
|
{
|
|
NS_LOG_LOGIC("Name is already taken");
|
|
return false;
|
|
}
|
|
|
|
NameNode* newNode = new NameNode(node, name, object);
|
|
node->m_nameMap[name] = newNode;
|
|
m_objectMap[object] = newNode;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
NamesPriv::Rename(std::string oldpath, std::string newname)
|
|
{
|
|
NS_LOG_FUNCTION(this << oldpath << newname);
|
|
//
|
|
// This is the simple, easy to use version of Rename, so we want it to be
|
|
// flexible. We don't want to force a user to always type the fully
|
|
// qualified namespace name, so we allow the namespace name to be omitted.
|
|
// For example, calling Rename ("Client/ath0", "eth0") should result in
|
|
// exactly the same behavior as Rename ("/Names/Client/ath0", "eth0").
|
|
// Calling Rename ("Client", "Router") should have the same effect as
|
|
// Rename ("Names/Client", "Router")
|
|
//
|
|
// The first thing to do, then, is to "canonicalize" the input string to always
|
|
// be a fully qualified path.
|
|
//
|
|
// If we are given a name that begins with "/Names/" we assume that this is a
|
|
// fully qualified path to the object we want to change. We split the path into
|
|
// path string (cf directory) and a final segment (cf filename) and then call
|
|
// the "Real" Rename.
|
|
//
|
|
std::string namespaceName = "/Names";
|
|
std::string::size_type offset = oldpath.find(namespaceName);
|
|
if (offset != 0)
|
|
{
|
|
//
|
|
// This must be a name that has the "/Names" namespace prefix omitted.
|
|
// Do some reasonableness checking on the rest of the name.
|
|
//
|
|
offset = oldpath.find('/');
|
|
if (offset == 0)
|
|
{
|
|
NS_ASSERT_MSG(false, "NamesPriv::Add(): Name begins with '/' but not \"/Names\"");
|
|
return false;
|
|
}
|
|
|
|
oldpath = "/Names/" + oldpath;
|
|
}
|
|
|
|
//
|
|
// There must now be a fully qualified path in the oldpath string. All
|
|
// fully qualified names begin with "/Names". We have to split off the final
|
|
// segment which will become the name we want to rename. A '/' that
|
|
// separates the path from the final segment (name) had better be there since
|
|
// we just made sure that at least the namespace name was there.
|
|
//
|
|
std::string::size_type i = oldpath.rfind('/');
|
|
NS_ASSERT_MSG(i != std::string::npos,
|
|
"NamesPriv::Add(): Internal error. Can't find '/' in name");
|
|
|
|
//
|
|
// The slash we found cannot be the slash at the start of the namespaceName.
|
|
// This would indicate there is no name in the path at all. It can be
|
|
// any other index.
|
|
//
|
|
NS_ASSERT_MSG(i != 0, "NamesPriv::Add(): Can't find a name in the path string");
|
|
|
|
//
|
|
// We now know where the path part of the string starts and ends, and where the
|
|
// name part starts and ends. All we have to do is to call our available
|
|
// function for creating adding a name under a path string.
|
|
//
|
|
return Rename(oldpath.substr(0, i), oldpath.substr(i + 1), newname);
|
|
}
|
|
|
|
bool
|
|
NamesPriv::Rename(std::string path, std::string oldname, std::string newname)
|
|
{
|
|
NS_LOG_FUNCTION(this << path << oldname << newname);
|
|
if (path == "/Names")
|
|
{
|
|
return Rename(Ptr<Object>(nullptr, false), oldname, newname);
|
|
}
|
|
return Rename(Find(path), oldname, newname);
|
|
}
|
|
|
|
bool
|
|
NamesPriv::Rename(Ptr<Object> context, std::string oldname, std::string newname)
|
|
{
|
|
NS_LOG_FUNCTION(this << context << oldname << newname);
|
|
|
|
NameNode* node = nullptr;
|
|
if (context)
|
|
{
|
|
node = IsNamed(context);
|
|
NS_ASSERT_MSG(node, "NamesPriv::Name(): context must point to a previously named node");
|
|
}
|
|
else
|
|
{
|
|
node = &m_root;
|
|
}
|
|
|
|
if (IsDuplicateName(node, newname))
|
|
{
|
|
NS_LOG_LOGIC("New name is already taken");
|
|
return false;
|
|
}
|
|
|
|
std::map<std::string, NameNode*>::iterator i = node->m_nameMap.find(oldname);
|
|
if (i == node->m_nameMap.end())
|
|
{
|
|
NS_LOG_LOGIC("Old name does not exist in name map");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
NS_LOG_LOGIC("Old name exists in name map");
|
|
|
|
//
|
|
// The rename process consists of:
|
|
// 1. Getting the pointer to the name node from the map and remembering it;
|
|
// 2. Removing the map entry corresponding to oldname from the map;
|
|
// 3. Changing the name string in the name node;
|
|
// 4. Adding the name node back in the map under the newname.
|
|
//
|
|
NameNode* changeNode = i->second;
|
|
node->m_nameMap.erase(i);
|
|
changeNode->m_name = newname;
|
|
node->m_nameMap[newname] = changeNode;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
std::string
|
|
NamesPriv::FindName(Ptr<Object> object)
|
|
{
|
|
NS_LOG_FUNCTION(this << object);
|
|
|
|
std::map<Ptr<Object>, NameNode*>::iterator i = m_objectMap.find(object);
|
|
if (i == m_objectMap.end())
|
|
{
|
|
NS_LOG_LOGIC("Object does not exist in object map");
|
|
return "";
|
|
}
|
|
else
|
|
{
|
|
NS_LOG_LOGIC("Object exists in object map");
|
|
return i->second->m_name;
|
|
}
|
|
}
|
|
|
|
std::string
|
|
NamesPriv::FindPath(Ptr<Object> object)
|
|
{
|
|
NS_LOG_FUNCTION(this << object);
|
|
|
|
std::map<Ptr<Object>, NameNode*>::iterator i = m_objectMap.find(object);
|
|
if (i == m_objectMap.end())
|
|
{
|
|
NS_LOG_LOGIC("Object does not exist in object map");
|
|
return "";
|
|
}
|
|
|
|
NameNode* p = i->second;
|
|
NS_ASSERT_MSG(p,
|
|
"NamesPriv::FindFullName(): Internal error: Invalid NameNode pointer from map");
|
|
|
|
std::string path;
|
|
|
|
do
|
|
{
|
|
path = "/" + p->m_name + path;
|
|
NS_LOG_LOGIC("path is " << path);
|
|
} while ((p = p->m_parent) != nullptr);
|
|
|
|
return path;
|
|
}
|
|
|
|
Ptr<Object>
|
|
NamesPriv::Find(std::string path)
|
|
{
|
|
//
|
|
// This is hooked in from simple, easy to use version of Find, so we want it
|
|
// to be flexible.
|
|
//
|
|
// If we are provided a path that doesn't begin with "/Names", we assume
|
|
// that the caller has simply given us a path starting with a name that
|
|
// is in the root namespace. This allows people to omit the "/Names" prefix.
|
|
// and simply do a Find ("Client/eth0") instead of having to always do a
|
|
// Find ("/Names/Client/eth0");
|
|
//
|
|
// So, if we are given a name that begins with "/Names/" the upshot is that we
|
|
// just remove that prefix and treat the rest of the string as starting with a
|
|
// name in the root namespace.
|
|
//
|
|
|
|
NS_LOG_FUNCTION(this << path);
|
|
std::string namespaceName = "/Names/";
|
|
std::string remaining;
|
|
|
|
std::string::size_type offset = path.find(namespaceName);
|
|
if (offset == 0)
|
|
{
|
|
NS_LOG_LOGIC(path << " is a fully qualified name");
|
|
remaining = path.substr(namespaceName.size());
|
|
}
|
|
else
|
|
{
|
|
NS_LOG_LOGIC(path << " begins with a relative name");
|
|
remaining = path;
|
|
}
|
|
|
|
NameNode* node = &m_root;
|
|
|
|
//
|
|
// The string <remaining> is now composed entirely of path segments in
|
|
// the /Names name space and we have eaten the leading slash. e.g.,
|
|
// remaining = "ClientNode/eth0"
|
|
//
|
|
// The start of the search is always at the root of the name space.
|
|
//
|
|
for (;;)
|
|
{
|
|
NS_LOG_LOGIC("Looking for the object of name " << remaining);
|
|
offset = remaining.find('/');
|
|
if (offset == std::string::npos)
|
|
{
|
|
//
|
|
// There are no remaining slashes so this is the last segment of the
|
|
// specified name. We're done when we find it
|
|
//
|
|
std::map<std::string, NameNode*>::iterator i = node->m_nameMap.find(remaining);
|
|
if (i == node->m_nameMap.end())
|
|
{
|
|
NS_LOG_LOGIC("Name does not exist in name map");
|
|
return nullptr;
|
|
}
|
|
else
|
|
{
|
|
NS_LOG_LOGIC("Name parsed, found object");
|
|
return i->second->m_object;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There are more slashes so this is an intermediate segment of the
|
|
// specified name. We need to "recurse" when we find this segment.
|
|
//
|
|
offset = remaining.find('/');
|
|
std::string segment = remaining.substr(0, offset);
|
|
|
|
std::map<std::string, NameNode*>::iterator i = node->m_nameMap.find(segment);
|
|
if (i == node->m_nameMap.end())
|
|
{
|
|
NS_LOG_LOGIC("Name does not exist in name map");
|
|
return nullptr;
|
|
}
|
|
else
|
|
{
|
|
node = i->second;
|
|
remaining = remaining.substr(offset + 1);
|
|
NS_LOG_LOGIC("Intermediate segment parsed");
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
NS_ASSERT_MSG(node, "NamesPriv::Find(): Internal error: this can't happen");
|
|
return nullptr;
|
|
}
|
|
|
|
Ptr<Object>
|
|
NamesPriv::Find(std::string path, std::string name)
|
|
{
|
|
NS_LOG_FUNCTION(this << path << name);
|
|
|
|
if (path == "/Names")
|
|
{
|
|
return Find(Ptr<Object>(nullptr, false), name);
|
|
}
|
|
return Find(Find(path), name);
|
|
}
|
|
|
|
Ptr<Object>
|
|
NamesPriv::Find(Ptr<Object> context, std::string name)
|
|
{
|
|
NS_LOG_FUNCTION(this << context << name);
|
|
|
|
NameNode* node = nullptr;
|
|
|
|
if (!context)
|
|
{
|
|
NS_LOG_LOGIC("Zero context implies root NameNode");
|
|
node = &m_root;
|
|
}
|
|
else
|
|
{
|
|
node = IsNamed(context);
|
|
if (node == nullptr)
|
|
{
|
|
NS_LOG_LOGIC("Context does not point to a previously named node");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
std::map<std::string, NameNode*>::iterator i = node->m_nameMap.find(name);
|
|
if (i == node->m_nameMap.end())
|
|
{
|
|
NS_LOG_LOGIC("Name does not exist in name map");
|
|
return nullptr;
|
|
}
|
|
else
|
|
{
|
|
NS_LOG_LOGIC("Name exists in name map");
|
|
return i->second->m_object;
|
|
}
|
|
}
|
|
|
|
NameNode*
|
|
NamesPriv::IsNamed(Ptr<Object> object)
|
|
{
|
|
NS_LOG_FUNCTION(this << object);
|
|
|
|
std::map<Ptr<Object>, NameNode*>::iterator i = m_objectMap.find(object);
|
|
if (i == m_objectMap.end())
|
|
{
|
|
NS_LOG_LOGIC("Object does not exist in object map, returning NameNode 0");
|
|
return nullptr;
|
|
}
|
|
else
|
|
{
|
|
NS_LOG_LOGIC("Object exists in object map, returning NameNode " << &i->second);
|
|
return i->second;
|
|
}
|
|
}
|
|
|
|
bool
|
|
NamesPriv::IsDuplicateName(NameNode* node, std::string name)
|
|
{
|
|
NS_LOG_FUNCTION(this << node << name);
|
|
|
|
std::map<std::string, NameNode*>::iterator i = node->m_nameMap.find(name);
|
|
if (i == node->m_nameMap.end())
|
|
{
|
|
NS_LOG_LOGIC("Name does not exist in name map");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
NS_LOG_LOGIC("Name exists in name map");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void
|
|
Names::Add(std::string name, Ptr<Object> object)
|
|
{
|
|
NS_LOG_FUNCTION(name << object);
|
|
bool result = NamesPriv::Get()->Add(name, object);
|
|
NS_ABORT_MSG_UNLESS(result, "Names::Add(): Error adding name " << name);
|
|
}
|
|
|
|
void
|
|
Names::Rename(std::string oldpath, std::string newname)
|
|
{
|
|
NS_LOG_FUNCTION(oldpath << newname);
|
|
bool result = NamesPriv::Get()->Rename(oldpath, newname);
|
|
NS_ABORT_MSG_UNLESS(result, "Names::Rename(): Error renaming " << oldpath << " to " << newname);
|
|
}
|
|
|
|
void
|
|
Names::Add(std::string path, std::string name, Ptr<Object> object)
|
|
{
|
|
NS_LOG_FUNCTION(path << name << object);
|
|
bool result = NamesPriv::Get()->Add(path, name, object);
|
|
NS_ABORT_MSG_UNLESS(result, "Names::Add(): Error adding " << path << " " << name);
|
|
}
|
|
|
|
void
|
|
Names::Rename(std::string path, std::string oldname, std::string newname)
|
|
{
|
|
NS_LOG_FUNCTION(path << oldname << newname);
|
|
bool result = NamesPriv::Get()->Rename(path, oldname, newname);
|
|
NS_ABORT_MSG_UNLESS(result,
|
|
"Names::Rename (): Error renaming " << path << " " << oldname << " to "
|
|
<< newname);
|
|
}
|
|
|
|
void
|
|
Names::Add(Ptr<Object> context, std::string name, Ptr<Object> object)
|
|
{
|
|
NS_LOG_FUNCTION(context << name << object);
|
|
bool result = NamesPriv::Get()->Add(context, name, object);
|
|
NS_ABORT_MSG_UNLESS(result,
|
|
"Names::Add(): Error adding name " << name << " under context "
|
|
<< &context);
|
|
}
|
|
|
|
void
|
|
Names::Rename(Ptr<Object> context, std::string oldname, std::string newname)
|
|
{
|
|
NS_LOG_FUNCTION(context << oldname << newname);
|
|
bool result = NamesPriv::Get()->Rename(context, oldname, newname);
|
|
NS_ABORT_MSG_UNLESS(result,
|
|
"Names::Rename (): Error renaming " << oldname << " to " << newname
|
|
<< " under context " << &context);
|
|
}
|
|
|
|
std::string
|
|
Names::FindName(Ptr<Object> object)
|
|
{
|
|
NS_LOG_FUNCTION(object);
|
|
return NamesPriv::Get()->FindName(object);
|
|
}
|
|
|
|
std::string
|
|
Names::FindPath(Ptr<Object> object)
|
|
{
|
|
NS_LOG_FUNCTION(object);
|
|
return NamesPriv::Get()->FindPath(object);
|
|
}
|
|
|
|
void
|
|
Names::Clear()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS();
|
|
return NamesPriv::Get()->Clear();
|
|
}
|
|
|
|
Ptr<Object>
|
|
Names::FindInternal(std::string name)
|
|
{
|
|
NS_LOG_FUNCTION(name);
|
|
return NamesPriv::Get()->Find(name);
|
|
}
|
|
|
|
Ptr<Object>
|
|
Names::FindInternal(std::string path, std::string name)
|
|
{
|
|
NS_LOG_FUNCTION(path << name);
|
|
return NamesPriv::Get()->Find(path, name);
|
|
}
|
|
|
|
Ptr<Object>
|
|
Names::FindInternal(Ptr<Object> context, std::string name)
|
|
{
|
|
NS_LOG_FUNCTION(context << name);
|
|
return NamesPriv::Get()->Find(context, name);
|
|
}
|
|
|
|
} // namespace ns3
|