add an object name service
authorCraig Dowell <craigdo@ee.washington.edu>
Tue Jan 20 15:47:14 2009 -0800 (12 months ago)
changeset 4139d45e62c78504
parent 4110 04170734fa8b
child 4140 6bbf05bf4826
add an object name service
examples/names.cc
examples/wscript
src/core/config.cc
src/core/object-names.cc
src/core/object-names.h
src/core/wscript
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/examples/names.cc	Tue Jan 20 15:47:14 2009 -0800
     1.3 @@ -0,0 +1,142 @@
     1.4 +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
     1.5 +/*
     1.6 + * This program is free software; you can redistribute it and/or modify
     1.7 + * it under the terms of the GNU General Public License version 2 as
     1.8 + * published by the Free Software Foundation;
     1.9 + *
    1.10 + * This program is distributed in the hope that it will be useful,
    1.11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.13 + * GNU General Public License for more details.
    1.14 + *
    1.15 + * You should have received a copy of the GNU General Public License
    1.16 + * along with this program; if not, write to the Free Software
    1.17 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    1.18 + */
    1.19 +
    1.20 +// Network topology
    1.21 +//
    1.22 +//       n0    n1   n2   n3
    1.23 +//       |     |    |    |
    1.24 +//       =================
    1.25 +//              LAN
    1.26 +//
    1.27 +
    1.28 +#include <fstream>
    1.29 +#include "ns3/core-module.h"
    1.30 +#include "ns3/simulator-module.h"
    1.31 +#include "ns3/helper-module.h"
    1.32 +
    1.33 +using namespace ns3;
    1.34 +
    1.35 +NS_LOG_COMPONENT_DEFINE ("NamesExample");
    1.36 +
    1.37 +void 
    1.38 +RxEvent (std::string context, Ptr<const Packet> packet)
    1.39 +{
    1.40 +  NS_LOG_INFO (context << " packet " << packet);
    1.41 +}
    1.42 +
    1.43 +int 
    1.44 +main (int argc, char *argv[])
    1.45 +{
    1.46 +  //
    1.47 +  // Users may find it convenient to turn on explicit debugging
    1.48 +  // for selected modules; the below lines suggest how to do this
    1.49 +  //
    1.50 +#if 1
    1.51 +  LogComponentEnable ("NamesExample", LOG_LEVEL_INFO);
    1.52 +#endif
    1.53 +
    1.54 +  //
    1.55 +  // Allow the user to override any of the defaults and the above Bind() at
    1.56 +  // run-time, via command-line arguments
    1.57 +  //
    1.58 +  CommandLine cmd;
    1.59 +  cmd.Parse (argc, argv);
    1.60 +
    1.61 +  //
    1.62 +  // Explicitly create the nodes required by the topology (shown above).
    1.63 +  //
    1.64 +  NS_LOG_INFO ("Create nodes.");
    1.65 +  NodeContainer n;
    1.66 +  n.Create (4);
    1.67 +
    1.68 +  //
    1.69 +  // We're going to use the zeroth node in the container as the client, and
    1.70 +  // the first node as the server.  Add some "human readable" names for these
    1.71 +  // nodes.  The first parameter specifies the root of the "/Names" name space
    1.72 +  // as the destination, so these will go into the name system as "/Names/client"
    1.73 +  // and "/Names/server".  
    1.74 +  //
    1.75 +  Names::Add ("/Names", "client", n.Get (0));
    1.76 +  Names::Add ("/Names", "server", n.Get (1));
    1.77 +
    1.78 +  InternetStackHelper internet;
    1.79 +  internet.Install (n);
    1.80 +
    1.81 +  NS_LOG_INFO ("Create devices.");
    1.82 +  CsmaHelper csma;
    1.83 +  csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate(5000000)));
    1.84 +  csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2)));
    1.85 +  csma.SetDeviceAttribute ("Mtu", UintegerValue (1400));
    1.86 +  NetDeviceContainer d = csma.Install (n);
    1.87 +
    1.88 +  //
    1.89 +  // Add some human readable names for the devices we'll be interested in.
    1.90 +  // We add the names to the name space "under" the nodes we created above.
    1.91 +  // This has the effect of making "/Names/client/eth0" and "/Names/server/eth0"
    1.92 +  // Note that the first parameter must reference a previously named object,
    1.93 +  // and we have, in fact, already named objects "/Names/client" and
    1.94 +  // "/Names/server"
    1.95 +  //
    1.96 +  Names::Add ("/Names/client", "eth0", d.Get (0));
    1.97 +  Names::Add ("/Names/server", "eth0", d.Get (1));
    1.98 +
    1.99 +  Ipv4AddressHelper ipv4;
   1.100 +
   1.101 +  //
   1.102 +  // We've got the "hardware" in place.  Now we need to add IP addresses.
   1.103 +  //
   1.104 +  NS_LOG_INFO ("Assign IP Addresses.");
   1.105 +  ipv4.SetBase ("10.1.1.0", "255.255.255.0");
   1.106 +  Ipv4InterfaceContainer i = ipv4.Assign (d);
   1.107 +
   1.108 +  NS_LOG_INFO ("Create Applications.");
   1.109 +
   1.110 +  //
   1.111 +  // Create a UdpEchoServer application on the server node.  Note that we 
   1.112 +  // reference the server node by name in the Install method below.
   1.113 +  //
   1.114 +  uint16_t port = 9;  // well-known echo port number
   1.115 +  UdpEchoServerHelper server (port);
   1.116 +  ApplicationContainer apps = server.Install (Names::Find<Node> ("/Names/server"));
   1.117 +  apps.Start (Seconds (1.0));
   1.118 +  apps.Stop (Seconds (10.0));
   1.119 +
   1.120 +  //
   1.121 +  // Create a UdpEchoClient application to send UDP datagrams from node zero to
   1.122 +  // node one.  Notice that we reference the client node by name in the Install
   1.123 +  // method below.
   1.124 +  //
   1.125 +  uint32_t packetSize = 1024;
   1.126 +  uint32_t maxPacketCount = 1;
   1.127 +  Time interPacketInterval = Seconds (1.);
   1.128 +  UdpEchoClientHelper client (i.GetAddress (1), port);
   1.129 +  client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
   1.130 +  client.SetAttribute ("Interval", TimeValue (interPacketInterval));
   1.131 +  client.SetAttribute ("PacketSize", UintegerValue (packetSize));
   1.132 +  apps = client.Install (Names::Find<Node> ("/Names/client"));
   1.133 +  apps.Start (Seconds (2.0));
   1.134 +  apps.Stop (Seconds (10.0));
   1.135 +
   1.136 +  Config::Connect ("/Names/client/eth0/Rx", MakeCallback (&RxEvent));
   1.137 +
   1.138 +  //
   1.139 +  // Now, do the actual simulation.
   1.140 +  //
   1.141 +  NS_LOG_INFO ("Run Simulation.");
   1.142 +  Simulator::Run ();
   1.143 +  Simulator::Destroy ();
   1.144 +  NS_LOG_INFO ("Done.");
   1.145 +}
     2.1 --- a/examples/wscript	Sun Jan 18 22:47:25 2009 +0000
     2.2 +++ b/examples/wscript	Tue Jan 20 15:47:14 2009 -0800
     2.3 @@ -16,6 +16,10 @@
     2.4                                   ['core', 'simulator', 'point-to-point', 'csma', 'wifi', 'internet-stack'])
     2.5      obj.source = 'third.cc'
     2.6          
     2.7 +    obj = bld.create_ns3_program('names',
     2.8 +                                 ['core', 'simulator', 'csma', 'internet-stack'])
     2.9 +    obj.source = 'names.cc'
    2.10 +        
    2.11      obj = bld.create_ns3_program('mixed-wireless',
    2.12                                   ['core', 'simulator', 'mobility', 'wifi', 'point-to-point', 'internet-stack'])
    2.13      obj.source = 'mixed-wireless.cc'
     3.1 --- a/src/core/config.cc	Sun Jan 18 22:47:25 2009 +0000
     3.2 +++ b/src/core/config.cc	Tue Jan 20 15:47:14 2009 -0800
     3.3 @@ -22,6 +22,7 @@
     3.4  #include "object.h"
     3.5  #include "global-value.h"
     3.6  #include "object-vector.h"
     3.7 +#include "object-names.h"
     3.8  #include "pointer.h"
     3.9  #include "log.h"
    3.10  #include <sstream>
    3.11 @@ -294,6 +295,45 @@
    3.12    std::string item = path.substr (1, next-1);
    3.13    std::string pathLeft = path.substr (next, path.size ()-next);
    3.14  
    3.15 +  //
    3.16 +  // If root is zero, we're beginning to see if we can use the object name 
    3.17 +  // service to resolve this path.  In this case, we must see the name space 
    3.18 +  // "/Names" on the front of this path.  There is no object associated with 
    3.19 +  // the root of the "/Names" namespace, so we just ignore it and move on to 
    3.20 +  // the next segment.
    3.21 +  //
    3.22 +  if (root == 0)
    3.23 +    {
    3.24 +      std::string::size_type offset = path.find ("/Names");
    3.25 +      if (offset == 0)
    3.26 +        {
    3.27 +          m_workStack.push_back (item);
    3.28 +          DoResolve (pathLeft, root);
    3.29 +          m_workStack.pop_back ();
    3.30 +          return;
    3.31 +        }
    3.32 +    }
    3.33 +
    3.34 +  //
    3.35 +  // We have an item (possibly a segment of a namespace path.  Check to see if
    3.36 +  // we can determine that this segment refers to a named object.  If root is
    3.37 +  // zero, this means to look in the root of the "/Names" name space, otherwise
    3.38 +  // it refers to a name space context (level).
    3.39 +  //
    3.40 +  Ptr<Object> namedObject = Names::FindObjectFromShortName<Object> (root, item);
    3.41 +  if (namedObject)
    3.42 +    {
    3.43 +      NS_LOG_DEBUG ("Name system resolved item = " << item << " to " << namedObject);
    3.44 +      m_workStack.push_back (item);
    3.45 +      DoResolve (pathLeft, namedObject);
    3.46 +      m_workStack.pop_back ();
    3.47 +      return;
    3.48 +    }
    3.49 +
    3.50 +  //
    3.51 +  // We're done with the object name service hooks, so proceed down the path
    3.52 +  // of types and attributes.
    3.53 +  //
    3.54    std::string::size_type dollarPos = item.find ("$");
    3.55    if (dollarPos == 0)
    3.56      {
    3.57 @@ -480,6 +520,14 @@
    3.58      {
    3.59        resolver.Resolve (*i);
    3.60      }
    3.61 +
    3.62 +  //
    3.63 +  // See if we can do something with the object name service.  Starting with
    3.64 +  // the root pointer zeroed indicates to the resolver that it should start
    3.65 +  // looking at the root of the "/Names" namespace during this go.
    3.66 +  //
    3.67 +  resolver.Resolve (0);
    3.68 +
    3.69    return Config::MatchContainer (resolver.m_objects, resolver.m_contexts, path);
    3.70  }
    3.71  
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/core/object-names.cc	Tue Jan 20 15:47:14 2009 -0800
     4.3 @@ -0,0 +1,624 @@
     4.4 +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
     4.5 +/*
     4.6 + * Copyright (c) 2009 University of Washington
     4.7 + *
     4.8 + * This program is free software; you can redistribute it and/or modify
     4.9 + * it under the terms of the GNU General Public License version 2 as
    4.10 + * published by the Free Software Foundation;
    4.11 + *
    4.12 + * This program is distributed in the hope that it will be useful,
    4.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.15 + * GNU General Public License for more details.
    4.16 + *
    4.17 + * You should have received a copy of the GNU General Public License
    4.18 + * along with this program; if not, write to the Free Software
    4.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    4.20 + */
    4.21 +
    4.22 +#include <map>
    4.23 +#include "ns3/object.h"
    4.24 +#include "ns3/log.h"
    4.25 +#include "ns3/assert.h"
    4.26 +#include "ns3/abort.h"
    4.27 +#include "ns3/simulator.h"
    4.28 +#include "object-names.h"
    4.29 +
    4.30 +namespace ns3 {
    4.31 +
    4.32 +NS_LOG_COMPONENT_DEFINE ("Names");
    4.33 +
    4.34 +class NameNode
    4.35 +{
    4.36 +public:
    4.37 +  NameNode ();
    4.38 +  NameNode (const NameNode &nameNode);
    4.39 +  NameNode (NameNode *parent, std::string name, Ptr<Object> object);
    4.40 +  NameNode &operator = (const NameNode &rhs);
    4.41 +
    4.42 + ~NameNode ();
    4.43 +
    4.44 +  NameNode *m_parent;
    4.45 +  std::string m_name;
    4.46 +  Ptr<Object> m_object;
    4.47 +
    4.48 +  std::map<std::string, NameNode *> m_nameMap;
    4.49 +};
    4.50 +
    4.51 +NameNode::NameNode ()
    4.52 +  : m_parent (0), m_name (""), m_object (0)
    4.53 +{
    4.54 +}
    4.55 +
    4.56 +NameNode::NameNode (const NameNode &nameNode)
    4.57 +{
    4.58 +  m_parent = nameNode.m_parent;
    4.59 +  m_name = nameNode.m_name;
    4.60 +  m_object = nameNode.m_object;
    4.61 +  m_nameMap = nameNode.m_nameMap;
    4.62 +}
    4.63 +
    4.64 +NameNode &
    4.65 +NameNode::operator = (const NameNode &rhs)
    4.66 +{
    4.67 +  m_parent = rhs.m_parent;
    4.68 +  m_name = rhs.m_name;
    4.69 +  m_object = rhs.m_object;
    4.70 +  m_nameMap = rhs.m_nameMap;
    4.71 +  return *this;
    4.72 +}
    4.73 +
    4.74 +NameNode::NameNode (NameNode *parent, std::string name, Ptr<Object> object)
    4.75 +  : m_parent (parent), m_name (name), m_object (object)
    4.76 +{
    4.77 +}
    4.78 +
    4.79 +NameNode::~NameNode ()
    4.80 +{
    4.81 +}
    4.82 +
    4.83 +class NamesPriv 
    4.84 +{
    4.85 +public:
    4.86 +  NamesPriv ();
    4.87 +  ~NamesPriv ();
    4.88 +
    4.89 +  bool Add (std::string name, Ptr<Object> obj);
    4.90 +  bool Add (Ptr<Object> context, std::string name, Ptr<Object> object);
    4.91 +  bool Add (std::string context, std::string name, Ptr<Object> object);
    4.92 +  std::string FindShortName (Ptr<Object> object);
    4.93 +  std::string FindFullName (Ptr<Object> object);
    4.94 +  Ptr<Object> FindObjectFromFullName (std::string name);
    4.95 +  Ptr<Object> FindObjectFromShortName (Ptr<Object> context, std::string name);
    4.96 +
    4.97 +  static NamesPriv *Get (void);
    4.98 +  
    4.99 +private:
   4.100 +  static NamesPriv **DoGet (void);
   4.101 +  static void Delete (void);
   4.102 +
   4.103 +  NameNode *IsNamed (Ptr<Object>);
   4.104 +  bool IsDuplicateName (NameNode *node, std::string name);
   4.105 +
   4.106 +  NameNode m_root;
   4.107 +  std::map<Ptr<Object>, NameNode *> m_objectMap;
   4.108 +};
   4.109 +
   4.110 +NamesPriv *
   4.111 +NamesPriv::Get (void)
   4.112 +{
   4.113 +  return *(DoGet ());
   4.114 +}
   4.115 +
   4.116 +NamesPriv **
   4.117 +NamesPriv::DoGet (void)
   4.118 +{
   4.119 +  static NamesPriv *ptr = 0;
   4.120 +
   4.121 +  if (ptr == 0)
   4.122 +    {
   4.123 +      ptr = new NamesPriv;
   4.124 +      Simulator::ScheduleDestroy (&NamesPriv::Delete);
   4.125 +    }
   4.126 +
   4.127 +  return &ptr;
   4.128 +}
   4.129 +
   4.130 +void 
   4.131 +NamesPriv::Delete (void)
   4.132 +{
   4.133 +  NS_LOG_FUNCTION_NOARGS ();
   4.134 +
   4.135 +  NamesPriv **ptr = DoGet ();
   4.136 +  delete *ptr;
   4.137 +  *ptr = 0;
   4.138 +}
   4.139 +
   4.140 +NamesPriv::NamesPriv ()
   4.141 +{
   4.142 +  NS_LOG_FUNCTION_NOARGS ();
   4.143 +
   4.144 +  m_root.m_parent = 0;
   4.145 +  m_root.m_name = "Names";
   4.146 +  m_root.m_object = 0;
   4.147 +}
   4.148 +
   4.149 +NamesPriv::~NamesPriv ()
   4.150 +{
   4.151 +  NS_LOG_FUNCTION_NOARGS ();
   4.152 +
   4.153 +  //
   4.154 +  // Every name is associated with an object in the object map, so freeing the
   4.155 +  // NameNodes in this map will free all of the memory allocated for the NameNodes
   4.156 +  //
   4.157 +  for (std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.begin (); i != m_objectMap.end (); ++i)
   4.158 +    {
   4.159 +      delete i->second;
   4.160 +      i->second = 0;
   4.161 +    }
   4.162 +}
   4.163 +
   4.164 +bool
   4.165 +NamesPriv::Add (std::string name, Ptr<Object> object)
   4.166 +{
   4.167 +  return Add (Ptr<Object> (0, false), name, object);
   4.168 +}
   4.169 +
   4.170 +bool
   4.171 +NamesPriv::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
   4.172 +{
   4.173 +  NS_LOG_FUNCTION (context << name << object);
   4.174 +
   4.175 +  if (IsNamed (object))
   4.176 +    {
   4.177 +      NS_LOG_LOGIC ("Object is already named");
   4.178 +      return false;
   4.179 +    }
   4.180 +
   4.181 +  NameNode *node = 0;
   4.182 +  if (context)
   4.183 +    {
   4.184 +      node = IsNamed (context);
   4.185 +      NS_ASSERT_MSG (node, "NamesPriv::Name(): context must point to a previously named node");
   4.186 +    }
   4.187 +  else
   4.188 +    {
   4.189 +      node = &m_root;
   4.190 +    }
   4.191 +
   4.192 +  if (IsDuplicateName (node, name))
   4.193 +    {
   4.194 +      NS_LOG_LOGIC ("Name is already taken");
   4.195 +      return false;
   4.196 +    }
   4.197 +
   4.198 +  NameNode *newNode = new NameNode(node, name, object);
   4.199 +  node->m_nameMap[name] = newNode;
   4.200 +  m_objectMap[object] = newNode;
   4.201 +
   4.202 +  return true;
   4.203 +}
   4.204 +
   4.205 +bool
   4.206 +NamesPriv::Add (std::string context, std::string name, Ptr<Object> object)
   4.207 +{
   4.208 +  if (context == "/Names")
   4.209 +    {
   4.210 +      return Add (name, object);
   4.211 +    }
   4.212 +  return Add (FindObjectFromFullName (context), name, object);
   4.213 +}
   4.214 +
   4.215 +std::string
   4.216 +NamesPriv::FindShortName (Ptr<Object> object)
   4.217 +{
   4.218 +  NS_LOG_FUNCTION (object);
   4.219 +
   4.220 +  std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
   4.221 +  if (i == m_objectMap.end ())
   4.222 +    {
   4.223 +      NS_LOG_LOGIC ("Object does not exist in object map");
   4.224 +      return "";
   4.225 +    }
   4.226 +  else
   4.227 +    {
   4.228 +      NS_LOG_LOGIC ("Object exists in object map");
   4.229 +      return i->second->m_name;
   4.230 +    }
   4.231 +}
   4.232 +
   4.233 +std::string
   4.234 +NamesPriv::FindFullName (Ptr<Object> object)
   4.235 +{
   4.236 +  NS_LOG_FUNCTION (object);
   4.237 +
   4.238 +  std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
   4.239 +  if (i == m_objectMap.end ())
   4.240 +    {
   4.241 +      NS_LOG_LOGIC ("Object does not exist in object map");
   4.242 +      return "";
   4.243 +    }
   4.244 +
   4.245 +  NameNode *p = i->second;
   4.246 +  NS_ASSERT_MSG (p, "NamesPriv::FindFullName(): Internal error: Invalid NameNode pointer from map");
   4.247 +
   4.248 +  std::string fullname;
   4.249 +
   4.250 +  do
   4.251 +    {
   4.252 +      fullname = "/" + p->m_name + fullname;
   4.253 +      NS_LOG_LOGIC ("fullname is " << fullname);
   4.254 +    }
   4.255 +  while ((p = p->m_parent) != 0);
   4.256 +
   4.257 +  return fullname;
   4.258 +}
   4.259 +
   4.260 +
   4.261 +Ptr<Object>
   4.262 +NamesPriv::FindObjectFromFullName (std::string name)
   4.263 +{
   4.264 +  std::string namespaceName = "/Names/";
   4.265 +  std::string::size_type offset = name.find (namespaceName);
   4.266 +  if (offset == std::string::npos)
   4.267 +    {
   4.268 +      NS_LOG_LOGIC (name << " is not in the " << namespaceName << " name space");
   4.269 +      return 0;
   4.270 +    }
   4.271 +
   4.272 +  std::string remaining = name.substr (namespaceName.size ());
   4.273 +  NameNode *node = &m_root;
   4.274 +
   4.275 +  //
   4.276 +  // remaining is now composed entirely of path segments in the /Names name space.
   4.277 +  // and we have eaten the leading slash. e.g., remaining = "ClientNode/eth0"
   4.278 +  // The start of the search is at the root of the name space.
   4.279 +  //
   4.280 +  for (;;)
   4.281 +    {
   4.282 +      NS_LOG_LOGIC ("Looking for the object of name " << remaining);
   4.283 +      offset = remaining.find ("/");
   4.284 +      if (offset == std::string::npos)
   4.285 +        {
   4.286 +          //
   4.287 +          // There are no remaining slashes so this is the last segment of the 
   4.288 +          // specified name.  We're done when we find it
   4.289 +          //
   4.290 +          std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (remaining);
   4.291 +          if (i == node->m_nameMap.end ())
   4.292 +            {
   4.293 +              NS_LOG_LOGIC ("Name does not exist in name map");
   4.294 +              return 0;
   4.295 +            }
   4.296 +          else
   4.297 +            {
   4.298 +              NS_LOG_LOGIC ("Name parsed, found object");
   4.299 +              return i->second->m_object;
   4.300 +            }
   4.301 +        }
   4.302 +      else
   4.303 +        {
   4.304 +          //
   4.305 +          // There are more slashes so this is an intermediate segment of the 
   4.306 +          // specified name.  We need to "recurse" when we find this segment.
   4.307 +          //
   4.308 +          offset = remaining.find ("/");
   4.309 +          std::string segment = remaining.substr(0, offset);
   4.310 +
   4.311 +          std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (segment);
   4.312 +          if (i == node->m_nameMap.end ())
   4.313 +            {
   4.314 +              NS_LOG_LOGIC ("Name does not exist in name map");
   4.315 +              return 0;
   4.316 +            }
   4.317 +          else
   4.318 +            {
   4.319 +              node = i->second;
   4.320 +              remaining = remaining.substr (offset + 1);
   4.321 +              NS_LOG_LOGIC ("Intermediate segment parsed");
   4.322 +              continue;
   4.323 +            }
   4.324 +        }
   4.325 +    }
   4.326 +
   4.327 +  NS_ASSERT_MSG (node, "NamesPriv::FindObjectFromFullName(): Internal error:  this can't happen");
   4.328 +  return 0;
   4.329 +}
   4.330 +
   4.331 +Ptr<Object>
   4.332 +NamesPriv::FindObjectFromShortName (Ptr<Object> context, std::string name)
   4.333 +{
   4.334 +  NS_LOG_FUNCTION (context << name);
   4.335 +
   4.336 +  NameNode *node = 0;
   4.337 +
   4.338 +  if (context == 0)
   4.339 +    {
   4.340 +      NS_LOG_LOGIC ("Zero context implies root NameNode");
   4.341 +      node = &m_root;
   4.342 +    }
   4.343 +  else
   4.344 +    {
   4.345 +      node = IsNamed (context);
   4.346 +      if (node == 0)
   4.347 +        {
   4.348 +          NS_LOG_LOGIC ("Context does not point to a previously named node");
   4.349 +          return 0;
   4.350 +        }
   4.351 +    }
   4.352 +
   4.353 +  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name);
   4.354 +  if (i == node->m_nameMap.end ())
   4.355 +    {
   4.356 +      NS_LOG_LOGIC ("Name does not exist in name map");
   4.357 +      return 0;
   4.358 +    }
   4.359 +  else
   4.360 +    {
   4.361 +      NS_LOG_LOGIC ("Name exists in name map");
   4.362 +      return i->second->m_object;
   4.363 +    }
   4.364 +}
   4.365 +
   4.366 +NameNode *
   4.367 +NamesPriv::IsNamed (Ptr<Object> object)
   4.368 +{
   4.369 +  NS_LOG_FUNCTION (object);
   4.370 +
   4.371 +  std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
   4.372 +  if (i == m_objectMap.end ())
   4.373 +    {
   4.374 +      NS_LOG_LOGIC ("Object does not exist in object map, returning NameNode 0");
   4.375 +      return 0;
   4.376 +    }
   4.377 +  else
   4.378 +    {
   4.379 +      NS_LOG_LOGIC ("Object exists in object map, returning NameNode " << &i->second);
   4.380 +      return i->second;
   4.381 +    }
   4.382 +}
   4.383 +
   4.384 +bool
   4.385 +NamesPriv::IsDuplicateName (NameNode *node, std::string name)
   4.386 +{
   4.387 +  NS_LOG_FUNCTION (node << name);
   4.388 +
   4.389 +  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name);
   4.390 +  if (i == node->m_nameMap.end ())
   4.391 +    {
   4.392 +      NS_LOG_LOGIC ("Name does not exist in name map");
   4.393 +      return false;
   4.394 +    }
   4.395 +  else
   4.396 +    {
   4.397 +      NS_LOG_LOGIC ("Name exists in name map");
   4.398 +      return true;
   4.399 +    }
   4.400 +}
   4.401 +
   4.402 +bool
   4.403 +Names::Add (std::string name, Ptr<Object> object)
   4.404 +{
   4.405 +  return NamesPriv::Get ()->Add (name, object);
   4.406 +}
   4.407 +
   4.408 +bool
   4.409 +Names::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
   4.410 +{
   4.411 +  return NamesPriv::Get ()->Add (context, name, object);
   4.412 +}
   4.413 +
   4.414 +bool
   4.415 +Names::Add (std::string context, std::string name, Ptr<Object> object)
   4.416 +{
   4.417 +  return NamesPriv::Get ()->Add (context, name, object);
   4.418 +}
   4.419 +
   4.420 +std::string
   4.421 +Names::FindShortName (Ptr<Object> object)
   4.422 +{
   4.423 +  return NamesPriv::Get ()->FindShortName (object);
   4.424 +}
   4.425 +
   4.426 +std::string
   4.427 +Names::FindFullName (Ptr<Object> object)
   4.428 +{
   4.429 +  return NamesPriv::Get ()->FindFullName (object);
   4.430 +}
   4.431 +
   4.432 +Ptr<Object>
   4.433 +Names::FindObjectFromFullNameInternal (std::string name)
   4.434 +{
   4.435 +  return NamesPriv::Get ()->FindObjectFromFullName (name);
   4.436 +}
   4.437 +
   4.438 +Ptr<Object>
   4.439 +Names::FindObjectFromShortNameInternal (Ptr<Object> context, std::string name)
   4.440 +{
   4.441 +  return NamesPriv::Get ()->FindObjectFromShortName (context, name);
   4.442 +}
   4.443 +
   4.444 +} //namespace ns3
   4.445 +
   4.446 +#ifdef RUN_SELF_TESTS
   4.447 +
   4.448 +#include "test.h"
   4.449 +#include "object-factory.h"
   4.450 +
   4.451 +namespace ns3 {
   4.452 +
   4.453 +class TestObject : public Object
   4.454 +{
   4.455 +public:
   4.456 +  static TypeId GetTypeId (void) 
   4.457 +  {
   4.458 +    static TypeId tid = TypeId ("TestObject")
   4.459 +      .SetParent (Object::GetTypeId ())
   4.460 +      .HideFromDocumentation ()
   4.461 +      .AddConstructor<TestObject> ();
   4.462 +    return tid;
   4.463 +  }
   4.464 +  TestObject () {}
   4.465 +  virtual void Dispose (void) {}
   4.466 +};
   4.467 +
   4.468 +class NamesTest : public Test
   4.469 +{
   4.470 +public:
   4.471 +  NamesTest ();
   4.472 +  virtual bool RunTests (void);
   4.473 +};
   4.474 +
   4.475 +NamesTest::NamesTest ()
   4.476 +  : Test ("Names")
   4.477 +{
   4.478 +}
   4.479 +
   4.480 +bool 
   4.481 +NamesTest::RunTests (void)
   4.482 +{
   4.483 +  bool result = true;
   4.484 +
   4.485 +  // 
   4.486 +  // Name a couple of objects at the root level
   4.487 +  //
   4.488 +  Ptr<TestObject> client = CreateObject<TestObject> ();
   4.489 +  result = Names::Add ("Client", client);
   4.490 +  NS_TEST_ASSERT_EQUAL (result, true);
   4.491 +
   4.492 +  Ptr<TestObject> server = CreateObject<TestObject> ();
   4.493 +  result = Names::Add ("Server", server);
   4.494 +  NS_TEST_ASSERT_EQUAL (result, true);
   4.495 +
   4.496 +  //
   4.497 +  // We shouldn't be able to add another name to a previously named object
   4.498 +  //
   4.499 +  result = Names::Add ("Not Client", client);
   4.500 +  NS_TEST_ASSERT_EQUAL (result, false);
   4.501 +
   4.502 +  //
   4.503 +  // We shouldn't be able to duplicate a name at the root level.
   4.504 +  //
   4.505 +  Ptr<TestObject> secondClient = CreateObject<TestObject> ();
   4.506 +  result = Names::Add ("Client", secondClient);
   4.507 +  NS_TEST_ASSERT_EQUAL (result, false);
   4.508 +
   4.509 +  //
   4.510 +  // We should be able to add a new name in the first object's context
   4.511 +  //
   4.512 +  Ptr<TestObject> clientEth0 = CreateObject<TestObject> ();
   4.513 +  result = Names::Add (client, "eth0", clientEth0);
   4.514 +  NS_TEST_ASSERT_EQUAL (result, true);
   4.515 +
   4.516 +  //
   4.517 +  // We shouldn't be able to duplicate a name in that context.
   4.518 +  //
   4.519 +  Ptr<TestObject> secondClientEth0 = CreateObject<TestObject> ();
   4.520 +  result = Names::Add (client, "eth0", secondClientEth0);
   4.521 +  NS_TEST_ASSERT_EQUAL (result, false);
   4.522 +
   4.523 +  //
   4.524 +  // We should be able to add the same name in the second object's context
   4.525 +  //
   4.526 +  Ptr<TestObject> serverEth0 = CreateObject<TestObject> ();
   4.527 +  result = Names::Add (server, "eth0", serverEth0);
   4.528 +  NS_TEST_ASSERT_EQUAL (result, true);
   4.529 +
   4.530 +  //
   4.531 +  // We should be able to find the short names for the objects we created
   4.532 +  //
   4.533 +  std::string found;
   4.534 +
   4.535 +  found = Names::FindShortName (client);
   4.536 +  NS_TEST_ASSERT_EQUAL (found, "Client");
   4.537 +
   4.538 +  found = Names::FindShortName (server);
   4.539 +  NS_TEST_ASSERT_EQUAL (found, "Server");
   4.540 +
   4.541 +  found = Names::FindShortName (clientEth0);
   4.542 +  NS_TEST_ASSERT_EQUAL (found, "eth0");
   4.543 +
   4.544 +  found = Names::FindShortName (serverEth0);
   4.545 +  NS_TEST_ASSERT_EQUAL (found, "eth0");
   4.546 +
   4.547 +  //
   4.548 +  // We should be able to find the full names for the objects we created
   4.549 +  //
   4.550 +  found = Names::FindFullName (client);
   4.551 +  NS_TEST_ASSERT_EQUAL (found, "/Names/Client");
   4.552 +
   4.553 +  found = Names::FindFullName (server);
   4.554 +  NS_TEST_ASSERT_EQUAL (found, "/Names/Server");
   4.555 +
   4.556 +  found = Names::FindFullName (clientEth0);
   4.557 +  NS_TEST_ASSERT_EQUAL (found, "/Names/Client/eth0");
   4.558 +
   4.559 +  found = Names::FindFullName (serverEth0);
   4.560 +  NS_TEST_ASSERT_EQUAL (found, "/Names/Server/eth0");
   4.561 +
   4.562 +  // 
   4.563 +  // We should be able to find the objects from the short names
   4.564 +  //
   4.565 +  Ptr<TestObject> foundObject;
   4.566 +
   4.567 +  foundObject = Names::FindObjectFromShortName<TestObject> (0, "Client");
   4.568 +  NS_TEST_ASSERT_EQUAL (foundObject, client);
   4.569 +
   4.570 +  foundObject = Names::FindObjectFromShortName<TestObject> (0, "Server");
   4.571 +  NS_TEST_ASSERT_EQUAL (foundObject, server);
   4.572 +
   4.573 +  foundObject = Names::FindObjectFromShortName<TestObject> (client, "eth0");
   4.574 +  NS_TEST_ASSERT_EQUAL (foundObject, clientEth0);
   4.575 +
   4.576 +  foundObject = Names::FindObjectFromShortName<TestObject> (server, "eth0");
   4.577 +  NS_TEST_ASSERT_EQUAL (foundObject, serverEth0);
   4.578 +
   4.579 +  // 
   4.580 +  // We should be able to find the objects from their full names
   4.581 +  //
   4.582 +  foundObject = Names::Find<TestObject> ("/Names/Client");
   4.583 +  NS_TEST_ASSERT_EQUAL (foundObject, client);
   4.584 +
   4.585 +  foundObject = Names::Find<TestObject> ("/Names/Server");
   4.586 +  NS_TEST_ASSERT_EQUAL (foundObject, server);
   4.587 +
   4.588 +  foundObject = Names::Find<TestObject> ("/Names/Client/eth0");
   4.589 +  NS_TEST_ASSERT_EQUAL (foundObject, clientEth0);
   4.590 +
   4.591 +  foundObject = Names::Find<TestObject> ("/Names/Server/eth0");
   4.592 +  NS_TEST_ASSERT_EQUAL (foundObject, serverEth0);
   4.593 +
   4.594 +  //
   4.595 +  // We also have some syntactical sugary methods, so make sure they do what
   4.596 +  // they should as well.
   4.597 +  //
   4.598 +  Ptr<TestObject> bridge = CreateObject<TestObject> ();
   4.599 +  result = Names::Add ("/Names", "Bridge", client);
   4.600 +  NS_TEST_ASSERT_EQUAL (result, true);
   4.601 +
   4.602 +  Ptr<TestObject> bridgeEth0 = CreateObject<TestObject> ();
   4.603 +  result = Names::Add ("/Names/Bridge", "eth0", bridgeEth0);
   4.604 +  NS_TEST_ASSERT_EQUAL (result, true);
   4.605 +
   4.606 +  foundObject = Names::Find<TestObject> ("/Names/Bridge");
   4.607 +  NS_TEST_ASSERT_EQUAL (foundObject, bridge);
   4.608 +
   4.609 +  foundObject = Names::Find<TestObject> ("/Names/Bridge/eth0");
   4.610 +  NS_TEST_ASSERT_EQUAL (foundObject, bridgeEth0);
   4.611 +
   4.612 +  //
   4.613 +  // Run the simulator and destroy it to get the Destroy method called on the
   4.614 +  // private implementation object.  We depend on seeing a valgrind-clean run of
   4.615 +  // the unit tests to really determine if the clean up was really successful.
   4.616 +  //
   4.617 +  Simulator::Run ();
   4.618 +  Simulator::Destroy ();
   4.619 +  
   4.620 +  return true;
   4.621 +}
   4.622 +
   4.623 +static NamesTest g_namesTests;
   4.624 +
   4.625 +} // namespace ns3
   4.626 +
   4.627 +#endif /* RUN_SELF_TESTS */
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/core/object-names.h	Tue Jan 20 15:47:14 2009 -0800
     5.3 @@ -0,0 +1,245 @@
     5.4 +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
     5.5 +/*
     5.6 + * Copyright (c) 2009 University of Washington
     5.7 + *
     5.8 + * This program is free software; you can redistribute it and/or modify
     5.9 + * it under the terms of the GNU General Public License version 2 as
    5.10 + * published by the Free Software Foundation;
    5.11 + *
    5.12 + * This program is distributed in the hope that it will be useful,
    5.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.15 + * GNU General Public License for more details.
    5.16 + *
    5.17 + * You should have received a copy of the GNU General Public License
    5.18 + * along with this program; if not, write to the Free Software
    5.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    5.20 + */
    5.21 +
    5.22 +#ifndef OBJECT_NAMES_H
    5.23 +#define OBJECT_NAMES_H
    5.24 +
    5.25 +#include "ns3/ptr.h"
    5.26 +#include "ns3/object.h"
    5.27 +
    5.28 +namespace ns3 {
    5.29 +
    5.30 +/**
    5.31 + * \brief A directory of name and Ptr<Object> associations that allows us to
    5.32 + * give any ns3 Object a name.
    5.33 + */
    5.34 +class Names
    5.35 +{
    5.36 +public:
    5.37 +
    5.38 +  /**
    5.39 +   * Add the association between the string "name" and the Ptr<Object> obj
    5.40 +   * at the root of the "/Names" name space.  This can be seen as equivalent
    5.41 +   * to adding a Pointer Attribute called "name" to the to the root name 
    5.42 +   * space object and then assigning the value obj to that attribute.  The 
    5.43 +   * config facility will see it that way.
    5.44 +   *
    5.45 +   * \param name The name of the object you want to associate.
    5.46 +   * \param obj A smart pointer to the object itself.
    5.47 +   */
    5.48 +  static bool Add (std::string name, Ptr<Object> obj);
    5.49 +
    5.50 +  /**
    5.51 +   * Add the association between the string "name" and the Ptr<Object> obj
    5.52 +   * in the object context given by the Ptr<Object> context.  This can be
    5.53 +   * seen as equivalent to adding a Pointer Attribute called "name" to the 
    5.54 +   * object given by "context" and then assigning the value obj to that
    5.55 +   * attribute.  The config facility will see it that way.
    5.56 +   *
    5.57 +   * \param context A spart pointer to an object under which you want this
    5.58 +   *                name to be defined.
    5.59 +   * \param name The name of the object you want to associate.
    5.60 +   * \param obj A smart pointer to the object itself.
    5.61 +   */
    5.62 +  static bool Add (Ptr<Object> context, std::string name, Ptr<Object> object);
    5.63 +
    5.64 +  /**
    5.65 +   * Syntactic sugar around the Object context Name method.  Allows you to 
    5.66 +   * specify the context with a string instead of the pointer.  If the first
    5.67 +   * parameter (context) is "/Names" this turns into a call into Name at the
    5.68 +   * root of the name space.  Otherwise it does a FindObjectFromFullNameInternal
    5.69 +   * on the context and adds the name to a subspace.
    5.70 +   *
    5.71 +   * \param context A fully qualified name describing a previously named object.
    5.72 +   *                under which you want this name to be defined.
    5.73 +   * \param name The name of the object you want to associate.
    5.74 +   * \param obj A smart pointer to the object itself.
    5.75 +   */
    5.76 +  static bool Add (std::string context, std::string name, Ptr<Object> object);
    5.77 +
    5.78 +  /**
    5.79 +   * Given a pointer to an object, look to see if that object has a name
    5.80 +   * associated with it and return the shortname for the object.
    5.81 +   *
    5.82 +   * The fullname of an object is a fully qualified namespace name, for example
    5.83 +   * if you have a device that you have previously named "eth0" under a node
    5.84 +   * you have named "client", the fullname of the device will then be
    5.85 +   * "/Names/client/eth0".
    5.86 +   *
    5.87 +   * The shortname of an object is the name of the object in its parent name
    5.88 +   * space.  Using the example above, asking for the shortname of the device
    5.89 +   * will result in "eth0" being returned.
    5.90 +   *
    5.91 +   * \param object A spart pointer to an object for which you want to find
    5.92 +   *               its shortname.
    5.93 +   */
    5.94 +  static std::string FindShortName (Ptr<Object> object);
    5.95 +
    5.96 +  /**
    5.97 +   * Given a pointer to an object, look to see if that object has a name
    5.98 +   * associated with it and return the fully qualified namespace name
    5.99 +   * for the object.
   5.100 +   *
   5.101 +   * The fullname of an object is a fully qualified namespace name, for example
   5.102 +   * if you have a device that you have previously named "eth0" under a node
   5.103 +   * you have named "client", the fullname of the device will then be
   5.104 +   * "/Names/client/eth0".
   5.105 +   *
   5.106 +   * The shortname of an object is the name of the object in its parent name
   5.107 +   * space.  Using the example above, asking for the shortname of the device
   5.108 +   * will result in "eth0" being returned.
   5.109 +   *
   5.110 +   * \param object A spart pointer to an object for which you want to find
   5.111 +   *               its fullname.
   5.112 +   */
   5.113 +  static std::string FindFullName (Ptr<Object> object);
   5.114 +
   5.115 +  /**
   5.116 +   * Given a fullname string, look to see if there's an object in the system
   5.117 +   * with a that associated with it.  If there is, do a QueryObject on the 
   5.118 +   * resulting object to convert it to the requested typename.  
   5.119 +   * 
   5.120 +   * The fullname of an object is a fully qualified namespace name, for example
   5.121 +   * if you have a device that you have previously named "eth0" under a node
   5.122 +   * you have named "client", the fullname of the device will then be
   5.123 +   * "/Names/client/eth0".
   5.124 +   *
   5.125 +   * \param name A string containing a fully qualified name space name 
   5.126 +   *             used to locate the object.
   5.127 +   */
   5.128 +  template <typename T>
   5.129 +  static Ptr<T> FindObjectFromFullName (std::string name);
   5.130 +
   5.131 +  /**
   5.132 +   * Given a fullname string, look to see if there's an object in the system
   5.133 +   * with a that associated with it.  If there is, do a QueryObject on the 
   5.134 +   * resulting object to convert it to the requested typename.  
   5.135 +   * 
   5.136 +   * The fullname of an object is a fully qualified namespace name, for example
   5.137 +   * if you have a device that you have previously named "eth0" under a node
   5.138 +   * you have named "client", the fullname of the device will then be
   5.139 +   * "/Names/client/eth0".
   5.140 +   *
   5.141 +   * \param name A string containing a fully qualified name space name 
   5.142 +   *             used to locate the object.
   5.143 +   *
   5.144 +   * @comment This method is identical to FindObjectFromFullName, but has a
   5.145 +   * short signature since it is a common use and we want it to be easy to 
   5.146 +   * type.
   5.147 +   */
   5.148 +  template <typename T>
   5.149 +  static Ptr<T> Find (std::string name);
   5.150 +
   5.151 +  /**
   5.152 +   * Given an object context and a shortname string, look through the names 
   5.153 +   * associated with the namespace defined by the context object to see if 
   5.154 +   * there's an object there with the given shortname.
   5.155 +   *
   5.156 +   * The fullname of an object is a fully qualified namespace name, for example
   5.157 +   * if you have a device that you have previously named "eth0" under a node
   5.158 +   * you have named "client", the fullname of the device will then be
   5.159 +   * "/Names/client/eth0".
   5.160 +   *
   5.161 +   * The shortname of an object is the name of the object in its parent name
   5.162 +   * space.  Using the example above, asking for the shortname of the device
   5.163 +   * will result in "eth0" being returned.
   5.164 +   *
   5.165 +   * The context object provides a namespace context, in the case of the example
   5.166 +   * it would be the "client" object under which we look for the short name.
   5.167 +   * In the example above, the context pointer would be the Ptr<Object> to the 
   5.168 +   * client node, and the name would be the shortname "eth0"  
   5.169 +   *
   5.170 +   * \param context A spart pointer to an object under which you want to look 
   5.171 +   *                for the provided name.
   5.172 +   * \param name A string containing a shortname to look for.
   5.173 +   */
   5.174 +  template <typename T>
   5.175 +  static Ptr<T> FindObjectFromShortName (Ptr<Object> context, std::string name);
   5.176 +
   5.177 +private:
   5.178 +
   5.179 +  /**
   5.180 +   * \internal
   5.181 +   *
   5.182 +   * \brief Non-templated internal version of FindObjectFromLongName
   5.183 +   *
   5.184 +   * \param name A string containing a longname to look for.
   5.185 +   */
   5.186 +  static Ptr<Object> FindObjectFromFullNameInternal (std::string name);
   5.187 +
   5.188 +  /**
   5.189 +   * \internal
   5.190 +   *
   5.191 +   * \brief Non-templated internal version of FindObjectFromShortName
   5.192 +   *
   5.193 +   * \param context A spart pointer to an object under which you want to look 
   5.194 +   *                for the provided name.
   5.195 +   * \param name A string containing a shortname to look for.
   5.196 +   */
   5.197 +  static Ptr<Object> FindObjectFromShortNameInternal (Ptr<Object> context, std::string name);
   5.198 +};
   5.199 +
   5.200 +/**
   5.201 + * \brief Template definition of corresponding template declaration found in class Names.
   5.202 + */
   5.203 +template <typename T>
   5.204 +Ptr<T> 
   5.205 +Names::Find (std::string name)
   5.206 +{
   5.207 +  return FindObjectFromFullName<T> (name);
   5.208 +}
   5.209 +
   5.210 +/**
   5.211 + * \brief Template definition of corresponding template declaration found in class Names.
   5.212 + */
   5.213 +template <typename T>
   5.214 +Ptr<T> 
   5.215 +Names::FindObjectFromFullName (std::string name)
   5.216 +{
   5.217 +  Ptr<Object> obj = FindObjectFromFullNameInternal (name);
   5.218 +  if (obj)
   5.219 +    {
   5.220 +      return obj->GetObject<T> ();
   5.221 +    }
   5.222 +  else
   5.223 +    {
   5.224 +      return 0;
   5.225 +    }
   5.226 +}
   5.227 +
   5.228 +/**
   5.229 + * \brief Template definition of corresponding template declaration found in class Names.
   5.230 + */
   5.231 +template <typename T>
   5.232 +Ptr<T> 
   5.233 +Names::FindObjectFromShortName (Ptr<Object> context, std::string name)
   5.234 +{
   5.235 +  Ptr<Object> obj = FindObjectFromShortNameInternal (context, name);
   5.236 +  if (obj)
   5.237 +    {
   5.238 +      return obj->GetObject<T> ();
   5.239 +    }
   5.240 +  else
   5.241 +    {
   5.242 +      return 0;
   5.243 +    }
   5.244 +}
   5.245 +
   5.246 +}//namespace ns3
   5.247 +
   5.248 +#endif /* OBJECT_NAMES_H */
     6.1 --- a/src/core/wscript	Sun Jan 18 22:47:25 2009 +0000
     6.2 +++ b/src/core/wscript	Tue Jan 20 15:47:14 2009 -0800
     6.3 @@ -53,6 +53,7 @@
     6.4          'trace-source-accessor.cc',
     6.5          'config.cc',
     6.6          'callback.cc',
     6.7 +        'object-names.cc',
     6.8          ]
     6.9      core.uselib = 'RT'
    6.10  
    6.11 @@ -98,6 +99,7 @@
    6.12          'object-vector.h',
    6.13          'deprecated.h',
    6.14          'abort.h',
    6.15 +        'object-names.h',
    6.16          ]
    6.17  
    6.18      if sys.platform == 'win32':