--- 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