3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
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.
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.
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.
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.
29 * For more info, check our website at http://www.gromacs.org
31 /*! \libinternal \file
33 * Defines gmx::OptionStorageTemplate template.
35 * \author Teemu Murtola <teemu.murtola@cbr.su.se>
37 * \ingroup module_options
39 #ifndef GMX_OPTIONS_OPTIONSTORAGETEMPLATE_H
40 #define GMX_OPTIONS_OPTIONSTORAGETEMPLATE_H
45 #include <boost/scoped_ptr.hpp>
47 #include "../utility/exceptions.h"
48 #include "../utility/gmxassert.h"
50 #include "abstractoption.h"
51 #include "abstractoptionstorage.h"
58 /*! \libinternal \brief
59 * Templated base class for constructing option value storage classes.
61 * \tparam T Assignable type that stores a single option value.
63 * Provides an implementation of the clearSet(), valueCount(), and processSet()
64 * methods of AbstractOptionStorage, as well as a basic no-action
65 * implementation of processAll(). Two new virtual methods are added:
66 * processSetValues() and refreshValues(). The default implementation of
67 * processSetValues() does nothing, and refreshValues() is used to update
68 * secondary storage after values have been added/changed.
69 * This leaves typeString(), formatValue(), and convertValue() to be
70 * implemented in derived classes. processSetValues() and processAll() can
71 * also be implemented if necessary.
73 * Implements transaction support for adding values within a set: all calls to
74 * addValue() add the value to a temporary storage, processSetValues() operates
75 * on this temporary storage, and commitValues() then copies these values to
76 * the real storage. commitValues() provides a strong exception safety
77 * guarantee for the process (and it only throws if it runs out of memory).
80 * \ingroup module_options
83 class OptionStorageTemplate : public AbstractOptionStorage
86 //! Alias for the template class for use in base classes.
87 typedef OptionStorageTemplate<T> MyBase;
88 //! Type of the container that contains the current values.
89 typedef std::vector<T> ValueList;
91 virtual ~OptionStorageTemplate();
93 // No implementation in this class for the pure virtual methods, but
94 // the declarations are still included for clarity.
95 virtual const char *typeString() const = 0;
96 virtual int valueCount() const { return static_cast<int>(values_->size()); }
97 /*! \copydoc gmx::AbstractOptionStorage::formatValue()
99 * OptionStorageTemplate implements handling of DefaultValueIfSetIndex
100 * in this method, as well as checking that \p i is a valid index.
101 * Derived classes must implement formatSingleValue() to provide the
102 * actual formatting for a value of type \p T.
104 virtual std::string formatValue(int i) const;
108 * Initializes the storage from option settings.
110 * \param[in] settings Option settings.
111 * \param[in] staticFlags Option flags that are always set and specify
112 * generic behavior of the option.
113 * \throws APIError if invalid settings have been provided.
116 explicit OptionStorageTemplate(const OptionTemplate<T, U> &settings,
117 OptionFlags staticFlags = OptionFlags());
120 virtual void clearSet();
121 /*! \copydoc gmx::AbstractOptionStorage::convertValue()
123 * Derived classes should call addValue() after they have converted
124 * \p value to the storage type. It is allowed to call addValue()
125 * more than once, or not at all. OptionsAssigner::appendValue()
126 * provides the same exception safety guarantee as this method, so it
127 * should be considered whether the implementation can be made strongly
130 virtual void convertValue(const std::string &value) = 0;
132 * Processes values for a set after all have been converted.
134 * \param[in,out] values Valid values in the set.
135 * \throws InvalidInputError if the values do not form a valid set.
137 * This method is called after all convertValue() calls for a set.
138 * \p values contains all values that were validly converted by
139 * convertValue(). The derived class may alter the values, but should
140 * in such a case ensure that a correct number of values is produced.
141 * If the derived class throws, all values in \p values are discarded.
143 virtual void processSetValues(ValueList *values)
146 /*! \copydoc gmx::AbstractOptionStorage::processSet()
148 * OptionStorageTemplate implements transaction support for a set of
149 * values in this method (see the class description), and provides a
150 * more detailed processSetValues() method that can be overridden in
151 * subclasses to process the actual values. Derived classes should
152 * override that method instead of this one if set value processing is
155 virtual void processSet();
156 /*! \copydoc gmx::AbstractOptionStorage::processAll()
158 * The implementation in OptionStorageTemplate does nothing.
160 virtual void processAll()
164 * Formats a single value as a string.
166 * \param[in] value Value to format.
167 * \returns \p value formatted as a string.
169 * The derived class must provide this method to format values a
170 * strings. Called by formatValue() to do the actual formatting.
172 virtual std::string formatSingleValue(const T &value) const = 0;
175 * Removes all values from the storage.
179 void clear() { values_->clear(); }
181 * Adds a value to a temporary storage.
183 * \param[in] value Value to add. A copy is made.
184 * \throws std::bad_alloc if out of memory.
185 * \throws InvalidInputError if the maximum value count has been reached.
187 * Derived classes should call this function from the convertValue()
188 * implementation to add converted values to the storage.
189 * If the maximum value count has been reached, the value is discarded
190 * and an exception is thrown.
192 * If adding values outside convertValue() (e.g., to set a custom
193 * default value), derived classes should call clearSet() before adding
194 * values (unless in the constructor) and commitValues() once all
197 void addValue(const T &value);
199 * Commits values added with addValue().
201 * \throws std::bad_alloc if out of memory.
203 * If this function succeeds, values added with addValue() since the
204 * previous clearSet() are added to the storage for the option.
205 * Only throws in out-of-memory conditions, and provides the strong
206 * exception safety guarantee.
208 * See addValue() for cases where this method should be used in derived
211 * Calls refreshValues() and clearSet() if it is successful.
215 * Updates alternative store locations.
217 * Derived classes should override this method if they implement
218 * alternative store locations, and copy/translate values from the
219 * values() vector to these alternative storages. They should also
220 * call the base class implementation as part of their implementation.
222 * Should be called in derived classes if values are modified directly
223 * through the values() method, e.g., in processAll(). Does not need
224 * to be called if commitValues() is used.
226 * Does not throw, and derived classes should not change that.
228 virtual void refreshValues();
231 * Sets the default value for the option.
233 * \param[in] value Default value to set.
234 * \throws std::bad_alloc if out of memory.
236 * This method can be used from the derived class constructor to
237 * programmatically set a default value.
239 void setDefaultValue(const T &value);
241 * Sets the default value if set for the option.
243 * \param[in] value Default value to set.
244 * \throws std::bad_alloc if out of memory.
246 * This method can be used from the derived class constructor to
247 * programmatically set a default value.
249 void setDefaultValueIfSet(const T &value);
252 * Provides derived classes access to the current list of values.
254 * The non-const variant should only be used from processAll() in
255 * derived classes if necessary, and refreshValues() should be called
256 * if any changes are made.
258 ValueList &values() { return *values_; }
259 //! Provides derived classes access to the current list of values.
260 const ValueList &values() const { return *values_; }
264 * Vector for temporary storage of values before commitSet() is called.
266 ValueList setValues_;
268 * Vector for primary storage of option values.
270 * Is never NULL; points either to externally provided vector, or an
271 * internally allocated one. The allocation is performed by the
274 * Primarily, modifications to values are done only to this storage,
275 * and other storage locations are updated only when refreshValues() is
281 boost::scoped_ptr<ValueList> ownedValues_;
282 boost::scoped_ptr<T> defaultValueIfSet_;
284 // Copy and assign disallowed by base.
288 template <typename T>
290 OptionStorageTemplate<T>::OptionStorageTemplate(const OptionTemplate<T, U> &settings,
291 OptionFlags staticFlags)
292 : AbstractOptionStorage(settings, staticFlags),
293 values_(settings.storeVector_),
294 store_(settings.store_),
295 countptr_(settings.countptr_)
297 // If the maximum number of values is not known, storage to
298 // caller-allocated memory is unsafe.
299 if (store_ != NULL && (maxValueCount() < 0 || hasFlag(efOption_MultipleTimes)))
301 GMX_THROW(APIError("Cannot set user-allocated storage for arbitrary number of values"));
305 ownedValues_.reset(new std::vector<T>);
306 values_ = ownedValues_.get();
308 if (hasFlag(efOption_NoDefaultValue)
309 && (settings.defaultValue_ != NULL
310 || settings.defaultValueIfSet_ != NULL))
312 GMX_THROW(APIError("Option does not support default value, but one is set"));
314 if (store_ != NULL && countptr_ == NULL && !isVector()
315 && minValueCount() != maxValueCount())
317 GMX_THROW(APIError("Count storage is not set, although the number of produced values is not known"));
319 if (!hasFlag(efOption_NoDefaultValue))
321 setFlag(efOption_HasDefaultValue);
322 if (settings.defaultValue_ != NULL)
324 setDefaultValue(*settings.defaultValue_);
326 else if (ownedValues_.get() != NULL && store_ != NULL)
329 int count = (settings.isVector() ?
330 settings.maxValueCount_ : settings.minValueCount_);
331 for (int i = 0; i < count; ++i)
333 values_->push_back(store_[i]);
336 if (settings.defaultValueIfSet_ != NULL)
338 setDefaultValueIfSet(*settings.defaultValueIfSet_);
344 template <typename T>
345 OptionStorageTemplate<T>::~OptionStorageTemplate()
350 template <typename T>
351 std::string OptionStorageTemplate<T>::formatValue(int i) const
353 GMX_RELEASE_ASSERT(i == DefaultValueIfSetIndex || (i >= 0 && i < valueCount()),
354 "Invalid value index");
355 if (i == DefaultValueIfSetIndex)
357 if (defaultValueIfSet_.get() != NULL)
359 return formatSingleValue(*defaultValueIfSet_);
361 return std::string();
363 return formatSingleValue(values()[i]);
367 template <typename T>
368 void OptionStorageTemplate<T>::clearSet()
374 template <typename T>
375 void OptionStorageTemplate<T>::processSet()
377 processSetValues(&setValues_);
378 if (setValues_.empty() && defaultValueIfSet_.get() != NULL)
380 addValue(*defaultValueIfSet_);
381 setFlag(efOption_HasDefaultValue);
385 clearFlag(efOption_HasDefaultValue);
387 if (!hasFlag(efOption_DontCheckMinimumCount)
388 && setValues_.size() < static_cast<size_t>(minValueCount()))
390 GMX_THROW(InvalidInputError("Too few (valid) values"));
396 template <typename T>
397 void OptionStorageTemplate<T>::addValue(const T &value)
399 if (maxValueCount() >= 0
400 && setValues_.size() >= static_cast<size_t>(maxValueCount()))
402 GMX_THROW(InvalidInputError("Too many values"));
404 setValues_.push_back(value);
408 template <typename T>
409 void OptionStorageTemplate<T>::commitValues()
411 if (hasFlag(efOption_ClearOnNextSet))
413 values_->swap(setValues_);
417 values_->insert(values_->end(), setValues_.begin(), setValues_.end());
424 template <typename T>
425 void OptionStorageTemplate<T>::refreshValues()
427 if (countptr_ != NULL)
429 *countptr_ = static_cast<int>(values_->size());
433 for (size_t i = 0; i < values_->size(); ++i)
435 store_[i] = (*values_)[i];
441 template <typename T>
442 void OptionStorageTemplate<T>::setDefaultValue(const T &value)
444 if (hasFlag(efOption_NoDefaultValue))
446 GMX_THROW(APIError("Option does not support default value, but one is set"));
448 if (hasFlag(efOption_HasDefaultValue))
450 setFlag(efOption_ExplicitDefaultValue);
454 // TODO: As this is called from the constructor, it should not call
455 // virtual functions.
461 template <typename T>
462 void OptionStorageTemplate<T>::setDefaultValueIfSet(const T &value)
464 if (hasFlag(efOption_NoDefaultValue))
466 GMX_THROW(APIError("Option does not support default value, but one is set"));
468 if (hasFlag(efOption_MultipleTimes))
470 GMX_THROW(APIError("defaultValueIfSet() is not supported with allowMultiple()"));
472 defaultValueIfSet_.reset(new T(value));