From 4b530ecb8e87d80b4e26705be411d29b2d245df9 Mon Sep 17 00:00:00 2001 From: Dmitri Naumov <dmitri.naumov@ufz.de> Date: Tue, 30 Jan 2024 13:28:32 +0100 Subject: [PATCH] [BL] findElementOrError w/ callback Using in MPL shows no difference in runtime, one assembly instruction is different. --- BaseLib/Algorithm.h | 25 ++++++++++++ ChemistryLib/PhreeqcIO.cpp | 39 ++++++++++++------- MaterialLib/MPL/Medium.cpp | 12 ++---- MaterialLib/MPL/Phase.cpp | 12 ++---- .../SolidModels/MFront/MFrontGeneric.h | 6 +-- 5 files changed, 59 insertions(+), 35 deletions(-) diff --git a/BaseLib/Algorithm.h b/BaseLib/Algorithm.h index 774146c8ef9..07c86faa2d5 100644 --- a/BaseLib/Algorithm.h +++ b/BaseLib/Algorithm.h @@ -12,10 +12,14 @@ #include <algorithm> #include <cassert> +#include <concepts> #include <optional> +#include <range/v3/algorithm/find_if.hpp> +#include <range/v3/range/concepts.hpp> #include <string> #include <typeindex> #include <typeinfo> +#include <utility> #include "Error.h" @@ -65,6 +69,27 @@ void excludeObjectCopy(std::vector<T> const& src_vec, dest_vec = excludeObjectCopy(src_vec, exclude_positions); } +/// Returns reference to an element in the range satisfying the predicate. If no +/// such element is found, error_callback is called and reference to +/// past-the-end of the range is returned. +template <ranges::input_range Range> +ranges::range_reference_t<Range> findElementOrError( + Range& range, + std::predicate<ranges::range_reference_t<Range>> auto&& predicate, + std::invocable auto error_callback) +{ + auto it = + ranges::find_if(range, std::forward<decltype(predicate)>(predicate)); + if (it == ranges::end(range)) + { + error_callback(); + OGS_FATAL( + "Element not found in the input range. The user provided error " + "callback is meant not to return. That has not happened."); + } + return *it; +} + template <typename InputIt, typename Predicate> typename std::iterator_traits<InputIt>::reference findElementOrError( InputIt begin, InputIt end, Predicate predicate, diff --git a/ChemistryLib/PhreeqcIO.cpp b/ChemistryLib/PhreeqcIO.cpp index b4404552546..d109707cf2b 100644 --- a/ChemistryLib/PhreeqcIO.cpp +++ b/ChemistryLib/PhreeqcIO.cpp @@ -787,9 +787,12 @@ std::istream& operator>>(std::istream& in, PhreeqcIO& phreeqc_io) case ItemType::Component: { // Update component concentrations - auto& component = BaseLib::findElementOrError( - components.begin(), components.end(), compare_by_name, - "Could not find component '" + item_name + "'."); + auto const& component = BaseLib::findElementOrError( + components, compare_by_name, + [&]() { + OGS_FATAL("Could not find component '{:s}'.", + item_name); + }); MathLib::LinAlg::setLocalAccessibleVector( *component.amount); component.amount->set(global_index, @@ -801,10 +804,14 @@ std::istream& operator>>(std::istream& in, PhreeqcIO& phreeqc_io) // Update amounts of equilibrium reactant auto const& equilibrium_reactant = BaseLib::findElementOrError( - equilibrium_reactants.begin(), - equilibrium_reactants.end(), compare_by_name, - "Could not find equilibrium reactant '" + - item_name + "'."); + equilibrium_reactants, compare_by_name, + [&]() + { + OGS_FATAL( + "Could not find equilibrium reactant " + "'{:s}'", + item_name); + }); (*equilibrium_reactant.molality)[chemical_system_id] = accepted_items[item_id]; break; @@ -813,9 +820,11 @@ std::istream& operator>>(std::istream& in, PhreeqcIO& phreeqc_io) { // Update amounts of kinetic reactants auto const& kinetic_reactant = BaseLib::findElementOrError( - kinetic_reactants.begin(), kinetic_reactants.end(), - compare_by_name, - "Could not find kinetic reactant '" + item_name + "'."); + kinetic_reactants, compare_by_name, + [&]() { + OGS_FATAL("Could not find kinetic reactant '{:s}'.", + item_name); + }); (*kinetic_reactant.molality)[chemical_system_id] = accepted_items[item_id]; break; @@ -828,10 +837,12 @@ std::istream& operator>>(std::istream& in, PhreeqcIO& phreeqc_io) // Update values of secondary variables auto const& secondary_variable = BaseLib::findElementOrError( - secondary_variables.begin(), - secondary_variables.end(), compare_by_name, - "Could not find secondary variable '" + item_name + - "'."); + secondary_variables, compare_by_name, + [&]() { + OGS_FATAL( + "Could not find secondary variable '{:s}'.", + item_name); + }); (*secondary_variable.value)[chemical_system_id] = accepted_items[item_id]; break; diff --git a/MaterialLib/MPL/Medium.cpp b/MaterialLib/MPL/Medium.cpp index 8501f576acc..de36a444bd7 100644 --- a/MaterialLib/MPL/Medium.cpp +++ b/MaterialLib/MPL/Medium.cpp @@ -12,8 +12,6 @@ #include "Medium.h" -#include <range/v3/algorithm/find_if.hpp> - #include "BaseLib/Algorithm.h" #include "BaseLib/Error.h" #include "Properties/Properties.h" @@ -39,15 +37,11 @@ Phase const& Medium::phase(std::size_t const index) const Phase const& Medium::phase(std::string const& phase_name) const { - auto it = ranges::find_if( + return *BaseLib::findElementOrError( phases_, [&phase_name](std::unique_ptr<MaterialPropertyLib::Phase> const& phase) - { return phase->name == phase_name; }); - if (it == phases_.end()) - { - OGS_FATAL("Could not find phase name '{:s}.'", phase_name); - } - return **it; + { return phase->name == phase_name; }, + [&]() { OGS_FATAL("Could not find phase named '{:s}.'", phase_name); }); } bool Medium::hasPhase(std::string const& phase_name) const diff --git a/MaterialLib/MPL/Phase.cpp b/MaterialLib/MPL/Phase.cpp index e2e9e56b338..8a26de94c42 100644 --- a/MaterialLib/MPL/Phase.cpp +++ b/MaterialLib/MPL/Phase.cpp @@ -12,8 +12,6 @@ #include "Phase.h" -#include <range/v3/algorithm/find_if.hpp> - #include "BaseLib/Algorithm.h" #include "BaseLib/Error.h" #include "Component.h" @@ -44,16 +42,12 @@ bool Phase::hasComponent(std::size_t const& index) const Component const& Phase::component(std::string const& name) const { - auto it = ranges::find_if( + return *BaseLib::findElementOrError( components_, [&name]( std::unique_ptr<MaterialPropertyLib::Component> const& component) - { return component->name == name; }); - if (it == components_.end()) - { - OGS_FATAL("Could not find component name '{:s}.'", name); - } - return **it; + { return component->name == name; }, + [&]() { OGS_FATAL("Could not find component named '{:s}.'", name); }); } Property const& Phase::property(PropertyType const& p) const diff --git a/MaterialLib/SolidModels/MFront/MFrontGeneric.h b/MaterialLib/SolidModels/MFront/MFrontGeneric.h index b0e049d2de6..57118e3a181 100644 --- a/MaterialLib/SolidModels/MFront/MFrontGeneric.h +++ b/MaterialLib/SolidModels/MFront/MFrontGeneric.h @@ -427,11 +427,11 @@ public: { // find corresponding internal variable auto const& iv = BaseLib::findElementOrError( - begin(ivs), - end(ivs), + ivs, [name = name](InternalVariable const& iv) { return iv.name == name; }, - fmt::format("Internal variable `{:s}' not found.", name)); + [name = name]() + { OGS_FATAL("Internal variable `{:s}' not found.", name); }); // evaluate parameter std::vector<double> values = (*parameter)(t, x); -- GitLab