Incorporated defaults and command-line arguments
authorRaj Bhattacharjea <raj.b@gatech.edu>
Thu, 26 Apr 2007 11:36:05 -0400
changeset 439 fed13fb45eef
parent 436 e3223ddba0fb
child 440 d1ffec80b2d6
Incorporated defaults and command-line arguments
SConstruct
examples/simple-p2p.cc
src/core/command-line.cc
src/core/command-line.h
src/core/default-value.cc
src/core/default-value.h
src/core/type-name.cc
src/core/type-name.h
src/node/drop-tail.cc
src/node/queue.cc
src/node/queue.h
src/simulator/scheduler-factory.cc
src/simulator/scheduler-factory.h
src/simulator/scheduler-heap.cc
src/simulator/scheduler-list.cc
src/simulator/scheduler-map.cc
src/simulator/simulator.cc
src/simulator/simulator.h
--- a/SConstruct	Thu Apr 19 22:29:09 2007 +0200
+++ b/SConstruct	Thu Apr 26 11:36:05 2007 -0400
@@ -26,6 +26,9 @@
     'random-variable.cc',
     'rng-stream.cc',
     'object-container.cc',
+    'default-value.cc',
+    'command-line.cc',
+    'type-name.cc',
     ])
 env = Environment()
 if env['PLATFORM'] == 'posix' or env['PLATFORM'] == 'darwin' or env['PLATFORM'] == 'cygwin':
@@ -52,7 +55,10 @@
     'test.h',
     'random-variable.h',
     'rng-stream.h',
-    'object-container.h'
+    'object-container.h',
+    'default-value.h',
+    'command-line.h',
+    'type-name.h',
     ])
 
 def config_core (env, config):
--- a/examples/simple-p2p.cc	Thu Apr 19 22:29:09 2007 +0200
+++ b/examples/simple-p2p.cc	Thu Apr 26 11:36:05 2007 -0400
@@ -43,6 +43,8 @@
 #include <cassert>
 
 #include "ns3/debug.h"
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
 
 #include "ns3/simulator.h"
 #include "ns3/nstime.h"
@@ -70,6 +72,7 @@
 
 int main (int argc, char *argv[])
 {
+  CommandLine::Parse (argc, argv);
 #if 0
   DebugComponentEnable("Object");
   DebugComponentEnable("Queue");
@@ -84,7 +87,7 @@
   // be a DropTail queue, with a limit of 30 packets.
   // Specify DropTail for default queue type (note. this is actually
   // the default, but included here as an example).
-  Queue::Default(DropTailQueue());
+  Bind ("queue", "DropTail"); //Queue::Default(DropTailQueue());
   // Specify limit of 30 in units of packets (not implemented).
   //  Queue::Default().SetLimitPackets(30);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/command-line.cc	Thu Apr 26 11:36:05 2007 -0400
@@ -0,0 +1,131 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include "command-line.h"
+#include <unistd.h>
+
+namespace ns3 {
+
+CommandDefaultValue CommandLine::g_help ("help",
+                                         "Print Help text for all commands",
+                                         MakeCallback (&CommandLine::PrintHelp));
+
+void 
+CommandLine::AddArgCommand (const std::string &name,
+                            const std::string &help,
+                            Callback<void> cb)
+{
+  DefaultValueBase *base = 
+    new CommandDefaultValue (name, help, cb);
+  GetUserList ()->push_back (base);
+}
+
+CommandLine::List *
+CommandLine::GetUserList (void)
+{
+  static List list;
+  return &list;
+}
+
+void 
+CommandLine::PrintHelp (void)
+{
+  for (List::iterator i = GetUserList ()->begin ();
+       i != GetUserList ()->end (); i++)
+    {
+      DefaultValueBase *item = *i;
+      if (item->GetType () == "" &&
+          item->GetDefaultValue () == "")
+        {
+          std::cout << "--" << item->GetName () << "\t" << item->GetHelp () << std::endl;
+        }
+      else
+        {
+          std::cout << "--" << item->GetName () << "=[" << item->GetType () << ":"
+                    << item->GetDefaultValue () << "]\t" << item->GetHelp () << std::endl;
+        }
+    }
+  for (List::iterator i = DefaultValueList::Begin ();
+       i != DefaultValueList::End (); i++)
+    {
+      DefaultValueBase *item = *i;
+      if (item->GetType () == "" &&
+          item->GetDefaultValue () == "")
+        {
+          std::cout << "--" << item->GetName () << "\t" << item->GetHelp () << std::endl;
+        }
+      else
+        {
+          std::cout << "--" << item->GetName () << "=[" << item->GetType () << ":"
+                    << item->GetDefaultValue () << "]\t" << item->GetHelp () << std::endl;
+        }
+    }
+  // XXX on win32, do the right thing here.
+  exit (0);
+}
+
+void 
+CommandLine::Parse (int argc, char *argv[])
+{
+  argc--;
+  argv++;
+  while (argc > 0)
+    {
+      // remove "--" or "-" heading.
+      std::string param = *argv;
+      std::string::size_type cur = param.find ("--");
+      if (cur == std::string::npos)
+        {
+          cur = param.find ("-");
+          if (cur == std::string::npos)
+            {
+              // invalid argument. ignore it.
+              continue;
+            }
+        }
+      if (cur != 0)
+        {
+          // invalid argument. ignore it.
+          continue;
+        }
+      param = std::string (param, 2, param.size ());
+      cur = param.find ("=");
+      std::string name, value;
+      if (cur == std::string::npos)
+        {
+          name = param;
+          value = "";
+        }
+      else
+        {
+          name = std::string (param, 0, cur);
+          value = std::string (param, cur + 1, std::string::npos);
+        }
+      // try to find this argument in the user args.
+      for (List::iterator i = GetUserList ()->begin ();
+           i != GetUserList ()->end (); i++)
+        {
+          DefaultValueBase *item = *i;
+          if (item->GetName () == name)
+            {
+              item->ParseValue (value);
+              continue;
+            }
+        }
+           
+      // try to find this argument in the default args.
+      for (List::iterator i = DefaultValueList::Begin ();
+           i != DefaultValueList::End (); i++)
+        {
+          DefaultValueBase *item = *i;
+          if (item->GetName () == name)
+            {
+              item->ParseValue (value);
+              continue;
+            }
+        }
+      argc--;
+      argv++;
+    }
+}
+
+}//namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/command-line.h	Thu Apr 26 11:36:05 2007 -0400
@@ -0,0 +1,93 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+#ifndef COMMAND_LINE_H
+#define COMMAND_LINE_H
+
+#include <list>
+#include <string>
+#include "default-value.h"
+
+namespace ns3 {
+
+class CommandLine
+{
+public:
+  template <typename T>
+  static void AddArgValue (const std::string &name,
+			   const std::string &help, 
+			   T &value);
+  static void AddArgCommand (const std::string &name,
+			     const std::string &help,
+			     Callback<void> cb);
+  static void Parse (int argc, char *argv[]);
+ private:
+  template <typename T>
+  class UserDefaultValue : public DefaultValueBase 
+  {
+  public:
+    UserDefaultValue (const std::string &name,
+                      const std::string &help,
+		      T &value);
+  private:
+    virtual bool DoParseValue (const std::string &value);
+    virtual std::string DoGetType (void) const;
+    virtual std::string DoGetDefaultValue (void) const;
+    T *m_valuePtr;
+  };
+  static void PrintHelp (void);
+  typedef std::list<DefaultValueBase *> List;
+  static List *GetUserList (void);
+  static CommandDefaultValue g_help;
+};
+
+}//namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void 
+CommandLine::AddArgValue (const std::string &name,
+			  const std::string &help, 
+			  T &value)
+{
+  DefaultValueBase *base = 
+    new UserDefaultValue<T> (name, help, value);
+  GetUserList ()->push_back (base);
+}
+
+
+template <typename T>
+CommandLine::UserDefaultValue<T>::UserDefaultValue (const std::string &name,
+						    const std::string &help,
+						    T &value)
+  : DefaultValueBase (name, help),
+    m_valuePtr (&value)
+{
+  // we do not register in the DefaultValueList class on purpose.
+}
+template <typename T>
+bool
+CommandLine::UserDefaultValue<T>::DoParseValue (const std::string &value)
+{
+  std::ostringstream iss;
+  iss.str (value);
+  T v;
+  iss >> v;
+  *m_valuePtr = v;
+  return !iss.bad () && !iss.fail ();
+}
+template <typename T>
+std::string
+CommandLine::UserDefaultValue<T>::DoGetType (void) const
+{
+  return "";
+}
+template <typename T>
+std::string
+CommandLine::UserDefaultValue<T>::DoGetDefaultValue (void) const
+{
+  return "";
+}
+
+}//namespace ns3
+
+#endif /* COMMAND_LINE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/default-value.cc	Thu Apr 26 11:36:05 2007 -0400
@@ -0,0 +1,447 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include "default-value.h"
+#include "fatal-error.h"
+
+namespace ns3 {
+
+DefaultValueBase::DefaultValueBase (const std::string &name,
+				    const std::string &help)
+  : m_name (name),
+    m_help (help)
+{}
+DefaultValueBase::~DefaultValueBase ()
+{}
+std::string 
+DefaultValueBase::GetName (void) const
+{
+  return m_name;
+}
+std::string 
+DefaultValueBase::GetHelp (void) const
+{
+  return m_help;
+}
+bool 
+DefaultValueBase::ParseValue (const std::string &value)
+{
+  return DoParseValue (value);
+}
+std::string 
+DefaultValueBase::GetType (void) const
+{
+  return DoGetType ();
+}
+std::string 
+DefaultValueBase::GetDefaultValue (void) const
+{
+  return DoGetDefaultValue ();
+}
+
+
+DefaultValueList::Iterator 
+DefaultValueList::Begin (void)
+{
+  return GetList ()->begin ();
+}
+DefaultValueList::Iterator 
+DefaultValueList::End (void)
+{
+  return GetList ()->end ();
+}
+void
+DefaultValueList::Remove (const std::string &name)
+{
+  DefaultValueList::List *list = GetList ();
+  for (List::iterator i = list->begin (); i != list->end (); /* nothing */)
+    {
+      if ((*i)->GetName () == name)
+        {
+          i = list->erase (i);
+        }
+      else
+        {
+          i++;
+        }
+    }
+}
+void 
+DefaultValueList::Add (DefaultValueBase *defaultValue)
+{
+  GetList ()->push_back (defaultValue);
+}
+
+DefaultValueList::List *
+DefaultValueList::GetList (void)
+{
+  static List list;
+  return &list;
+}
+
+enum BindStatus {
+  OK,
+  INVALID_VALUE,
+  NOT_FOUND
+};
+
+
+static 
+enum BindStatus
+BindSafe (std::string name, std::string value)
+{
+  for (DefaultValueList::Iterator i = DefaultValueList::Begin ();
+       i != DefaultValueList::End (); i++)
+    {
+      DefaultValueBase *cur = *i;
+      if (cur->GetName () == name)
+	{
+	  if (!cur->ParseValue (value))
+	    {
+	      return INVALID_VALUE;
+	    }
+	  return OK;
+	}
+    }
+  return NOT_FOUND;
+}
+
+void
+Bind (std::string name, std::string value)
+{
+  switch (BindSafe (name, value)) {
+  case INVALID_VALUE:
+    NS_FATAL_ERROR ("Invalid value: "<<name<<"="<<value);
+    break;
+  case NOT_FOUND:
+    NS_FATAL_ERROR ("No registered DefaultValue=\"" << name << "\"");
+    break;
+  case OK:
+    break;
+  }
+}
+
+BooleanDefaultValue::BooleanDefaultValue (std::string name,
+					  std::string help,
+					  bool defaultValue)
+  : DefaultValueBase (name, help),
+    m_defaultValue (defaultValue),
+    m_value (defaultValue)
+{
+  DefaultValueList::Add (this);
+}
+bool 
+BooleanDefaultValue::GetValue (void) const
+{
+  return m_value;
+}
+bool 
+BooleanDefaultValue::DoParseValue (const std::string &value)
+{
+  if (value.compare ("0") == 0 ||
+      value.compare ("f") == 0 ||
+      value.compare ("false") == 0 ||
+      value.compare ("FALSE") == 0) 
+    {
+      m_value = false;
+      return true;
+    } 
+  else if (value.compare ("1") == 0 ||
+	   value.compare ("t") == 0 ||
+	   value.compare ("true") == 0 ||
+	   value.compare ("TRUE") == 0) 
+    {
+      m_value = true;
+      return true;
+    } 
+  else 
+    {
+      return false;
+    }
+}
+std::string 
+BooleanDefaultValue::DoGetType (void) const
+{
+  return "bool";
+}
+std::string 
+BooleanDefaultValue::DoGetDefaultValue (void) const
+{
+  return m_defaultValue?"true":"false";
+}
+
+
+StringEnumDefaultValue::StringEnumDefaultValue (const std::string &name,
+                                                const std::string &help)
+  : DefaultValueBase (name, help),
+    m_oneDefault (false)
+{
+  DefaultValueList::Add (this);
+}
+void 
+StringEnumDefaultValue::AddDefaultValue (const std::string &value)
+{
+  if (m_oneDefault)
+    {
+      NS_FATAL_ERROR ("More than one default value registered: " << value);
+    }
+  m_oneDefault = true;
+  for (std::list<std::string>::iterator i = m_possibleValues.begin ();
+       i != m_possibleValues.end (); i++)
+    {
+      if (value == *i)
+        {
+          NS_FATAL_ERROR ("Value already exists: " << value);
+        }
+    }  
+  m_possibleValues.push_back (value);
+  m_value = value;
+  m_defaultValue = value;
+}
+void 
+StringEnumDefaultValue::AddPossibleValue (const std::string &value)
+{
+  for (std::list<std::string>::iterator i = m_possibleValues.begin ();
+       i != m_possibleValues.end (); i++)
+    {
+      if (value == *i)
+        {
+          NS_FATAL_ERROR ("Value already exists: " << value);
+        }
+    }
+  m_possibleValues.push_back (value);
+}
+std::string 
+StringEnumDefaultValue::GetValue (void) const
+{
+  return m_value;
+}
+bool 
+StringEnumDefaultValue::DoParseValue (const std::string &value)
+{
+  for (std::list<std::string>::iterator i = m_possibleValues.begin ();
+       i != m_possibleValues.end (); i++)
+    {
+      if (value == *i)
+        {
+          m_value = value;
+          return true;
+        }
+    }
+  return false;
+}
+std::string 
+StringEnumDefaultValue::DoGetType (void) const
+{
+  std::string retval;
+  retval += "(";
+  for (std::list<std::string>::const_iterator i = m_possibleValues.begin ();
+       i != m_possibleValues.end (); i++)
+    {
+      if (i != m_possibleValues.begin ())
+	{
+	  retval += "|";
+	}
+      retval += *i;
+    }
+  retval += ")";
+  return retval;
+}
+std::string 
+StringEnumDefaultValue::DoGetDefaultValue (void) const
+{
+  return m_defaultValue;
+}
+
+
+CommandDefaultValue::CommandDefaultValue (const std::string &name,
+					  const std::string &help,
+					  Callback<void> cb)
+  : DefaultValueBase (name, help),
+    m_cb (cb)
+{
+  DefaultValueList::Add (this);
+}
+bool 
+CommandDefaultValue::DoParseValue (const std::string &value)
+{
+  m_cb ();
+  return true;
+}
+std::string 
+CommandDefaultValue::DoGetType (void) const
+{
+  return "";
+}
+std::string 
+CommandDefaultValue::DoGetDefaultValue (void) const
+{
+  return "";
+}
+
+
+}//namespace ns3
+
+#ifdef RUN_SELF_TESTS
+#include "test.h"
+
+namespace ns3 {
+
+enum MyEnum {
+  MY_ENUM_A,
+  MY_ENUM_B,
+  MY_ENUM_C,
+  MY_ENUM_D,
+};
+
+
+class DefaultValueTest : public Test
+{
+public:
+  DefaultValueTest ();
+  virtual bool RunTests (void);
+};
+
+DefaultValueTest::DefaultValueTest ()
+  : Test ("DefaultValue")
+{}
+bool 
+DefaultValueTest::RunTests (void)
+{
+  bool ok = true;
+
+  BooleanDefaultValue a ("bool-a", "help a", true);
+  if (!a.GetValue ())
+    {
+      ok = false;
+    }
+  Bind ("bool-a", "false");
+  if (a.GetValue ())
+    {
+      ok = false;
+    }
+  BooleanDefaultValue b ("bool-b", "help b", false);
+  Bind ("bool-b", "true");
+  if (!b.GetValue ())
+    {
+      ok = false;
+    }
+  Bind ("bool-b", "0");
+  if (b.GetValue ())
+    {
+      ok = false;
+    }
+  Bind ("bool-b", "1");
+  if (!b.GetValue ())
+    {
+      ok = false;
+    }
+  Bind ("bool-b", "f");
+  if (b.GetValue ())
+    {
+      ok = false;
+    }
+  Bind ("bool-b", "t");
+  if (!b.GetValue ())
+    {
+      ok = false;
+    }
+
+  Bind ("bool-b", "false");
+  if (b.GetValue ())
+    {
+      ok = false;
+    }
+  if (BindSafe ("bool-b", "tr") != INVALID_VALUE)
+    {
+      ok = false;
+    }
+
+  IntegerDefaultValue<int> i ("test-i", "help-i", -1);
+  if (i.GetValue () != -1)
+    {
+      ok = false;
+    }  
+  Bind ("test-i", "-2");
+  if (i.GetValue () != -2)
+    {
+      ok = false;
+    }
+  Bind ("test-i", "+2");
+  if (i.GetValue () != 2)
+    {
+      ok = false;
+    }
+  if (i.GetType () != "int32_t(-2147483648:2147483647)")
+    {
+      ok = false;
+    }
+  IntegerDefaultValue<uint32_t> ui32 ("test-ui32", "help-ui32", 10);
+  if (ui32.GetType () != "uint32_t(0:4294967295)")
+    {
+      ok = false;
+    }
+  IntegerDefaultValue<char> c ("test-c", "help-c", 10);
+  if (c.GetValue () != 10)
+    {
+      ok = false;
+    }
+  Bind ("test-c", "257");  
+
+  EnumDefaultValue<enum MyEnum> e ("test-e", "help-e",
+				   MY_ENUM_C, "C",
+				   MY_ENUM_A, "A",
+				   MY_ENUM_B, "B",
+				   0, (void*)0);
+  if (e.GetValue () != MY_ENUM_C)
+    {
+      ok = false;
+    }
+  Bind ("test-e", "B");
+  if (e.GetValue () != MY_ENUM_B)
+    {
+      ok = false;
+    }
+  if (BindSafe ("test-e", "D") != INVALID_VALUE)
+    {
+      ok = false;
+    }
+
+  class MyEnumSubclass : public EnumDefaultValue<enum MyEnum>
+  {
+  public:
+    MyEnumSubclass () 
+      : EnumDefaultValue<enum MyEnum> ("test-e1", "help-e1",
+				       MY_ENUM_B, "B",
+				       MY_ENUM_A, "A",
+				       0, (void*)0)
+    {
+      AddPossibleValue (MY_ENUM_C, "C");
+      AddPossibleValue (MY_ENUM_D, "D");
+    }
+  } e1 ;
+  if (e1.GetValue () != MY_ENUM_B)
+    {
+      ok = false;
+    }
+  Bind ("test-e1", "D");
+  if (e1.GetValue () != MY_ENUM_D)
+    {
+      ok = false;
+    }
+
+  DefaultValueList::Remove ("test-e1");
+  DefaultValueList::Remove ("test-e");
+  DefaultValueList::Remove ("bool-b");
+  DefaultValueList::Remove ("bool-a");
+  DefaultValueList::Remove ("test-i");
+  DefaultValueList::Remove ("test-c");
+  DefaultValueList::Remove ("test-ui32");
+  
+  return ok;
+}
+
+static DefaultValueTest g_default_value_tests;
+
+}//namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/default-value.h	Thu Apr 26 11:36:05 2007 -0400
@@ -0,0 +1,423 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+#ifndef DEFAULT_VALUE_H
+#define DEFAULT_VALUE_H
+
+#include <string>
+#include <list>
+#include "callback.h"
+
+namespace ns3 {
+
+class DefaultValueBase
+{
+public:
+  virtual ~DefaultValueBase ();
+  std::string GetName (void) const;
+  std::string GetHelp (void) const;
+  // parse a matching parameter
+  // return true in case of success, false otherwise.
+  bool ParseValue (const std::string &value);
+  std::string GetType (void) const;
+  std::string GetDefaultValue (void) const;
+protected:
+  DefaultValueBase (const std::string &name, 
+		    const std::string &help);
+private:
+  virtual bool DoParseValue (const std::string &value) = 0;
+  virtual std::string DoGetType (void) const = 0;
+  virtual std::string DoGetDefaultValue (void) const = 0;
+  std::string m_name;
+  std::string m_help;
+};
+
+class DefaultValueList
+{
+ public:
+  typedef std::list<DefaultValueBase *>::iterator Iterator;
+
+  static Iterator Begin (void);
+  static Iterator End (void);
+  static void Remove (const std::string &name);
+  static void Add (DefaultValueBase *defaultValue);
+ private:
+  typedef std::list<DefaultValueBase *> List;
+  static List *GetList (void);
+};
+
+/**
+ * \param name name of variable to bind
+ * \param value value to bind to the specified variable
+ *
+ * If the variable name does not match any existing
+ * variable or if the value is not compatible with
+ * the variable type, this function will abort
+ * at runtime and print an error message detailing
+ * which variable or value triggered the problem.
+ */
+void Bind (std::string name, std::string value);
+
+/**
+ * \brief A Boolean variable for ns3::Bind
+ *
+ * Every instance of this type is automatically 
+ * registered in the variable pool which is used
+ * by ns3::Bind. 
+ */
+class BooleanDefaultValue : public DefaultValueBase
+{
+public:
+  /**
+   * \param name name of variable
+   * \param help help text which explains the purpose
+   *        and the semantics of this variable
+   * \param defaultValue the default value to assign
+   *        to this variable.
+   *
+   * Unless the user invokes ns3::Bind with the right arguments,
+   * the GetValue method will return the default value. Otherwise,
+   * it will return the user-specified value.
+   */
+  BooleanDefaultValue (std::string name,
+		       std::string help,
+		       bool defaultValue);
+  /**
+   * \returns the default value for this variable or a
+   *          user-provided overriden variable.
+   */
+  bool GetValue (void) const;
+private:
+  virtual bool DoParseValue (const std::string &value);
+  virtual std::string DoGetType (void) const;
+  virtual std::string DoGetDefaultValue (void) const;
+  bool m_defaultValue;
+  bool m_value;
+};
+
+/**
+ * \brief An Integer variable for ns3::Bind
+ *
+ * Every instance of this type is automatically 
+ * registered in the variable pool which is used
+ * by ns3::Bind. 
+ */
+template <typename T>
+class IntegerDefaultValue : public DefaultValueBase
+{
+public:
+  /**
+   * \param name the name of the variable
+   * \param help help text which explains the purpose
+   *        and the semantics of this variable
+   * \param defaultValue the default value assigned
+   *        to this variable
+   *
+   * By default, the set of allowed values is the entire range
+   * of values which can be stored and retrieved from the underlying
+   * type.
+   */
+  IntegerDefaultValue (std::string name,
+		       std::string help,
+		       T defaultValue);
+  /**
+   * \param name the name of the variable
+   * \param help help text which explains the purpose
+   *        and the semantics of this variable
+   * \param defaultValue the default value assigned to this
+   *        variable
+   * \param minValue the minimum value which can be set
+   *        in this variable
+   * \param maxValue the maximum value which can be set in this
+   *        variable.
+   */
+  IntegerDefaultValue (std::string name,
+		       std::string help,
+		       T defaultValue,
+		       T minValue,
+		       T maxValue);
+
+
+  T GetValue (void) const;
+private:
+  virtual bool DoParseValue (const std::string &value);
+  virtual std::string DoGetType (void) const;
+  virtual std::string DoGetDefaultValue (void) const;
+  T m_defaultValue;
+  T m_minValue;
+  T m_maxValue;
+  T m_value;
+};
+
+class StringEnumDefaultValue : public DefaultValueBase
+{
+public:
+  StringEnumDefaultValue (const std::string &name,
+                          const std::string &help);
+  void AddDefaultValue (const std::string &value);
+  void AddPossibleValue (const std::string &value);
+  std::string GetValue (void) const;
+private:
+  virtual bool DoParseValue (const std::string &value);
+  virtual std::string DoGetType (void) const;
+  virtual std::string DoGetDefaultValue (void) const;
+
+  bool m_oneDefault;
+  std::list<std::string> m_possibleValues;
+  std::string m_defaultValue;
+  std::string m_value;
+};
+
+/**
+ * \brief An enum variable for ns3::Bind
+ *
+ * Every instance of this type is automatically 
+ * registered in the variable pool which is used
+ * by ns3::Bind. 
+ */
+template <typename T>
+class EnumDefaultValue : public DefaultValueBase
+{
+public:
+  /**
+   * \param name the name of this variable
+   * \param help help text which explains the purpose
+   *        and the semantics of this variable
+   * \param defaultValue the default value assigned to this
+   *        variable unless it is overriden with ns3::Bind
+   * \param defaultValueString the string which represents
+   *        the default value which should be used by ns3::Bind
+   *
+   * This method takes a variable number of arguments. The list of
+   * arguments is terminated by the pair of values 0 and (void *)0.
+   * Each pair of extra argument is assumed to be of the form 
+   * (enum value, string representing enum value). If ns3::Bind
+   * is invoked on this variable, it will check that the user-provided
+   * values are within the set of values specified in this constructor.
+   *
+   * Typical useage of this method will look like this:
+   * \code
+   * enum MyEnum {
+   *   MY_ENUM_A,
+   *   MY_ENUM_B,
+   *   MY_ENUM_C,
+   * };
+   * // set default value to be "B".
+   * static EnumDefaultValue<enum MyEnum> 
+   *  g_myDefaultValue ("my", "my help",
+   *                    MY_ENUM_B, "B",
+   *                    MY_ENUM_A, "A",
+   *                    MY_ENUM_C, "C",);
+   *                    0, (void*)0);
+   * \endcode
+   * Note that to ensure portability to 64 bit systems, make sure that
+   * the last element in the variable list of arguments is (void *)0.
+   */
+  EnumDefaultValue (const std::string &name, const std::string &help,
+		    T defaultValue, const char *defaultValueString, 
+		    ...);
+  void AddPossibleValue (T value, const std::string &valueString);
+  /**
+   * \returns the default value or any other value specified by the 
+   *          user with ns3::Bind
+   */
+  T GetValue (void);
+ private:
+  virtual bool DoParseValue (const std::string &value);
+  virtual std::string DoGetType (void) const;
+  virtual std::string DoGetDefaultValue (void) const;
+
+  typedef std::list<std::pair<T,std::string> > PossibleValues;
+
+  T m_defaultValue;
+  PossibleValues m_possibleValues;
+  T m_value;
+};
+
+class CommandDefaultValue : public DefaultValueBase
+{
+public:
+  CommandDefaultValue (const std::string &name,
+		       const std::string &help,
+		       Callback<void> cb);
+private:
+  virtual bool DoParseValue (const std::string &value);
+  virtual std::string DoGetType (void) const;
+  virtual std::string DoGetDefaultValue (void) const;
+  Callback<void> m_cb;
+};
+
+}//namespace ns3
+
+#include "type-name.h"
+#include "assert.h"
+#include <sstream>
+#include <stdarg.h>
+#include <limits>
+
+namespace ns3 {
+
+/**************************************************************
+ **************************************************************/
+
+
+template <typename T>
+IntegerDefaultValue<T>::IntegerDefaultValue (std::string name,
+					     std::string help,
+					     T defaultValue)
+  : DefaultValueBase (name, help),
+    m_defaultValue (defaultValue),
+    m_minValue (std::numeric_limits<T>::min ()),
+    m_maxValue (std::numeric_limits<T>::max ()),
+    m_value (defaultValue)
+{
+  DefaultValueList::Add (this);
+}
+template <typename T>
+IntegerDefaultValue<T>::IntegerDefaultValue (std::string name,
+					     std::string help,
+					     T defaultValue,
+					     T minValue,
+					     T maxValue)
+  : DefaultValueBase (name, help),
+    m_defaultValue (defaultValue),
+    m_minValue (minValue),
+    m_maxValue (maxValue),
+    m_value (defaultValue)
+{
+  DefaultValueList::Add (this);
+  NS_ASSERT (m_defaultValue <= m_maxValue &&
+	     m_defaultValue >= m_minValue);
+}
+
+template <typename T>
+T
+IntegerDefaultValue<T>::GetValue (void) const
+{
+  return m_value;
+}
+
+template <typename T>
+bool
+IntegerDefaultValue<T>::DoParseValue (const std::string &value)
+{
+  std::istringstream iss;
+  iss.str (value);
+  iss >> m_value;
+  if (m_value > m_maxValue ||
+      m_value < m_minValue)
+    {
+      return false;
+    }
+  return !iss.bad () && !iss.fail ();
+}
+
+template <typename T>
+std::string
+IntegerDefaultValue<T>::DoGetType (void) const
+{
+  std::ostringstream oss;
+  oss << TypeNameGet<T> () << "("
+      << m_minValue << ":" 
+      << m_maxValue << ")";
+  return oss.str ();
+}
+
+template <typename T>
+std::string
+IntegerDefaultValue<T>::DoGetDefaultValue (void) const
+{
+  std::ostringstream oss;
+  oss << m_defaultValue;
+  return oss.str ();
+}
+
+/**************************************************************
+ **************************************************************/
+
+template <typename T>
+EnumDefaultValue<T>::EnumDefaultValue (const std::string &name, const std::string &help,
+				       T defaultValue, const char *defaultValueString, 
+				       ...)
+  : DefaultValueBase (name, help),
+    m_defaultValue (defaultValue),
+    m_value (defaultValue)
+{
+  AddPossibleValue (defaultValue, defaultValueString);
+  va_list list;
+  va_start (list, defaultValueString);
+  while (true)
+    {
+      T v = (T) va_arg (list, int);
+      const char *str = va_arg (list, const char *);
+      if (v == 0 && str == 0)
+	{
+	  break;
+	}
+      AddPossibleValue (v, str);
+    }
+  DefaultValueList::Add (this);
+}
+template <typename T>
+void 
+EnumDefaultValue<T>::AddPossibleValue (T value, const std::string &valueString)
+{
+  m_possibleValues.push_back (std::make_pair (value, valueString));
+}
+template <typename T>
+T 
+EnumDefaultValue<T>::GetValue (void)
+{
+  return m_value;
+}
+template <typename T>
+bool 
+EnumDefaultValue<T>::DoParseValue (const std::string &value)
+{
+  for (typename PossibleValues::iterator i = m_possibleValues.begin ();
+       i != m_possibleValues.end (); i++)
+    {
+      if (value == i->second)
+	{
+	  m_value = i->first;
+	  return true;
+	}
+    }
+  return false;
+}
+template <typename T>
+std::string 
+EnumDefaultValue<T>::DoGetType (void) const
+{
+  std::string retval;
+  retval += "(";
+  for (typename PossibleValues::const_iterator i = m_possibleValues.begin ();
+       i != m_possibleValues.end (); i++)
+    {
+      if (i != m_possibleValues.begin ())
+	{
+	  retval += "|";
+	}
+      retval += i->second;
+    }
+  retval += ")";
+  return retval;
+}
+template <typename T>
+std::string 
+EnumDefaultValue<T>::DoGetDefaultValue (void) const
+{
+  for (typename PossibleValues::const_iterator i = m_possibleValues.begin ();
+       i != m_possibleValues.end (); i++)
+    {
+      if (i->first == m_defaultValue)
+	{
+	  return i->second;
+	}
+    }
+  // cannot happen theoretically.
+  NS_ASSERT (false);
+  return ""; // quiet compiler
+}
+
+}//namespace ns3
+
+#endif /* DEFAULT_VALUE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/type-name.cc	Thu Apr 26 11:36:05 2007 -0400
@@ -0,0 +1,24 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include "type-name.h"
+
+namespace ns3 {
+
+#define DEF_TYPE(x)				\
+  template <>					\
+  std::string TypeNameGet<x> (void)		\
+  {						\
+    return #x;					\
+  }
+  
+DEF_TYPE (uint8_t);
+DEF_TYPE (uint16_t);
+DEF_TYPE (uint32_t);
+DEF_TYPE (uint64_t);
+DEF_TYPE (int8_t);
+DEF_TYPE (int16_t);
+DEF_TYPE (int32_t);
+DEF_TYPE (int64_t);
+
+
+}//namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/type-name.h	Thu Apr 26 11:36:05 2007 -0400
@@ -0,0 +1,34 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#ifndef TYPE_NAME_H
+#define TYPE_NAME_H
+
+#include <stdint.h>
+#include <string>
+
+namespace ns3 {
+
+template <typename T>
+std::string TypeNameGet (void)
+{
+  return "unknown";
+}
+
+#define DEF_TYPE(x)				\
+  template <>					\
+    std::string TypeNameGet<x> (void)
+  
+DEF_TYPE (uint8_t);
+DEF_TYPE (uint16_t);
+DEF_TYPE (uint32_t);
+DEF_TYPE (uint64_t);
+DEF_TYPE (int8_t);
+DEF_TYPE (int16_t);
+DEF_TYPE (int32_t);
+DEF_TYPE (int64_t);
+
+#undef DEF_TYPE
+
+}//namespace ns3
+
+#endif /* TYPE_NAME_H */
--- a/src/node/drop-tail.cc	Thu Apr 19 22:29:09 2007 +0200
+++ b/src/node/drop-tail.cc	Thu Apr 26 11:36:05 2007 -0400
@@ -28,6 +28,8 @@
 public:
   QueueStackInitializationClass () {
     Queue::Default (DropTailQueue ());
+    static DropTailQueue queue;
+    Queue::AddDefault (queue, "DropTail");
   }
 } queue_stack_initialization_class;
 
--- a/src/node/queue.cc	Thu Apr 19 22:29:09 2007 +0200
+++ b/src/node/queue.cc	Thu Apr 26 11:36:05 2007 -0400
@@ -20,6 +20,7 @@
 #include "ns3/debug.h"
 #include "ns3/composite-trace-resolver.h"
 #include "queue.h"
+#include "ns3/default-value.h"
 
 NS_DEBUG_COMPONENT_DEFINE ("Queue");
 
@@ -209,4 +210,47 @@
   return *defaultQueue;
 }
 
+
+Queue *
+Queue::CreateDefault (void)
+{
+  std::string defaultValue = GetDefault ()->GetValue ();
+  for (List::iterator i = GetList ()->begin ();
+       i != GetList ()->end (); i++)
+    {
+      if (i->second == defaultValue)
+        {
+          return i->first->Copy ();
+        }
+    }
+  NS_ASSERT (false);
+  // quiet compiler
+  return 0;
+}
+void 
+Queue::Add (Queue &queue, const std::string &name)
+{
+  GetDefault ()->AddPossibleValue (name);
+  GetList ()->push_back (std::make_pair (&queue, name));
+}
+void 
+Queue::AddDefault (Queue &queue, const std::string &name)
+{
+  GetDefault ()->AddDefaultValue (name);
+  GetList ()->push_back (std::make_pair (&queue, name));
+}
+StringEnumDefaultValue *
+Queue::GetDefault (void)
+{
+  static StringEnumDefaultValue value ("queue", "Packet Queue");
+  return &value;
+}
+Queue::List *
+Queue::GetList (void)
+{
+  static List list;
+  return &list;
+}
+
+
 }; // namespace ns3
--- a/src/node/queue.h	Thu Apr 19 22:29:09 2007 +0200
+++ b/src/node/queue.h	Thu Apr 26 11:36:05 2007 -0400
@@ -26,12 +26,15 @@
 #define QUEUE_H
 
 #include <string>
+#include <list>
 #include "ns3/packet.h"
 #include "ns3/callback-trace-source.h"
 #include "ns3/trace-resolver.h"
 
 namespace ns3 {
 
+class StringEnumDefaultValue;
+
 class Queue
 {
 public:
@@ -109,6 +112,15 @@
   uint32_t m_nTotalDroppedPackets;
 
 public:
+  static Queue *CreateDefault (void);
+  static void Add (Queue &queue, const std::string &name);
+  static void AddDefault (Queue &queue, const std::string &name);
+private:
+  typedef std::list<std::pair<Queue *,std::string> > List;
+  static StringEnumDefaultValue *GetDefault (void);
+  static List *GetList (void);
+
+public:
   // Static methods to manage queue default
   // Set desired queue default
   static void    Default(const Queue& q);
--- a/src/simulator/scheduler-factory.cc	Thu Apr 19 22:29:09 2007 +0200
+++ b/src/simulator/scheduler-factory.cc	Thu Apr 26 11:36:05 2007 -0400
@@ -19,6 +19,9 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 #include "scheduler-factory.h"
+#include "ns3/assert.h"
+#include "ns3/fatal-error.h"
+#include "ns3/default-value.h"
 
 namespace ns3 {
 
@@ -28,7 +31,73 @@
 Scheduler *
 SchedulerFactory::Create (void) const
 {
-  return RealCreate ();
+  return DoCreate ();
+}
+
+Scheduler *
+SchedulerFactory::CreateDefault (void)
+{
+  NS_ASSERT_MSG (!GetList ()->empty (), "No Scheduler factory registered");
+  std::string defaultValue = GetDefault ()->GetValue ();
+  for (List::const_iterator i = GetList ()->begin ();
+       i != GetList ()->end (); i++)
+    {
+      if (i->second == defaultValue)
+        {
+          return i->first->Create ();
+        }
+    }
+  NS_ASSERT (false);
+  // quiet compiler
+  return 0;
 }
 
+Scheduler *
+SchedulerFactory::Create (const std::string &name)
+{
+  for (List::iterator i = GetList ()->begin ();
+       i != GetList ()->end (); i++)
+    {
+      if (i->second == name)
+        {
+          return i->first->Create ();
+        }
+    }
+  NS_ASSERT_MSG (false, "Tried to create non-existant scheduler: " << name);
+  // quiet compiler.
+  return 0;
+}
+
+void 
+SchedulerFactory::AddDefault (const SchedulerFactory *factory,
+                              const std::string &name)
+{
+  GetDefault ()->AddDefaultValue (name);
+  GetList ()->push_back (std::make_pair (factory, name));
+}
+
+
+void 
+SchedulerFactory::Add (const SchedulerFactory *factory,
+                       const std::string &name)
+{
+  GetDefault ()->AddPossibleValue (name);
+  GetList ()->push_back (std::make_pair (factory, name));
+}
+
+StringEnumDefaultValue *
+SchedulerFactory::GetDefault (void)
+{
+  static StringEnumDefaultValue value ("scheduler", "Event Scheduler algorithm");
+  return &value;
+}
+
+SchedulerFactory::List *
+SchedulerFactory::GetList (void)
+{
+  static SchedulerFactory::List list;
+  return &list;
+}
+
+
 }; // namespace ns3
--- a/src/simulator/scheduler-factory.h	Thu Apr 19 22:29:09 2007 +0200
+++ b/src/simulator/scheduler-factory.h	Thu Apr 26 11:36:05 2007 -0400
@@ -21,9 +21,12 @@
 #ifndef SCHEDULER_FACTORY_H
 #define SCHEDULER_FACTORY_H
 
+#include <list>
+
 namespace ns3 {
 
 class Scheduler;
+class StringEnumDefaultValue;
 
 /**
  * \brief a base class to create event schedulers
@@ -36,13 +39,39 @@
 class SchedulerFactory {
 public:
   virtual ~SchedulerFactory ();
+  /**
+   * \returns a newly-created scheduler.
+   */
   Scheduler *Create (void) const;
+  /**
+   * \returns a newly-created scheduler.
+   *
+   * Return a "default" scheduler.
+   */
+  static Scheduler *CreateDefault (void);
+  /**
+   * \param name of scheduler to create.
+   * \returns a newly-created scheduler.
+   *
+   * Create a scheduler registered under the specified name.
+   */
+  static Scheduler *Create (const std::string &name);
+protected:
+  static void Add (const SchedulerFactory *factory,
+                   const std::string &name);  
+  static void AddDefault (const SchedulerFactory *factory,
+                          const std::string &name);  
 private:
+  typedef std::list<std::pair<const SchedulerFactory *, std::string> > List;
+  static SchedulerFactory::List *GetList (void);
+  static StringEnumDefaultValue *GetDefault (void);
   /**
    * \returns a newly-created scheduler. The caller takes 
    *      ownership of the returned pointer.
+   *
+   * This method must be implemented by subclasses.
    */
-  virtual Scheduler *RealCreate (void) const = 0;
+  virtual Scheduler *DoCreate (void) const = 0;
 };
 
 }; // namespace ns3
--- a/src/simulator/scheduler-heap.cc	Thu Apr 19 22:29:09 2007 +0200
+++ b/src/simulator/scheduler-heap.cc	Thu Apr 26 11:36:05 2007 -0400
@@ -33,6 +33,7 @@
  */
 
 #include "scheduler-heap.h"
+#include "scheduler-factory.h"
 #include "event-impl.h"
 #include "ns3/assert.h"
 
@@ -51,6 +52,21 @@
 
 namespace ns3 {
 
+static class SchedulerHeapFactory : public SchedulerFactory 
+{
+public:
+  SchedulerHeapFactory ()
+  {
+    SchedulerFactory::Add (this, "BinaryHeap");
+  }
+private:
+  virtual Scheduler *DoCreate (void) const
+  {
+    return new SchedulerHeap ();
+  }
+} g_schedulerHeapFactory;
+
+
 SchedulerHeap::SchedulerHeap ()
 {
   // we purposedly waste an item at the start of
--- a/src/simulator/scheduler-list.cc	Thu Apr 19 22:29:09 2007 +0200
+++ b/src/simulator/scheduler-list.cc	Thu Apr 26 11:36:05 2007 -0400
@@ -20,12 +20,28 @@
  */
 
 #include "scheduler-list.h"
+#include "scheduler-factory.h"
 #include "event-impl.h"
 #include <utility>
 #include "ns3/assert.h"
 
 namespace ns3 {
 
+static class SchedulerListFactory : public SchedulerFactory 
+{
+public:
+  SchedulerListFactory ()
+  {
+    SchedulerFactory::AddDefault (this, "list");
+  }
+private:
+  virtual Scheduler *DoCreate (void) const
+  {
+    return new SchedulerList ();
+  }
+} g_schedulerListFactory;
+
+
 SchedulerList::SchedulerList ()
 {}
 SchedulerList::~SchedulerList ()
--- a/src/simulator/scheduler-map.cc	Thu Apr 19 22:29:09 2007 +0200
+++ b/src/simulator/scheduler-map.cc	Thu Apr 26 11:36:05 2007 -0400
@@ -21,6 +21,7 @@
  */
 
 #include "scheduler-map.h"
+#include "scheduler-factory.h"
 #include "event-impl.h"
 #include "ns3/assert.h"
 
@@ -37,6 +38,20 @@
 
 namespace ns3 {
 
+static class SchedulerMapFactory : public SchedulerFactory 
+{
+public:
+  SchedulerMapFactory ()
+  {
+    SchedulerFactory::Add (this, "map");
+  }
+private:
+  virtual Scheduler *DoCreate (void) const
+  {
+    return new SchedulerMap ();
+  }
+} g_schedulerMapFactory;
+
 
 SchedulerMap::SchedulerMap ()
 {}
--- a/src/simulator/simulator.cc	Thu Apr 19 22:29:09 2007 +0200
+++ b/src/simulator/simulator.cc	Thu Apr 26 11:36:05 2007 -0400
@@ -23,8 +23,11 @@
 #include "scheduler.h"
 #include "event-impl.h"
 
+#include "ns3/assert.h"
+#include "ns3/default-value.h"
+
+
 #include <math.h>
-#include "ns3/assert.h"
 #include <fstream>
 #include <list>
 #include <vector>
@@ -294,27 +297,23 @@
 namespace ns3 {
 
 SimulatorPrivate *Simulator::m_priv = 0;
-Simulator::ListType Simulator::m_listType = LINKED_LIST;
-SchedulerFactory const*Simulator::m_schedFactory = 0;
 
 void Simulator::SetLinkedList (void)
 {
-  m_listType = LINKED_LIST;
+  Bind ("scheduler", "list");
 }
 void Simulator::SetBinaryHeap (void)
 {
-  m_listType = BINARY_HEAP;
+  Bind ("scheduler", "BinaryHeap");
 }
 void Simulator::SetStdMap (void)
 {
-  m_listType = STD_MAP;
+  Bind ("scheduler", "map");
 }
 void 
-Simulator::SetExternal (SchedulerFactory const*factory)
+Simulator::SetExternal (const std::string &external)
 {
-  NS_ASSERT (factory != 0);
-  m_schedFactory = factory;
-  m_listType = EXTERNAL;
+  Bind ("scheduler", external);
 }
 void Simulator::EnableLogTo (char const *filename)
 {
@@ -327,24 +326,7 @@
 {
   if (m_priv == 0) 
     {
-      Scheduler *events;
-      switch (m_listType) {
-      case LINKED_LIST:
-          events = new SchedulerList ();
-          break;
-      case BINARY_HEAP:
-          events = new SchedulerHeap ();
-          break;
-      case STD_MAP:
-          events = new SchedulerMap ();
-          break;
-      case EXTERNAL:
-          events = m_schedFactory->Create ();
-      default: // not reached
-          events = 0;
-          NS_ASSERT (false); 
-          break;
-      }
+      Scheduler *events = SchedulerFactory::CreateDefault ();
       m_priv = new SimulatorPrivate (events);
     }
   TRACE_S ("priv " << m_priv);
--- a/src/simulator/simulator.h	Thu Apr 19 22:29:09 2007 +0200
+++ b/src/simulator/simulator.h	Thu Apr 26 11:36:05 2007 -0400
@@ -85,7 +85,7 @@
    * This method must be invoked before any other method exported
    * by the Simulator class.
    */
-  static void SetExternal (SchedulerFactory const*factory);
+  static void SetExternal (const std::string &name);
 
   /**
    * Enable logging to the file identified by filename. If the file
@@ -557,13 +557,6 @@
   static void ScheduleDestroy (EventImpl *event);
   static void ScheduleNow (EventImpl *event);
   static SimulatorPrivate *m_priv;
-  static SchedulerFactory const*m_schedFactory;
-  static enum ListType {
-      LINKED_LIST,
-      BINARY_HEAP,
-      STD_MAP,
-      EXTERNAL
-  } m_listType;
 };
 
 }; // namespace ns3