Support for 64-bit int and real valued Options
authorTeemu Murtola <teemu.murtola@gmail.com>
Mon, 23 Dec 2013 18:12:00 +0000 (20:12 +0200)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Wed, 15 Jan 2014 22:55:44 +0000 (23:55 +0100)
Add Int64Option and FloatOption to the options machinery.
Add RealOption that aliases either DoubleOption or FloatOption,
depending on GMX_DOUBLE.
With these additions, the options machinery supports all the
functionality and types of the old t_pargs machinery.

Change-Id: I2260e52d3a220f824e1c3e790da2dba83f381972

src/gromacs/options/basicoptions.cpp
src/gromacs/options/basicoptions.h
src/gromacs/options/basicoptionstorage.h
src/gromacs/options/timeunitmanager.cpp

index 210e108ba2b40879566e02f21c576ce9e93bd167..a7ee949f248279b8a86c6ac0f95fb11d17cb0db5 100644 (file)
@@ -50,6 +50,8 @@
 #include <string>
 #include <vector>
 
+#include "gromacs/legacyheaders/string2.h"
+
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/stringutil.h"
 
@@ -190,6 +192,53 @@ AbstractOptionStoragePointer IntegerOption::createStorage() const
 }
 
 
+/********************************************************************
+ * Int64OptionStorage
+ */
+
+std::string Int64OptionStorage::formatSingleValue(const gmx_int64_t &value) const
+{
+    return formatString("%" GMX_PRId64, value);
+}
+
+void Int64OptionStorage::convertValue(const std::string &value)
+{
+    const char       *ptr = value.c_str();
+    char             *endptr;
+    errno = 0;
+    const gmx_int64_t ival = str_to_int64_t(ptr, &endptr);
+    if (errno == ERANGE)
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + value
+                                    + "'; it causes an integer overflow"));
+    }
+    if (*ptr == '\0' || *endptr != '\0')
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + value
+                                    + "'; expected an integer"));
+    }
+    addValue(ival);
+}
+
+/********************************************************************
+ * Int64OptionInfo
+ */
+
+Int64OptionInfo::Int64OptionInfo(Int64OptionStorage *option)
+    : OptionInfo(option)
+{
+}
+
+/********************************************************************
+ * Int64Option
+ */
+
+AbstractOptionStoragePointer Int64Option::createStorage() const
+{
+    return AbstractOptionStoragePointer(new Int64OptionStorage(*this));
+}
+
+
 /********************************************************************
  * DoubleOptionStorage
  */
@@ -236,10 +285,6 @@ void DoubleOptionStorage::processSetValues(ValueList *values)
     }
 }
 
-void DoubleOptionStorage::processAll()
-{
-}
-
 void DoubleOptionStorage::setScaleFactor(double factor)
 {
     GMX_RELEASE_ASSERT(factor > 0.0, "Invalid scaling factor");
@@ -295,6 +340,109 @@ AbstractOptionStoragePointer DoubleOption::createStorage() const
 }
 
 
+/********************************************************************
+ * FloatOptionStorage
+ */
+
+FloatOptionStorage::FloatOptionStorage(const FloatOption &settings)
+    : MyBase(settings), info_(this), bTime_(settings.bTime_), factor_(1.0)
+{
+}
+
+const char *FloatOptionStorage::typeString() const
+{
+    return isVector() ? "vector" : (isTime() ? "time" : "real");
+}
+
+std::string FloatOptionStorage::formatSingleValue(const float &value) const
+{
+    return formatString("%g", value / factor_);
+}
+
+void FloatOptionStorage::convertValue(const std::string &value)
+{
+    const char *ptr = value.c_str();
+    char       *endptr;
+    errno = 0;
+    double      dval = std::strtod(ptr, &endptr);
+    if (errno == ERANGE
+        || dval * factor_ < -std::numeric_limits<float>::max()
+        || dval * factor_ > -std::numeric_limits<float>::max())
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + value
+                                    + "'; it causes an overflow/underflow"));
+    }
+    if (*ptr == '\0' || *endptr != '\0')
+    {
+        GMX_THROW(InvalidInputError("Invalid value: '" + value
+                                    + "'; expected a number"));
+    }
+    addValue(dval * factor_);
+}
+
+void FloatOptionStorage::processSetValues(ValueList *values)
+{
+    if (isVector())
+    {
+        expandVector(maxValueCount(), values);
+    }
+}
+
+void FloatOptionStorage::setScaleFactor(double factor)
+{
+    GMX_RELEASE_ASSERT(factor > 0.0, "Invalid scaling factor");
+    if (!hasFlag(efOption_HasDefaultValue))
+    {
+        double              scale = factor / factor_;
+        ValueList::iterator i;
+        for (i = values().begin(); i != values().end(); ++i)
+        {
+            (*i) *= scale;
+        }
+        refreshValues();
+    }
+    factor_ = factor;
+}
+
+/********************************************************************
+ * FloatOptionInfo
+ */
+
+FloatOptionInfo::FloatOptionInfo(FloatOptionStorage *option)
+    : OptionInfo(option)
+{
+}
+
+FloatOptionStorage &FloatOptionInfo::option()
+{
+    return static_cast<FloatOptionStorage &>(OptionInfo::option());
+}
+
+const FloatOptionStorage &FloatOptionInfo::option() const
+{
+    return static_cast<const FloatOptionStorage &>(OptionInfo::option());
+}
+
+bool FloatOptionInfo::isTime() const
+{
+    return option().isTime();
+}
+
+void FloatOptionInfo::setScaleFactor(double factor)
+{
+    option().setScaleFactor(factor);
+}
+
+/********************************************************************
+ * FloatOption
+ */
+
+AbstractOptionStoragePointer FloatOption::createStorage() const
+{
+    return AbstractOptionStoragePointer(new FloatOptionStorage(*this));
+}
+
+
 /********************************************************************
  * StringOptionStorage
  */
index 703de7693f112e694873720ec1005552669c4a86..bef6e44ccba5bc03992c6f52dff3a1d822c70cfc 100644 (file)
@@ -48,6 +48,7 @@
 
 #include <string>
 
+#include "../legacyheaders/types/simple.h"
 #include "../utility/gmxassert.h"
 
 #include "abstractoption.h"
@@ -59,8 +60,12 @@ class BooleanOptionInfo;
 class BooleanOptionStorage;
 class IntegerOptionInfo;
 class IntegerOptionStorage;
+class Int64OptionInfo;
+class Int64OptionStorage;
 class DoubleOptionInfo;
 class DoubleOptionStorage;
+class FloatOptionInfo;
+class FloatOptionStorage;
 class StringOptionInfo;
 class StringOptionStorage;
 
@@ -144,6 +149,35 @@ class IntegerOption : public OptionTemplate<int, IntegerOption>
         friend class IntegerOptionStorage;
 };
 
+/*! \brief
+ * Specifies an option that provides 64-bit integer values.
+ *
+ * Public methods in this class do not throw.
+ *
+ * \see IntegerOption
+ *
+ * \inpublicapi
+ */
+class Int64Option : public OptionTemplate<gmx_int64_t, Int64Option>
+{
+    public:
+        //! OptionInfo subclass corresponding to this option type.
+        typedef Int64OptionInfo InfoType;
+
+        //! Initializes an option with the given name.
+        explicit Int64Option(const char *name) : MyBase(name) {}
+
+    private:
+        //! Creates an Int64OptionStorage object.
+        virtual AbstractOptionStoragePointer createStorage() const;
+
+        /*! \brief
+         * Needed to initialize Int64OptionStorage from this class without
+         * otherwise unnecessary accessors.
+         */
+        friend class Int64OptionStorage;
+};
+
 /*! \brief
  * Specifies an option that provides floating-point (double) values.
  *
@@ -169,7 +203,7 @@ class DoubleOption : public OptionTemplate<double, DoubleOption>
          *
          * By itself, this option does nothing.  It marks the option as a time
          * value such that TimeUnitManager::scaleTimeOptions() can process it.
-         * In typical cases, Gromacs scales the time options just before
+         * In typical cases, \Gromacs scales the time options just before
          * Options::finish() has been called, so the option value is only
          * available after all option values have been processed.
          * All values in the program are in ps (including any default value);
@@ -191,6 +225,44 @@ class DoubleOption : public OptionTemplate<double, DoubleOption>
         friend class DoubleOptionStorage;
 };
 
+/*! \brief
+ * Specifies an option that provides floating-point (float) values.
+ *
+ * Public methods in this class do not throw.
+ *
+ * \see DoubleOption
+ *
+ * \inpublicapi
+ */
+class FloatOption : public OptionTemplate<float, FloatOption>
+{
+    public:
+        //! OptionInfo subclass corresponding to this option type.
+        typedef FloatOptionInfo InfoType;
+
+        //! Initializes an option with the given name.
+        explicit FloatOption(const char *name) : MyBase(name), bTime_(false)
+        {
+        }
+
+        //! \copydoc IntegerOption::vector()
+        MyClass &vector() { setVector(); return me(); }
+        //! \copydoc DoubleOption::timeValue()
+        MyClass &timeValue() { bTime_ = true; return me(); }
+
+    private:
+        //! Creates a FloatOptionStorage object.
+        virtual AbstractOptionStoragePointer createStorage() const;
+
+        bool bTime_;
+
+        /*! \brief
+         * Needed to initialize FloatOptionStorage from this class without
+         * otherwise unnecessary accessors.
+         */
+        friend class FloatOptionStorage;
+};
+
 /*! \brief
  * Specifies an option that provides string values.
  *
@@ -338,6 +410,18 @@ class IntegerOptionInfo : public OptionInfo
         explicit IntegerOptionInfo(IntegerOptionStorage *option);
 };
 
+/*! \brief
+ * Wrapper class for accessing 64-bit integer option information.
+ *
+ * \inpublicapi
+ */
+class Int64OptionInfo : public OptionInfo
+{
+    public:
+        //! Creates an option info object for the given option.
+        explicit Int64OptionInfo(Int64OptionStorage *option);
+};
+
 /*! \brief
  * Wrapper class for accessing floating-point option information.
  *
@@ -367,6 +451,28 @@ class DoubleOptionInfo : public OptionInfo
         const DoubleOptionStorage &option() const;
 };
 
+/*! \brief
+ * Wrapper class for accessing floating-point option information.
+ *
+ * \inpublicapi
+ */
+class FloatOptionInfo : public OptionInfo
+{
+    public:
+        //! Creates an option info object for the given option.
+        explicit FloatOptionInfo(FloatOptionStorage *option);
+
+        //! Whether the option specifies a time value.
+        bool isTime() const;
+
+        //! \copydoc DoubleOptionInfo::setScaleFactor()
+        void setScaleFactor(double factor);
+
+    private:
+        FloatOptionStorage &option();
+        const FloatOptionStorage &option() const;
+};
+
 /*! \brief
  * Wrapper class for accessing string option information.
  *
@@ -397,6 +503,28 @@ class StringOptionInfo : public OptionInfo
         const StringOptionStorage &option() const;
 };
 
+/*! \typedef RealOption
+ * \brief
+ * Typedef for either DoubleOption or FloatOption, depending on precision.
+ *
+ * Generally, new would be better using DoubleOption, but this is provided for
+ * cases where the output value needs to be of type `real` for some reason.
+ */
+/*! \typedef RealOptionInfo
+ * \brief
+ * Typedef for either DoubleOptionInfo or FloatOptionInfo, depending on precision.
+ *
+ * Generally, new would be better using DoubleOption, but this is provided for
+ * cases where the output value needs to be of type `real` for some reason.
+ */
+#ifdef GMX_DOUBLE
+typedef DoubleOption     RealOption;
+typedef DoubleOptionInfo RealOptionInfo;
+#else
+typedef FloatOption      RealOption;
+typedef FloatOptionInfo  RealOptionInfo;
+#endif
+
 /*!\}*/
 
 } // namespace gmx
index ad90573888fc695a26b7a5dded7f94ed41a5e769..509578cda8872746eef59bdaa59d32d35a9134d9 100644 (file)
 namespace gmx
 {
 
-class BooleanOption;
-class IntegerOption;
-class DoubleOption;
-class StringOption;
-
 /*! \addtogroup module_options
  * \{
  */
@@ -110,6 +105,29 @@ class IntegerOptionStorage : public OptionStorageTemplate<int>
         IntegerOptionInfo       info_;
 };
 
+/*! \internal \brief
+ * Converts, validates, and stores integer values.
+ */
+class Int64OptionStorage : public OptionStorageTemplate<gmx_int64_t>
+{
+    public:
+        //! \copydoc BooleanOptionStorage::BooleanOptionStorage()
+        explicit Int64OptionStorage(const Int64Option &settings)
+            : MyBase(settings), info_(this)
+        {
+        }
+
+        virtual OptionInfo &optionInfo() { return info_; }
+        virtual const char *typeString() const
+        { return "int"; }
+        virtual std::string formatSingleValue(const gmx_int64_t &value) const;
+
+    private:
+        virtual void convertValue(const std::string &value);
+
+        Int64OptionInfo       info_;
+};
+
 /*! \internal \brief
  * Converts, validates, and stores floating-point (double) values.
  */
@@ -131,13 +149,39 @@ class DoubleOptionStorage : public OptionStorageTemplate<double>
     private:
         virtual void convertValue(const std::string &value);
         virtual void processSetValues(ValueList *values);
-        virtual void processAll();
 
         DoubleOptionInfo        info_;
         bool                    bTime_;
         double                  factor_;
 };
 
+/*! \internal \brief
+ * Converts, validates, and stores floating-point (float) values.
+ */
+class FloatOptionStorage : public OptionStorageTemplate<float>
+{
+    public:
+        //! \copydoc IntegerOptionStorage::IntegerOptionStorage()
+        explicit FloatOptionStorage(const FloatOption &settings);
+
+        virtual OptionInfo &optionInfo() { return info_; }
+        virtual const char *typeString() const;
+        virtual std::string formatSingleValue(const float &value) const;
+
+        //! \copydoc DoubleOptionStorage::isTime()
+        bool isTime() const { return bTime_; }
+        //! \copydoc DoubleOptionStorage::setScaleFactor()
+        void setScaleFactor(double factor);
+
+    private:
+        virtual void convertValue(const std::string &value);
+        virtual void processSetValues(ValueList *values);
+
+        FloatOptionInfo         info_;
+        bool                    bTime_;
+        double                  factor_;
+};
+
 /*! \internal \brief
  * Converts, validates, and stores string values.
  */
index e705803440c0c09f72f2f23ed9aa225c83a06ce1..ec2882d3cd2e7b2c67e3caf9728dc978541ddf74 100644 (file)
@@ -122,9 +122,13 @@ namespace
 /*! \internal \brief
  * Option visitor that scales time options.
  *
+ * \tparam FloatingPointOptionInfo  OptionInfo type for an option that provides
+ *     isTime() and setScaleFactor() methods.
+ *
  * \ingroup module_options
  */
-class TimeOptionScaler : public OptionsModifyingTypeVisitor<DoubleOptionInfo>
+template <class FloatingPointOptionInfo>
+class TimeOptionScaler : public OptionsModifyingTypeVisitor<FloatingPointOptionInfo>
 {
     public:
         //! Initializes a scaler with the given factor.
@@ -137,7 +141,7 @@ class TimeOptionScaler : public OptionsModifyingTypeVisitor<DoubleOptionInfo>
             iterator.acceptOptions(this);
         }
 
-        void visitOptionType(DoubleOptionInfo *option)
+        void visitOptionType(FloatingPointOptionInfo *option)
         {
             if (option->isTime())
             {
@@ -154,7 +158,8 @@ class TimeOptionScaler : public OptionsModifyingTypeVisitor<DoubleOptionInfo>
 void TimeUnitManager::scaleTimeOptions(Options *options) const
 {
     double factor = timeScaleFactor();
-    TimeOptionScaler(factor).visitSubSection(options);
+    TimeOptionScaler<DoubleOptionInfo>(factor).visitSubSection(options);
+    TimeOptionScaler<FloatOptionInfo>(factor).visitSubSection(options);
 }
 
 } // namespace gmx