Replace EnumOption with EnumerationArrayOption
[alexxy/gromacs.git] / src / gromacs / options / basicoptions.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2010-2018, The GROMACS development team.
5  * Copyright (c) 2019,2020, by the GROMACS development team, led by
6  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7  * and including many others, as listed in the AUTHORS file in the
8  * top-level source directory and at http://www.gromacs.org.
9  *
10  * GROMACS is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * as published by the Free Software Foundation; either version 2.1
13  * of the License, or (at your option) any later version.
14  *
15  * GROMACS is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with GROMACS; if not, see
22  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
24  *
25  * If you want to redistribute modifications to GROMACS, please
26  * consider that scientific software is very special. Version
27  * control is crucial - bugs must be traceable. We will be happy to
28  * consider code for inclusion in the official distribution, but
29  * derived work must not be called official GROMACS. Details are found
30  * in the README & COPYING files - if they are missing, get the
31  * official version at http://www.gromacs.org.
32  *
33  * To help us fund GROMACS development, we humbly ask that you cite
34  * the research papers on the package. Check out http://www.gromacs.org.
35  */
36 /*! \file
37  * \brief
38  * Declares option objects for basic option types.
39  *
40  * Together with options.h, this header forms the part of the public API
41  * that most classes will use to provide options.
42  *
43  * \author Teemu Murtola <teemu.murtola@gmail.com>
44  * \inpublicapi
45  * \ingroup module_options
46  */
47 #ifndef GMX_OPTIONS_BASICOPTIONS_H
48 #define GMX_OPTIONS_BASICOPTIONS_H
49
50 #include <memory>
51 #include <string>
52 #include <vector>
53
54 #include "gromacs/options/abstractoption.h"
55 #include "gromacs/utility/arrayref.h"
56 #include "gromacs/utility/basedefinitions.h"
57 #include "gromacs/utility/enumerationhelpers.h"
58 #include "gromacs/utility/gmxassert.h"
59
60 #include "ivaluestore.h"
61
62 namespace gmx
63 {
64
65 class BooleanOptionInfo;
66 class BooleanOptionStorage;
67 class IntegerOptionInfo;
68 class IntegerOptionStorage;
69 class Int64OptionInfo;
70 class Int64OptionStorage;
71 class DoubleOptionInfo;
72 class DoubleOptionStorage;
73 class FloatOptionInfo;
74 class FloatOptionStorage;
75 class StringOptionInfo;
76 class StringOptionStorage;
77 class EnumOptionInfo;
78 class EnumOptionStorage;
79
80 //! \addtogroup module_options
81 //! \{
82
83 /*! \brief
84  * Specifies an option that provides boolean values.
85  *
86  * Example:
87  * \code
88    bool  bPBC;
89    using gmx::BooleanOption;
90    options.addOption(BooleanOption("pbc").store(&bPBC));
91  * \endcode
92  *
93  * Public methods in this class do not throw.
94  *
95  * \inpublicapi
96  */
97 class BooleanOption : public OptionTemplate<bool, BooleanOption>
98 {
99 public:
100     //! OptionInfo subclass corresponding to this option type.
101     typedef BooleanOptionInfo InfoType;
102
103     //! Initializes an option with the given name.
104     explicit BooleanOption(const char* name) : MyBase(name) {}
105
106 private:
107     //! Creates a BooleanOptionStorage object.
108     AbstractOptionStorage* createStorage(const OptionManagerContainer& managers) const override;
109 };
110
111 /*! \brief
112  * Specifies an option that provides integer values.
113  *
114  * Examples:
115  * \code
116    using gmx::IntegerOption;
117    // Simple option
118    int  rcut = 0;
119    options.addOption(IntegerOption("rcut").store(&rcut));
120    // Vector-valued option
121    int  box[3] = {1, 1, 1};  // Default value
122    options.addOption(IntegerOption("box").store(box).vector());
123  * \endcode
124  *
125  * Public methods in this class do not throw.
126  *
127  * \inpublicapi
128  */
129 class IntegerOption : public OptionTemplate<int, IntegerOption>
130 {
131 public:
132     //! OptionInfo subclass corresponding to this option type.
133     typedef IntegerOptionInfo InfoType;
134
135     //! Initializes an option with the given name.
136     explicit IntegerOption(const char* name) : MyBase(name) {}
137
138     /*! \brief
139      * Sets the option to return a vector value.
140      *
141      * A vector value returns a fixed number of values, the default being
142      * three (can be changed with valueCount()).  However, it also accepts
143      * a single value, in which case the value is used to fill the whole
144      * vector.
145      */
146     MyClass& vector()
147     {
148         setVector();
149         return me();
150     }
151
152 private:
153     //! Creates an IntegerOptionStorage object.
154     AbstractOptionStorage* createStorage(const OptionManagerContainer& managers) const override;
155
156     /*! \brief
157      * Needed to initialize IntegerOptionStorage from this class without
158      * otherwise unnecessary accessors.
159      */
160     friend class IntegerOptionStorage;
161 };
162
163 /*! \brief
164  * Specifies an option that provides 64-bit integer values.
165  *
166  * Public methods in this class do not throw.
167  *
168  * \see IntegerOption
169  *
170  * \inpublicapi
171  */
172 class Int64Option : public OptionTemplate<int64_t, Int64Option>
173 {
174 public:
175     //! OptionInfo subclass corresponding to this option type.
176     typedef Int64OptionInfo InfoType;
177
178     //! Initializes an option with the given name.
179     explicit Int64Option(const char* name) : MyBase(name) {}
180
181 private:
182     //! Creates an Int64OptionStorage object.
183     AbstractOptionStorage* createStorage(const OptionManagerContainer& managers) const override;
184
185     /*! \brief
186      * Needed to initialize Int64OptionStorage from this class without
187      * otherwise unnecessary accessors.
188      */
189     friend class Int64OptionStorage;
190 };
191
192 /*! \brief
193  * Specifies an option that provides floating-point (double) values.
194  *
195  * Public methods in this class do not throw.
196  *
197  * \inpublicapi
198  */
199 class DoubleOption : public OptionTemplate<double, DoubleOption>
200 {
201 public:
202     //! OptionInfo subclass corresponding to this option type.
203     typedef DoubleOptionInfo InfoType;
204
205     //! Initializes an option with the given name.
206     explicit DoubleOption(const char* name) : MyBase(name), bTime_(false) {}
207
208     //! \copydoc IntegerOption::vector()
209     MyClass& vector()
210     {
211         setVector();
212         return me();
213     }
214     /*! \brief
215      * Marks this option as providing a time value whose unit can be changed.
216      *
217      * By itself, this option does nothing.  It marks the option as a time
218      * value such that TimeUnitManager::scaleTimeOptions() can process it.
219      * In typical cases, \Gromacs scales the time options just before
220      * Options::finish() has been called, so the option value is only
221      * available after all option values have been processed.
222      * All values in the program are in ps (including any default value);
223      * user-provided values are scaled according to the time unit set in
224      * TimeUnitManager.
225      */
226     MyClass& timeValue()
227     {
228         bTime_ = true;
229         return me();
230     }
231
232 private:
233     //! Creates a DoubleOptionStorage object.
234     AbstractOptionStorage* createStorage(const OptionManagerContainer& managers) const override;
235
236     bool bTime_;
237
238     /*! \brief
239      * Needed to initialize DoubleOptionStorage from this class without
240      * otherwise unnecessary accessors.
241      */
242     friend class DoubleOptionStorage;
243 };
244
245 /*! \brief
246  * Specifies an option that provides floating-point (float) values.
247  *
248  * Public methods in this class do not throw.
249  *
250  * \see DoubleOption
251  *
252  * \inpublicapi
253  */
254 class FloatOption : public OptionTemplate<float, FloatOption>
255 {
256 public:
257     //! OptionInfo subclass corresponding to this option type.
258     typedef FloatOptionInfo InfoType;
259
260     //! Initializes an option with the given name.
261     explicit FloatOption(const char* name) : MyBase(name), bTime_(false) {}
262
263     //! \copydoc IntegerOption::vector()
264     MyClass& vector()
265     {
266         setVector();
267         return me();
268     }
269     //! \copydoc DoubleOption::timeValue()
270     MyClass& timeValue()
271     {
272         bTime_ = true;
273         return me();
274     }
275
276 private:
277     //! Creates a FloatOptionStorage object.
278     AbstractOptionStorage* createStorage(const OptionManagerContainer& managers) const override;
279
280     bool bTime_;
281
282     /*! \brief
283      * Needed to initialize FloatOptionStorage from this class without
284      * otherwise unnecessary accessors.
285      */
286     friend class FloatOptionStorage;
287 };
288
289 /*! \brief
290  * Specifies an option that provides string values.
291  *
292  * Examples:
293  * \code
294    using gmx::StringOption;
295    // Simple option
296    std::string  str;
297    options.addOption(StringOption("str").store(&str));
298    // Option that only accepts predefined values
299    const char * const  allowed[] = { "atom", "residue", "molecule" };
300    std::string  str;
301    options.addOption(StringOption("type").enumValue(allowed).store(&str));
302  * \endcode
303  *
304  * Public methods in this class do not throw.
305  *
306  * \inpublicapi
307  */
308 class StringOption : public OptionTemplate<std::string, StringOption>
309 {
310 public:
311     //! OptionInfo subclass corresponding to this option type.
312     typedef StringOptionInfo InfoType;
313
314     //! Initializes an option with the given name.
315     explicit StringOption(const char* name) :
316         MyBase(name),
317         enumValues_(nullptr),
318         enumValuesCount_(0),
319         defaultEnumIndex_(-1)
320     {
321     }
322
323     /*! \brief
324      * Sets the option to only accept one of a fixed set of strings.
325      *
326      * \param[in] values  Array of strings to accept.
327      *
328      * Also accepts prefixes of the strings; if a prefix matches more than
329      * one of the possible strings, the shortest one is used (in a tie, the
330      * first one is).
331      *
332      * The strings are copied once the option is created.
333      */
334     template<size_t count>
335     MyClass& enumValue(const char* const (&values)[count])
336     {
337         GMX_ASSERT(enumValues_ == nullptr, "Multiple sets of enumerated values specified");
338         enumValues_      = values;
339         enumValuesCount_ = count;
340         return me();
341     }
342     /*! \brief
343      * Sets the option to only accept one of a fixed set of strings.
344      *
345      * \param[in] values  Array of strings to accept, with a NULL pointer
346      *      following the last string.
347      *
348      * Works otherwise as the array version, but accepts a pointer to
349      * an array of undetermined length.  The end of the array is indicated
350      * by a NULL pointer in the array.
351      *
352      * \see enumValue()
353      */
354     MyClass& enumValueFromNullTerminatedArray(const char* const* values)
355     {
356         GMX_ASSERT(enumValues_ == nullptr, "Multiple sets of enumerated values specified");
357         enumValues_      = values;
358         enumValuesCount_ = -1;
359         return me();
360     }
361     /*! \brief
362      * Sets the default value using an index into the enumeration table.
363      *
364      * Cannot be specified without enumValue().
365      */
366     MyClass& defaultEnumIndex(int index)
367     {
368         GMX_ASSERT(index >= 0, "Invalid enumeration index");
369         defaultEnumIndex_ = index;
370         return me();
371     }
372
373 private:
374     //! Creates a StringOptionStorage object.
375     AbstractOptionStorage* createStorage(const OptionManagerContainer& managers) const override;
376
377     const char* const* enumValues_;
378     int                enumValuesCount_;
379     int                defaultEnumIndex_;
380
381     /*! \brief
382      * Needed to initialize StringOptionStorage from this class without
383      * otherwise unnecessary accessors.
384      */
385     friend class StringOptionStorage;
386 };
387
388 //! \}
389
390 namespace internal
391 {
392
393 /*! \internal
394  * \brief
395  * Type-specific implementation for IOptionValueStore for an enum option.
396  *
397  * This class is instantiated for each enum type for which EnumOption is used,
398  * and takes care of managing `int`-to-`enum` conversions.  Having this part in
399  * the header allows the actual storage implementation to not be in the header,
400  * which would require exposing all the internals through this one header...
401  *
402  * \ingroup module_options
403  */
404 template<typename EnumType>
405 class EnumIndexStore : public IOptionValueStore<int>
406 {
407 public:
408     //! Initializes the storage for the given actual enum variables.
409     EnumIndexStore(EnumType* store, std::vector<EnumType>* storeVector) :
410         store_(store),
411         storeVector_(storeVector)
412     {
413         if (storeVector_ != nullptr)
414         {
415             for (EnumType value : *storeVector_)
416             {
417                 intStore_.push_back(static_cast<int>(value));
418             }
419         }
420         else if (store_ != nullptr)
421         {
422             // TODO: Copy more than one value if that would make sense.
423             intStore_.push_back(static_cast<int>(store_[0]));
424         }
425     }
426
427     int           valueCount() override { return ssize(intStore_); }
428     ArrayRef<int> values() override { return intStore_; }
429     void          clear() override
430     {
431         intStore_.clear();
432         if (storeVector_ != nullptr)
433         {
434             storeVector_->clear();
435         }
436     }
437     void reserve(size_t count) override
438     {
439         intStore_.reserve(intStore_.size() + count);
440         if (storeVector_ != nullptr)
441         {
442             storeVector_->reserve(storeVector_->size() + count);
443         }
444     }
445     void append(const int& value) override
446     {
447         const size_t count = intStore_.size();
448         intStore_.push_back(value);
449         if (store_ != nullptr)
450         {
451             store_[count] = static_cast<EnumType>(value);
452         }
453         if (storeVector_ != nullptr)
454         {
455             storeVector_->push_back(static_cast<EnumType>(value));
456         }
457     }
458
459 private:
460     //! Stores the integer values for values().
461     std::vector<int>       intStore_;
462     EnumType*              store_;
463     std::vector<EnumType>* storeVector_;
464 };
465
466 //! \cond internal
467 /*! \internal
468  * \brief
469  * Helper to create EnumOptionStorage instances.
470  *
471  * This function works as a proxy between EnumOption::createStorage() and the
472  * EnumOptionStorage constructor, such that the latter does not need to be
473  * exposed in the header.
474  *
475  * \ingroup module_options
476  */
477 AbstractOptionStorage* createEnumOptionStorage(const AbstractOption& option,
478                                                const char* const*    enumValues,
479                                                int                   count,
480                                                int                   defaultValue,
481                                                int                   defaultValueIfSet,
482                                                std::unique_ptr<IOptionValueStore<int>> store);
483 //! \endcond
484
485 } // namespace internal
486
487 //! \addtogroup module_options
488 //! \{
489
490 /*! \brief
491 * Specifies an option that accepts an EnumerationArray of string values and writes the
492 * selected index into an `enum` variable.
493 *
494 * \tparam EnumType  DataType of the variable that receives the values
495 *
496 * Examples:
497 * \code
498   enum class MyEnum { Atom, Res, Mol, Count } : int;
499   EnumerationArray<MyEnum, const char *> myEnumNames = { "atom", "residue", "molecule" };
500   MyEnum       value = MyEnum::Atom; // default value
501   options.addOption(EnumOption<MyEnum>("type").enumValue(myEnumNames).store(&value));
502 * \endcode
503 *
504 * storeCount() is not currently implemented for this option type, and
505 * providing multiple default values through an array passed to store() does
506 * not work consistently in all cases.
507 * In the current implementation, the values of the enum type should correspond
508 * to indices in the array passed to enumValue(), i.e., be consecutive
509 * starting from zero.  Only values corresponding to valid indices are accepted
510 * as parameters to, e.g., defaultValue().  However, other values can be used
511 * as the initial value of the variable (`value` in the above example), and
512 * those will be preserved if the option is not set.
513 *
514 * Public methods in this class do not throw.
515 *
516 * \inpublicapi
517 */
518 template<typename EnumType>
519 class EnumOption : public OptionTemplate<EnumType, EnumOption<EnumType>>
520 {
521 public:
522     //! OptionInfo subclass corresponding to this option type.
523     typedef EnumOptionInfo InfoType;
524
525     // This needs to be duplicated from OptionTemplate because this class
526     // is a template.
527     //! Short-hand for the base class.
528     typedef OptionTemplate<EnumType, EnumOption<EnumType>> MyBase;
529
530     //! Initializes an option with the given name.
531     explicit EnumOption(const char* name) : MyBase(name), enumValues_(nullptr), enumValuesCount_(0)
532     {
533     }
534
535     /*! \brief
536      * Sets the option to only accept one of a fixed set of strings.
537      *
538
539      * \param[in] values  Array of strings to accept.
540      *
541      * Also accepts prefixes of the strings; if a prefix matches more than
542      * one of the possible strings, the shortest one is used (in a tie, the
543      * first one is).
544      *
545      * The strings are copied once the option is created.
546      */
547     EnumOption& enumValue(const EnumerationArray<EnumType, const char*>& values)
548     {
549         GMX_ASSERT(enumValues_ == nullptr, "Multiple sets of enumerated values specified");
550         enumValues_      = values.data();
551         enumValuesCount_ = values.size();
552         return MyBase::me();
553     }
554
555 private:
556     //! Helper function to convert default values for storage initialization.
557     static int convertToInt(const EnumType* defaultValue)
558     {
559         return defaultValue != nullptr ? static_cast<int>(*defaultValue) : -1;
560     }
561
562     //! Creates a EnumOptionStorage object.
563     AbstractOptionStorage* createStorage(const OptionManagerContainer& /*managers*/) const override
564     {
565         // TODO: Implement storeCount() if necessary.
566         return internal::createEnumOptionStorage(*this, enumValues_, enumValuesCount_,
567                                                  convertToInt(MyBase::defaultValue()),
568                                                  convertToInt(MyBase::defaultValueIfSet()),
569                                                  std::make_unique<internal::EnumIndexStore<EnumType>>(
570                                                          MyBase::store(), MyBase::storeVector()));
571     }
572
573     const char* const* enumValues_;
574     int                enumValuesCount_;
575
576     /*! \brief
577      * Needed to initialize EnumOptionStorage from this class without
578      * otherwise unnecessary accessors.
579      */
580     friend class EnumOptionStorage;
581 };
582
583 /*! \brief
584 * Specifies an option that accepts enumerated string values and writes the
585 * selected index into an `enum` variable.
586 *
587 * \tparam EnumType  Type of the variable that receives the values
588 *     (can also be `int`).
589 *
590 * Examples:
591 * \code
592   enum MyEnum { eAtom, eRes, eMol };
593   using gmx::LegacyEnumOption;
594   const char * const  allowed[] = { "atom", "residue", "molecule" };
595   MyEnum       value = eAtom; // default value
596   options.addOption(LegacyEnumOption<MyEnum>("type").enumValue(allowed).store(&value));
597 * \endcode
598 *
599 * Works exactly as EnumOption.
600 *
601 * This is legacy support for pargsToOptions and can be removed when it
602 * is removed.  No new uses of it should be made.
603 *
604 * Public methods in this class do not throw.
605 *
606 * \inpublicapi
607 */
608 template<typename EnumType>
609 class LegacyEnumOption : public OptionTemplate<EnumType, LegacyEnumOption<EnumType>>
610 {
611 public:
612     //! OptionInfo subclass corresponding to this option type.
613     typedef EnumOptionInfo InfoType;
614
615     // This needs to be duplicated from OptionTemplate because this class
616     // is a template.
617     //! Short-hand for the base class.
618     typedef OptionTemplate<EnumType, LegacyEnumOption<EnumType>> MyBase;
619
620     //! Initializes an option with the given name.
621     explicit LegacyEnumOption(const char* name) :
622         MyBase(name),
623         enumValues_(nullptr),
624         enumValuesCount_(0)
625     {
626     }
627
628     /*! \brief
629      * Sets the option to only accept one of a fixed set of strings.
630      *
631      * \param[in] values  Array of strings to accept.
632      *
633      * Also accepts prefixes of the strings; if a prefix matches more than
634      * one of the possible strings, the shortest one is used (in a tie, the
635      * first one is).
636      *
637      * The strings are copied once the option is created.
638      */
639     template<size_t count>
640     LegacyEnumOption& enumValue(const char* const (&values)[count])
641     {
642         GMX_ASSERT(enumValues_ == nullptr, "Multiple sets of enumerated values specified");
643         enumValues_      = values;
644         enumValuesCount_ = count;
645         return MyBase::me();
646     }
647     /*! \brief
648      * Sets the option to only accept one of a fixed set of strings.
649      *
650      * \param[in] values  Array of strings to accept, with a NULL pointer
651      *      following the last string.
652      *
653      * Works otherwise as the array version, but accepts a pointer to
654      * an array of undetermined length.  The end of the array is indicated
655      * by a NULL pointer in the array.
656      *
657      * \see enumValue()
658      */
659     LegacyEnumOption& enumValueFromNullTerminatedArray(const char* const* values)
660     {
661         GMX_ASSERT(enumValues_ == nullptr, "Multiple sets of enumerated values specified");
662         enumValues_      = values;
663         enumValuesCount_ = -1;
664         return MyBase::me();
665     }
666
667 private:
668     //! Helper function to convert default values for storage initialization.
669     static int convertToInt(const EnumType* defaultValue)
670     {
671         return defaultValue != nullptr ? static_cast<int>(*defaultValue) : -1;
672     }
673
674     //! Creates a EnumOptionStorage object.
675     AbstractOptionStorage* createStorage(const OptionManagerContainer& /*managers*/) const override
676     {
677         // TODO: Implement storeCount() if necessary.
678         return internal::createEnumOptionStorage(*this, enumValues_, enumValuesCount_,
679                                                  convertToInt(MyBase::defaultValue()),
680                                                  convertToInt(MyBase::defaultValueIfSet()),
681                                                  std::make_unique<internal::EnumIndexStore<EnumType>>(
682                                                          MyBase::store(), MyBase::storeVector()));
683     }
684
685     const char* const* enumValues_;
686     int                enumValuesCount_;
687
688     /*! \brief
689      * Needed to initialize EnumOptionStorage from this class without
690      * otherwise unnecessary accessors.
691      */
692     friend class EnumOptionStorage;
693 };
694
695 /*! \brief
696  * Wrapper class for accessing boolean option information.
697  *
698  * \inpublicapi
699  */
700 class BooleanOptionInfo : public OptionInfo
701 {
702 public:
703     //! Creates an option info object for the given option.
704     explicit BooleanOptionInfo(BooleanOptionStorage* option);
705
706     //! Returns the default value for this option.
707     bool defaultValue() const;
708
709 private:
710     const BooleanOptionStorage& option() const;
711 };
712
713 /*! \brief
714  * Wrapper class for accessing integer option information.
715  *
716  * \inpublicapi
717  */
718 class IntegerOptionInfo : public OptionInfo
719 {
720 public:
721     //! Creates an option info object for the given option.
722     explicit IntegerOptionInfo(IntegerOptionStorage* option);
723 };
724
725 /*! \brief
726  * Wrapper class for accessing 64-bit integer option information.
727  *
728  * \inpublicapi
729  */
730 class Int64OptionInfo : public OptionInfo
731 {
732 public:
733     //! Creates an option info object for the given option.
734     explicit Int64OptionInfo(Int64OptionStorage* option);
735 };
736
737 /*! \brief
738  * Wrapper class for accessing floating-point option information.
739  *
740  * \inpublicapi
741  */
742 class DoubleOptionInfo : public OptionInfo
743 {
744 public:
745     //! Creates an option info object for the given option.
746     explicit DoubleOptionInfo(DoubleOptionStorage* option);
747
748     //! Whether the option specifies a time value.
749     bool isTime() const;
750
751     /*! \brief
752      * Sets a scale factor for user-provided values.
753      *
754      * Any user-provided value is scaled by the provided factor.
755      * Programmatically set default values are not scaled.
756      * If called multiple times, later calls override the previously set
757      * value.  In other words, the scaling is not cumulative.
758      */
759     void setScaleFactor(double factor);
760
761 private:
762     DoubleOptionStorage&       option();
763     const DoubleOptionStorage& option() const;
764 };
765
766 /*! \brief
767  * Wrapper class for accessing floating-point option information.
768  *
769  * \inpublicapi
770  */
771 class FloatOptionInfo : public OptionInfo
772 {
773 public:
774     //! Creates an option info object for the given option.
775     explicit FloatOptionInfo(FloatOptionStorage* option);
776
777     //! Whether the option specifies a time value.
778     bool isTime() const;
779
780     //! \copydoc DoubleOptionInfo::setScaleFactor()
781     void setScaleFactor(double factor);
782
783 private:
784     FloatOptionStorage&       option();
785     const FloatOptionStorage& option() const;
786 };
787
788 /*! \brief
789  * Wrapper class for accessing string option information.
790  *
791  * \inpublicapi
792  */
793 class StringOptionInfo : public OptionInfo
794 {
795 public:
796     //! Creates an option info object for the given option.
797     explicit StringOptionInfo(StringOptionStorage* option);
798
799     /*! \brief
800      * Whether this option accepts an enumerated set of values.
801      *
802      * Returns true if StringOption::enumValues() was used when creating
803      * this option.
804      */
805     bool isEnumerated() const;
806     /*! \brief
807      * Returns the set of allowed values for this option.
808      *
809      * Returns an empty vector if isEnumerated() returns false.
810      */
811     const std::vector<std::string>& allowedValues() const;
812
813 private:
814     const StringOptionStorage& option() const;
815 };
816
817 /*! \brief
818  * Wrapper class for accessing enum option information.
819  *
820  * \inpublicapi
821  */
822 class EnumOptionInfo : public OptionInfo
823 {
824 public:
825     //! Creates an option info object for the given option.
826     explicit EnumOptionInfo(EnumOptionStorage* option);
827
828     /*! \brief
829      * Returns the set of allowed values for this option.
830      */
831     const std::vector<std::string>& allowedValues() const;
832
833 private:
834     const EnumOptionStorage& option() const;
835 };
836
837 /*! \typedef RealOption
838  * \brief
839  * Typedef for either DoubleOption or FloatOption, depending on precision.
840  *
841  * Generally, new would be better using DoubleOption, but this is provided for
842  * cases where the output value needs to be of type `real` for some reason.
843  */
844 /*! \typedef RealOptionInfo
845  * \brief
846  * Typedef for either DoubleOptionInfo or FloatOptionInfo, depending on precision.
847  *
848  * Generally, new would be better using DoubleOption, but this is provided for
849  * cases where the output value needs to be of type `real` for some reason.
850  */
851 #if GMX_DOUBLE
852 typedef DoubleOption     RealOption;
853 typedef DoubleOptionInfo RealOptionInfo;
854 #else
855 typedef FloatOption     RealOption;
856 typedef FloatOptionInfo RealOptionInfo;
857 #endif
858
859 //! \}
860
861 } // namespace gmx
862
863 #endif