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 classes in symrec.h.
35 * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36 * \ingroup module_selection
42 #include "gromacs/legacyheaders/macros.h"
44 #include "gromacs/utility/exceptions.h"
45 #include "gromacs/utility/gmxassert.h"
46 #include "gromacs/utility/stringutil.h"
47 #include "gromacs/utility/uniqueptr.h"
56 /********************************************************************
57 * SelectionParserSymbol
61 * Private implementation class for SelectionParserSymbol.
63 * \ingroup module_selection
65 class SelectionParserSymbol::Impl
69 * Initializes a symbol.
71 * \param[in] type Type for the symbol.
72 * \param[in] name Name for the symbol.
74 * The symbol table is responsible for initializing the \a meth_ and
75 * \a var_ members as appropriate.
77 Impl(SymbolType type, const char *name)
78 : name_(name), type_(type), meth_(NULL)
82 //! Name of the symbol.
84 //! Type of the symbol.
86 //! Pointer to the method structure (\ref MethodSymbol).
87 gmx_ana_selmethod_t *meth_;
88 //! Pointer to the variable value (\ref VariableSymbol).
89 SelectionTreeElementPointer var_;
92 SelectionParserSymbol::SelectionParserSymbol(Impl *impl)
97 SelectionParserSymbol::~SelectionParserSymbol()
102 SelectionParserSymbol::name() const
107 SelectionParserSymbol::SymbolType
108 SelectionParserSymbol::type() const
113 gmx_ana_selmethod_t *
114 SelectionParserSymbol::methodValue() const
116 GMX_RELEASE_ASSERT(type() == MethodSymbol,
117 "Attempting to get method handle for a non-method symbol");
121 const gmx::SelectionTreeElementPointer &
122 SelectionParserSymbol::variableValue() const
124 GMX_RELEASE_ASSERT(type() == VariableSymbol,
125 "Attempting to get variable value for a non-variable symbol");
129 /********************************************************************
130 * SelectionParserSymbolTable::Impl
134 * Private implementation class for SelectionParserSymbolTable.
136 * All methods in this class may throw std::bad_alloc if out of memory.
138 * \ingroup module_selection
140 class SelectionParserSymbolTable::Impl
143 //! Smart pointer type for managing a SelectionParserSymbol.
144 typedef gmx::gmx_unique_ptr<SelectionParserSymbol>::type
146 //! Container type for the list of symbols.
147 typedef std::map<std::string, SymbolPointer> SymbolMap;
150 * Adds a symbol to the symbol list.
152 * \param[in] symbol Symbol to add.
154 void addSymbol(SymbolPointer symbol);
155 //! Adds the reserved symbols to this symbol table.
156 void addReservedSymbols();
157 //! Adds the position symbols to this symbol table.
158 void addPositionSymbols();
160 //! Symbols in this symbol table.
165 SelectionParserSymbolTable::Impl::addSymbol(SymbolPointer symbol)
167 symbols_.insert(std::make_pair(symbol->name(), move(symbol)));
171 SelectionParserSymbolTable::Impl::addReservedSymbols()
173 const char *const sym_reserved[] = {
187 for (size_t i = 0; i < asize(sym_reserved); ++i)
189 SymbolPointer sym(new SelectionParserSymbol(
190 new SelectionParserSymbol::Impl(
191 SelectionParserSymbol::ReservedSymbol, sym_reserved[i])));
192 addSymbol(move(sym));
197 SelectionParserSymbolTable::Impl::addPositionSymbols()
199 const char *const *postypes
200 = gmx::PositionCalculationCollection::typeEnumValues;
201 for (int i = 0; postypes[i] != NULL; ++i)
203 SymbolPointer sym(new SelectionParserSymbol(
204 new SelectionParserSymbol::Impl(
205 SelectionParserSymbol::PositionSymbol, postypes[i])));
206 addSymbol(move(sym));
210 /********************************************************************
211 * SelectionParserSymbolIterator
215 * Private implementation class for SelectionParserSymbolIterator.
217 * \ingroup module_selection
219 class SelectionParserSymbolIterator::Impl
222 //! Shorthand for the underlying iterator type.
223 typedef SelectionParserSymbolTable::Impl::SymbolMap::const_iterator
227 * Constructs an end iterator.
229 * \param[in] end Iterator to the end of the iterated container.
231 explicit Impl(IteratorType end)
232 : iter_(end), end_(end)
236 * Constructs an iterator.
238 * \param[in] iter Iterator to the current symbol.
239 * \param[in] end Iterator to the end of the iterated container.
241 Impl(IteratorType iter, IteratorType end)
242 : iter_(iter), end_(end)
246 //! Underlying iterator to the symbol container.
248 //! End of the symbol container being iterated.
252 SelectionParserSymbolIterator::SelectionParserSymbolIterator(Impl *impl)
257 SelectionParserSymbolIterator::SelectionParserSymbolIterator(
258 const SelectionParserSymbolIterator &other)
259 : impl_(new Impl(*other.impl_))
263 SelectionParserSymbolIterator::~SelectionParserSymbolIterator()
267 SelectionParserSymbolIterator &SelectionParserSymbolIterator::operator=(
268 const SelectionParserSymbolIterator &other)
270 impl_.reset(new Impl(*other.impl_));
274 bool SelectionParserSymbolIterator::operator==(
275 const SelectionParserSymbolIterator &other) const
277 return impl_->iter_ == other.impl_->iter_;
280 const SelectionParserSymbol &SelectionParserSymbolIterator::operator*() const
282 return *impl_->iter_->second;
285 SelectionParserSymbolIterator &SelectionParserSymbolIterator::operator++()
287 SelectionParserSymbol::SymbolType type = impl_->iter_->second->type();
292 while (impl_->iter_ != impl_->end_ && impl_->iter_->second->type() != type);
296 /********************************************************************
297 * SelectionParserSymbolTable
300 SelectionParserSymbolTable::SelectionParserSymbolTable()
303 impl_->addReservedSymbols();
304 impl_->addPositionSymbols();
307 SelectionParserSymbolTable::~SelectionParserSymbolTable()
311 const SelectionParserSymbol *
312 SelectionParserSymbolTable::findSymbol(const std::string &name,
315 Impl::SymbolMap::const_iterator sym = impl_->symbols_.lower_bound(name);
316 if (sym == impl_->symbols_.end())
320 if (sym->second->name() == name)
322 return sym->second.get();
324 if (!bExact && startsWith(sym->second->name(), name))
326 Impl::SymbolMap::const_iterator next = sym;
328 if (next != impl_->symbols_.end()
329 && startsWith(next->second->name(), name))
331 GMX_THROW(InvalidInputError("'" + name + "' is ambiguous"));
333 if (sym->second->type() == SelectionParserSymbol::MethodSymbol)
335 return sym->second.get();
341 SelectionParserSymbolIterator
342 SelectionParserSymbolTable::beginIterator(SelectionParserSymbol::SymbolType type) const
344 Impl::SymbolMap::const_iterator sym;
345 Impl::SymbolMap::const_iterator end = impl_->symbols_.end();
346 for (sym = impl_->symbols_.begin(); sym != end; ++sym)
348 if (sym->second->type() == type)
350 return SelectionParserSymbolIterator(
351 new SelectionParserSymbolIterator::Impl(sym, end));
354 return endIterator();
357 SelectionParserSymbolIterator
358 SelectionParserSymbolTable::endIterator() const
360 return SelectionParserSymbolIterator(
361 new SelectionParserSymbolIterator::Impl(impl_->symbols_.end()));
365 SelectionParserSymbolTable::addVariable(const char *name,
366 const gmx::SelectionTreeElementPointer &sel)
368 // In the current parser implementation, a syntax error is produced before
369 // this point is reached, but the check is here for robustness.
370 Impl::SymbolMap::const_iterator other = impl_->symbols_.find(name);
371 if (other != impl_->symbols_.end())
373 if (other->second->type() == SelectionParserSymbol::VariableSymbol)
375 GMX_THROW(InvalidInputError(
376 formatString("Reassigning variable '%s' is not supported",
381 GMX_THROW(InvalidInputError(
382 formatString("Variable name '%s' conflicts with a reserved keyword",
386 Impl::SymbolPointer sym(new SelectionParserSymbol(
387 new SelectionParserSymbol::Impl(
388 SelectionParserSymbol::VariableSymbol, name)));
389 sym->impl_->var_ = sel;
390 impl_->addSymbol(move(sym));
394 SelectionParserSymbolTable::addMethod(const char *name,
395 gmx_ana_selmethod_t *method)
397 if (impl_->symbols_.find(name) != impl_->symbols_.end())
400 formatString("Method name '%s' conflicts with another symbol",
403 Impl::SymbolPointer sym(new SelectionParserSymbol(
404 new SelectionParserSymbol::Impl(
405 SelectionParserSymbol::MethodSymbol, name)));
406 sym->impl_->meth_ = method;
407 impl_->addSymbol(move(sym));