Merge branch 'release-4-6'
[alexxy/gromacs.git] / src / gromacs / options / abstractoption.cpp
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11  * Copyright (c) 2001-2009, The GROMACS development team,
12  * check out http://www.gromacs.org for more information.
13
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * If you want to redistribute modifications, please consider that
20  * scientific software is very special. Version control is crucial -
21  * bugs must be traceable. We will be happy to consider code for
22  * inclusion in the official distribution, but derived work must not
23  * be called official GROMACS. Details are found in the README & COPYING
24  * files - if they are missing, get the official version at www.gromacs.org.
25  *
26  * To help us fund GROMACS development, we humbly ask that you cite
27  * the papers on the package - you can find them in the top README file.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal \file
32  * \brief
33  * Implements classes in abstractoption.h and abstractoptionstorage.h.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \ingroup module_options
37  */
38 #include "gromacs/options/abstractoption.h"
39
40 #include "gromacs/options/abstractoptionstorage.h"
41 #include "gromacs/options/optionflags.h"
42 #include "gromacs/options/optioninfo.h"
43 #include "gromacs/utility/exceptions.h"
44 #include "gromacs/utility/gmxassert.h"
45
46 #include "basicoptionstorage.h"
47
48 namespace gmx
49 {
50
51 /********************************************************************
52  * AbstractOptionStorage
53  */
54
55 AbstractOptionStorage::AbstractOptionStorage(const AbstractOption &settings,
56                                              OptionFlags staticFlags)
57     : _flags(settings._flags | staticFlags),
58       _minValueCount(settings._minValueCount),
59       _maxValueCount(settings._maxValueCount),
60       _inSet(false)
61 {
62     // If the maximum number of values is not known, storage to
63     // caller-allocated memory is unsafe.
64     if ((_maxValueCount < 0 || hasFlag(efMulti)) && hasFlag(efExternalStore))
65     {
66         GMX_THROW(APIError("Cannot set user-allocated storage for arbitrary number of values"));
67     }
68     // Check that user has not provided incorrect values for vectors.
69     if (hasFlag(efVector) && (_minValueCount > 1 || _maxValueCount < 1))
70     {
71         GMX_THROW(APIError("Inconsistent value counts for vector values"));
72     }
73
74     if (settings._name != NULL)
75     {
76         _name  = settings._name;
77     }
78     _descr = settings.createDescription();
79 }
80
81 AbstractOptionStorage::~AbstractOptionStorage()
82 {
83 }
84
85 bool AbstractOptionStorage::isBoolean() const
86 {
87     return dynamic_cast<const BooleanOptionStorage *>(this) != NULL;
88 }
89
90 void AbstractOptionStorage::startSource()
91 {
92     setFlag(efClearOnNextSet);
93 }
94
95 void AbstractOptionStorage::startSet()
96 {
97     GMX_RELEASE_ASSERT(!_inSet, "finishSet() not called");
98     // The last condition takes care of the situation where multiple
99     // sources are used, and a later source should be able to reassign
100     // the value even though the option is already set.
101     if (isSet() && !hasFlag(efMulti) && !hasFlag(efClearOnNextSet))
102     {
103         GMX_THROW(InvalidInputError("Option specified multiple times"));
104     }
105     clearSet();
106     _inSet = true;
107 }
108
109 void AbstractOptionStorage::appendValue(const std::string &value)
110 {
111     GMX_RELEASE_ASSERT(_inSet, "startSet() not called");
112     convertValue(value);
113 }
114
115 void AbstractOptionStorage::finishSet()
116 {
117     GMX_RELEASE_ASSERT(_inSet, "startSet() not called");
118     _inSet = false;
119     // TODO: Should this be done only when processSet() does not throw?
120     setFlag(efSet);
121     processSet();
122 }
123
124 void AbstractOptionStorage::finish()
125 {
126     GMX_RELEASE_ASSERT(!_inSet, "finishSet() not called");
127     processAll();
128     if (hasFlag(efRequired) && !isSet())
129     {
130         GMX_THROW(InvalidInputError("Option is required, but not set"));
131     }
132 }
133
134 void AbstractOptionStorage::setMinValueCount(int count)
135 {
136     GMX_RELEASE_ASSERT(!hasFlag(efMulti),
137                        "setMinValueCount() not supported with efMulti");
138     GMX_RELEASE_ASSERT(count >= 0, "Invalid value count");
139     _minValueCount = count;
140     if (isSet()
141         && !hasFlag(efDontCheckMinimumCount) && valueCount() < _minValueCount)
142     {
143         GMX_THROW(InvalidInputError("Too few values"));
144     }
145 }
146
147 void AbstractOptionStorage::setMaxValueCount(int count)
148 {
149     GMX_RELEASE_ASSERT(!hasFlag(efMulti),
150                        "setMaxValueCount() not supported with efMulti");
151     GMX_RELEASE_ASSERT(count >= -1, "Invalid value count");
152     _maxValueCount = count;
153     if (isSet() && _maxValueCount >= 0 && valueCount() > _maxValueCount)
154     {
155         GMX_THROW(InvalidInputError("Too many values"));
156     }
157 }
158
159 /********************************************************************
160  * OptionInfo
161  */
162
163 /*! \cond libapi */
164 OptionInfo::OptionInfo(AbstractOptionStorage *option)
165     : option_(*option)
166 {
167 }
168 //! \endcond
169
170 OptionInfo::~OptionInfo()
171 {
172 }
173
174 bool OptionInfo::isSet() const
175 {
176     return option().isSet();
177 }
178
179 bool OptionInfo::isHidden() const
180 {
181     return option().isHidden();
182 }
183
184 bool OptionInfo::isRequired() const
185 {
186     return option().isRequired();
187 }
188
189 const std::string &OptionInfo::name() const
190 {
191     return option().name();
192 }
193
194 const std::string &OptionInfo::description() const
195 {
196     return option().description();
197 }
198
199 const char *OptionInfo::type() const
200 {
201     return option().typeString();
202 }
203
204 int OptionInfo::valueCount() const
205 {
206     return option().valueCount();
207 }
208
209 std::string OptionInfo::formatValue(int i) const
210 {
211     return option().formatValue(i);
212 }
213
214 std::string OptionInfo::formatDefaultValueIfSet() const
215 {
216     return option().formatDefaultValueIfSet();
217 }
218
219 } // namespace gmx