src/core/default-value.cc
author Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
Sun, 02 Mar 2008 21:12:21 +0100
changeset 2532 86a40c7cbfe9
parent 2114 bfd8e5afb36d
permissions -rw-r--r--
register and unregister the NodeList as a config root namespace

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2007 INRIA
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
 */

#include "default-value.h"
#include "fatal-error.h"

namespace ns3 {

namespace DefaultValue {

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

}

DefaultValueBase::DefaultValueBase (const std::string &name,
				    const std::string &help)
  : m_name (name),
    m_help (help),
    m_dirty (false)
{}
DefaultValueBase::~DefaultValueBase ()
{}
std::string 
DefaultValueBase::GetName (void) const
{
  return m_name;
}
std::string 
DefaultValueBase::GetHelp (void) const
{
  return m_help;
}
bool 
DefaultValueBase::IsDirty (void) const
{
  return m_dirty;
}
void 
DefaultValueBase::ClearDirtyFlag (void)
{
  m_dirty = false;
}
bool 
DefaultValueBase::ParseValue (const std::string &value)
{
  bool ok = DoParseValue (value);
  if (ok)
    {
      m_dirty = true;
    }
  return ok;
}
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;
}

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 "";
}


StringDefaultValue::StringDefaultValue (const std::string &name,
                                        const std::string &help,
                                        const std::string defaultValue)
  : DefaultValueBase (name, help),
    m_defaultValue (defaultValue),
    m_value (defaultValue),
    m_minSize (0),
    m_maxSize (-1)
{
  DefaultValueList::Add (this);
}
StringDefaultValue::StringDefaultValue (const std::string &name,
                                        const std::string &help,
                                        const std::string defaultValue,
                                        int maxSize)
  : DefaultValueBase (name, help),
    m_defaultValue (defaultValue),
    m_value (defaultValue),
    m_minSize (0),
    m_maxSize (maxSize)
{
  DefaultValueList::Add (this);
}
StringDefaultValue::StringDefaultValue (const std::string &name,
                                        const std::string &help,
                                        const std::string defaultValue,
                                        int minSize,
                                        int maxSize)
  : DefaultValueBase (name, help),
    m_defaultValue (defaultValue),
    m_value (defaultValue),
    m_minSize (minSize),
    m_maxSize (maxSize)
{
  DefaultValueList::Add (this);
}


std::string 
StringDefaultValue::GetValue (void) const
{
  return m_value;
}

bool 
StringDefaultValue::DoParseValue (const std::string &value)
{
  if ((int)value.size () < m_minSize)
    {
      return false;
    }
  if (m_maxSize != -1 && (int)value.size () > m_maxSize)
    {
      return false;
    }
  m_value = value;
  return true;
}
std::string 
StringDefaultValue::DoGetType (void) const
{
  if (m_maxSize == -1)
    {
      return "string:0";
    }
  else 
    {
      std::ostringstream oss;
      oss << "string:0:" << m_maxSize;
      return oss.str ();
    }
}
std::string 
StringDefaultValue::DoGetDefaultValue (void) const
{
  return m_defaultValue;
}



}//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 result = true;

  BooleanDefaultValue a ("bool-a", "help a", true);
  NS_TEST_ASSERT (a.GetValue ());
  DefaultValue::Bind ("bool-a", "false");
  NS_TEST_ASSERT (!a.GetValue ());
  BooleanDefaultValue b ("bool-b", "help b", false);
  DefaultValue::Bind ("bool-b", "true");
  NS_TEST_ASSERT (b.GetValue ());
  DefaultValue::Bind ("bool-b", "0");
  NS_TEST_ASSERT (!b.GetValue ());
  DefaultValue::Bind ("bool-b", "1");
  NS_TEST_ASSERT (b.GetValue ());
  DefaultValue::Bind ("bool-b", "f");
  NS_TEST_ASSERT (!b.GetValue ());
  DefaultValue::Bind ("bool-b", "t");
  NS_TEST_ASSERT (b.GetValue ());

  DefaultValue::Bind ("bool-b", "false");
  NS_TEST_ASSERT (!b.GetValue ());
  NS_TEST_ASSERT_EQUAL (DefaultValue::BindSafe ("bool-b", "tr"), DefaultValue::INVALID_VALUE)

  NumericDefaultValue<int32_t> i ("test-i", "help-i", -1);
  NS_TEST_ASSERT_EQUAL (i.GetValue (), -1);
  DefaultValue::Bind ("test-i", "-2");
  NS_TEST_ASSERT_EQUAL (i.GetValue (), -2);
  DefaultValue::Bind ("test-i", "+2");
  NS_TEST_ASSERT_EQUAL (i.GetValue (), 2);
  NS_TEST_ASSERT_EQUAL (i.GetType (), "int32_t(-2147483648:2147483647)");
  NumericDefaultValue<uint32_t> ui32 ("test-ui32", "help-ui32", 10);
  NS_TEST_ASSERT_EQUAL (ui32.GetType (), "uint32_t(0:4294967295)");
  NumericDefaultValue<int8_t> c ("test-c", "help-c", 10);
  NS_TEST_ASSERT_EQUAL (c.GetValue (), 10);
  DefaultValue::Bind ("test-c", "257");  
  NumericDefaultValue<float> x ("test-x", "help-x", 10.0);
  NumericDefaultValue<double> y ("test-y", "help-y", 10.0);
  DefaultValue::Bind ("test-y", "-3");  

  EnumDefaultValue<enum MyEnum> e ("test-e", "help-e",
				   MY_ENUM_C, "C",
				   MY_ENUM_A, "A",
				   MY_ENUM_B, "B",
				   0, (void*)0);
  NS_TEST_ASSERT_EQUAL (e.GetValue (), MY_ENUM_C);
  DefaultValue::Bind ("test-e", "B");
  NS_TEST_ASSERT_EQUAL (e.GetValue (), MY_ENUM_B);
  NS_TEST_ASSERT_EQUAL (DefaultValue::BindSafe ("test-e", "D"), DefaultValue::INVALID_VALUE);

  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 ;
  NS_TEST_ASSERT_EQUAL (e1.GetValue (), MY_ENUM_B);
  DefaultValue::Bind ("test-e1", "D");
  NS_TEST_ASSERT_EQUAL (e1.GetValue (), MY_ENUM_D);

  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-x");
  DefaultValueList::Remove ("test-y");
  DefaultValueList::Remove ("test-ui32");
  
  return result;
}

static DefaultValueTest g_default_value_tests;

}//namespace ns3

#endif /* RUN_SELF_TESTS */