Sort all includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / options / optionstoragetemplate.h
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 /*! \libinternal \file
36  * \brief
37  * Defines gmx::OptionStorageTemplate template.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \inlibraryapi
41  * \ingroup module_options
42  */
43 #ifndef GMX_OPTIONS_OPTIONSTORAGETEMPLATE_H
44 #define GMX_OPTIONS_OPTIONSTORAGETEMPLATE_H
45
46 #include <string>
47 #include <vector>
48
49 #include <boost/scoped_ptr.hpp>
50
51 #include "gromacs/options/abstractoption.h"
52 #include "gromacs/options/abstractoptionstorage.h"
53 #include "gromacs/utility/common.h"
54 #include "gromacs/utility/exceptions.h"
55 #include "gromacs/utility/gmxassert.h"
56
57 namespace gmx
58 {
59
60 class Options;
61
62 /*! \libinternal \brief
63  * Templated base class for constructing option value storage classes.
64  *
65  * \tparam T Assignable type that stores a single option value.
66  *
67  * Provides an implementation of the clearSet(), valueCount(), and processSet()
68  * methods of AbstractOptionStorage, as well as a basic no-action
69  * implementation of processAll().  Two new virtual methods are added:
70  * processSetValues() and refreshValues().  The default implementation of
71  * processSetValues() does nothing, and refreshValues() is used to update
72  * secondary storage after values have been added/changed.
73  * This leaves typeString(), formatValue(), and convertValue() to be
74  * implemented in derived classes.  processSetValues() and processAll() can
75  * also be implemented if necessary.
76  *
77  * Implements transaction support for adding values within a set: all calls to
78  * addValue() add the value to a temporary storage, processSetValues() operates
79  * on this temporary storage, and commitValues() then copies these values to
80  * the real storage.  commitValues() provides a strong exception safety
81  * guarantee for the process (and it only throws if it runs out of memory).
82  *
83  * \inlibraryapi
84  * \ingroup module_options
85  */
86 template <typename T>
87 class OptionStorageTemplate : public AbstractOptionStorage
88 {
89     public:
90         //! Alias for the template class for use in base classes.
91         typedef OptionStorageTemplate<T> MyBase;
92         //! Type of the container that contains the current values.
93         typedef std::vector<T> ValueList;
94
95         virtual ~OptionStorageTemplate();
96
97         // No implementation in this class for the pure virtual methods, but
98         // the declarations are still included for clarity.
99         virtual std::string typeString() const = 0;
100         virtual int valueCount() const { return static_cast<int>(values_->size()); }
101         /*! \copydoc gmx::AbstractOptionStorage::formatValue()
102          *
103          * OptionStorageTemplate implements handling of DefaultValueIfSetIndex
104          * in this method, as well as checking that \p i is a valid index.
105          * Derived classes must implement formatSingleValue() to provide the
106          * actual formatting for a value of type \p T.
107          */
108         virtual std::string formatValue(int i) const;
109
110     protected:
111         /*! \brief
112          * Initializes the storage from option settings.
113          *
114          * \param[in] settings  Option settings.
115          * \param[in] staticFlags Option flags that are always set and specify
116          *      generic behavior of the option.
117          * \throws  APIError if invalid settings have been provided.
118          */
119         template <class U>
120         explicit OptionStorageTemplate(const OptionTemplate<T, U> &settings,
121                                        OptionFlags staticFlags = OptionFlags());
122
123
124         virtual void clearSet();
125         /*! \copydoc gmx::AbstractOptionStorage::convertValue()
126          *
127          * Derived classes should call addValue() after they have converted
128          * \p value to the storage type.  It is allowed to call addValue()
129          * more than once, or not at all.  OptionsAssigner::appendValue()
130          * provides the same exception safety guarantee as this method, so it
131          * should be considered whether the implementation can be made strongly
132          * exception safe.
133          */
134         virtual void convertValue(const std::string &value) = 0;
135         /*! \brief
136          * Processes values for a set after all have been converted.
137          *
138          * \param[in,out] values Valid values in the set.
139          * \throws InvalidInputError if the values do not form a valid set.
140          *
141          * This method is called after all convertValue() calls for a set.
142          * \p values contains all values that were validly converted by
143          * convertValue().  The derived class may alter the values, but should
144          * in such a case ensure that a correct number of values is produced.
145          * If the derived class throws, all values in \p values are discarded.
146          */
147         virtual void processSetValues(ValueList *values)
148         {
149             GMX_UNUSED_VALUE(values);
150         }
151         /*! \copydoc gmx::AbstractOptionStorage::processSet()
152          *
153          * OptionStorageTemplate implements transaction support for a set of
154          * values in this method (see the class description), and provides a
155          * more detailed processSetValues() method that can be overridden in
156          * subclasses to process the actual values.  Derived classes should
157          * override that method instead of this one if set value processing is
158          * necessary.
159          */
160         virtual void processSet();
161         /*! \copydoc gmx::AbstractOptionStorage::processAll()
162          *
163          * The implementation in OptionStorageTemplate does nothing.
164          */
165         virtual void processAll()
166         {
167         }
168         /*! \brief
169          * Formats a single value as a string.
170          *
171          * \param[in] value  Value to format.
172          * \returns   \p value formatted as a string.
173          *
174          * The derived class must provide this method to format values a
175          * strings.  Called by formatValue() to do the actual formatting.
176          */
177         virtual std::string formatSingleValue(const T &value) const = 0;
178
179         /*! \brief
180          * Removes all values from the storage.
181          *
182          * Does not throw.
183          */
184         void clear() { values_->clear(); }
185         /*! \brief
186          * Adds a value to a temporary storage.
187          *
188          * \param[in] value  Value to add. A copy is made.
189          * \throws std::bad_alloc if out of memory.
190          * \throws InvalidInputError if the maximum value count has been reached.
191          *
192          * Derived classes should call this function from the convertValue()
193          * implementation to add converted values to the storage.
194          * If the maximum value count has been reached, the value is discarded
195          * and an exception is thrown.
196          *
197          * If adding values outside convertValue() (e.g., to set a custom
198          * default value), derived classes should call clearSet() before adding
199          * values (unless in the constructor) and commitValues() once all
200          * values are added.
201          */
202         void addValue(const T &value);
203         /*! \brief
204          * Commits values added with addValue().
205          *
206          * \throws std::bad_alloc if out of memory.
207          *
208          * If this function succeeds, values added with addValue() since the
209          * previous clearSet() are added to the storage for the option.
210          * Only throws in out-of-memory conditions, and provides the strong
211          * exception safety guarantee.
212          *
213          * See addValue() for cases where this method should be used in derived
214          * classes.
215          *
216          * Calls refreshValues() and clearSet() if it is successful.
217          */
218         void commitValues();
219         /*! \brief
220          * Updates alternative store locations.
221          *
222          * Derived classes should override this method if they implement
223          * alternative store locations, and copy/translate values from the
224          * values() vector to these alternative storages.  They should also
225          * call the base class implementation as part of their implementation.
226          *
227          * Should be called in derived classes if values are modified directly
228          * through the values() method, e.g., in processAll().  Does not need
229          * to be called if commitValues() is used.
230          *
231          * Does not throw, and derived classes should not change that.
232          */
233         virtual void refreshValues();
234
235         /*! \brief
236          * Sets the default value for the option.
237          *
238          * \param[in] value  Default value to set.
239          * \throws    std::bad_alloc if out of memory.
240          *
241          * This method can be used from the derived class constructor to
242          * programmatically set a default value.
243          */
244         void setDefaultValue(const T &value);
245         /*! \brief
246          * Sets the default value if set for the option.
247          *
248          * \param[in] value  Default value to set.
249          * \throws    std::bad_alloc if out of memory.
250          *
251          * This method can be used from the derived class constructor to
252          * programmatically set a default value.
253          */
254         void setDefaultValueIfSet(const T &value);
255
256         /*! \brief
257          * Provides derived classes access to the current list of values.
258          *
259          * The non-const variant should only be used from processAll() in
260          * derived classes if necessary, and refreshValues() should be called
261          * if any changes are made.
262          */
263         ValueList       &values() { return *values_; }
264         //! Provides derived classes access to the current list of values.
265         const ValueList &values() const { return *values_; }
266
267     private:
268         /*! \brief
269          * Vector for temporary storage of values before commitSet() is called.
270          */
271         ValueList               setValues_;
272         /*! \brief
273          * Vector for primary storage of option values.
274          *
275          * Is never NULL; points either to externally provided vector, or an
276          * internally allocated one.  The allocation is performed by the
277          * constructor.
278          *
279          * Primarily, modifications to values are done only to this storage,
280          * and other storage locations are updated only when refreshValues() is
281          * called.
282          */
283         ValueList                   *values_;
284         T                           *store_;
285         int                         *countptr_;
286         boost::scoped_ptr<ValueList> ownedValues_;
287         boost::scoped_ptr<T>         defaultValueIfSet_;
288
289         // Copy and assign disallowed by base.
290 };
291
292
293 template <typename T>
294 template <class U>
295 OptionStorageTemplate<T>::OptionStorageTemplate(const OptionTemplate<T, U> &settings,
296                                                 OptionFlags staticFlags)
297     : AbstractOptionStorage(settings, staticFlags),
298       values_(settings.storeVector_),
299       store_(settings.store_),
300       countptr_(settings.countptr_)
301 {
302     // If the maximum number of values is not known, storage to
303     // caller-allocated memory is unsafe.
304     if (store_ != NULL && (maxValueCount() < 0 || hasFlag(efOption_MultipleTimes)))
305     {
306         GMX_THROW(APIError("Cannot set user-allocated storage for arbitrary number of values"));
307     }
308     if (values_ == NULL)
309     {
310         ownedValues_.reset(new std::vector<T>);
311         values_ = ownedValues_.get();
312     }
313     if (hasFlag(efOption_NoDefaultValue)
314         && (settings.defaultValue_ != NULL
315             || settings.defaultValueIfSet_ != NULL))
316     {
317         GMX_THROW(APIError("Option does not support default value, but one is set"));
318     }
319     if (store_ != NULL && countptr_ == NULL && !isVector()
320         && minValueCount() != maxValueCount())
321     {
322         GMX_THROW(APIError("Count storage is not set, although the number of produced values is not known"));
323     }
324     if (!hasFlag(efOption_NoDefaultValue))
325     {
326         setFlag(efOption_HasDefaultValue);
327         if (settings.defaultValue_ != NULL)
328         {
329             setDefaultValue(*settings.defaultValue_);
330         }
331         else if (ownedValues_.get() != NULL && store_ != NULL)
332         {
333             values_->clear();
334             int count = (settings.isVector() ?
335                          settings.maxValueCount_ : settings.minValueCount_);
336             for (int i = 0; i < count; ++i)
337             {
338                 values_->push_back(store_[i]);
339             }
340         }
341         if (settings.defaultValueIfSet_ != NULL)
342         {
343             setDefaultValueIfSet(*settings.defaultValueIfSet_);
344         }
345     }
346 }
347
348
349 template <typename T>
350 OptionStorageTemplate<T>::~OptionStorageTemplate()
351 {
352 }
353
354
355 template <typename T>
356 std::string OptionStorageTemplate<T>::formatValue(int i) const
357 {
358     GMX_RELEASE_ASSERT(i == DefaultValueIfSetIndex || (i >= 0 && i < valueCount()),
359                        "Invalid value index");
360     if (i == DefaultValueIfSetIndex)
361     {
362         if (defaultValueIfSet_.get() != NULL)
363         {
364             return formatSingleValue(*defaultValueIfSet_);
365         }
366         return std::string();
367     }
368     return formatSingleValue(values()[i]);
369 }
370
371
372 template <typename T>
373 void OptionStorageTemplate<T>::clearSet()
374 {
375     setValues_.clear();
376 }
377
378
379 template <typename T>
380 void OptionStorageTemplate<T>::processSet()
381 {
382     processSetValues(&setValues_);
383     if (setValues_.empty() && defaultValueIfSet_.get() != NULL)
384     {
385         addValue(*defaultValueIfSet_);
386         setFlag(efOption_HasDefaultValue);
387     }
388     else
389     {
390         clearFlag(efOption_HasDefaultValue);
391     }
392     if (!hasFlag(efOption_DontCheckMinimumCount)
393         && setValues_.size() < static_cast<size_t>(minValueCount()))
394     {
395         GMX_THROW(InvalidInputError("Too few (valid) values"));
396     }
397     commitValues();
398 }
399
400
401 template <typename T>
402 void OptionStorageTemplate<T>::addValue(const T &value)
403 {
404     if (maxValueCount() >= 0
405         && setValues_.size() >= static_cast<size_t>(maxValueCount()))
406     {
407         GMX_THROW(InvalidInputError("Too many values"));
408     }
409     setValues_.push_back(value);
410 }
411
412
413 template <typename T>
414 void OptionStorageTemplate<T>::commitValues()
415 {
416     if (hasFlag(efOption_ClearOnNextSet))
417     {
418         values_->swap(setValues_);
419     }
420     else
421     {
422         values_->insert(values_->end(), setValues_.begin(), setValues_.end());
423     }
424     clearSet();
425     refreshValues();
426 }
427
428
429 template <typename T>
430 void OptionStorageTemplate<T>::refreshValues()
431 {
432     if (countptr_ != NULL)
433     {
434         *countptr_ = static_cast<int>(values_->size());
435     }
436     if (store_ != NULL)
437     {
438         for (size_t i = 0; i < values_->size(); ++i)
439         {
440             store_[i] = (*values_)[i];
441         }
442     }
443 }
444
445
446 template <typename T>
447 void OptionStorageTemplate<T>::setDefaultValue(const T &value)
448 {
449     if (hasFlag(efOption_NoDefaultValue))
450     {
451         GMX_THROW(APIError("Option does not support default value, but one is set"));
452     }
453     if (hasFlag(efOption_HasDefaultValue))
454     {
455         setFlag(efOption_ExplicitDefaultValue);
456         clear();
457         clearSet();
458         addValue(value);
459         // TODO: As this is called from the constructor, it should not call
460         // virtual functions.
461         commitValues();
462     }
463 }
464
465
466 template <typename T>
467 void OptionStorageTemplate<T>::setDefaultValueIfSet(const T &value)
468 {
469     if (hasFlag(efOption_NoDefaultValue))
470     {
471         GMX_THROW(APIError("Option does not support default value, but one is set"));
472     }
473     if (hasFlag(efOption_MultipleTimes))
474     {
475         GMX_THROW(APIError("defaultValueIfSet() is not supported with allowMultiple()"));
476     }
477     setFlag(efOption_DefaultValueIfSetExists);
478     defaultValueIfSet_.reset(new T(value));
479 }
480
481 } // namespace gmx
482
483 #endif