.. _program_listing_file_mcfp_sections.hpp: Program Listing for File sections.hpp ===================================== |exhale_lsh| :ref:`Return to documentation for file ` (``mcfp/sections.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2025 Maarten L. Hekkelman * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include "mcfp/options.hpp" #include #include #include #include #include #include #include // -------------------------------------------------------------------- namespace mcfp { class section { public: template requires(not(std::is_reference_v and ...)) explicit section(std::string name, Options const &...options) : m_name(std::move(name)) , m_impl(new config_impl(options...)) { } template requires(std::is_rvalue_reference_v and ...) explicit section(std::string name, Options &&...options) : m_name(std::move(name)) , m_impl(new config_impl(std::forward(options)...)) { } [[nodiscard]] const std::string &name() const noexcept { return m_name; } void write(std::ostream &os, size_t indent, size_t output_width) const { os << '\n'; if (not m_name.empty()) os << "section " << std::quoted(m_name) << "\n\n"; m_impl->write(os, m_name, indent, output_width); } [[nodiscard]] option_base *get_option(std::string_view name) const { return m_impl->get_option(name); } [[nodiscard]] option_base *get_option(char short_name) const { return m_impl->get_option(short_name); } [[nodiscard]] size_t get_option_width() const { return m_impl->get_option_width(m_name); } private: // -------------------------------------------------------------------- struct config_impl_base { virtual ~config_impl_base() = default; [[nodiscard]] virtual option_base *get_option(std::string_view name) = 0; [[nodiscard]] virtual option_base *get_option(char short_name) = 0; [[nodiscard]] virtual size_t get_option_width(std::string_view section_name) const = 0; virtual void write(std::ostream &os, std::string_view section_name, size_t wrap_width, size_t output_width) const = 0; [[nodiscard]] virtual config_impl_base *next() const noexcept { return nullptr; } }; template struct config_impl : public config_impl_base { static constexpr size_t N = sizeof...(Options); explicit config_impl(Options const &...options) requires(sizeof...(Options) > 0) : m_options(options...) { } explicit config_impl(Options &&...options) : m_options(std::forward(options)...) { } option_base *get_option(std::string_view name) override { return get_option_by_nr<0>(name); } template option_base *get_option_by_nr([[maybe_unused]] std::string_view name) { if constexpr (Ix == N) return nullptr; else { option_base &opt = std::get(m_options); return (opt.m_name == name) ? &opt : get_option_by_nr(name); } } option_base *get_option(char short_name) override { return get_option_by_nr<0>(short_name); } template option_base *get_option_by_nr([[maybe_unused]] char short_name) { if constexpr (Ix == N) return nullptr; else { option_base &opt = std::get(m_options); return (opt.m_short_name == short_name) ? &opt : get_option_by_nr(short_name); } } [[nodiscard]] size_t get_option_width(std::string_view section_name) const override { return std::apply([section_name](Options const &...opts) { size_t width = 0; ((width = std::max(width, opts.width(section_name))), ...); return width; }, m_options); } void write(std::ostream &os, std::string_view section_name, size_t wrap_width, size_t output_width) const override { std::apply([&os, section_name, wrap_width, output_width](auto &&...opts) { (opts.write(os, section_name, wrap_width, output_width), ...); }, m_options); } std::tuple m_options; }; template struct lib_config_impl : public config_impl { explicit lib_config_impl(std::string lib_name, Options &&...options) : config_impl(std::forward(options)...) , m_lib_name(std::move(lib_name)) { } [[nodiscard]] config_impl_base *next() const noexcept override { return m_next; } std::string m_lib_name; config_impl_base *m_next = nullptr; }; std::string m_name; std::unique_ptr m_impl; }; } // namespace mcfp