.. _program_listing_file_uconfig_impl_Interface.ipp: Program Listing for File Interface.ipp ====================================== |exhale_lsh| :ref:`Return to documentation for file ` (``uconfig/impl/Interface.ipp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #pragma once namespace uconfig { template template ConfigIface::ConfigIface(const std::string& parse_path, Config* config) : path_(parse_path) { if (!config) { throw std::runtime_error("invalid section pointer to parse"); } config->Reset(); config->template SetFormat(); config->Init(Path()); cfg_optional_ = config->Optional(); cfg_interfaces_ = &config->template Interfaces(); cfg_validate_ = [config]() { config->Validate(); }; } template bool ConfigIface::Parse(const format_type& parser, const source_type* source, bool throw_on_fail) { bool config_parsed = false; for (auto& iface : *cfg_interfaces_) { bool iface_parsed; try { iface_parsed = iface->Parse(parser, source, throw_on_fail); } catch (const Error& ex) { iface_parsed = false; if (!Optional() && throw_on_fail) { throw ParseError(ex.what()); } } // section considered parsed if at least one of its' interfaces parsed config_parsed |= iface_parsed; } try { cfg_validate_(); } catch (const Error& ex) { if (throw_on_fail) { throw ParseError(ex.what()); } } catch (const std::exception& ex) { if (throw_on_fail) { throw ParseError(format_type::name + " config '" + Path() + "' is not valid: " + ex.what()); } } return config_parsed; } template void ConfigIface::Emit(const format_type& emitter, dest_type* dest, bool throw_on_fail) { for (auto& iface : *cfg_interfaces_) { try { iface->Emit(emitter, dest, throw_on_fail); } catch (const Error& ex) { if (!Optional() && throw_on_fail) { throw EmitError(ex.what()); } } } } template const std::string& ConfigIface::Path() const noexcept { return path_; } template bool ConfigIface::Initialized() const noexcept { for (const auto& iface : *cfg_interfaces_) { if (!iface->Initialized() && !iface->Optional()) { return false; } } return true; } template bool ConfigIface::Optional() const noexcept { return cfg_optional_; } template ValueIface::ValueIface(const std::string& variable_path, T* value) : path_(variable_path) , initialized_(false) , value_ptr_(value) { if (!value_ptr_) { throw std::runtime_error("invalid variable pointer to parse"); } } template bool ValueIface::Parse(const format_type& parser, const source_type* source, bool throw_on_fail) { std::optional result_opt = parser.template Parse(source, Path()); if (!result_opt) { if (!Optional() && throw_on_fail) { throw ParseError(format_type::name + " config '" + Path() + "' is not valid: variable is not set"); } return false; } *value_ptr_ = std::move(*result_opt); initialized_ = true; return true; } template void ValueIface::Emit(const format_type& emitter, dest_type* dest, bool /*throw_on_fail*/) { emitter.Emit(dest, Path(), *value_ptr_); } template const std::string& ValueIface::Path() const noexcept { return path_; } template bool ValueIface::Initialized() const noexcept { return initialized_; } template bool ValueIface::Optional() const noexcept { return false; } template VariableIface::VariableIface(const std::string& variable_path, Variable* variable) : path_(variable_path) , variable_ptr_(variable) { if (!variable_ptr_) { throw std::runtime_error("invalid variable pointer to parse"); } } template bool VariableIface::Parse(const format_type& parser, const source_type* source, bool throw_on_fail) { std::optional result_opt = parser.template Parse(source, Path()); if (!result_opt) { if (!Initialized() && throw_on_fail) { throw ParseError(format_type::name + " config '" + Path() + "' is not valid: variable is not set"); } return false; } *variable_ptr_ = std::move(*result_opt); try { variable_ptr_->Validate(); } catch (const Error& ex) { if (throw_on_fail) { throw ParseError(ex.what()); } } catch (const std::exception& ex) { if (throw_on_fail) { throw ParseError(format_type::name + " config '" + Path() + "' is not valid: " + ex.what()); } } return true; } template void VariableIface::Emit(const format_type& emitter, dest_type* dest, bool throw_on_fail) { try { emitter.Emit(dest, Path(), variable_ptr_->Get()); } catch (const std::exception& ex) { if (throw_on_fail) { throw EmitError(format_type::name + " config '" + Path() + "' is not valid: " + ex.what()); } return; } } template const std::string& VariableIface::Path() const noexcept { return path_; } template bool VariableIface::Initialized() const noexcept { return variable_ptr_->Initialized(); } template bool VariableIface::Optional() const noexcept { return variable_ptr_->Optional(); } template VectorIface::VectorIface(const std::string& vector_path, Vector* vector) : path_(vector_path) , vector_ptr_(vector) { if (!vector_ptr_) { throw std::runtime_error("invalid list pointer to parse"); } } template bool VectorIface::Parse(const format_type& parser, const source_type* source, bool throw_on_fail) { using elem_iface_type = detail::deduce_iface_t; std::size_t index = 0; std::optional last_error; while (true) { T element; bool elem_parsed = false; elem_iface_type elem_iface(parser.VectorElementPath(Path(), index), &element); try { elem_parsed = elem_iface.Parse(parser, source, true); } catch (const Error& ex) { last_error = ex; break; } // always stop on fail to prevent looping if (!elem_parsed || last_error) { break; } // we are about to emplace first parsed value, vector should be empty-initialized to do so if (!Initialized() || index == 0) { vector_ptr_->value_ = std::vector(); } vector_ptr_->value_->emplace_back(std::move(element)); ++index; } if (!Initialized() && !Optional()) { // notify that mandatory vector was not parsed if (last_error) { throw ParseError(last_error->what()); } else { throw ParseError(format_type::name + " config '" + Path() + "' is not valid: vector is not set"); } } try { vector_ptr_->Validate(); } catch (const Error& ex) { if (throw_on_fail) { throw ParseError(ex.what()); } } catch (const std::exception& ex) { if (throw_on_fail) { throw ParseError(format_type::name + " config '" + Path() + "' is not valid: " + ex.what()); } } return index > 0; } template void VectorIface::Emit(const format_type& emitter, dest_type* dest, bool throw_on_fail) { using elem_iface_type = detail::deduce_iface_t; std::size_t index = 0; while (true) { T* elem = nullptr; std::string elem_path = emitter.VectorElementPath(Path(), index); try { elem = &(*vector_ptr_)->at(index); } catch (const Error& ex) { if (!Optional() && throw_on_fail) { throw EmitError(format_type::name + " config '" + elem_path + "' is not valid: " + ex.what()); } return; } catch (const std::out_of_range& ex) { if (!Optional() && throw_on_fail) { throw EmitError(format_type::name + " config '" + elem_path + "' is not valid: variable is not set"); } return; } elem_iface_type iface(elem_path, elem); iface.Emit(emitter, dest, throw_on_fail); if (++index >= (*vector_ptr_)->size()) { return; } } } template const std::string& VectorIface::Path() const noexcept { return path_; } template bool VectorIface::Initialized() const noexcept { return vector_ptr_->Initialized(); } template bool VectorIface::Optional() const noexcept { return vector_ptr_->Optional(); } } // namespace uconfig