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
33 * Implements gmx::SelectionOptionManager.
35 * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36 * \ingroup module_selection
38 #include "selectionoptionmanager.h"
42 #include "gromacs/selection/selection.h"
43 #include "gromacs/selection/selectioncollection.h"
44 #include "gromacs/utility/exceptions.h"
45 #include "gromacs/utility/format.h"
47 #include "selectionoptionstorage.h"
52 /********************************************************************
53 * SelectionOptionManager::Impl
57 * Private implemention class for SelectionOptionManager.
59 * \ingroup module_selection
61 class SelectionOptionManager::Impl
65 * Request for postponed parsing of selections.
67 struct SelectionRequest
69 //! Initializes a request for the given option.
70 explicit SelectionRequest(SelectionOptionStorage *storage)
75 //! Returns name of the requested selection optin.
76 const std::string &name() const
78 return storage_->name();
80 //! Returns description for the requested selection option.
81 const std::string &description() const
83 return storage_->description();
86 * Returns the number of selections requested in this request.
88 * -1 indicates no upper limit.
92 return storage_->maxValueCount();
95 //! Storage object to which the selections will be added.
96 SelectionOptionStorage *storage_;
99 //! Collection for a list of selection requests.
100 typedef std::vector<SelectionRequest> RequestList;
101 //! Collection for list of option storage objects.
102 typedef std::vector<SelectionOptionStorage *> OptionList;
105 * Helper class that clears a request list on scope exit.
107 * Methods in this class do not throw.
109 class RequestsClearer
112 //! Constructs an object that clears given list on scope exit.
113 explicit RequestsClearer(RequestList *requests)
114 : requests_(requests)
117 //! Clears the request list given to the constructor.
124 RequestList *requests_;
128 * Creates a new selection collection.
130 * \throws std::bad_alloc if out of memory.
132 explicit Impl(SelectionCollection *collection);
135 * Assign selections from a list to pending requests.
137 * \param[in] selections List of selections to assign.
138 * \throws std::bad_alloc if out of memory.
139 * \throws InvalidInputError if the assignment cannot be done
140 * (see parseRequestedFromFile() for documented conditions).
142 * Loops through \p selections and the pending requests lists in order,
143 * and for each requests, assigns the first yet unassigned selections
146 void placeSelectionsInRequests(const SelectionList &selections);
148 * Adds a request for each required option that is not yet set.
150 * \throws std::bad_alloc if out of memory.
152 void requestUnsetRequiredOptions();
154 //! Selection collection to which selections are stored.
155 SelectionCollection &collection_;
156 //! List of selection options (storage objects) this manager manages.
158 //! List of selections requested for later parsing.
159 RequestList requests_;
162 SelectionOptionManager::Impl::Impl(SelectionCollection *collection)
163 : collection_(*collection)
167 void SelectionOptionManager::Impl::placeSelectionsInRequests(
168 const SelectionList &selections)
170 if (requests_.empty())
172 requestUnsetRequiredOptions();
175 RequestsClearer clearRequestsOnExit(&requests_);
177 SelectionList::const_iterator first = selections.begin();
178 SelectionList::const_iterator last = first;
179 RequestList::const_iterator i;
180 // TODO: Improve error messages.
181 for (i = requests_.begin(); i != requests_.end(); ++i)
183 const SelectionRequest &request = *i;
184 if (request.count() > 0)
186 if (selections.end() - first < request.count())
188 GMX_THROW(InvalidInputError("Too few selections provided"));
190 last = first + request.count();
194 if (i != requests_.end() - 1)
196 GMX_THROW(InvalidInputError(
197 formatString("Request for selection '%s' must "
198 "not be followed by others",
199 request.name().c_str())));
201 last = selections.end();
203 SelectionList curr(first, last);
204 request.storage_->addSelections(curr, true);
207 if (last != selections.end())
209 GMX_THROW(InvalidInputError("Too many selections provided"));
213 void SelectionOptionManager::Impl::requestUnsetRequiredOptions()
215 OptionList::const_iterator i;
216 for (i = options_.begin(); i != options_.end(); ++i)
218 SelectionOptionStorage &storage = **i;
219 if (storage.isRequired() && !storage.isSet())
221 requests_.push_back(SelectionRequest(&storage));
227 /********************************************************************
228 * SelectionOptionManager
231 SelectionOptionManager::SelectionOptionManager(SelectionCollection *collection)
232 : impl_(new Impl(collection))
236 SelectionOptionManager::~SelectionOptionManager()
241 SelectionOptionManager::registerOption(SelectionOptionStorage *storage)
243 impl_->requests_.reserve(impl_->options_.size() + 1);
244 impl_->options_.push_back(storage);
248 SelectionOptionManager::convertOptionValue(SelectionOptionStorage *storage,
249 const std::string &value)
251 SelectionList selections = impl_->collection_.parseFromString(value);
252 storage->addSelections(selections, false);
256 SelectionOptionManager::requestOptionDelayedParsing(
257 SelectionOptionStorage *storage)
259 impl_->requests_.push_back(Impl::SelectionRequest(storage));
263 SelectionOptionManager::parseRequestedFromStdin(bool bInteractive)
265 Impl::RequestsClearer clearRequestsOnExit(&impl_->requests_);
267 Impl::RequestList::const_iterator i;
268 for (i = impl_->requests_.begin(); i != impl_->requests_.end(); ++i)
270 const Impl::SelectionRequest &request = *i;
273 std::fprintf(stderr, "\nSpecify ");
274 if (request.count() < 0)
276 std::fprintf(stderr, "any number of selections");
278 else if (request.count() == 1)
280 std::fprintf(stderr, "a selection");
284 std::fprintf(stderr, "%d selections", request.count());
286 std::fprintf(stderr, " for option '%s' (%s):\n",
287 request.name().c_str(), request.description().c_str());
288 std::fprintf(stderr, "(one selection per line, 'help' for help%s)\n",
289 request.count() < 0 ? ", Ctrl-D to end" : "");
291 SelectionList selections
292 = impl_->collection_.parseFromStdin(request.count(), bInteractive);
293 request.storage_->addSelections(selections, true);
298 SelectionOptionManager::parseRequestedFromFile(const std::string &filename)
300 SelectionList selections = impl_->collection_.parseFromFile(filename);
301 impl_->placeSelectionsInRequests(selections);
305 SelectionOptionManager::parseRequestedFromString(const std::string &str)
307 SelectionList selections = impl_->collection_.parseFromString(str);
308 impl_->placeSelectionsInRequests(selections);