Merge origin/release-4-6 into master
[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/utility/exceptions.h"
43 #include "gromacs/utility/gmxassert.h"
44
45 #include "basicoptionstorage.h"
46
47 namespace gmx
48 {
49
50 /********************************************************************
51  * AbstractOptionStorage
52  */
53
54 AbstractOptionStorage::AbstractOptionStorage(const AbstractOption &settings,
55                                              OptionFlags staticFlags)
56     : flags_(settings.flags_ | staticFlags),
57       minValueCount_(settings.minValueCount_),
58       maxValueCount_(settings.maxValueCount_),
59       bInSet_(false), bSetValuesHadErrors_(false)
60 {
61     // Check that user has not provided incorrect values for vectors.
62     if (hasFlag(efOption_Vector) && (minValueCount_ > 1 || maxValueCount_ < 1))
63     {
64         GMX_THROW(APIError("Inconsistent value counts for vector values"));
65     }
66
67     if (settings.name_ != NULL)
68     {
69         name_  = settings.name_;
70     }
71     descr_ = settings.createDescription();
72     setFlag(efOption_ClearOnNextSet);
73 }
74
75 AbstractOptionStorage::~AbstractOptionStorage()
76 {
77 }
78
79 bool AbstractOptionStorage::isBoolean() const
80 {
81     return dynamic_cast<const BooleanOptionStorage *>(this) != NULL;
82 }
83
84 void AbstractOptionStorage::startSource()
85 {
86     setFlag(efOption_ClearOnNextSet);
87 }
88
89 void AbstractOptionStorage::startSet()
90 {
91     GMX_RELEASE_ASSERT(!bInSet_, "finishSet() not called");
92     // The last condition takes care of the situation where multiple
93     // sources are used, and a later source should be able to reassign
94     // the value even though the option is already set.
95     if (isSet() && !hasFlag(efOption_MultipleTimes)
96         && !hasFlag(efOption_ClearOnNextSet))
97     {
98         GMX_THROW(InvalidInputError("Option specified multiple times"));
99     }
100     clearSet();
101     bInSet_ = true;
102     bSetValuesHadErrors_ = false;
103 }
104
105 void AbstractOptionStorage::appendValue(const std::string &value)
106 {
107     GMX_RELEASE_ASSERT(bInSet_, "startSet() not called");
108     try
109     {
110         convertValue(value);
111     }
112     catch (...)
113     {
114         bSetValuesHadErrors_ = true;
115         throw;
116     }
117 }
118
119 void AbstractOptionStorage::finishSet()
120 {
121     GMX_RELEASE_ASSERT(bInSet_, "startSet() not called");
122     bInSet_ = false;
123     // We mark the option as set even when there are errors to avoid additional
124     // errors from required options not set.
125     // TODO: There could be a separate flag for this purpose.
126     setFlag(efOption_Set);
127     if (!bSetValuesHadErrors_)
128     {
129         // TODO: Correct handling of the efOption_ClearOnNextSet requires
130         // processSet() and/or convertValue() to check it internally.
131         // OptionStorageTemplate takes care of it, but it's error-prone if
132         // a custom option is implemented that doesn't use it.
133         processSet();
134     }
135     bSetValuesHadErrors_ = false;
136     clearFlag(efOption_ClearOnNextSet);
137     clearSet();
138 }
139
140 void AbstractOptionStorage::finish()
141 {
142     GMX_RELEASE_ASSERT(!bInSet_, "finishSet() not called");
143     processAll();
144     if (isRequired() && !(isSet() || hasFlag(efOption_ExplicitDefaultValue)))
145     {
146         GMX_THROW(InvalidInputError("Option is required, but not set"));
147     }
148 }
149
150 void AbstractOptionStorage::setMinValueCount(int count)
151 {
152     GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes),
153                        "setMinValueCount() not supported with efOption_MultipleTimes");
154     GMX_RELEASE_ASSERT(count >= 0, "Invalid value count");
155     minValueCount_ = count;
156     if (isSet() && !hasFlag(efOption_DontCheckMinimumCount)
157         && valueCount() < minValueCount_)
158     {
159         GMX_THROW(InvalidInputError("Too few values"));
160     }
161 }
162
163 void AbstractOptionStorage::setMaxValueCount(int count)
164 {
165     GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes),
166                        "setMaxValueCount() not supported with efOption_MultipleTimes");
167     GMX_RELEASE_ASSERT(count >= -1, "Invalid value count");
168     maxValueCount_ = count;
169     if (isSet() && maxValueCount_ >= 0 && valueCount() > maxValueCount_)
170     {
171         GMX_THROW(InvalidInputError("Too many values"));
172     }
173 }
174
175 /********************************************************************
176  * OptionInfo
177  */
178
179 /*! \cond libapi */
180 OptionInfo::OptionInfo(AbstractOptionStorage *option)
181     : option_(*option)
182 {
183 }
184 //! \endcond
185
186 OptionInfo::~OptionInfo()
187 {
188 }
189
190 bool OptionInfo::isSet() const
191 {
192     return option().isSet();
193 }
194
195 bool OptionInfo::isHidden() const
196 {
197     return option().isHidden();
198 }
199
200 bool OptionInfo::isRequired() const
201 {
202     return option().isRequired();
203 }
204
205 const std::string &OptionInfo::name() const
206 {
207     return option().name();
208 }
209
210 const std::string &OptionInfo::description() const
211 {
212     return option().description();
213 }
214
215 const char *OptionInfo::type() const
216 {
217     return option().typeString();
218 }
219
220 int OptionInfo::valueCount() const
221 {
222     return option().valueCount();
223 }
224
225 std::string OptionInfo::formatValue(int i) const
226 {
227     return option().formatValue(i);
228 }
229
230 std::string OptionInfo::formatDefaultValueIfSet() const
231 {
232     return option().formatDefaultValueIfSet();
233 }
234
235 } // namespace gmx