c81d0e2a56ae05bd6e1074b7f60f1700f2c1b676
[alexxy/gromacs.git] / src / gromacs / options / abstractoption.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 /*! \internal \file
36  * \brief
37  * Implements classes in abstractoption.h and abstractoptionstorage.h.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_options
41  */
42 #include "gmxpre.h"
43
44 #include "gromacs/options/abstractoption.h"
45
46 #include "gromacs/options/abstractoptionstorage.h"
47 #include "gromacs/options/optionflags.h"
48 #include "gromacs/utility/exceptions.h"
49 #include "gromacs/utility/gmxassert.h"
50
51 #include "basicoptionstorage.h"
52
53 namespace gmx
54 {
55
56 /********************************************************************
57  * AbstractOptionStorage
58  */
59
60 AbstractOptionStorage::AbstractOptionStorage(const AbstractOption &settings,
61                                              OptionFlags           staticFlags)
62     : flags_(settings.flags_ | staticFlags),
63       minValueCount_(settings.minValueCount_),
64       maxValueCount_(settings.maxValueCount_),
65       bInSet_(false), bSetValuesHadErrors_(false)
66 {
67     // Check that user has not provided incorrect values for vectors.
68     if (hasFlag(efOption_Vector) && (minValueCount_ > 1 || maxValueCount_ < 1))
69     {
70         GMX_THROW(APIError("Inconsistent value counts for vector values"));
71     }
72
73     if (settings.name_ != NULL)
74     {
75         name_  = settings.name_;
76     }
77     if (settings.descr_ != NULL)
78     {
79         descr_ = settings.descr_;
80     }
81     setFlag(efOption_ClearOnNextSet);
82 }
83
84 AbstractOptionStorage::~AbstractOptionStorage()
85 {
86 }
87
88 bool AbstractOptionStorage::isBoolean() const
89 {
90     return dynamic_cast<const BooleanOptionStorage *>(this) != NULL;
91 }
92
93 void AbstractOptionStorage::startSource()
94 {
95     setFlag(efOption_ClearOnNextSet);
96 }
97
98 void AbstractOptionStorage::startSet()
99 {
100     GMX_RELEASE_ASSERT(!bInSet_, "finishSet() not called");
101     // The last condition takes care of the situation where multiple
102     // sources are used, and a later source should be able to reassign
103     // the value even though the option is already set.
104     if (isSet() && !hasFlag(efOption_MultipleTimes)
105         && !hasFlag(efOption_ClearOnNextSet))
106     {
107         GMX_THROW(InvalidInputError("Option specified multiple times"));
108     }
109     clearSet();
110     bInSet_              = true;
111     bSetValuesHadErrors_ = false;
112 }
113
114 void AbstractOptionStorage::appendValue(const std::string &value)
115 {
116     GMX_RELEASE_ASSERT(bInSet_, "startSet() not called");
117     try
118     {
119         convertValue(value);
120     }
121     catch (...)
122     {
123         bSetValuesHadErrors_ = true;
124         throw;
125     }
126 }
127
128 void AbstractOptionStorage::finishSet()
129 {
130     GMX_RELEASE_ASSERT(bInSet_, "startSet() not called");
131     bInSet_ = false;
132     // We mark the option as set even when there are errors to avoid additional
133     // errors from required options not set.
134     // TODO: There could be a separate flag for this purpose.
135     setFlag(efOption_Set);
136     if (!bSetValuesHadErrors_)
137     {
138         // TODO: Correct handling of the efOption_ClearOnNextSet requires
139         // processSet() and/or convertValue() to check it internally.
140         // OptionStorageTemplate takes care of it, but it's error-prone if
141         // a custom option is implemented that doesn't use it.
142         processSet();
143     }
144     bSetValuesHadErrors_ = false;
145     clearFlag(efOption_ClearOnNextSet);
146     clearSet();
147 }
148
149 void AbstractOptionStorage::finish()
150 {
151     GMX_RELEASE_ASSERT(!bInSet_, "finishSet() not called");
152     processAll();
153     if (isRequired() && !(isSet() || hasFlag(efOption_ExplicitDefaultValue)))
154     {
155         GMX_THROW(InvalidInputError("Option is required, but not set"));
156     }
157 }
158
159 void AbstractOptionStorage::setMinValueCount(int count)
160 {
161     GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes),
162                        "setMinValueCount() not supported with efOption_MultipleTimes");
163     GMX_RELEASE_ASSERT(count >= 0, "Invalid value count");
164     minValueCount_ = count;
165     if (isSet() && !hasFlag(efOption_DontCheckMinimumCount)
166         && valueCount() < minValueCount_)
167     {
168         GMX_THROW(InvalidInputError("Too few values"));
169     }
170 }
171
172 void AbstractOptionStorage::setMaxValueCount(int count)
173 {
174     GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes),
175                        "setMaxValueCount() not supported with efOption_MultipleTimes");
176     GMX_RELEASE_ASSERT(count >= -1, "Invalid value count");
177     maxValueCount_ = count;
178     if (isSet() && maxValueCount_ >= 0 && valueCount() > maxValueCount_)
179     {
180         GMX_THROW(InvalidInputError("Too many values"));
181     }
182 }
183
184 /********************************************************************
185  * OptionInfo
186  */
187
188 /*! \cond libapi */
189 OptionInfo::OptionInfo(AbstractOptionStorage *option)
190     : option_(*option)
191 {
192 }
193 //! \endcond
194
195 OptionInfo::~OptionInfo()
196 {
197 }
198
199 bool OptionInfo::isSet() const
200 {
201     return option().isSet();
202 }
203
204 bool OptionInfo::isHidden() const
205 {
206     return option().isHidden();
207 }
208
209 bool OptionInfo::isRequired() const
210 {
211     return option().isRequired();
212 }
213
214 int OptionInfo::minValueCount() const
215 {
216     if (option().defaultValueIfSetExists())
217     {
218         return 0;
219     }
220     return option().minValueCount();
221 }
222
223 int OptionInfo::maxValueCount() const
224 {
225     return option().maxValueCount();
226 }
227
228 const std::string &OptionInfo::name() const
229 {
230     return option().name();
231 }
232
233 std::string OptionInfo::type() const
234 {
235     return option().typeString();
236 }
237
238 std::string OptionInfo::formatDescription() const
239 {
240     std::string description(option().description());
241     std::string extraDescription(option().formatExtraDescription());
242     if (!extraDescription.empty())
243     {
244         description.append(extraDescription);
245     }
246     return description;
247 }
248
249 std::string OptionInfo::formatDefaultValueIfSet() const
250 {
251     return option().formatDefaultValueIfSet();
252 }
253
254 int OptionInfo::valueCount() const
255 {
256     return option().valueCount();
257 }
258
259 std::string OptionInfo::formatValue(int i) const
260 {
261     return option().formatValue(i);
262 }
263
264 } // namespace gmx