2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 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.
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.
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.
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.
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.
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.
38 #include "gromacs/options/basicoptions.h"
39 #include "gromacs/options/filenameoption.h"
40 #include "gromacs/selection/selectionoption.h"
44 class PyOptionsHolder {
46 class DuplicateOption: public std::exception {
48 virtual const char* what() const noexcept;
52 StringList(const std::vector < std::string > *);
53 StringList(const std::string*, size_t);
54 const char * operator[] (size_t);
56 const std::string *list;
58 const std::vector < std::string > *vector;
60 gmx::DoubleOption doubleOption(const char*, size_t = 1, double* = NULL);
61 gmx::IntegerOption integerOption(const char*, size_t = 1, int* = NULL);
62 gmx::StringOption stringOption(const char*, size_t = 1, const char* = NULL);
63 gmx::BooleanOption booleanOption(const char*, size_t = 1, bool = 0);
64 gmx::SelectionOption selectionOption(const char*, size_t = 1);
65 gmx::FileNameOption fileNameOption(const char*, size_t = 1);
66 PyObject* get_value(const char*);
76 std::map < std::string, option_value > storage;
77 template < typename T, typename U > U createStorage(const char*, const char*, int, const T* = 0);
78 template < typename T > PyObject* buildValue(const char*, const option_value &, const sipTypeDef* = NULL, size_t = 0);
79 template < typename T > void deleteStorage(const option_value &);
84 #include "gromacs/utility/gmxassert.h"
86 const char* PyOptionsHolder::DuplicateOption::what() const noexcept {
87 return "This option is already defined";
90 PyOptionsHolder::StringList::StringList(const std::vector < std::string > *vector) :
91 list(NULL), size(vector->size()), vector(vector)
94 PyOptionsHolder::StringList::StringList(const std::string *list, size_t size) :
95 list(list), size(size), vector(NULL)
98 const char* PyOptionsHolder::StringList::operator[] (size_t i) {
103 return vector ? (*vector)[i].data() : list[i].data();
106 template < typename T, typename U > U PyOptionsHolder::createStorage(const char *name, const char *type, int count, const T *def)
108 if (storage.count(name))
110 throw DuplicateOption();
117 value.count = new int;
120 if (count == 0) // std::vector of values
122 auto *store = new std::vector < T > ();
123 option.storeVector(store);
125 option.storeCount(value.count);
130 store->push_back(*def);
137 else // exactly `count` values
139 auto *store = new T[count];
148 option.valueCount(count);
152 value.vector = false;
153 *value.count = count;
156 storage[name] = value;
160 gmx::DoubleOption PyOptionsHolder::doubleOption(const char *name, size_t count, double *def)
162 gmx::DoubleOption option = createStorage < double, gmx::DoubleOption > (name, "d", count, def);
167 gmx::IntegerOption PyOptionsHolder::integerOption(const char *name, size_t count, int *def)
169 gmx::IntegerOption option = createStorage < int, gmx::IntegerOption > (name, "i", count, def);
174 gmx::StringOption PyOptionsHolder::stringOption(const char *name, size_t count, const char* def)
176 std::string *s_def = NULL;
179 s_def = new std::string(def);
182 gmx::StringOption option = createStorage < std::string, gmx::StringOption > (name, "A", count, s_def);
188 // FIXME: Unify with the rest
189 gmx::BooleanOption PyOptionsHolder::booleanOption(const char *name, size_t count, bool def)
191 if (storage.count(name))
193 throw DuplicateOption();
196 bool *store = new bool;
198 gmx::BooleanOption option(name);
200 storage[name] = {store, "b"};
205 gmx::SelectionOption PyOptionsHolder::selectionOption(const char *name, size_t count)
207 gmx::SelectionOption option = createStorage < gmx::Selection, gmx::SelectionOption > (name, "S", count);
212 gmx::FileNameOption PyOptionsHolder::fileNameOption(const char *name, size_t count)
214 gmx::FileNameOption option = createStorage < std::string, gmx::FileNameOption > (name, "f", count);
219 template < typename T > PyObject* PyOptionsHolder::buildValue(const char *sipType, const PyOptionsHolder::option_value &value, const sipTypeDef *td, size_t size)
221 int count = *value.count;
222 T *store = !value.vector ? (T*) value.value : ((std::vector < T > *)value.value)->data();
224 if (count == 1 && !value.vector)
228 return sipConvertFromType(store, td, NULL);
232 return sipBuildResult(NULL, sipType, *store);
239 return sipConvertToTypedArray(store, td, NULL, size, count, SIP_READ_ONLY);
243 return sipConvertToArray(store, sipType, count, SIP_READ_ONLY);
249 PyObject* PyOptionsHolder::get_value(const char *name)
251 if (!storage.count(name))
256 option_value v = storage[name];
260 return buildValue < double > ("d", v);
263 return buildValue < int > ("i", v);
265 case 'A': // std::string
266 case 'f': // FileNameOption
269 return sipConvertFromType(new PyOptionsHolder::StringList(((std::vector < std::string > *)v.value)), sipType_PyOptionsHolder_StringList, Py_None);
271 else if (*v.count == 1)
273 return sipBuildResult(NULL, "A", ((std::string*) v.value)->data());
277 return sipConvertFromType(new PyOptionsHolder::StringList((std::string*) v.value, *v.count), sipType_PyOptionsHolder_StringList, Py_None);
281 // TODO: support vector bool options
282 return sipBuildResult(NULL, v.type, *((bool*) v.value));
284 case 'S': // Selection
285 return buildValue < gmx::Selection > (NULL, v, sipType_Selection, sizeof(gmx::Selection));
289 GMX_ASSERT(false, "Some type is not handled in PyOptionsHolder.get_value");
293 template < typename T > void PyOptionsHolder::deleteStorage(const PyOptionsHolder::option_value &value)
297 delete (std::vector < T > *) value.value;
301 delete[] (T*) value.value;
307 PyOptionsHolder::~PyOptionsHolder()
309 for (auto e : storage)
311 switch (*e.second.type)
314 deleteStorage < double > (e.second);
317 deleteStorage < int > (e.second);
319 case 'A': // std::string
320 case 'f': // FileNameOption (the storage type is still std::string)
321 deleteStorage < std::string > (e.second);
324 delete (bool*) e.second.value;
326 case 'S': // Selection
327 deleteStorage < gmx::Selection > (e.second);
334 %Exception PyOptionsHolder::DuplicateOption {
337 PyErr_SetString(PyExc_ValueError, sipExceptionRef.what());
342 class PyOptionsHolder {
344 #include "gromacs/options/basicoptions.h"
348 class StringList /NoDefaultCtors/ {
350 const char* operator[] (int);
352 sipRes = (*sipCpp)[a0];
357 PyErr_SetString(PyExc_IndexError, "Index out of range");
363 // These methods are given twice to workaround sip setting 0 for when '*def = NULL' option is not given
364 DoubleOption doubleOption(const char *name /KeepReference/, int count = 1) throw (PyOptionsHolder::DuplicateOption);
365 DoubleOption doubleOption(const char *name /KeepReference/, int count, const double *def) throw (PyOptionsHolder::DuplicateOption);
367 IntegerOption integerOption(const char *name /KeepReference/, int count = 1) throw (PyOptionsHolder::DuplicateOption);
368 IntegerOption integerOption(const char *name /KeepReference/, int count, const int *def) throw (PyOptionsHolder::DuplicateOption);
370 StringOption stringOption(const char *name /KeepReference/, int count = 1) throw (PyOptionsHolder::DuplicateOption);
371 StringOption stringOption(const char *name /KeepReference/, int count, const char *def) throw (PyOptionsHolder::DuplicateOption);
373 BooleanOption booleanOption(const char *name /KeepReference/, int count = 1, bool def = 0) throw (PyOptionsHolder::DuplicateOption);
375 SelectionOption selectionOption(const char *name /KeepReference/, int count = 1) throw (PyOptionsHolder::DuplicateOption);
377 FileNameOption fileNameOption(const char *name /KeepReference/, int count = 1) throw (PyOptionsHolder::DuplicateOption);
378 SIP_PYOBJECT __getitem__(const char *name);
380 sipRes = sipCpp->get_value(a0);
385 PyErr_SetString(PyExc_KeyError, "Invalid option name");