diff --git a/SConstruct b/SConstruct index c7c1fb3e1..7483596b2 100644 --- a/SConstruct +++ b/SConstruct @@ -27,6 +27,9 @@ core.add_sources([ 'rng-stream.cc', 'ns-unknown.cc', 'iid-manager.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,6 +55,9 @@ core.add_inst_headers([ 'rng-stream.h', 'ns-unknown.h', 'iid-manager.h', + 'default-value.h', + 'command-line.h', + 'type-name.h', ]) def config_core (env, config): @@ -377,6 +383,18 @@ ns3.add(sample_simple) sample_simple.add_deps(['core', 'simulator', 'node']) sample_simple.add_source('main-simple.cc') +sample_sp2p = build.Ns3Module('sample-simple-p2p', 'samples') +sample_sp2p.set_executable() +#n3.add(sample_sp2p) +sample_sp2p.add_deps(['core', 'simulator', 'node', 'p2p']) +sample_sp2p.add_source('main-simple-p2p.cc') + +sample_default_value = build.Ns3Module('sample-default-value', 'samples') +sample_default_value.set_executable() +ns3.add(sample_default_value) +sample_default_value.add_deps(['core', 'simulator', 'node', 'p2p']) +sample_default_value.add_source('main-default-value.cc') + # examples example_simple_p2p = build.Ns3Module('simple-p2p', 'examples') example_simple_p2p.set_executable() diff --git a/examples/simple-p2p.cc b/examples/simple-p2p.cc index 8adafb2a7..4e789a835 100644 --- a/examples/simple-p2p.cc +++ b/examples/simple-p2p.cc @@ -43,6 +43,8 @@ #include #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 @@ using namespace ns3; int main (int argc, char *argv[]) { + CommandLine::Parse (argc, argv); #if 0 DebugComponentEnable("Object"); DebugComponentEnable("Queue"); @@ -84,7 +87,7 @@ int main (int argc, char *argv[]) // 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); diff --git a/samples/main-default-value.cc b/samples/main-default-value.cc new file mode 100644 index 000000000..b3a7b2b2d --- /dev/null +++ b/samples/main-default-value.cc @@ -0,0 +1,85 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +#include +#include "ns3/default-value.h" +#include "ns3/command-line.h" +#include "ns3/debug.h" + +using namespace ns3; + +// +// This sample file demonstrates how to take some simple member +// variables and hook them into the default variable system +// Typically, you will establish a static variable to maintain the current +// value of the default parameter. Then as other code require the values of +// the defaults, they query them with GetValue() to get the present value. +static BooleanDefaultValue defaultTestBool1 ("testBool1", "helpBool", true); +static IntegerDefaultValue defaultTestInt1 ("testInt1", "helpInt1", 33); +static IntegerDefaultValue defaultTestInt2 ("testInt2", "helpInt2", 47); + +// +// This test class demonstrates the declaration of variables that +// may be overridden by the default-value system +// +// You will see in the core ns-3 modules that many member variables +// can be overridden in this manner +// +class TestClass { +public: + TestClass(); + virtual ~TestClass () {} + + bool m_testBool1; + int m_testInt1; + uint32_t m_testInt2; +}; + +// +// In the constructor, you can assign default values in the initializer +// list such as below; note that the instance of the created TestClass +// will have the values as dictated by the current value of the default. +// This means that the behavior of this class can be changed on the fly with +// calls to bind. +// +TestClass::TestClass () : + m_testBool1(defaultTestBool1.GetValue()), + m_testInt1(defaultTestInt1.GetValue()), + m_testInt2(defaultTestInt2.GetValue()) +{ +} +using std::cout; +int main (int argc, char* argv[]) +{ + //The following allows the default values established so far to be hooked + //into the command line argument processing unit. Essentially, the command + //line processor is aware of the DefaultValues that have been registered, and + //will accept command line overrides of these. The call automatically + //provides a --help option in addition to allowing overrides of defaults. + uint32_t loops = 0; + CommandLine::AddArgValue("loops","a test of the command line",loops); + CommandLine::Parse(argc,argv); + + //utilize the loops variable to show that it can be read from the command line + if(loops>0) + { + cout<<"You requested "<m_testBool1 << ")"); + NS_DEBUG_UNCOND("TestInt1 default value (" << testclass->m_testInt1 << ")"); + NS_DEBUG_UNCOND("TestInt2 default value (" << testclass->m_testInt2 << ")"); + delete testclass; + + return 0; +} diff --git a/src/core/command-line.cc b/src/core/command-line.cc new file mode 100644 index 000000000..88a14263b --- /dev/null +++ b/src/core/command-line.cc @@ -0,0 +1,131 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +#include "command-line.h" +#include + +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 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 diff --git a/src/core/command-line.h b/src/core/command-line.h new file mode 100644 index 000000000..f3186fde5 --- /dev/null +++ b/src/core/command-line.h @@ -0,0 +1,93 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +#ifndef COMMAND_LINE_H +#define COMMAND_LINE_H + +#include +#include +#include "default-value.h" + +namespace ns3 { + +class CommandLine +{ +public: + template + 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 cb); + static void Parse (int argc, char *argv[]); + private: + template + 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 List; + static List *GetUserList (void); + static CommandDefaultValue g_help; +}; + +}//namespace ns3 + +namespace ns3 { + +template +void +CommandLine::AddArgValue (const std::string &name, + const std::string &help, + T &value) +{ + DefaultValueBase *base = + new UserDefaultValue (name, help, value); + GetUserList ()->push_back (base); +} + + +template +CommandLine::UserDefaultValue::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 +bool +CommandLine::UserDefaultValue::DoParseValue (const std::string &value) +{ + std::istringstream iss; + iss.str (value); + T v; + iss >> v; + *m_valuePtr = v; + return !iss.bad () && !iss.fail (); +} +template +std::string +CommandLine::UserDefaultValue::DoGetType (void) const +{ + return ""; +} +template +std::string +CommandLine::UserDefaultValue::DoGetDefaultValue (void) const +{ + return ""; +} + +}//namespace ns3 + +#endif /* COMMAND_LINE_H */ diff --git a/src/core/default-value.cc b/src/core/default-value.cc new file mode 100644 index 000000000..163497baf --- /dev/null +++ b/src/core/default-value.cc @@ -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: "<::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::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::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::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 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 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 ui32 ("test-ui32", "help-ui32", 10); + if (ui32.GetType () != "uint32_t(0:4294967295)") + { + ok = false; + } + IntegerDefaultValue c ("test-c", "help-c", 10); + if (c.GetValue () != 10) + { + ok = false; + } + Bind ("test-c", "257"); + + EnumDefaultValue 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 + { + public: + MyEnumSubclass () + : EnumDefaultValue ("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 */ diff --git a/src/core/default-value.h b/src/core/default-value.h new file mode 100644 index 000000000..ef703ce84 --- /dev/null +++ b/src/core/default-value.h @@ -0,0 +1,423 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +#ifndef DEFAULT_VALUE_H +#define DEFAULT_VALUE_H + +#include +#include +#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::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 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 +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 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 +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 + * 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 > 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 cb); +private: + virtual bool DoParseValue (const std::string &value); + virtual std::string DoGetType (void) const; + virtual std::string DoGetDefaultValue (void) const; + Callback m_cb; +}; + +}//namespace ns3 + +#include "type-name.h" +#include "assert.h" +#include +#include +#include + +namespace ns3 { + +/************************************************************** + **************************************************************/ + + +template +IntegerDefaultValue::IntegerDefaultValue (std::string name, + std::string help, + T defaultValue) + : DefaultValueBase (name, help), + m_defaultValue (defaultValue), + m_minValue (std::numeric_limits::min ()), + m_maxValue (std::numeric_limits::max ()), + m_value (defaultValue) +{ + DefaultValueList::Add (this); +} +template +IntegerDefaultValue::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 +T +IntegerDefaultValue::GetValue (void) const +{ + return m_value; +} + +template +bool +IntegerDefaultValue::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 +std::string +IntegerDefaultValue::DoGetType (void) const +{ + std::ostringstream oss; + oss << TypeNameGet () << "(" + << m_minValue << ":" + << m_maxValue << ")"; + return oss.str (); +} + +template +std::string +IntegerDefaultValue::DoGetDefaultValue (void) const +{ + std::ostringstream oss; + oss << m_defaultValue; + return oss.str (); +} + +/************************************************************** + **************************************************************/ + +template +EnumDefaultValue::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 +void +EnumDefaultValue::AddPossibleValue (T value, const std::string &valueString) +{ + m_possibleValues.push_back (std::make_pair (value, valueString)); +} +template +T +EnumDefaultValue::GetValue (void) +{ + return m_value; +} +template +bool +EnumDefaultValue::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 +std::string +EnumDefaultValue::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 +std::string +EnumDefaultValue::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 */ diff --git a/src/core/random-variable.cc b/src/core/random-variable.cc index 62d7935da..c797841e1 100644 --- a/src/core/random-variable.cc +++ b/src/core/random-variable.cc @@ -44,16 +44,33 @@ namespace ns3{ uint32_t RandomVariable::runNumber = 0; bool RandomVariable::initialized = false; // True if RngStream seed set -bool RandomVariable::useDevRandom = false; // True if use /dev/random desired +bool RandomVariable::useDevRandom = false; // True if use /dev/random bool RandomVariable::globalSeedSet = false; // True if GlobalSeed called int RandomVariable::devRandom = -1; -uint32_t RandomVariable::globalSeed[6]; +uint32_t RandomVariable::globalSeed[6]; unsigned long RandomVariable::heuristic_sequence; +RngStream* RandomVariable::m_static_generator = 0; + +//the static object random_variable_initializer initializes the static members +//of RandomVariable +static class RandomVariableInitializer +{ + public: + RandomVariableInitializer() + { + RandomVariable::Initialize(); // sets the static package seed + RandomVariable::m_static_generator = new RngStream(); + RandomVariable::m_static_generator->InitializeStream(); + } + ~RandomVariableInitializer() + { + delete RandomVariable::m_static_generator; + } +} random_variable_initializer; RandomVariable::RandomVariable() { m_generator = new RngStream(); - RandomVariable::Initialize(); // sets the seed for the static object m_generator->InitializeStream(); m_generator->ResetNthSubstream(RandomVariable::runNumber); } @@ -173,7 +190,7 @@ void RandomVariable::SetRunNumber(uint32_t n) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -// UniformVariable methods +// UniformVariable UniformVariable::UniformVariable() : m_min(0), m_max(1.0) { } @@ -192,6 +209,12 @@ RandomVariable* UniformVariable::Copy() const { return new UniformVariable(*this); } + +double UniformVariable::GetSingleValue(double s, double l) +{ + return s + m_static_generator->RandU01() * (l - s);; +} + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ConstantVariable methods @@ -291,6 +314,12 @@ RandomVariable* ExponentialVariable::Copy() const { return new ExponentialVariable(*this); } +double ExponentialVariable::GetSingleValue(double m, double b/*=0*/) +{ + double r = -m*log(m_static_generator->RandU01()); + if (b != 0 && r > b) return b; + return r; +} //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ParetoVariable methods @@ -322,6 +351,14 @@ RandomVariable* ParetoVariable::Copy() const { return new ParetoVariable(*this); } + +double ParetoVariable::GetSingleValue(double m, double s, double b/*=0*/) +{ + double scale = m * ( s - 1.0) / s; + double r = (scale * ( 1.0 / pow(m_static_generator->RandU01(), 1.0 / s))); + if (b != 0 && r > b) return b; + return r; +} //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // WeibullVariable methods @@ -348,14 +385,25 @@ RandomVariable* WeibullVariable::Copy() const { return new WeibullVariable(*this); } + +double WeibullVariable::GetSingleValue(double m, double s, double b/*=0*/) +{ + double exponent = 1.0 / s; + double r = m * pow( -log(m_static_generator->RandU01()), exponent); + if (b != 0 && r > b) return b; + return r; +} //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // NormalVariable methods +bool NormalVariable::m_static_nextValid = false; +double NormalVariable::m_static_next; const double NormalVariable::INFINITE_VALUE = 1e307; + NormalVariable::NormalVariable() : m_mean(0.0), m_variance(1.0), m_bound(INFINITE_VALUE), m_nextValid(false){} -NormalVariable::NormalVariable(double m, double v, double b) +NormalVariable::NormalVariable(double m, double v, double b/*=INFINITE_VALUE*/) : m_mean(m), m_variance(v), m_bound(b), m_nextValid(false) { } NormalVariable::NormalVariable(const NormalVariable& c) @@ -395,6 +443,34 @@ RandomVariable* NormalVariable::Copy() const return new NormalVariable(*this); } +double NormalVariable::GetSingleValue(double m, double v, double b) +{ + if (m_static_nextValid) + { // use previously generated + m_static_nextValid = false; + return m_static_next; + } + while(1) + { // See Simulation Modeling and Analysis p. 466 (Averill Law) + // for algorithm + double u1 = m_static_generator->RandU01(); + double u2 = m_static_generator->RandU01();; + double v1 = 2 * u1 - 1; + double v2 = 2 * u2 - 1; + double w = v1 * v1 + v2 * v2; + if (w <= 1.0) + { // Got good pair + double y = sqrt((-2 * log(w))/w); + m_static_next = m + v2 * y * sqrt(v); + if (fabs(m_static_next) > b) m_static_next = b * (m_static_next)/fabs(m_static_next); + m_static_nextValid = true; + double x1 = m + v1 * y * sqrt(v); + if (fabs(x1) > b) x1 = b * (x1)/fabs(x1); + return x1; + } + } +} + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ValueCDF methods @@ -522,5 +598,91 @@ RandomVariable* DeterministicVariable::Copy() const return new DeterministicVariable(*this); } + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// LogNormalVariable + +RandomVariable* LogNormalVariable::Copy () const +{ + return new LogNormalVariable (m_mu, m_sigma); +} + +LogNormalVariable::LogNormalVariable (double mu, double sigma) + :m_mu(mu), m_sigma(sigma) +{ +} + +// The code from this function was adapted from the GNU Scientific +// Library 1.8: +/* randist/lognormal.c + * + * Copyright (C) 1996, 1997, 1998, 1999, 2000 James Theiler, Brian Gough + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +/* The lognormal distribution has the form + + p(x) dx = 1/(x * sqrt(2 pi sigma^2)) exp(-(ln(x) - zeta)^2/2 sigma^2) dx + + for x > 0. Lognormal random numbers are the exponentials of + gaussian random numbers */ +double +LogNormalVariable::GetValue () +{ + double u, v, r2, normal, z; + + do + { + /* choose x,y in uniform square (-1,-1) to (+1,+1) */ + + u = -1 + 2 * m_generator->RandU01 (); + v = -1 + 2 * m_generator->RandU01 (); + + /* see if it is in the unit circle */ + r2 = u * u + v * v; + } + while (r2 > 1.0 || r2 == 0); + + normal = u * sqrt (-2.0 * log (r2) / r2); + + z = exp (m_sigma * normal + m_mu); + + return z; +} + +double LogNormalVariable::GetSingleValue(double sigma,double mu) +{ + double u, v, r2, normal, z; + do + { + /* choose x,y in uniform square (-1,-1) to (+1,+1) */ + u = -1 + 2 * m_static_generator->RandU01 (); + v = -1 + 2 * m_static_generator->RandU01 (); + + /* see if it is in the unit circle */ + r2 = u * u + v * v; + } + while (r2 > 1.0 || r2 == 0); + + normal = u * sqrt (-2.0 * log (r2) / r2); + + z = exp (sigma * normal + mu); + + return z; +} + }//namespace ns3 diff --git a/src/core/random-variable.h b/src/core/random-variable.h index 5c28f47c6..b5076ca5f 100644 --- a/src/core/random-variable.h +++ b/src/core/random-variable.h @@ -182,8 +182,10 @@ private: static int devRandom; // File handle for /dev/random static uint32_t globalSeed[6]; // The global seed to use static uint32_t runNumber; + friend class RandomVariableInitializer; protected: static unsigned long heuristic_sequence; + static RngStream* m_static_generator; RngStream* m_generator; //underlying generator being wrapped }; @@ -191,6 +193,13 @@ protected: /** * \brief The uniform distribution RNG for NS-3. * \ingroup randomvariable + * This class supports the creation of objects that return random numbers + * from a fixed uniform distribution. It also supports the generation of + * single random numbers from various uniform distributions. + * \code + * UniformVariable x(0,10); + * x.GetValue(); //will always return numbers [0,10] + * UniformVariable::GetSingleValue(100,1000); //returns a value [100,1000] */ class UniformVariable : public RandomVariable { public: @@ -214,6 +223,13 @@ public: */ virtual double GetValue(); virtual RandomVariable* Copy() const; +public: + /** + * \param s Low end of the range + * \param l High end of the range + * \return A uniformly distributed random number between s and l + */ + static double GetSingleValue(double s, double l); private: double m_min; double m_max; @@ -317,8 +333,16 @@ private: /** * \brief Exponentially Distributed random var * \ingroup randomvariable + * This class supports the creation of objects that return random numbers + * from a fixed exponential distribution. It also supports the generation of + * single random numbers from various exponential distributions. + * \code + * ExponentialVariable x(3.14); + * x.GetValue(); //will always return with mean 3.14 + * ExponentialVariable::GetSingleValue(20.1); //returns with mean 20.1 + * ExponentialVariable::GetSingleValue(108); //returns with mean 108 + * \endcode * - * ExponentialVariable defines a random variable with an exponential distribution */ class ExponentialVariable : public RandomVariable { public: @@ -354,6 +378,13 @@ public: */ virtual double GetValue(); virtual RandomVariable* Copy() const; +public: + /** + * \param m The mean of the distribution from which the return value is drawn + * \param b The upper bound value desired, beyond which values get clipped + * \return A random number from an exponential distribution with mean m + */ + static double GetSingleValue(double m, double b=0); private: double m_mean; // Mean value of RV double m_bound; // Upper bound on value (if non-zero) @@ -362,8 +393,17 @@ private: /** * \brief ParetoVariable distributed random var * \ingroup randomvariable + * This class supports the creation of objects that return random numbers + * from a fixed pareto distribution. It also supports the generation of + * single random numbers from various pareto distributions. + * \code + * ParetoVariable x(3.14); + * x.GetValue(); //will always return with mean 3.14 + * ParetoVariable::GetSingleValue(20.1); //returns with mean 20.1 + * ParetoVariable::GetSingleValue(108); //returns with mean 108 + * \endcode */ -class ParetoVariable : public RandomVariable { // +class ParetoVariable : public RandomVariable { public: /** * Constructs a pareto random variable with a mean of 1 and a shape @@ -389,6 +429,7 @@ public: /** * \brief Constructs a pareto random variable with the specified mean * \brief value, shape (alpha), and upper bound. + * * Since pareto distributions can theoretically return unbounded values, * it is sometimes useful to specify a fixed upper limit. Note however * when the upper limit is specified, the true mean of the distribution @@ -406,6 +447,17 @@ public: */ virtual double GetValue(); virtual RandomVariable* Copy() const; +public: + /** + * \param m The mean value of the distribution from which the return value + * is drawn. + * \param s The shape parameter of the distribution from which the return + * value is drawn. + * \param b The upper bound to which to restrict return values + * \return A random number from a Pareto distribution with mean m and shape + * parameter s. + */ + static double GetSingleValue(double m, double s, double b=0); private: double m_mean; // Mean value of RV double m_shape; // Shape parameter @@ -415,6 +467,9 @@ private: /** * \brief WeibullVariable distributed random var * \ingroup randomvariable + * This class supports the creation of objects that return random numbers + * from a fixed weibull distribution. It also supports the generation of + * single random numbers from various weibull distributions. */ class WeibullVariable : public RandomVariable { public: @@ -460,6 +515,14 @@ public: */ virtual double GetValue(); virtual RandomVariable* Copy() const; +public: + /** + * \param m Mean value for the distribution. + * \param s Shape (alpha) parameter for the distribution. + * \param b Upper limit on returned values + * \return Random number from a distribution specified by m,s, and b + */ + static double GetSingleValue(double m, double s, double b=0); private: double m_mean; // Mean value of RV double m_alpha; // Shape parameter @@ -469,6 +532,10 @@ private: /** * \brief Class NormalVariable defines a random variable with a * normal (Gaussian) distribution. + * + * This class supports the creation of objects that return random numbers + * from a fixed normal distribution. It also supports the generation of + * single random numbers from various normal distributions. * \ingroup randomvariable */ class NormalVariable : public RandomVariable { // Normally Distributed random var @@ -481,7 +548,6 @@ public: */ NormalVariable(); - /** * \brief Construct a normal random variable with specified mean and variance * \param m Mean value @@ -497,12 +563,22 @@ public: */ virtual double GetValue(); virtual RandomVariable* Copy() const; +public: + /** + * \param m Mean value + * \param v Variance + * \param b Bound. The NormalVariable is bounded within +-bound. + * \return A random number from a distribution specified by m,v, and b. + */ + static double GetSingleValue(double m, double v, double b = INFINITE_VALUE); private: double m_mean; // Mean value of RV double m_variance; // Mean value of RV double m_bound; // Bound on value (absolute value) - bool m_nextValid; // True if next valid + bool m_nextValid; // True if next valid double m_next; // The algorithm produces two values at a time + static bool m_static_nextValid; + static double m_static_next; }; /** @@ -612,5 +688,54 @@ private: double* data; }; + +/** + * \brief Log-normal Distributed random var + * \ingroup randomvariable + * LogNormalVariable defines a random variable with log-normal + * distribution. If one takes the natural logarithm of random + * variable following the log-normal distribution, the obtained values + * follow a normal distribution. + * This class supports the creation of objects that return random numbers + * from a fixed lognormal distribution. It also supports the generation of + * single random numbers from various lognormal distributions. + */ +class LogNormalVariable : public RandomVariable { +public: + /** + * \param mu Mean value of the underlying normal distribution. + * \param sigma Standard deviation of the underlying normal distribution. + * + * Notice: the parameters mu and sigma are _not_ the mean and standard + * deviation of the log-normal distribution. To obtain the + * parameters mu and sigma for a given mean and standard deviation + * of the log-normal distribution the following convertion can be + * used: + * \code + * double tmp = log (1 + pow (stddev/mean, 2)); + * double sigma = sqrt (tmp); + * double mu = log (mean) - 0.5*tmp; + * \endcode + */ + LogNormalVariable (double mu, double sigma); + + /** + * \return A random value from this distribution + */ + virtual double GetValue (); + virtual RandomVariable* Copy() const; +public: + /** + * \param mu Mean value of the underlying normal distribution. + * \param sigma Standard deviation of the underlying normal distribution. + * \return A random number from the distribution specified by mu and sigma + */ + static double GetSingleValue(double mu, double sigma); +private: + double m_mu; + double m_sigma; +}; + + }//namespace ns3 #endif diff --git a/src/core/type-name.cc b/src/core/type-name.cc new file mode 100644 index 000000000..0bc6b9b46 --- /dev/null +++ b/src/core/type-name.cc @@ -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 (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 diff --git a/src/core/type-name.h b/src/core/type-name.h new file mode 100644 index 000000000..9390b9473 --- /dev/null +++ b/src/core/type-name.h @@ -0,0 +1,34 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +#ifndef TYPE_NAME_H +#define TYPE_NAME_H + +#include +#include + +namespace ns3 { + +template +std::string TypeNameGet (void) +{ + return "unknown"; +} + +#define DEF_TYPE(x) \ + template <> \ + std::string TypeNameGet (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 */ diff --git a/src/node/drop-tail.cc b/src/node/drop-tail.cc index 6585db6f2..a951a6f5a 100644 --- a/src/node/drop-tail.cc +++ b/src/node/drop-tail.cc @@ -28,6 +28,8 @@ static class QueueStackInitializationClass { public: QueueStackInitializationClass () { Queue::Default (DropTailQueue ()); + static DropTailQueue queue; + Queue::AddDefault (queue, "DropTail"); } } queue_stack_initialization_class; diff --git a/src/node/queue.cc b/src/node/queue.cc index dbea2d964..1ba10ecc1 100644 --- a/src/node/queue.cc +++ b/src/node/queue.cc @@ -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 @@ Queue& Queue::Default() 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 diff --git a/src/node/queue.h b/src/node/queue.h index ac7736ff4..9119832a9 100644 --- a/src/node/queue.h +++ b/src/node/queue.h @@ -26,12 +26,15 @@ #define QUEUE_H #include +#include #include "ns3/packet.h" #include "ns3/callback-trace-source.h" #include "ns3/trace-resolver.h" namespace ns3 { +class StringEnumDefaultValue; + class Queue { public: @@ -108,6 +111,15 @@ private: uint32_t m_nTotalDroppedBytes; 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 > List; + static StringEnumDefaultValue *GetDefault (void); + static List *GetList (void); + public: // Static methods to manage queue default // Set desired queue default diff --git a/src/simulator/scheduler-factory.cc b/src/simulator/scheduler-factory.cc index ebc8042cb..fff4914bb 100644 --- a/src/simulator/scheduler-factory.cc +++ b/src/simulator/scheduler-factory.cc @@ -19,6 +19,9 @@ * Author: Mathieu Lacage */ #include "scheduler-factory.h" +#include "ns3/assert.h" +#include "ns3/fatal-error.h" +#include "ns3/default-value.h" namespace ns3 { @@ -28,7 +31,73 @@ SchedulerFactory::~SchedulerFactory () 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 diff --git a/src/simulator/scheduler-factory.h b/src/simulator/scheduler-factory.h index ce5a5706d..6883a6fd8 100644 --- a/src/simulator/scheduler-factory.h +++ b/src/simulator/scheduler-factory.h @@ -21,9 +21,12 @@ #ifndef SCHEDULER_FACTORY_H #define SCHEDULER_FACTORY_H +#include + namespace ns3 { class Scheduler; +class StringEnumDefaultValue; /** * \brief a base class to create event schedulers @@ -36,13 +39,39 @@ class Scheduler; 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 > 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 diff --git a/src/simulator/scheduler-heap.cc b/src/simulator/scheduler-heap.cc index 807c6b263..89be02fcc 100644 --- a/src/simulator/scheduler-heap.cc +++ b/src/simulator/scheduler-heap.cc @@ -33,6 +33,7 @@ */ #include "scheduler-heap.h" +#include "scheduler-factory.h" #include "event-impl.h" #include "ns3/assert.h" @@ -51,6 +52,21 @@ std::cout << "HEAP TRACE " << x << std::endl; 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 diff --git a/src/simulator/scheduler-list.cc b/src/simulator/scheduler-list.cc index 7f1f43f03..81372d794 100644 --- a/src/simulator/scheduler-list.cc +++ b/src/simulator/scheduler-list.cc @@ -20,12 +20,28 @@ */ #include "scheduler-list.h" +#include "scheduler-factory.h" #include "event-impl.h" #include #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 () diff --git a/src/simulator/scheduler-map.cc b/src/simulator/scheduler-map.cc index 5e07c9779..e5111dd6a 100644 --- a/src/simulator/scheduler-map.cc +++ b/src/simulator/scheduler-map.cc @@ -21,6 +21,7 @@ */ #include "scheduler-map.h" +#include "scheduler-factory.h" #include "event-impl.h" #include "ns3/assert.h" @@ -37,6 +38,20 @@ std::cout << "MAP TRACE " << x << std::endl; 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 () {} diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index bcb283144..0b499ecff 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -23,8 +23,11 @@ #include "scheduler.h" #include "event-impl.h" -#include #include "ns3/assert.h" +#include "ns3/default-value.h" + + +#include #include #include #include @@ -293,27 +296,23 @@ SimulatorPrivate::IsExpired (EventId ev) 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) { @@ -326,24 +325,7 @@ Simulator::GetPriv (void) { 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); diff --git a/src/simulator/simulator.h b/src/simulator/simulator.h index 6a9126be5..e3ec207de 100644 --- a/src/simulator/simulator.h +++ b/src/simulator/simulator.h @@ -85,7 +85,7 @@ public: * 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 @@ private: 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 diff --git a/utils/run-tests.cc b/utils/run-tests.cc index 5e7552654..774e88c1f 100644 --- a/utils/run-tests.cc +++ b/utils/run-tests.cc @@ -25,7 +25,9 @@ int main (int argc, char *argv[]) { #ifdef RUN_SELF_TESTS ns3::TestManager::EnableVerbose (); - ns3::TestManager::RunTests (); + bool success = ns3::TestManager::RunTests (); + if (!success) + return 1; #endif /* RUN_SELF_TESTS */ return 0;