Take over management of OpenCL context from PME and NBNXM
[gromacs.git] / src / gromacs / options / options.cpp
blob16e47937d2d6b305b33998f93c08ee7fdcf56e27
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2010-2018, The GROMACS development team.
5 * Copyright (c) 2019, by the GROMACS development team, led by
6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 * and including many others, as listed in the AUTHORS file in the
8 * top-level source directory and at http://www.gromacs.org.
10 * GROMACS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * GROMACS is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with GROMACS; if not, see
22 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If you want to redistribute modifications to GROMACS, please
26 * consider that scientific software is very special. Version
27 * control is crucial - bugs must be traceable. We will be happy to
28 * consider code for inclusion in the official distribution, but
29 * derived work must not be called official GROMACS. Details are found
30 * in the README & COPYING files - if they are missing, get the
31 * official version at http://www.gromacs.org.
33 * To help us fund GROMACS development, we humbly ask that you cite
34 * the research papers on the package. Check out http://www.gromacs.org.
36 /*! \internal \file
37 * \brief
38 * Implements gmx::Options.
40 * \author Teemu Murtola <teemu.murtola@gmail.com>
41 * \ingroup module_options
43 #include "gmxpre.h"
45 #include "options.h"
47 #include <memory>
48 #include <utility>
50 #include "gromacs/options/abstractoption.h"
51 #include "gromacs/options/abstractoptionstorage.h"
52 #include "gromacs/options/optionsection.h"
53 #include "gromacs/utility/arrayref.h"
54 #include "gromacs/utility/exceptions.h"
55 #include "gromacs/utility/gmxassert.h"
56 #include "gromacs/utility/stringutil.h"
58 #include "options_impl.h"
60 namespace gmx
63 /********************************************************************
64 * IOptionManager
67 IOptionManager::~IOptionManager() {}
69 /********************************************************************
70 * IOptionsContainer
73 IOptionsContainer::~IOptionsContainer() {}
75 /********************************************************************
76 * IOptionsContainerWithSections
79 IOptionsContainerWithSections::~IOptionsContainerWithSections() {}
81 /********************************************************************
82 * IOptionSectionStorage
85 IOptionSectionStorage::~IOptionSectionStorage() {}
87 /********************************************************************
88 * OptionsImpl
91 namespace internal
94 OptionsImpl::OptionsImpl() : rootSection_(managers_, nullptr, "") {}
96 /********************************************************************
97 * OptionSectionImpl
100 OptionSectionImpl* OptionSectionImpl::addSectionImpl(const AbstractOptionSection& section)
102 const char* name = section.name_;
103 // Make sure that there are no duplicate sections.
104 GMX_RELEASE_ASSERT(findSection(name) == nullptr, "Duplicate subsection name");
105 std::unique_ptr<IOptionSectionStorage> storage(section.createStorage());
106 subsections_.push_back(std::make_unique<OptionSectionImpl>(managers_, std::move(storage), name));
107 return subsections_.back().get();
110 IOptionsContainer& OptionSectionImpl::addGroup()
112 return rootGroup_.addGroup();
115 OptionInfo* OptionSectionImpl::addOptionImpl(const AbstractOption& settings)
117 return rootGroup_.addOptionImpl(settings);
120 OptionSectionImpl* OptionSectionImpl::findSection(const char* name) const
122 for (const auto& section : subsections_)
124 if (section->name_ == name)
126 return section.get();
129 return nullptr;
132 AbstractOptionStorage* OptionSectionImpl::findOption(const char* name) const
134 OptionMap::const_iterator i = optionMap_.find(name);
135 if (i == optionMap_.end())
137 return nullptr;
139 return i->second.get();
142 void OptionSectionImpl::start()
144 for (const auto& entry : optionMap_)
146 entry.second->startSource();
148 if (storage_ != nullptr)
150 if (!storageInitialized_)
152 storage_->initStorage();
153 storageInitialized_ = true;
155 storage_->startSection();
159 void OptionSectionImpl::finish()
161 // TODO: Consider how to customize these error messages based on context.
162 ExceptionInitializer errors("Invalid input values");
163 for (const auto& entry : optionMap_)
165 AbstractOptionStorage& option = *entry.second;
168 option.finish();
170 catch (UserInputError& ex)
172 ex.prependContext("In option " + option.name());
173 errors.addCurrentExceptionAsNested();
176 if (errors.hasNestedExceptions())
178 // TODO: This exception type may not always be appropriate.
179 GMX_THROW(InvalidInputError(errors));
181 if (storage_ != nullptr)
183 storage_->finishSection();
187 /********************************************************************
188 * OptionSectionImpl::Group
191 IOptionsContainer& OptionSectionImpl::Group::addGroup()
193 subgroups_.emplace_back(parent_);
194 return subgroups_.back();
197 OptionInfo* OptionSectionImpl::Group::addOptionImpl(const AbstractOption& settings)
199 OptionSectionImpl::AbstractOptionStoragePointer option(settings.createStorage(parent_->managers_));
200 options_.reserve(options_.size() + 1);
201 auto insertionResult = parent_->optionMap_.insert(std::make_pair(option->name(), std::move(option)));
202 if (!insertionResult.second)
204 const std::string& name = insertionResult.first->second->name();
205 GMX_THROW(APIError("Duplicate option: " + name));
207 AbstractOptionStorage& insertedOption = *insertionResult.first->second;
208 options_.push_back(&insertedOption);
209 return &insertedOption.optionInfo();
212 } // namespace internal
214 using internal::OptionsImpl;
216 /********************************************************************
217 * Options
220 Options::Options() : impl_(new OptionsImpl) {}
222 Options::~Options() {}
225 void Options::addManager(IOptionManager* manager)
227 // This ensures that all options see the same set of managers.
228 GMX_RELEASE_ASSERT(impl_->rootSection_.optionMap_.empty(),
229 "Can only add a manager before options");
230 // This check could be relaxed if we instead checked that the subsections
231 // do not have options.
232 GMX_RELEASE_ASSERT(impl_->rootSection_.subsections_.empty(),
233 "Can only add a manager before subsections");
234 impl_->managers_.add(manager);
237 internal::OptionSectionImpl* Options::addSectionImpl(const AbstractOptionSection& section)
239 return impl_->rootSection_.addSectionImpl(section);
242 IOptionsContainer& Options::addGroup()
244 return impl_->rootSection_.addGroup();
247 OptionInfo* Options::addOptionImpl(const AbstractOption& settings)
249 return impl_->rootSection_.addOptionImpl(settings);
252 OptionSectionInfo& Options::rootSection()
254 return impl_->rootSection_.info();
257 const OptionSectionInfo& Options::rootSection() const
259 return impl_->rootSection_.info();
262 void Options::finish()
264 impl_->rootSection_.finish();
267 } // namespace gmx