Remove Options::isSet()
[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,2015, 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 "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       storeIsSet_(settings.storeIsSet_),
64       minValueCount_(settings.minValueCount_),
65       maxValueCount_(settings.maxValueCount_),
66       bInSet_(false), bSetValuesHadErrors_(false)
67 {
68     // Check that user has not provided incorrect values for vectors.
69     if (hasFlag(efOption_Vector) && (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     if (settings.descr_ != NULL)
79     {
80         descr_ = settings.descr_;
81     }
82     if (storeIsSet_ != NULL)
83     {
84         *storeIsSet_ = false;
85     }
86     setFlag(efOption_ClearOnNextSet);
87 }
88
89 AbstractOptionStorage::~AbstractOptionStorage()
90 {
91 }
92
93 bool AbstractOptionStorage::isBoolean() const
94 {
95     return dynamic_cast<const BooleanOptionStorage *>(this) != NULL;
96 }
97
98 void AbstractOptionStorage::startSource()
99 {
100     setFlag(efOption_ClearOnNextSet);
101 }
102
103 void AbstractOptionStorage::startSet()
104 {
105     GMX_RELEASE_ASSERT(!bInSet_, "finishSet() not called");
106     // The last condition takes care of the situation where multiple
107     // sources are used, and a later source should be able to reassign
108     // the value even though the option is already set.
109     if (isSet() && !hasFlag(efOption_MultipleTimes)
110         && !hasFlag(efOption_ClearOnNextSet))
111     {
112         GMX_THROW(InvalidInputError("Option specified multiple times"));
113     }
114     clearSet();
115     bInSet_              = true;
116     bSetValuesHadErrors_ = false;
117 }
118
119 void AbstractOptionStorage::appendValue(const std::string &value)
120 {
121     GMX_RELEASE_ASSERT(bInSet_, "startSet() not called");
122     try
123     {
124         convertValue(value);
125     }
126     catch (...)
127     {
128         bSetValuesHadErrors_ = true;
129         throw;
130     }
131 }
132
133 void AbstractOptionStorage::markAsSet()
134 {
135     setFlag(efOption_Set);
136     if (storeIsSet_ != NULL)
137     {
138         *storeIsSet_ = true;
139     }
140 }
141
142 void AbstractOptionStorage::finishSet()
143 {
144     GMX_RELEASE_ASSERT(bInSet_, "startSet() not called");
145     bInSet_ = false;
146     // We mark the option as set even when there are errors to avoid additional
147     // errors from required options not set.
148     // TODO: There could be a separate flag for this purpose.
149     markAsSet();
150     if (!bSetValuesHadErrors_)
151     {
152         // TODO: Correct handling of the efOption_ClearOnNextSet requires
153         // processSet() and/or convertValue() to check it internally.
154         // OptionStorageTemplate takes care of it, but it's error-prone if
155         // a custom option is implemented that doesn't use it.
156         processSet();
157     }
158     bSetValuesHadErrors_ = false;
159     clearFlag(efOption_ClearOnNextSet);
160     clearSet();
161 }
162
163 void AbstractOptionStorage::finish()
164 {
165     GMX_RELEASE_ASSERT(!bInSet_, "finishSet() not called");
166     processAll();
167     if (isRequired() && !(isSet() || hasFlag(efOption_ExplicitDefaultValue)))
168     {
169         GMX_THROW(InvalidInputError("Option is required, but not set"));
170     }
171 }
172
173 void AbstractOptionStorage::setMinValueCount(int count)
174 {
175     GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes),
176                        "setMinValueCount() not supported with efOption_MultipleTimes");
177     GMX_RELEASE_ASSERT(count >= 0, "Invalid value count");
178     minValueCount_ = count;
179     if (isSet() && !hasFlag(efOption_DontCheckMinimumCount)
180         && valueCount() < minValueCount_)
181     {
182         GMX_THROW(InvalidInputError("Too few values"));
183     }
184 }
185
186 void AbstractOptionStorage::setMaxValueCount(int count)
187 {
188     GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes),
189                        "setMaxValueCount() not supported with efOption_MultipleTimes");
190     GMX_RELEASE_ASSERT(count >= -1, "Invalid value count");
191     maxValueCount_ = count;
192     if (isSet() && maxValueCount_ >= 0 && valueCount() > maxValueCount_)
193     {
194         GMX_THROW(InvalidInputError("Too many values"));
195     }
196 }
197
198 /********************************************************************
199  * OptionInfo
200  */
201
202 /*! \cond libapi */
203 OptionInfo::OptionInfo(AbstractOptionStorage *option)
204     : option_(*option)
205 {
206 }
207 //! \endcond
208
209 OptionInfo::~OptionInfo()
210 {
211 }
212
213 bool OptionInfo::isSet() const
214 {
215     return option().isSet();
216 }
217
218 bool OptionInfo::isHidden() const
219 {
220     return option().isHidden();
221 }
222
223 bool OptionInfo::isRequired() const
224 {
225     return option().isRequired();
226 }
227
228 int OptionInfo::minValueCount() const
229 {
230     if (option().defaultValueIfSetExists())
231     {
232         return 0;
233     }
234     return option().minValueCount();
235 }
236
237 int OptionInfo::maxValueCount() const
238 {
239     return option().maxValueCount();
240 }
241
242 const std::string &OptionInfo::name() const
243 {
244     return option().name();
245 }
246
247 std::string OptionInfo::type() const
248 {
249     return option().typeString();
250 }
251
252 std::string OptionInfo::formatDescription() const
253 {
254     std::string description(option().description());
255     std::string extraDescription(option().formatExtraDescription());
256     if (!extraDescription.empty())
257     {
258         description.append(extraDescription);
259     }
260     return description;
261 }
262
263 std::string OptionInfo::formatDefaultValueIfSet() const
264 {
265     return option().formatDefaultValueIfSet();
266 }
267
268 int OptionInfo::valueCount() const
269 {
270     return option().valueCount();
271 }
272
273 std::string OptionInfo::formatValue(int i) const
274 {
275     return option().formatValue(i);
276 }
277
278 } // namespace gmx