2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 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.
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 throw();
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 = 0);
61 gmx::IntegerOption integerOption(const char*, size_t = 1, int = 0);
62 gmx::StringOption stringOption(const char*, size_t = 1, const char* = "");
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, const char* = 0);
66 PyObject* get_value(const char*);
75 std::map<std::string, option_value> storage;
76 template<typename T, typename U> option_value createStorage(gmx::OptionTemplate<T, U>&, const char*, int);
77 template<typename T> PyObject* buildValue(const char*, const option_value&, const sipTypeDef* = NULL, size_t = 0);
78 template<typename T> void deleteStorage(const option_value&);
83 #include "gromacs/utility/gmxassert.h"
85 const char* PyOptionsHolder::DuplicateOption::what() const throw() {
86 return "This option is already defined";
89 PyOptionsHolder::StringList::StringList(const std::vector<std::string> *vector) :
90 list(NULL), size(vector->size()), vector(vector)
93 PyOptionsHolder::StringList::StringList(const std::string *list, size_t size) :
94 list(list), size(size), vector(NULL)
97 const char* PyOptionsHolder::StringList::operator[](size_t i) {
100 return vector ? (*vector)[i].data() : list[i].data();
103 template<typename T, typename U> PyOptionsHolder::option_value PyOptionsHolder::createStorage(gmx::OptionTemplate<T, U> &option, const char *type, int count) {
104 if (count == 0) { // std::vector of values
105 std::vector<T> *store = new std::vector<T>();
106 option.storeVector(store);
109 int *count = new int;
110 option.storeCount(count);
112 option_value value = { store, type, count, true };
114 } else { // exactly `count` values
115 T *store = new T[count];
118 option.valueCount(count);
120 int *count = new int;
121 option.storeCount(count);
123 option_value value = { store, type, count, false };
128 gmx::DoubleOption PyOptionsHolder::doubleOption(const char *name, size_t count, double def) {
129 if (storage.count(name))
130 throw DuplicateOption();
132 gmx::DoubleOption option(name);
133 storage[name] = createStorage(option, "d", count);
138 gmx::IntegerOption PyOptionsHolder::integerOption(const char *name, size_t count, int def) {
139 if (storage.count(name))
140 throw DuplicateOption();
142 gmx::IntegerOption option(name);
143 storage[name] = createStorage(option, "i", count);
148 gmx::StringOption PyOptionsHolder::stringOption(const char *name, size_t count, const char* def) {
149 if (storage.count(name))
150 throw DuplicateOption();
152 gmx::StringOption option(name);
153 storage[name] = createStorage(option, "A", count);
154 // FIXME: following does not work
155 //option.defaultValue(std::string(def));
160 gmx::BooleanOption PyOptionsHolder::booleanOption(const char *name, size_t count, bool def) {
161 if (storage.count(name))
162 throw DuplicateOption();
164 bool *store = new bool;
166 gmx::BooleanOption option(name);
168 option_value value = {store, "b"};
169 storage[name] = value;
174 gmx::SelectionOption PyOptionsHolder::selectionOption(const char *name, size_t count) {
175 if (storage.count(name))
176 throw DuplicateOption();
178 gmx::SelectionOption option(name);
179 storage[name] = createStorage(option, "S", count);
184 gmx::FileNameOption PyOptionsHolder::fileNameOption(const char *name, size_t count, const char* def) {
185 if (storage.count(name))
186 throw DuplicateOption();
188 gmx::FileNameOption option(name);
189 storage[name] = createStorage(option, "f", count);
190 option.defaultBasename(def); // Docs say to set default value like this
195 template<typename T> PyObject* PyOptionsHolder::buildValue(const char *sipType, const PyOptionsHolder::option_value &value, const sipTypeDef *td, size_t size) {
196 int count = *value.count;
197 T *store = !value.vector ? (T*) value.value : ((std::vector<T>*) value.value)->data();
199 if (count == 1 && !value.vector) {
201 return sipConvertFromType(store, td, NULL);
203 return sipBuildResult(NULL, sipType, *store);
206 return sipConvertToTypedArray(store, td, NULL, size, count, SIP_READ_ONLY);
208 return sipConvertToArray(store, sipType, count, SIP_READ_ONLY);
213 PyObject* PyOptionsHolder::get_value(const char *name) {
214 if (!storage.count(name))
217 option_value v = storage[name];
220 return buildValue<double>("d", v);
223 return buildValue<int>("i", v);
225 case 'A': // std::string
226 case 'f': // FileNameOption
228 return sipConvertFromType(new PyOptionsHolder::StringList(((std::vector<std::string>*) v.value)), sipType_PyOptionsHolder_StringList, Py_None);
229 else if (*v.count == 1)
230 return sipBuildResult(NULL, "A", ((std::string*) v.value)->data());
232 return sipConvertFromType(new PyOptionsHolder::StringList((std::string*) v.value, *v.count), sipType_PyOptionsHolder_StringList, Py_None);
235 // TODO: support vector bool options
236 return sipBuildResult(NULL, v.type, *((bool*) v.value));
238 case 'S': // Selection
239 return buildValue<gmx::Selection>(NULL, v, sipType_Selection, sizeof(gmx::Selection));
243 GMX_ASSERT(false, "Some type is not handled in PyOptionsHolder.get_value");
247 template<typename T> void PyOptionsHolder::deleteStorage(const PyOptionsHolder::option_value &value) {
249 delete (std::vector<T> *) value.value;
251 delete[] (T*) value.value;
256 PyOptionsHolder::~PyOptionsHolder() {
257 for (std::map<std::string, option_value>::iterator it = storage.begin(); it != storage.end(); it++)
258 switch (*(it->second.type)) {
260 deleteStorage<double>(it->second);
263 deleteStorage<int>(it->second);
265 case 'A': // std::string
266 case 'f': // FileNameOption (the storage type is still std::string)
267 deleteStorage<std::string>(it->second);
270 delete (bool*) it->second.value;
272 case 'S': // Selection
273 deleteStorage<gmx::Selection>(it->second);
279 %Exception PyOptionsHolder::DuplicateOption {
282 PyErr_SetString(PyExc_ValueError, sipExceptionRef.what());
287 class PyOptionsHolder {
289 #include "gromacs/options/basicoptions.h"
293 class StringList /NoDefaultCtors/ {
295 const char* operator[] (int);
297 sipRes = (*sipCpp)[a0];
301 PyErr_SetString(PyExc_IndexError, "Index out of range");
307 DoubleOption doubleOption(const char *name, int count = 1, double def = 0) throw (PyOptionsHolder::DuplicateOption);
308 IntegerOption integerOption(const char *name, int count = 1, int def = 0) throw (PyOptionsHolder::DuplicateOption);
309 StringOption stringOption(const char *name, int count = 1, const char *def = 0) throw (PyOptionsHolder::DuplicateOption);
310 BooleanOption booleanOption(const char *name, int count = 1, bool def = 0) throw (PyOptionsHolder::DuplicateOption);
311 SelectionOption selectionOption(const char *name, int count = 1) throw (PyOptionsHolder::DuplicateOption);
312 FileNameOption fileNameOption(const char *name, int count = 1, const char *def = 0) throw (PyOptionsHolder::DuplicateOption);
313 SIP_PYOBJECT __getitem__(const char *name);
315 sipRes = sipCpp->get_value(a0);
319 PyErr_SetString(PyExc_KeyError, "Invalid option name");