Merge 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       _inSet(false)
60 {
61     // If the maximum number of values is not known, storage to
62     // caller-allocated memory is unsafe.
63     if ((_maxValueCount < 0 || hasFlag(efMulti)) && hasFlag(efExternalStore))
64     {
65         GMX_THROW(APIError("Cannot set user-allocated storage for arbitrary number of values"));
66     }
67     // Check that user has not provided incorrect values for vectors.
68     if (hasFlag(efVector) && (_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     _descr = settings.createDescription();
78 }
79
80 AbstractOptionStorage::~AbstractOptionStorage()
81 {
82 }
83
84 bool AbstractOptionStorage::isBoolean() const
85 {
86     return dynamic_cast<const BooleanOptionStorage *>(this) != NULL;
87 }
88
89 void AbstractOptionStorage::startSource()
90 {
91     setFlag(efClearOnNextSet);
92 }
93
94 void AbstractOptionStorage::startSet()
95 {
96     GMX_RELEASE_ASSERT(!_inSet, "finishSet() not called");
97     // The last condition takes care of the situation where multiple
98     // sources are used, and a later source should be able to reassign
99     // the value even though the option is already set.
100     if (isSet() && !hasFlag(efMulti) && !hasFlag(efClearOnNextSet))
101     {
102         GMX_THROW(InvalidInputError("Option specified multiple times"));
103     }
104     clearSet();
105     _inSet = true;
106 }
107
108 void AbstractOptionStorage::appendValue(const std::string &value)
109 {
110     GMX_RELEASE_ASSERT(_inSet, "startSet() not called");
111     convertValue(value);
112 }
113
114 void AbstractOptionStorage::finishSet()
115 {
116     GMX_RELEASE_ASSERT(_inSet, "startSet() not called");
117     _inSet = false;
118     // TODO: Should this be done only when processSet() does not throw?
119     setFlag(efSet);
120     processSet();
121 }
122
123 void AbstractOptionStorage::finish()
124 {
125     GMX_RELEASE_ASSERT(!_inSet, "finishSet() not called");
126     processAll();
127     if (hasFlag(efRequired) && !isSet())
128     {
129         GMX_THROW(InvalidInputError("Option is required, but not set"));
130     }
131 }
132
133 void AbstractOptionStorage::setMinValueCount(int count)
134 {
135     GMX_RELEASE_ASSERT(!hasFlag(efMulti),
136                        "setMinValueCount() not supported with efMulti");
137     GMX_RELEASE_ASSERT(count >= 0, "Invalid value count");
138     _minValueCount = count;
139     if (isSet()
140         && !hasFlag(efDontCheckMinimumCount) && valueCount() < _minValueCount)
141     {
142         GMX_THROW(InvalidInputError("Too few values"));
143     }
144 }
145
146 void AbstractOptionStorage::setMaxValueCount(int count)
147 {
148     GMX_RELEASE_ASSERT(!hasFlag(efMulti),
149                        "setMaxValueCount() not supported with efMulti");
150     GMX_RELEASE_ASSERT(count >= -1, "Invalid value count");
151     _maxValueCount = count;
152     if (isSet() && _maxValueCount >= 0 && valueCount() > _maxValueCount)
153     {
154         GMX_THROW(InvalidInputError("Too many values"));
155     }
156 }
157
158 } // namespace gmx