src/core/default-value.h
author Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
Thu, 30 Aug 2007 13:58:15 +0200
changeset 1399 5945e92014e2
parent 1224 7cbc1d661b89
child 1642 8d5707931bb4
child 1701 5e9bd24a8716
permissions -rw-r--r--
move printing to client code

/* -*- 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>
 */
#ifndef DEFAULT_VALUE_H
#define DEFAULT_VALUE_H

#include <string>
#include <list>
#include "callback.h"

/**
 * \defgroup config Simulation configuration
 *
 */

namespace ns3 {

namespace DefaultValue
{

/**
 * \ingroup config
 * \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);

}


class DefaultValueBase
{
public:
  virtual ~DefaultValueBase ();
  std::string GetName (void) const;
  std::string GetHelp (void) const;

  /**
   * \returns true if this value is dirty, false otherwise.
   *
   * A value becomes dirty when ParseValue is invoked
   * and it successfully completes. Dirtyness indicates
   * that the state of the value was changed by a user.
   */
  bool IsDirty (void) const;
  /**
   * Clear the dirty state.
   */
  void ClearDirtyFlag (void);
  // 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:
  DefaultValueBase ();
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;
  bool m_dirty;
};

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

/**
 * \brief A Boolean variable for ns3::Bind
 * \ingroup config
 *
 * 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 A Numeric variable for ns3::Bind
 * \ingroup config
 *
 * Every instance of this type is automatically 
 * registered in the variable pool which is used
 * by ns3::Bind. 
 */
template <typename T>
class NumericDefaultValue : 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.
   */
  NumericDefaultValue (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
   */
  NumericDefaultValue (std::string name,
		       std::string help,
		       T defaultValue,
		       T minValue);

  /**
   * \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.
   */
  NumericDefaultValue (std::string name,
		       std::string help,
		       T defaultValue,
		       T minValue,
		       T maxValue);

  void SetValue (T v);

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

/**
 * \brief Named enumeration defaults
 * \ingroup config
 *
 * Every instance of this type is automatically 
 * registered in the variable pool which is used
 * by ns3::Bind. 
 */
class StringEnumDefaultValue : public DefaultValueBase
{
public:
  /**
   * \param name The name of the variable
   * \param help The help string
   */
  StringEnumDefaultValue (const std::string &name,
                          const std::string &help);
  /**
   * \brief Add a default value to this enumeration of strings
   * \param value The string to make the default for this
   */
  void AddDefaultValue (const std::string &value);
  /**
   * \brief Add a possible value to accept for this default value
   */
  void AddPossibleValue (const std::string &value);
  /**
   * \brief Get the value of this default value.
   * \return The string that has been assigned to this default value, either by
   * Bind() or by a command line setting
   */
  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
 * \ingroup config
 *
 * 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);
  /**
   * \param value the new default value.
   */
  void SetValue (T value);
 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;
};

/**
 * \brief Class used to call a certain function during the configuration of the
 * simulation
 * \ingroup config
 */
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>
NumericDefaultValue<T>::NumericDefaultValue (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);
  NS_ASSERT (m_minValue < m_maxValue);
}
template <typename T>
NumericDefaultValue<T>::NumericDefaultValue (std::string name,
					     std::string help,
					     T defaultValue,
					     T minValue)
  : DefaultValueBase (name, help),
    m_defaultValue (defaultValue),
    m_minValue (minValue),
    m_maxValue (std::numeric_limits<T>::max ()),
    m_value (defaultValue)
{
  DefaultValueList::Add (this);
  NS_ASSERT (m_minValue < m_maxValue);
  NS_ASSERT (m_defaultValue <= m_maxValue &&
	     m_defaultValue >= m_minValue);
}
template <typename T>
NumericDefaultValue<T>::NumericDefaultValue (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_minValue < m_maxValue);
  NS_ASSERT (m_defaultValue <= m_maxValue &&
	     m_defaultValue >= m_minValue);
}

template <typename T>
void 
NumericDefaultValue<T>::SetValue (T v)
{
  NS_ASSERT (v <= m_maxValue &&
	     v >= m_minValue);
  m_value = v;
}

template <typename T>
T
NumericDefaultValue<T>::GetValue (void) const
{
  return m_value;
}

template <typename T>
bool
NumericDefaultValue<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
NumericDefaultValue<T>::DoGetType (void) const
{
  std::ostringstream oss;
  oss << TypeNameGet<T> () << "("
      << m_minValue << ":" 
      << m_maxValue << ")";
  return oss.str ();
}

template <typename T>
std::string
NumericDefaultValue<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>
void
EnumDefaultValue<T>::SetValue (T value)
{
  m_value = 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 */