From e94f28292ba7233199a831c7b69acdae441af075 Mon Sep 17 00:00:00 2001 From: reneSchm <49305466+reneSchm@users.noreply.github.com> Date: Fri, 6 Feb 2026 12:25:39 +0100 Subject: [PATCH 01/10] modernize --- cpp/memilio/ad/ad.h | 20 ++ .../compartments/compartmental_model.h | 5 +- .../compartments/feedback_simulation.h | 8 +- cpp/memilio/compartments/flow_model.h | 10 +- cpp/memilio/compartments/parameter_studies.h | 12 +- cpp/memilio/compartments/simulation.h | 29 +-- cpp/memilio/compartments/stochastic_model.h | 1 - cpp/memilio/data/analyze_result.h | 105 ++++----- cpp/memilio/epidemiology/adoption_rate.h | 3 +- cpp/memilio/epidemiology/contact_matrix.h | 14 +- cpp/memilio/epidemiology/damping.cpp | 7 - cpp/memilio/epidemiology/damping.h | 16 +- cpp/memilio/epidemiology/damping_sampling.h | 8 +- cpp/memilio/epidemiology/dynamic_npis.h | 2 - .../epidemiology/lct_infection_state.h | 6 +- cpp/memilio/epidemiology/lct_populations.h | 53 ++--- cpp/memilio/epidemiology/populations.h | 14 +- cpp/memilio/epidemiology/state_age_function.h | 3 +- cpp/memilio/epidemiology/uncertain_matrix.h | 1 - cpp/memilio/geography/distance.h | 6 +- cpp/memilio/geography/geolocation.h | 3 +- cpp/memilio/geography/regions.cpp | 3 +- cpp/memilio/geography/regions.h | 11 +- cpp/memilio/geography/rtree.h | 8 +- cpp/memilio/io/binary_serializer.h | 33 ++- cpp/memilio/io/cli.cpp | 46 ++-- cpp/memilio/io/cli.h | 162 ++++++------- cpp/memilio/io/default_serialize.h | 57 +++-- cpp/memilio/io/hdf5_cpp.h | 8 +- cpp/memilio/io/history.h | 1 - cpp/memilio/io/io.h | 188 +++++++-------- cpp/memilio/io/json_serializer.h | 103 +++++---- cpp/memilio/io/parameters_io.cpp | 6 +- cpp/memilio/io/parameters_io.h | 25 +- cpp/memilio/math/eigen_util.h | 82 +++---- cpp/memilio/math/euler_maruyama.h | 2 +- cpp/memilio/math/math_utils.h | 4 +- cpp/memilio/math/matrix_shape.h | 9 +- cpp/memilio/math/smoother.h | 7 +- cpp/memilio/math/time_series_functor.h | 2 +- cpp/memilio/mobility/graph.h | 42 ++-- cpp/memilio/mobility/graph_builder.h | 7 +- cpp/memilio/mobility/graph_simulation.h | 2 +- .../metapopulation_mobility_instant.h | 50 +--- .../metapopulation_mobility_stochastic.h | 7 - cpp/memilio/timer/table_printer.h | 1 + cpp/memilio/timer/timer_registrar.h | 9 +- cpp/memilio/utils/base_dir.h | 2 +- cpp/memilio/utils/compiler_diagnostics.h | 12 +- cpp/memilio/utils/custom_index_array.h | 215 +++--------------- cpp/memilio/utils/logging.h | 27 +-- cpp/memilio/utils/metaprogramming.h | 116 +--------- cpp/memilio/utils/miompi.h | 2 +- cpp/memilio/utils/mioomp.h | 3 +- cpp/memilio/utils/parameter_distributions.h | 7 +- cpp/memilio/utils/parameter_set.h | 14 +- .../utils/pointer_dereferencing_iterator.h | 61 ----- cpp/memilio/utils/random_number_generator.h | 14 +- cpp/memilio/utils/span.h | 6 +- cpp/memilio/utils/stl_util.h | 38 +--- cpp/memilio/utils/time_series.h | 6 +- cpp/memilio/utils/transform_iterator.h | 212 ----------------- cpp/memilio/utils/type_list.h | 3 - cpp/memilio/utils/type_safe.h | 10 +- cpp/memilio/utils/uncertain_value.h | 6 +- cpp/tests/CMakeLists.txt | 1 - cpp/tests/actions.h | 6 +- cpp/tests/matchers.h | 6 +- cpp/tests/temp_file_register.h | 6 +- cpp/tests/test_graph.cpp | 18 +- cpp/tests/test_io_cli.cpp | 11 +- cpp/tests/test_metaprogramming.cpp | 34 --- cpp/tests/test_stl_util.cpp | 4 +- cpp/tests/test_transform_iterator.cpp | 53 ----- .../simulation/bindings/pickle_serializer.h | 3 - .../memilio/simulation/bindings/pybind_util.h | 6 +- .../memilio/simulation/bindings/utils/index.h | 2 +- 77 files changed, 681 insertions(+), 1424 deletions(-) delete mode 100644 cpp/memilio/utils/pointer_dereferencing_iterator.h delete mode 100644 cpp/memilio/utils/transform_iterator.h delete mode 100644 cpp/tests/test_transform_iterator.cpp diff --git a/cpp/memilio/ad/ad.h b/cpp/memilio/ad/ad.h index 9d2c3be434..e7cb865480 100644 --- a/cpp/memilio/ad/ad.h +++ b/cpp/memilio/ad/ad.h @@ -27,6 +27,26 @@ #include #include +namespace ad +{ +namespace internal +{ + +/** + * @brief Format AD types (like ad::gt1s::type) using their value for logging with spdlog. + * + * If derivative information is needed as well, use `ad::derivative(...)` or define a `fmt::formatter<...>`. + */ +template +const FP& format_as(const active_type& ad_type) +{ + // Note: the format_as function needs to be in the same namespace as the value it takes + return value(ad_type); +} + +} // namespace internal +} // namespace ad + // Allow std::numeric_limits to work with AD types. template struct std::numeric_limits> : public numeric_limits { diff --git a/cpp/memilio/compartments/compartmental_model.h b/cpp/memilio/compartments/compartmental_model.h index 532ff32c4f..0f8cabe048 100644 --- a/cpp/memilio/compartments/compartmental_model.h +++ b/cpp/memilio/compartments/compartmental_model.h @@ -20,8 +20,9 @@ #ifndef MIO_COMPARTMENTS_COMPARTMENTAL_MODEL_H #define MIO_COMPARTMENTS_COMPARTMENTAL_MODEL_H -#include "memilio/config.h" -#include "memilio/math/eigen.h" +#include "memilio/config.h" // IWYU pragma: keep +#include "memilio/math/eigen.h" // IWYU pragma: keep + #include namespace mio diff --git a/cpp/memilio/compartments/feedback_simulation.h b/cpp/memilio/compartments/feedback_simulation.h index e9f57bf4fa..9b7d5efb48 100644 --- a/cpp/memilio/compartments/feedback_simulation.h +++ b/cpp/memilio/compartments/feedback_simulation.h @@ -20,13 +20,11 @@ #ifndef MIO_COMPARTMENTS_FEEDBACK_SIMULATION_H #define MIO_COMPARTMENTS_FEEDBACK_SIMULATION_H -#include -#include "memilio/compartments/simulation.h" -#include "memilio/utils/time_series.h" -#include "memilio/utils/parameter_set.h" #include "memilio/epidemiology/age_group.h" -#include "memilio/utils/uncertain_value.h" #include "memilio/epidemiology/damping_sampling.h" +#include "memilio/utils/parameter_set.h" +#include "memilio/utils/time_series.h" +#include "memilio/utils/uncertain_value.h" namespace mio { diff --git a/cpp/memilio/compartments/flow_model.h b/cpp/memilio/compartments/flow_model.h index 1c59d42d1b..331dd230e2 100644 --- a/cpp/memilio/compartments/flow_model.h +++ b/cpp/memilio/compartments/flow_model.h @@ -24,7 +24,7 @@ #include "memilio/compartments/compartmental_model.h" #include "memilio/utils/index_range.h" #include "memilio/utils/flow.h" -#include "memilio/utils/type_list.h" +#include "memilio/utils/type_list.h" // IWYU pragma: keep for easier flow definitions namespace mio { @@ -37,8 +37,8 @@ namespace details // First a list of tuples is generated for each Tag in Tags, where the tuple is either of type tuple, or if // Tag == OmittedTag, of type tuple<>. This list is then concatenated, effectively removing OmittedTag. template -decltype(std::tuple_cat(std::declval::value, std::tuple<>, - std::tuple>::type>()...)) +decltype(std::tuple_cat( + std::declval, std::tuple<>, std::tuple>>()...)) filter_tuple(std::tuple); // Function declaration used to replace type T by std::tuple. @@ -135,7 +135,7 @@ class FlowModel : public CompartmentalModel * @param[out] dydt A reference to the calculated output. */ void get_derivatives(Eigen::Ref> pop, Eigen::Ref> y, FP t, - Eigen::Ref> dydt) const override final + Eigen::Ref> dydt) const final { m_flow_values.setZero(); get_flows(pop, y, t, m_flow_values); @@ -199,7 +199,7 @@ class FlowModel : public CompartmentalModel template constexpr size_t get_flat_flow_index() const { - static_assert(std::is_same>::value, "Other indices must be specified"); + static_assert(std::is_same_v>, "Other indices must be specified"); return index_of_type_v, Flows>; } diff --git a/cpp/memilio/compartments/parameter_studies.h b/cpp/memilio/compartments/parameter_studies.h index 72ccd8a0c9..674c72b8ff 100644 --- a/cpp/memilio/compartments/parameter_studies.h +++ b/cpp/memilio/compartments/parameter_studies.h @@ -22,9 +22,7 @@ #include "memilio/io/binary_serializer.h" #include "memilio/io/io.h" -#include "memilio/mobility/graph_simulation.h" #include "memilio/utils/logging.h" -#include "memilio/utils/metaprogramming.h" #include "memilio/utils/miompi.h" #include "memilio/utils/random_number_generator.h" #include "memilio/mobility/metapopulation_mobility_instant.h" @@ -160,14 +158,11 @@ class ParameterStudy run(CreateSimulationFunction&& create_simulation, ProcessSimulationResultFunction&& process_simulation_result) { using ResultT = EnsembleResultT; - int num_procs, rank; + int num_procs = 1, rank = 0; #ifdef MEMILIO_ENABLE_MPI MPI_Comm_size(mpi::get_world(), &num_procs); MPI_Comm_rank(mpi::get_world(), &rank); -#else - num_procs = 1; - rank = 0; #endif //The ParameterDistributions used for sampling parameters use thread_local_rng() @@ -176,9 +171,8 @@ class ParameterStudy m_rng.synchronize(); std::vector run_distribution = distribute_runs(m_num_runs, num_procs); - size_t start_run_idx = - std::accumulate(run_distribution.begin(), run_distribution.begin() + size_t(rank), size_t(0)); - size_t end_run_idx = start_run_idx + run_distribution[size_t(rank)]; + size_t start_run_idx = std::accumulate(run_distribution.begin(), run_distribution.begin() + rank, size_t(0)); + size_t end_run_idx = start_run_idx + run_distribution[rank]; if constexpr (std::is_void_v) { // if the processor returns nothing, there is nothing to synchronize diff --git a/cpp/memilio/compartments/simulation.h b/cpp/memilio/compartments/simulation.h index 9a872b811a..c468d8b8f4 100755 --- a/cpp/memilio/compartments/simulation.h +++ b/cpp/memilio/compartments/simulation.h @@ -23,7 +23,6 @@ #include "memilio/compartments/compartmental_model.h" #include "memilio/compartments/simulation_base.h" #include "memilio/math/integrator.h" -#include "memilio/utils/metaprogramming.h" #include "memilio/math/stepper_wrapper.h" #include "memilio/utils/time_series.h" @@ -75,27 +74,15 @@ class Simulation : public details::SimulationBase> }; /** - * Defines the return type of the `advance` member function of a type. - * Template is invalid if this member function does not exist. - * - * @tparam FP floating point type, e.g., double - * @tparam Sim a compartment model simulation type. - */ -template -using advance_expr_t = decltype(std::declval().advance(std::declval())); - -/** - * Template meta function to check if a type is a compartment model simulation. - * Defines a static constant of name `value`. - * The constant `value` will be equal to true if Sim is a valid compartment simulation type. - * Otherwise, `value` will be equal to false. - * @tparam FP floating point type, e.g., double - * @tparam Sim a type that may or may not be a compartment model simulation. + * Concept to check if a type is a simulation for a compartmental model. + * @tparam Simulation A type that may or may not be a compartmental model simulation. + * @tparam FP A floating point type, e.g., double. */ -template -using is_compartment_model_simulation = - std::integral_constant::value && - IsCompartmentalModel)>; +template +concept IsCompartmentalModelSimulation = requires(Simulation simulation, FP t) { + requires IsCompartmentalModel; + simulation.advance(t); +}; /** * @brief Run a Simulation of a CompartmentalModel. diff --git a/cpp/memilio/compartments/stochastic_model.h b/cpp/memilio/compartments/stochastic_model.h index 73f5cc33ce..ac998df646 100644 --- a/cpp/memilio/compartments/stochastic_model.h +++ b/cpp/memilio/compartments/stochastic_model.h @@ -22,7 +22,6 @@ #include "memilio/compartments/compartmental_model.h" #include "memilio/compartments/flow_model.h" -#include "memilio/utils/metaprogramming.h" #include "memilio/utils/random_number_generator.h" namespace mio diff --git a/cpp/memilio/data/analyze_result.h b/cpp/memilio/data/analyze_result.h index e78e0c6508..c07d1962e3 100644 --- a/cpp/memilio/data/analyze_result.h +++ b/cpp/memilio/data/analyze_result.h @@ -21,6 +21,7 @@ #define MEMILIO_DATA_ANALYZE_RESULT_H #include "memilio/config.h" +#include "memilio/utils/logging.h" #include "memilio/utils/time_series.h" #include "memilio/mobility/metapopulation_mobility_instant.h" #include "memilio/math/interpolation.h" @@ -376,81 +377,51 @@ template IOResult> merge_time_series(const TimeSeries& ts1, const TimeSeries& ts2, bool add_values = false) { - TimeSeries merged_ts(ts1.get_num_elements()); if (ts1.get_num_elements() != ts2.get_num_elements()) { log_error("TimeSeries have a different number of elements."); return failure(mio::StatusCode::InvalidValue); } - else { - Eigen::Index t1_iterator = 0; - Eigen::Index t2_iterator = 0; - bool t1_finished = false; - bool t2_finished = false; - while (!t1_finished || !t2_finished) { - if (!t1_finished) { - if (ts1.get_time(t1_iterator) < ts2.get_time(t2_iterator) || - t2_finished) { // Current time point of first TimeSeries is smaller than current time point of second TimeSeries or second TimeSeries has already been copied entirely - merged_ts.add_time_point(ts1.get_time(t1_iterator), ts1.get_value(t1_iterator)); - t1_iterator += 1; - } - else if (!t2_finished && ts1.get_time(t1_iterator) == - ts2.get_time(t2_iterator)) { // Both TimeSeries have the current time point - if (add_values) { - merged_ts.add_time_point(ts1.get_time(t1_iterator), - ts1.get_value(t1_iterator) + ts2.get_value(t2_iterator)); - } - else { - merged_ts.add_time_point(ts1.get_time(t1_iterator), ts1.get_value(t1_iterator)); - log_warning("Both TimeSeries have values for t={}. The value of the first TimeSeries is used", - ts1.get_time(t1_iterator)); - } - t1_iterator += 1; - t2_iterator += 1; - if (t2_iterator >= - ts2.get_num_time_points()) { // Check if all values of second TimeSeries have been copied - t2_finished = true; - t2_iterator = ts2.get_num_time_points() - 1; - } - } - if (t1_iterator >= - ts1.get_num_time_points()) { // Check if all values of first TimeSeries have been copied - t1_finished = true; - t1_iterator = ts1.get_num_time_points() - 1; - } + if (!ts1.is_strictly_monotonic() || !ts2.is_strictly_monotonic()) { + log_error("TimeSeries need to have strictly monotonic time points to be merged."); + return failure(mio::StatusCode::InvalidValue); + } + Eigen::Index t1_iterator = 0; + Eigen::Index t2_iterator = 0; + const Eigen::Index t1_size = ts1.get_num_time_points(); + const Eigen::Index t2_size = ts2.get_num_time_points(); + TimeSeries merged_ts(ts1.get_num_elements()); + merged_ts.reserve(t1_size + t2_size); + // merge entries of both time series until one finishes + while (t1_iterator < t1_size && t2_iterator < t2_size) { + // check which ts has the smaller time at the current iterator, and merge it + if (ts1.get_time(t1_iterator) < ts2.get_time(t2_iterator)) { + merged_ts.add_time_point(ts1.get_time(t1_iterator), ts1.get_value(t1_iterator)); + ++t1_iterator; + } + else if (ts1.get_time(t1_iterator) == ts2.get_time(t2_iterator)) { + merged_ts.add_time_point(ts1.get_time(t1_iterator), ts1.get_value(t1_iterator)); + if (add_values) { + merged_ts.get_last_value() += ts2.get_value(t2_iterator); } - if (!t2_finished) { - if (ts2.get_time(t2_iterator) < ts1.get_time(t1_iterator) || - t1_finished) { // Current time point of second TimeSeries is smaller than current time point of first TimeSeries or first TimeSeries has already been copied entirely - merged_ts.add_time_point(ts2.get_time(t2_iterator), ts2.get_value(t2_iterator)); - t2_iterator += 1; - } - else if (!t1_finished && ts2.get_time(t2_iterator) == - ts1.get_time(t1_iterator)) { // Both TimeSeries have the current time point - if (add_values) { - merged_ts.add_time_point(ts1.get_time(t1_iterator), - ts1.get_value(t1_iterator) + ts2.get_value(t2_iterator)); - } - else { - merged_ts.add_time_point(ts1.get_time(t1_iterator), ts1.get_value(t1_iterator)); - log_warning("Both TimeSeries have values for t={}. The value of the first TimeSeries is used", - ts1.get_time(t1_iterator)); - } - t1_iterator += 1; - t2_iterator += 1; - if (t1_iterator >= - ts1.get_num_time_points()) { // Check if all values of first TimeSeries have been copied - t1_finished = true; - t1_iterator = ts1.get_num_time_points() - 1; - } - } - if (t2_iterator >= - ts2.get_num_time_points()) { // Check if all values of second TimeSeries have been copied - t2_finished = true; - t2_iterator = ts2.get_num_time_points() - 1; - } + else { + log_warning("Both TimeSeries have values for t={}. The value of the first TimeSeries is used", + ts1.get_time(t1_iterator)); } + ++t1_iterator; + ++t2_iterator; + } + else { // " > " + merged_ts.add_time_point(ts2.get_time(t2_iterator), ts2.get_value(t2_iterator)); + ++t2_iterator; } } + // append remaining entries. at most one of the following for loops will be executed + for (; t1_iterator < t1_size; ++t1_iterator) { + merged_ts.add_time_point(ts1.get_time(t1_iterator), ts1.get_value(t1_iterator)); + } + for (; t2_iterator < t2_size; ++t2_iterator) { + merged_ts.add_time_point(ts2.get_time(t2_iterator), ts2.get_value(t2_iterator)); + } return success(merged_ts); } diff --git a/cpp/memilio/epidemiology/adoption_rate.h b/cpp/memilio/epidemiology/adoption_rate.h index 30f4a4f4e1..97b58e7b6a 100644 --- a/cpp/memilio/epidemiology/adoption_rate.h +++ b/cpp/memilio/epidemiology/adoption_rate.h @@ -20,8 +20,7 @@ #ifndef MIO_EPI_ADOPTIONRATE_H #define MIO_EPI_ADOPTIONRATE_H -#include "memilio/utils/index.h" -#include "memilio/config.h" +#include "memilio/config.h" // IWYU pragma: keep #include "memilio/geography/regions.h" namespace mio diff --git a/cpp/memilio/epidemiology/contact_matrix.h b/cpp/memilio/epidemiology/contact_matrix.h index 1414442560..c17cb23ab1 100644 --- a/cpp/memilio/epidemiology/contact_matrix.h +++ b/cpp/memilio/epidemiology/contact_matrix.h @@ -17,14 +17,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef EPI_ODE_CONTACT_FREQUENCY_MATRIX_H -#define EPI_ODE_CONTACT_FREQUENCY_MATRIX_H +#ifndef MIO_EPI_CONTACT_MATRIX_H +#define MIO_EPI_CONTACT_MATRIX_H #include "memilio/epidemiology/damping.h" -#include "memilio/math/matrix_shape.h" #include "memilio/math/math_utils.h" #include "memilio/utils/stl_util.h" -#include "memilio/utils/logging.h" #include #include @@ -84,7 +82,8 @@ class DampingMatrixExpression * @param shape_args shape arguments. * @tparam T shape arguments. */ - template ::value, void>> + template + requires std::is_constructible_v explicit DampingMatrixExpression(T... shape_args) : DampingMatrixExpression(Matrix::Zero(Shape(shape_args...).rows(), Shape(shape_args...).cols())) { @@ -287,7 +286,8 @@ class DampingMatrixExpressionGroup * @param num_groups number of groups. * @param num_matrices number of matrices. */ - template ::value, int>> + template + requires(std::is_constructible_v) explicit DampingMatrixExpressionGroup(size_t num_matrices, T... shape_args) : m_matrices(num_matrices, value_type{shape_args...}) { @@ -559,4 +559,4 @@ class ContactMatrixGroup : public DampingMatrixExpressionGroup -#include -#include -#include namespace mio { diff --git a/cpp/memilio/epidemiology/damping.h b/cpp/memilio/epidemiology/damping.h index 477d069989..3017db2373 100644 --- a/cpp/memilio/epidemiology/damping.h +++ b/cpp/memilio/epidemiology/damping.h @@ -20,8 +20,8 @@ #ifndef DAMPING_H #define DAMPING_H -#include "memilio/config.h" -#include "memilio/math/eigen.h" +#include "memilio/config.h" // IWYU pragma: keep +#include "memilio/math/eigen.h" // IWYU pragma: keep #include "memilio/utils/compiler_diagnostics.h" #include "memilio/utils/type_safe.h" #include "memilio/utils/stl_util.h" @@ -80,7 +80,8 @@ class Damping : public std::tuple::value, int>> + template + requires std::is_constructible_v explicit Damping(T... shape_args) : Base(Matrix::Zero(Shape(shape_args...).rows(), Shape(shape_args...).cols()), {}, {}, {}) { @@ -110,7 +111,8 @@ class Damping : public std::tuple::value, void>> + template + requires std::is_constructible_v Damping(FP d, DampingLevel level, DampingType type, SimulationTime t, T... shape_args) : Damping(Matrix::Constant(Shape(shape_args...).rows(), Shape(shape_args...).cols(), d), level, type, t) { @@ -135,7 +137,8 @@ class Damping : public std::tuple::value, void>> + template + requires std::is_constructible_v Damping(FP d, SimulationTime t, T... shape_args) : Damping(d, DampingLevel(0), DampingType(0), t, shape_args...) { @@ -267,7 +270,8 @@ class Dampings * @param num_dampings number of initial elements in the collection * @tparam T Shape constructor arguments. */ - template ::value, void>> + template + requires std::is_constructible_v explicit Dampings(T... shape_args) : m_dampings() , m_shape(shape_args...) diff --git a/cpp/memilio/epidemiology/damping_sampling.h b/cpp/memilio/epidemiology/damping_sampling.h index a699bba60f..e6e1818f2d 100644 --- a/cpp/memilio/epidemiology/damping_sampling.h +++ b/cpp/memilio/epidemiology/damping_sampling.h @@ -17,13 +17,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef EPI_SECIR_DAMPING_SAMPLING_H -#define EPI_SECIR_DAMPING_SAMPLING_H +#ifndef MIO_EPI_DAMPING_SAMPLING_H +#define MIO_EPI_DAMPING_SAMPLING_H #include "memilio/epidemiology/damping.h" -#include "memilio/utils/random_number_generator.h" #include "memilio/utils/uncertain_value.h" -#include namespace mio { @@ -309,4 +307,4 @@ auto make_mobility_damping_vector(ColumnVectorShape shape, V&& groups) } // namespace mio -#endif //EPI_SECIR_DAMPING_SAMPLING_H +#endif // MIO_EPI_DAMPING_SAMPLING_H diff --git a/cpp/memilio/epidemiology/dynamic_npis.h b/cpp/memilio/epidemiology/dynamic_npis.h index 46e6a707ca..091c97d8f9 100644 --- a/cpp/memilio/epidemiology/dynamic_npis.h +++ b/cpp/memilio/epidemiology/dynamic_npis.h @@ -20,9 +20,7 @@ #ifndef MIO_EPI_DYNAMIC_LOCKDOWN_H #define MIO_EPI_DYNAMIC_LOCKDOWN_H -#include "memilio/epidemiology/contact_matrix.h" #include "memilio/epidemiology/damping_sampling.h" -#include "memilio/math/floating_point.h" #include "memilio/utils/stl_util.h" namespace mio diff --git a/cpp/memilio/epidemiology/lct_infection_state.h b/cpp/memilio/epidemiology/lct_infection_state.h index bfd6bd65ed..151440653d 100644 --- a/cpp/memilio/epidemiology/lct_infection_state.h +++ b/cpp/memilio/epidemiology/lct_infection_state.h @@ -20,8 +20,8 @@ #ifndef MIO_EPI_LCT_INFECTION_STATE_H #define MIO_EPI_LCT_INFECTION_STATE_H -#include "memilio/config.h" -#include "memilio/math/eigen.h" +#include "memilio/config.h" // IWYU pragma: keep +#include "memilio/math/eigen.h" // IWYU pragma: keep #include @@ -97,7 +97,7 @@ class LctInfectionState Eigen::VectorX compartments((Eigen::Index)InfectionState::Count); // Use segment of the vector subcompartments of each InfectionState and sum up the values of subcompartments. for (int i = 0; i < (Eigen::Index)InfectionState::Count; i++) { - InfectionState State = static_cast(i); + auto State = static_cast(i); // first index of first subcompartment: size_t index = 0; for (size_t j = 0; j < (size_t)(State); j++) { diff --git a/cpp/memilio/epidemiology/lct_populations.h b/cpp/memilio/epidemiology/lct_populations.h index ee7fa4ef97..9dbcd65701 100644 --- a/cpp/memilio/epidemiology/lct_populations.h +++ b/cpp/memilio/epidemiology/lct_populations.h @@ -20,13 +20,13 @@ #ifndef MIO_EPI_LCT_POPULATIONS_H #define MIO_EPI_LCT_POPULATIONS_H -#include "boost/type_traits/make_void.hpp" -#include "memilio/config.h" -#include "memilio/utils/uncertain_value.h" -#include "memilio/math/eigen.h" -#include "memilio/epidemiology/lct_infection_state.h" -#include "memilio/utils/type_list.h" +#include "memilio/config.h" // IWYU pragma: keep +#include "memilio/math/eigen.h" // IWYU pragma: keep +#include "memilio/epidemiology/lct_infection_state.h" // IWYU pragma: keep for ease of use #include "memilio/utils/metaprogramming.h" +#include "memilio/utils/type_list.h" +#include "memilio/utils/uncertain_value.h" +#include namespace mio { @@ -64,9 +64,8 @@ class LctPopulations /// @brief Default constructor. LctPopulations() + : m_y(InternalArrayType::Constant(get_count(), UncertainValue(0.0))) { - set_count(); - m_y = InternalArrayType::Constant(m_count, UncertainValue(0.0)); } /** @@ -75,7 +74,7 @@ class LctPopulations */ size_t get_num_compartments() const { - return m_count; + return m_y.size(); } /** @@ -98,7 +97,7 @@ class LctPopulations */ Type& operator[](size_t index) { - assert(index < m_count); + assert(index < static_cast(m_y.size())); return m_y[index]; } @@ -125,7 +124,7 @@ class LctPopulations */ inline Eigen::VectorX get_compartments() const { - return m_y.array().template cast(); + return m_y.template cast(); } /** @@ -136,8 +135,7 @@ class LctPopulations template FP get_group_total() const { - return m_y.array() - .template cast() + return m_y.template cast() .segment(get_first_index_of_group(), type_at_index_t::Count) .sum(); } @@ -148,7 +146,7 @@ class LctPopulations */ FP get_total() const { - return m_y.array().template cast().sum(); + return m_y.template cast().sum(); } /** @@ -166,16 +164,16 @@ class LctPopulations bool apply_constraints() { bool corrected = false; - for (int i = 0; i < m_y.array().size(); i++) { - if (m_y.array()[i] < 0.0) { - if (m_y.array()[i] > -1e-10) { - log_warning("Constraint check: Compartment number {} changed from {} to {}", i, m_y.array()[i], 0); + for (int i = 0; i < m_y.size(); i++) { + if (m_y[i] < 0.0) { + if (m_y[i] > -1e-10) { + log_warning("Constraint check: Compartment number {} changed from {} to {}", i, m_y[i], 0); } else { - log_error("Constraint check: Compartment number {} changed from {} to {}", i, m_y.array()[i], 0); + log_error("Constraint check: Compartment number {} changed from {} to {}", i, m_y[i], 0); } - m_y.array()[i] = 0.; - corrected = true; + m_y[i] = 0.; + corrected = true; } } return corrected; @@ -187,7 +185,7 @@ class LctPopulations */ bool check_constraints() const { - if ((m_y.array() < 0.0).any()) { + if ((m_y < 0.0).any()) { log_error("Constraint check: At least one compartment size is smaller {}.", 0); return true; } @@ -200,18 +198,15 @@ class LctPopulations * The number also corresponds to the size of the internal vector. */ template - void set_count() + [[nodiscard]] static size_t get_count() { - if constexpr (Group == 0) { - m_count = 0; - } + size_t count = 0; if constexpr (Group < num_groups) { - m_count += type_at_index_t::Count; - set_count(); + count = type_at_index_t::Count + get_count(); } + return count; } - size_t m_count; //< Number of groups stored. InternalArrayType m_y{}; //< An array containing the number of people in the groups. }; diff --git a/cpp/memilio/epidemiology/populations.h b/cpp/memilio/epidemiology/populations.h index 7261c173e5..aca6921420 100644 --- a/cpp/memilio/epidemiology/populations.h +++ b/cpp/memilio/epidemiology/populations.h @@ -20,11 +20,11 @@ #ifndef MIO_EPI_POPULATIONS_H #define MIO_EPI_POPULATIONS_H -#include "memilio/config.h" -#include "memilio/utils/uncertain_value.h" -#include "memilio/utils/custom_index_array.h" -#include "memilio/math/eigen.h" +#include "memilio/config.h" // IWYU pragma: keep +#include "memilio/math/eigen.h" // IWYU pragma: keep #include "memilio/math/math_utils.h" +#include "memilio/utils/custom_index_array.h" +#include "memilio/utils/uncertain_value.h" #include #include @@ -57,8 +57,8 @@ class Populations : public CustomIndexArray, Categories...> using Base = CustomIndexArray, Categories...>; using Index = typename Base::Index; - template , Ts...>::value>* = nullptr> + template + requires std::is_constructible_v, Ts...> explicit Populations(Index const& sizes, Ts... args) : Base(sizes, args...) { @@ -122,7 +122,7 @@ class Populations : public CustomIndexArray, Categories...> template decltype(auto) get_from(Arr&& y, Index const& cats) const { - static_assert(std::is_lvalue_reference::value, "get_from is disabled for temporary arrays."); + static_assert(std::is_lvalue_reference_v, "get_from is disabled for temporary arrays."); return y[this->get_flat_index(cats)]; } diff --git a/cpp/memilio/epidemiology/state_age_function.h b/cpp/memilio/epidemiology/state_age_function.h index b54edb7575..1ac1246431 100644 --- a/cpp/memilio/epidemiology/state_age_function.h +++ b/cpp/memilio/epidemiology/state_age_function.h @@ -23,13 +23,12 @@ #include "memilio/config.h" #include "memilio/utils/compiler_diagnostics.h" -#include "memilio/utils/parameter_set.h" #include "memilio/math/smoother.h" #include "memilio/math/floating_point.h" -#include "memilio/epidemiology/uncertain_matrix.h" #include "boost/math/distributions/gamma.hpp" #include "boost/math/distributions/lognormal.hpp" +#include "memilio/utils/logging.h" namespace mio { diff --git a/cpp/memilio/epidemiology/uncertain_matrix.h b/cpp/memilio/epidemiology/uncertain_matrix.h index 646f499413..81715b32a6 100644 --- a/cpp/memilio/epidemiology/uncertain_matrix.h +++ b/cpp/memilio/epidemiology/uncertain_matrix.h @@ -20,7 +20,6 @@ #ifndef MIO_EPI_ODE_UNCERTAINMATRIX_H #define MIO_EPI_ODE_UNCERTAINMATRIX_H -#include "memilio/utils/date.h" #include "memilio/epidemiology/contact_matrix.h" #include "memilio/epidemiology/damping_sampling.h" diff --git a/cpp/memilio/geography/distance.h b/cpp/memilio/geography/distance.h index f8f7746e19..f436fa48d2 100644 --- a/cpp/memilio/geography/distance.h +++ b/cpp/memilio/geography/distance.h @@ -17,8 +17,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef MIO_DISTANCE_H -#define MIO_DISTANCE_H +#ifndef MIO_GEOGRAPHY_DISTANCE_H +#define MIO_GEOGRAPHY_DISTANCE_H #include "memilio/config.h" #include "memilio/io/default_serialize.h" @@ -150,4 +150,4 @@ constexpr inline Distance kilometers(ScalarType kilometers) } // namespace geo } // namespace mio -#endif +#endif // MIO_GEOGRAPHY_DISTANCE_H diff --git a/cpp/memilio/geography/geolocation.h b/cpp/memilio/geography/geolocation.h index 92491de0e5..e92a7cd573 100644 --- a/cpp/memilio/geography/geolocation.h +++ b/cpp/memilio/geography/geolocation.h @@ -24,10 +24,11 @@ #include "memilio/io/default_serialize.h" #include "memilio/geography/distance.h" #include "memilio/config.h" -#include "memilio/utils/logging.h" + #include #include #include + namespace mio { namespace geo diff --git a/cpp/memilio/geography/regions.cpp b/cpp/memilio/geography/regions.cpp index ac80aed64a..8b34d1449c 100644 --- a/cpp/memilio/geography/regions.cpp +++ b/cpp/memilio/geography/regions.cpp @@ -20,6 +20,7 @@ #include "memilio/geography/regions.h" #include "memilio/geography/holiday_data.ipp" +#include #include namespace mio @@ -102,7 +103,7 @@ get_holidays(StateId state, Date start_date, Date end_date) //all holiday periods that overlap with the specified period auto holidays_in_range = - std::equal_range(all.begin(), all.end(), std::make_pair(start_date, end_date), [](auto& p1, auto& p2) { + std::ranges::equal_range(all, std::make_pair(start_date, end_date), [](auto& p1, auto& p2) { return std::tie(p1.second.year, p1.second.month, p1.second.day) < std::tie(p2.first.year, p2.first.month, p2.first.day); }); diff --git a/cpp/memilio/geography/regions.h b/cpp/memilio/geography/regions.h index e44995a6fc..5013714df2 100644 --- a/cpp/memilio/geography/regions.h +++ b/cpp/memilio/geography/regions.h @@ -17,19 +17,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef MIO_EPI_REGIONS_H -#define MIO_EPI_REGIONS_H +#ifndef MIO_GEOGRAPHY_REGIONS_H +#define MIO_GEOGRAPHY_REGIONS_H #include "memilio/utils/date.h" #include "memilio/utils/stl_util.h" #include "memilio/utils/type_safe.h" #include "memilio/utils/index.h" -#include "boost/filesystem.hpp" - -//is used to provide some paths as function arguments -namespace fs = boost::filesystem; - namespace mio { /** @@ -106,4 +101,4 @@ get_holidays(StateId state, Date start_date, Date end_date); } // namespace regions } // namespace mio -#endif //MIO_EPI_REGIONS_H +#endif // MIO_GEOGRAPHY_REGIONS_H diff --git a/cpp/memilio/geography/rtree.h b/cpp/memilio/geography/rtree.h index f4fb837e60..10f048b54c 100644 --- a/cpp/memilio/geography/rtree.h +++ b/cpp/memilio/geography/rtree.h @@ -20,14 +20,16 @@ #ifndef MIO_GEOGRAPHY_RTREE_H #define MIO_GEOGRAPHY_RTREE_H -#include "memilio/utils/back_inserter_second_element.h" #include "memilio/geography/distance.h" +#include "memilio/utils/back_inserter_second_element.h" + #include +#include #include #include #include -#include -#include + +#include #include #include #include diff --git a/cpp/memilio/io/binary_serializer.h b/cpp/memilio/io/binary_serializer.h index ccbf8ee21f..95fb72701a 100644 --- a/cpp/memilio/io/binary_serializer.h +++ b/cpp/memilio/io/binary_serializer.h @@ -23,9 +23,8 @@ #include "memilio/io/io.h" #include "memilio/io/serializer_base.h" #include "memilio/utils/compiler_diagnostics.h" -#include "memilio/utils/metaprogramming.h" + #include -#include #include #include #include @@ -152,7 +151,8 @@ class BinarySerializerObject : public SerializerBase * @param name Name of the element. * @param value Value to be serialized. */ - template ::value, void*> = nullptr> + template + requires std::is_trivial_v void add_element(const std::string& name, const T& value); /** @@ -167,7 +167,8 @@ class BinarySerializerObject : public SerializerBase * @param name Name of the element. * @param value Value to be serialized. */ - template >, void*> = nullptr> + template + requires(!std::is_trivial_v) void add_element(const std::string& name, const T& value); /** @@ -178,7 +179,8 @@ class BinarySerializerObject : public SerializerBase * @param tag Tag that determines the type of the element. * @returns Deserialized value. */ - template ::value, void*> = nullptr> + template + requires std::is_trivial_v IOResult expect_element(const std::string& name, Tag tag); /** @@ -187,7 +189,8 @@ class BinarySerializerObject : public SerializerBase * @param tag Tag that determines the type of the element. * @returns Deserialized value. */ - template >::value, void*> = nullptr> + template + requires(!std::is_trivial_v) IOResult expect_element(const std::string& name, Tag tag); /** @@ -287,7 +290,8 @@ class BinarySerializerContext : public SerializerBase * @param ctxt The serialization context. * @param t The value to be serialized. */ - template ::value, void*> = nullptr> + template + requires std::is_trivial_v friend void serialize_internal(BinarySerializerContext& ctxt, const T& t) { //add element to dummy object. @@ -302,7 +306,8 @@ class BinarySerializerContext : public SerializerBase * @param tag The value to be serialized. * @returns The deserialized value. */ - template ::value, void*> = nullptr> + template + requires std::is_trivial_v friend IOResult deserialize_internal(BinarySerializerContext& ctxt, Tag tag) { unused(tag); @@ -315,7 +320,8 @@ class BinarySerializerContext : public SerializerBase ByteStream& m_stream; ///< Reference to a stream that stores the serialized bytes. }; -template ::value, void*>> +template + requires std::is_trivial_v void BinarySerializerObject::add_element(const std::string& name, const T& value) { mio::unused(name); @@ -323,7 +329,8 @@ void BinarySerializerObject::add_element(const std::string& name, const T& value m_stream.write(p, sizeof(value)); } -template >, void*>> +template + requires(!std::is_trivial_v) void BinarySerializerObject::add_element(const std::string& name, const T& value) { mio::unused(name); @@ -341,7 +348,8 @@ inline void BinarySerializerObject::add_element(const std::string& name, const s m_stream.write(p_data, size); } -template ::value, void*>> +template + requires std::is_trivial_v IOResult BinarySerializerObject::expect_element(const std::string& name, Tag /*tag*/) { mio::unused(name); @@ -359,7 +367,8 @@ IOResult BinarySerializerObject::expect_element(const std::string& name, Tag< return failure(*m_status); } -template >::value, void*>> +template + requires(!std::is_trivial_v) IOResult BinarySerializerObject::expect_element(const std::string& name, Tag tag) { mio::unused(name); diff --git a/cpp/memilio/io/cli.cpp b/cpp/memilio/io/cli.cpp index de2d9f583b..1ac5377024 100644 --- a/cpp/memilio/io/cli.cpp +++ b/cpp/memilio/io/cli.cpp @@ -120,8 +120,9 @@ mio::IOResult mio::cli::details::read_abstract_set_from_file(mio::cli::det return mio::success(); } -mio::IOResult mio::cli::details::command_line_interface(const std::string& executable_name, const int argc, - char** argv, cli::details::AbstractSet& set, +mio::IOResult mio::cli::details::command_line_interface(const std::string& executable_name, + const std::span& argv, + cli::details::AbstractSet& set, const std::vector& default_options) { assert(set.parameters().size() > 0 && "At least one parameter is required!"); @@ -137,8 +138,8 @@ mio::IOResult mio::cli::details::command_line_interface(const std::string& } // pre-scan all argumemts before doing anything with them to deal with help and print_option // this avoids returning e.g. parsing errors instead of the help dialogue - for (int i = 1; i < argc; i++) { - auto id_result = Identifier::parse(argv[i]); + for (auto arg_itr = argv.begin() + 1; arg_itr != argv.end(); ++arg_itr) { + auto id_result = Identifier::parse(*arg_itr); // skip non-option arguments if (!id_result) { continue; @@ -153,31 +154,32 @@ mio::IOResult mio::cli::details::command_line_interface(const std::string& } // handle print_option option else if (id.matches_parameter(PresetOptions::print_option)) { - i++; // skip the PrintOption argument + ++arg_itr; // skip the PrintOption argument std::stringstream ss; - for (; i < argc && !Identifier::is_option(argv[i]); i++) { + for (; arg_itr != argv.end() && !Identifier::is_option(*arg_itr); ++arg_itr) { // try to get the parameter's json value - BOOST_OUTCOME_TRY(auto&& value, set.get_param(Identifier::make_raw(argv[i]))); + BOOST_OUTCOME_TRY(auto&& value, set.get_param(Identifier::make_raw(*arg_itr))); // print the name (or alias) and value - ss << "Option " << argv[i] << ":\n" << value << "\n"; + ss << "Option " << *arg_itr << ":\n" << value << "\n"; } // return after all values are printed return mio::failure(StatusCode::OK, ss.str()); } } // main pass over all args to set options - int i = 1; + auto arg_itr = argv.begin() + 1; + auto def_itr = default_options.begin(); // handle parameter options that require values iteratively. assign given values or return an error - while (i < argc) { - const auto id_result = Identifier::parse(argv[i]); + while (arg_itr != argv.end()) { + const auto id_result = Identifier::parse(*arg_itr); // try to parse the first default_options.size() as arguments; afterwards, require an identifier if (!id_result) { // checking #defaults suffices, as non-option arguments are greedily collected into "arguments" below - if (i - 1 < static_cast(default_options.size())) { - const auto& param_name = Identifier::make_raw(default_options[i - 1]); - BOOST_OUTCOME_TRY(set.set_param(param_name, std::string(argv[i]))); - - i++; + if (def_itr != default_options.end()) { + const auto& param_name = Identifier::make_raw(*def_itr); + BOOST_OUTCOME_TRY(set.set_param(param_name, std::string(*arg_itr))); + ++arg_itr; + ++def_itr; continue; } else { @@ -185,19 +187,19 @@ mio::IOResult mio::cli::details::command_line_interface(const std::string& } } const Identifier current_option(id_result.value()); - i++; // go to first argument + ++arg_itr; // go to first argument // assert that the first argument is not an identifier (i.e. name or alias) - if (i == argc || Identifier::is_option(argv[i])) { + if (arg_itr == argv.end() || Identifier::is_option(*arg_itr)) { return mio::failure(mio::StatusCode::OutOfRange, "Missing value for option \"" + current_option.string + "\"."); } // collect all argv's that are not identifiers and set i to the position of the next identifier - std::string arguments(argv[i]); - i++; - for (; (i < argc) && !Identifier::is_option(argv[i]); i++) { + std::string arguments(*arg_itr); + ++arg_itr; + for (; (arg_itr != argv.end()) && !Identifier::is_option(*arg_itr); ++arg_itr) { // here space separated args are joined together. maybe a better way is to make users use 'ticks' to group // their input. - arguments.append(" ").append(argv[i]); + arguments.append(" ").append(*arg_itr); } // handle built-in options if (current_option.matches_parameter(PresetOptions::read_from_json)) { diff --git a/cpp/memilio/io/cli.h b/cpp/memilio/io/cli.h index e1ae87b44e..9ff6780d62 100644 --- a/cpp/memilio/io/cli.h +++ b/cpp/memilio/io/cli.h @@ -20,7 +20,7 @@ #ifndef MIO_IO_CLI_H #define MIO_IO_CLI_H -#include "memilio/config.h" // needed for defining MEMILIO_HAS_JSONCPP +#include "memilio/config.h" // IWYU pragma: keep #ifdef MEMILIO_HAS_JSONCPP @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -48,74 +49,48 @@ namespace cli namespace details { -/// @brief A Field that gets the name of a Parameter. -struct Name { - template - static const std::string get(const Parameter& p) - { - return p.name(); - } -}; - -/// @brief A Field that gets the alias of a Parameter, or an empty string if there is none. -struct Alias { - template - using alias_expr = decltype(std::declval().alias()); - - template - constexpr static bool has_alias_v = mio::is_expression_valid::value; +/// @brief Get the name of a Parameter. Expected to be always available. +template +const std::string get_name(const Parameter& p) +{ + return p.name(); +} - template - static const std::string get(const Parameter& p) - { - if constexpr (has_alias_v) { - return p.alias(); - } - else { - return ""; - } +/// @brief Get the alias of a Parameter, or an empty string if there is none. +template +const std::string get_alias(const Parameter& p) +{ + if constexpr (requires { p.alias(); }) { + return p.alias(); } -}; - -/// @brief A Field that gets the description of a Parameter, or an empty string if there is none. -struct Description { - template - using description_expr = decltype(std::declval().description()); - - template - constexpr static bool has_description_v = mio::is_expression_valid::value; - - template - static const std::string get(const Parameter& p) - { - if constexpr (has_description_v) { - return p.description(); - } - else { - return ""; - } + else { + return ""; } -}; - -/// @brief A Field that gets the required flag of a Parameter, or false if there is none. -struct IsRequired { - template - using is_required_expr = decltype(std::declval().is_required()); +} - template - constexpr static bool has_is_required_v = is_expression_valid::value; +/// @brief Get the description of a Parameter, or an empty string if there is none. +template +const std::string get_description(const Parameter& p) +{ + if constexpr (requires { p.description(); }) { + return p.description(); + } + else { + return ""; + } +} - template - constexpr static bool get(const Parameter& p) - { - if constexpr (has_is_required_v) { - return p.is_required(); - } - else { - return false; - } +/// @brief Get the required flag of a Parameter, or false if there is none. +template +constexpr bool get_is_required(const Parameter& p) +{ + if constexpr (requires { p.is_required(); }) { + return p.is_required(); } -}; + else { + return false; + } +} /// @brief Struct containing all non-data members of a parameter. Serves as base for AbstractParameter. struct DatalessParameter { @@ -178,7 +153,7 @@ class Identifier */ static Identifier make_raw(const std::string& raw_name) { - return Identifier(raw_name, IdentifierType::Raw); + return {raw_name, IdentifierType::Raw}; } /// @brief Check if a string is a name option. @@ -206,9 +181,9 @@ class Identifier { switch (type) { case IdentifierType::Name: - return std::string_view{string.data() + 2, string.size() - 2}; + return std::string_view{string}.substr(2); case IdentifierType::Alias: - return std::string_view{string.data() + 1, string.size() - 1}; + return std::string_view{string}.substr(1); case IdentifierType::Raw: return std::string_view{string}; } @@ -239,21 +214,30 @@ class Identifier /// @brief Static container holding all preset options. Used for matching input arguments and writing help text. struct PresetOptions { - const inline static DatalessParameter help{"help", "h", "Show this dialogue and exit.", false}; + const inline static DatalessParameter help{ + .name = "help", .alias = "h", .description = "Show this dialogue and exit.", .is_required = false}; const inline static DatalessParameter print_option{ - "print_option", "", - "Use with parameter option name(s) without \"--\" as value(s). Prints the current values of specified " - "options in their correct json format, then exits.", - false}; + .name = "print_option", + .alias = "", + .description = + "Use with parameter option name(s) without \"--\" as value(s). Prints the current values of specified " + "options in their correct json format, then exits.", + .is_required = false}; const inline static DatalessParameter read_from_json{ - "read_from_json", "", - "Takes a filepath as value. Reads and assigns parameter option values from the specified json file.", false}; + .name = "read_from_json", + .alias = "", + .description = + "Takes a filepath as value. Reads and assigns parameter option values from the specified json file.", + .is_required = false}; const inline static DatalessParameter write_to_json{ - "write_to_json", "", - "Takes a filepath as value. Writes current values of all parameter options to the specified json file.", false}; + .name = "write_to_json", + .alias = "", + .description = + "Takes a filepath as value. Writes current values of all parameter options to the specified json file.", + .is_required = false}; const inline static std::vector all_presets{help, print_option, read_from_json, write_to_json}; }; @@ -277,7 +261,7 @@ class AbstractParameter : public DatalessParameter template AbstractParameter(mio::Tag, const DatalessParameter& p, std::shared_ptr&& value) : DatalessParameter(p) - , m_data(value) + , m_data(std::move(value)) , m_serialize([](const std::shared_ptr& param) -> IOResult { return mio::serialize_json(*static_cast(param.get())); }) @@ -309,8 +293,8 @@ class AbstractParameter : public DatalessParameter template AbstractParameter(mio::Tag, typename Param::Type& value) : AbstractParameter(mio::Tag{}, - DatalessParameter{Name::get(Param{}), Alias::get(Param{}), Description::get(Param{}), - IsRequired::get(Param{})}, + DatalessParameter{get_name(Param{}), get_alias(Param{}), get_description(Param{}), + get_is_required(Param{})}, std::shared_ptr(static_cast(&value), [](void*) {})) { } @@ -419,7 +403,7 @@ class AbstractSet { auto param = find(id); if (!param) { - return IOResult(param.error().code(), "Could not get parameter: " + param.error().message()); + return mio::failure(param.error().code(), "Could not get parameter: " + param.error().message()); } else { return param.value()->second.get(); @@ -438,7 +422,7 @@ class AbstractSet std::string errors; Json::CharReaderBuilder builder; const std::unique_ptr parser(builder.newCharReader()); - parser->parse(args.c_str(), args.c_str() + args.size(), &js, &errors); + parser->parse(args.begin().base(), args.end().base(), &js, &errors); // do not directly raise errors, to avoid hiding e.g. a "parameter not found" return set_param(id, js, errors); } @@ -454,7 +438,7 @@ class AbstractSet { auto param = find(id); if (!param) { - return IOResult(param.error().code(), "Could not set parameter: " + param.error().message()); + return mio::failure(param.error().code(), "Could not set parameter: " + param.error().message()); } else { // try to set the value @@ -520,7 +504,7 @@ class AbstractSet */ IOResult find(const Identifier& id) { - MapType::iterator param_itr = m_map_by_alias.find(id.strip()); + auto param_itr = m_map_by_alias.find(id.strip()); if (param_itr != m_map_by_alias.end()) { return mio::success(param_itr); } @@ -577,7 +561,7 @@ void write_help(const std::string& executable_name, const AbstractSet& set, * @brief Implementation of the CLI. See the main function below for details. * This function may overwrite parameter values and is_required flags. */ -mio::IOResult command_line_interface(const std::string& executable_name, const int argc, char** argv, +mio::IOResult command_line_interface(const std::string& executable_name, const std::span& argv, cli::details::AbstractSet& parameters, const std::vector& default_options); @@ -601,7 +585,7 @@ class ParameterSet * @param[in] parameters A vector of AbstractParameter%s holding their own data. */ ParameterSet(std::vector&& parameters) - : m_parameters(parameters) + : m_parameters(std::move(parameters)) { } @@ -683,11 +667,13 @@ class ParameterSetBuilder // since we get *this as rvalue, we can move the parameters auto new_params = std::move(m_parameters); // create a new owning data pointer, stored as void* - std::shared_ptr data(new ValueType(initial_value), std::default_delete{}); + std::shared_ptr data(new ValueType(std::forward(initial_value)), std::default_delete{}); // create a new abstract parameter, then move all parameters to a new builder new_params.emplace_back(Tag{}, - details::DatalessParameter{std::string(Name), optionals.alias, optionals.description, - optionals.is_required}, + details::DatalessParameter{.name = std::string(Name), + .alias = std::move(optionals).alias, + .description = std::move(optionals).description, + .is_required = std::move(optionals).is_required}, std::move(data)); return ParameterSetBuilder, ValueType>>{std::move(new_params)}; } @@ -778,7 +764,7 @@ mio::IOResult command_line_interface(const std::string& executable_name, c { // parse the parameters into an iterable format BOOST_OUTCOME_TRY(auto&& set, cli::details::AbstractSet::build(parameters)); - return cli::details::command_line_interface(executable_name, argc, argv, set, default_options); + return cli::details::command_line_interface(executable_name, std::span(argv, argc), set, default_options); } /** diff --git a/cpp/memilio/io/default_serialize.h b/cpp/memilio/io/default_serialize.h index 77bf680584..6cb62c2dfd 100644 --- a/cpp/memilio/io/default_serialize.h +++ b/cpp/memilio/io/default_serialize.h @@ -21,11 +21,8 @@ #define MIO_IO_DEFAULT_SERIALIZE_H_ #include "memilio/io/io.h" -#include "memilio/utils/metaprogramming.h" #include -#include -#include namespace mio { @@ -59,15 +56,6 @@ struct NamedRef { namespace details { - -/** - * @brief Helper type to detect whether T has a default_serialize member function. - * Use has_default_serialize. - * @tparam T Any type. - */ -template -using default_serialize_expr_t = decltype(std::declval().default_serialize()); - /// Add a name-value pair to an io object. template void add_named_ref(IOObject& obj, const NamedRef named_ref) @@ -191,11 +179,26 @@ struct DefaultFactory { }; /** - * @brief Detect whether T has a default_serialize member function. + * @brief Detect whether T has a default_serialize member function, but no serialize member. * @tparam T Any type. + * @tparam IOContext Any context, e.g. JsonContext. */ -template -using has_default_serialize = is_expression_valid; +template +concept IsDefaultSerializable = requires(T t) { + t.default_serialize(); + !HasSerialize; +}; + +/** + * @brief Detect whether T has a default_serialize member function, but no deserialize member. + * @tparam T Any type. + * @tparam IOContext Any context, e.g. JsonContext. + */ +template +concept IsDefaultDeserializable = requires(T t) { + t.default_serialize(); + !HasDeserialize; +}; /** * @brief Serialization implementation for the default serialization feature. @@ -206,14 +209,11 @@ using has_default_serialize = is_expression_valid::value && - !has_serialize::value, - DefaultSerializable*> = nullptr> -void serialize_internal(IOContext& io, const DefaultSerializable& a) +template T> +void serialize_internal(IOContext& io, const T& a) { - // Note that the following cons_cast is only safe if we do not modify members. - const auto members = const_cast(a).default_serialize(); + // Note that the following cons_cast is safe as long as we do not modify members. + const auto members = const_cast(a).default_serialize(); // unpack members and serialize std::apply( [&io, &members](auto... named_refs) { @@ -224,7 +224,7 @@ void serialize_internal(IOContext& io, const DefaultSerializable& a) /** * @brief Deserialization implementation for the default serialization feature. - * Disables itself (SFINAE) if there is no default_serialize member or if a deserialize meember is present. + * Disables itself (SFINAE) if there is no default_serialize member or if a deserialize member is present. * Generates the deserialize method depending on the NamedRefs given by default_serialize. * @tparam IOContext A type that models the IOContext concept. * @tparam DefaultSerializable A type that can be default serialized. @@ -232,15 +232,12 @@ void serialize_internal(IOContext& io, const DefaultSerializable& a) * @param tag Defines the type of the object that is to be deserialized (i.e. DefaultSerializble). * @return The restored object if successful, an error otherwise. */ -template ::value && - !has_deserialize::value, - DefaultSerializable*> = nullptr> -IOResult deserialize_internal(IOContext& io, Tag tag) +template T> +IOResult deserialize_internal(IOContext& io, Tag tag) { mio::unused(tag); - DefaultSerializable a = DefaultFactory::create(); - auto members = a.default_serialize(); + T a = DefaultFactory::create(); + auto members = a.default_serialize(); // unpack members and deserialize return std::apply( [&io, &members, &a](auto... named_refs) { diff --git a/cpp/memilio/io/hdf5_cpp.h b/cpp/memilio/io/hdf5_cpp.h index 142b62495c..a4966f49bf 100644 --- a/cpp/memilio/io/hdf5_cpp.h +++ b/cpp/memilio/io/hdf5_cpp.h @@ -17,8 +17,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef EPI_IO_HDF5_CPP_H -#define EPI_IO_HDF5_CPP_H +#ifndef MIO_IO_HDF5_CPP_H +#define MIO_IO_HDF5_CPP_H #include "memilio/config.h" @@ -97,6 +97,6 @@ struct H5DataSet { } // namespace mio -#endif //MEMILIO_HAS_HDF5 +#endif // MEMILIO_HAS_HDF5 -#endif //EPI_IO_HDF5_CPP_H +#endif // MIO_IO_HDF5_CPP_H diff --git a/cpp/memilio/io/history.h b/cpp/memilio/io/history.h index 4b65a27934..6abe2de15f 100644 --- a/cpp/memilio/io/history.h +++ b/cpp/memilio/io/history.h @@ -23,7 +23,6 @@ #include "memilio/utils/metaprogramming.h" #include #include -#include namespace mio { diff --git a/cpp/memilio/io/io.h b/cpp/memilio/io/io.h index 0cd0f87558..3dd78a35d1 100644 --- a/cpp/memilio/io/io.h +++ b/cpp/memilio/io/io.h @@ -18,8 +18,8 @@ * limitations under the License. */ -#ifndef EPI_UTILS_IO_H -#define EPI_UTILS_IO_H +#ifndef MIO_IO_IO_H +#define MIO_IO_IO_H #include "memilio/utils/metaprogramming.h" #include "memilio/utils/compiler_diagnostics.h" @@ -29,9 +29,13 @@ #include "boost/optional.hpp" #include +#include +#include #include #include #include +#include +#include namespace mio { @@ -202,9 +206,9 @@ class IOStatus * @param ec error code * @param msg optional message with additional information about the error, default empty. */ - IOStatus(std::error_code ec, const std::string& msg = {}) + IOStatus(std::error_code ec, std::string msg = {}) : m_ec(ec) - , m_msg(msg) + , m_msg(std::move(msg)) { } @@ -439,19 +443,20 @@ struct IsIOResult> : std::true_type { template using ApplyResultT = FlattenIOResultT>; -//evaluates the function f using the values of the given IOResults as arguments, assumes all IOResults are succesful -//overload for functions that do internal validation, so return an IOResult -template >::value, void*> = nullptr> -ApplyResultT eval(F f, const IOResult&... rs) -{ - return f(rs.value()...); -} -//overload for functions that can't fail because all values are acceptable, so return some other type -template >::value, void*> = nullptr> +/// @brief Evaluates a function f using values of the given IOResults as arguments, assumes all IOResults are succesful. +template ApplyResultT eval(F f, const IOResult&... rs) { - return success(f(rs.value()...)); + if constexpr (IsIOResult>::value) { + // case for functions that do internal validation + return f(rs.value()...); + } + else { + // case for functions that can't fail, because all values are acceptable + return success(f(rs.value()...)); + } } + } // namespace details /** @@ -483,8 +488,8 @@ details::ApplyResultT apply(IOContext& io, F f, const IOResult&... r //and slightly worse performance in the case of an error is probably acceptable. //check for errors in the arguments - IOStatus status[] = {(rs ? IOStatus{} : rs.error())...}; - auto iter_err = std::find_if(std::begin(status), std::end(status), [](auto& s) { + auto status = std::array{(rs ? IOStatus{} : rs.error())...}; + auto iter_err = std::find_if(std::begin(status), std::end(status), [](auto& s) { return s.is_error(); }); @@ -512,6 +517,16 @@ details::ApplyResultT apply(IOContext& io, F f, const std::tuple +concept HasSerialize = requires(IOContext& ctxt, const T t) { t.serialize(ctxt); }; + +//detect a static deserialize member function +template +concept HasDeserialize = requires(IOContext& ctxt, const T t) { + { T::deserialize(ctxt) } -> std::same_as>; +}; + //utility for (de-)serializing tuple-like objects namespace details { @@ -524,49 +539,42 @@ std::string make_tuple_element_name() //recursive tuple serialization for each tuple element //store one tuple element after the other in the IOObject template -std::enable_if_t<(Idx >= std::tuple_size::value)> serialize_tuple_element(IOObj&, const Tup&) +void serialize_tuple_element(IOObj& obj, const Tup& tup) { - //end of recursion, no more elements to serialize -} -template -std::enable_if_t<(Idx < std::tuple_size::value)> serialize_tuple_element(IOObj& obj, const Tup& tup) -{ - //serialize one element, then recurse - obj.add_element(make_tuple_element_name(), std::get(tup)); - serialize_tuple_element(obj, tup); + if constexpr (Idx < std::tuple_size_v) { + //serialize one element, then recurse + obj.add_element(make_tuple_element_name(), std::get(tup)); + serialize_tuple_element(obj, tup); + } + // else: end of recursion, no more elements to serialize } //recursive tuple deserialization for each tuple element //read one tuple element after the other from the IOObject //argument pack rs contains the elements that have been read already template -std::enable_if_t<(sizeof...(Ts) == std::tuple_size::value), IOResult> -deserialize_tuple_element(IOObj& o, Tag, const IOResult&... rs) -{ - //end of recursion - //number of arguments in rs is the same as the size of the tuple - //no more elements to read, so finalize the object - return mio::apply( - o, - [](const Ts&... ts) { - return Tup(ts...); - }, - rs...); -} -template -std::enable_if_t<(sizeof...(Ts) < std::tuple_size::value), IOResult> -deserialize_tuple_element(IOObj& obj, Tag tag, const IOResult&... rs) -{ - //get the next element of the tuple from the IO object - const size_t Idx = sizeof...(Ts); - auto r = obj.expect_element(make_tuple_element_name(), Tag>{}); - //recurse, append the new element to the pack of arguments - return deserialize_tuple_element(obj, tag, rs..., r); +IOResult deserialize_tuple_element(IOObj& obj, Tag tag, const IOResult&... rs) +{ + if constexpr (sizeof...(Ts) < std::tuple_size_v) { + //get the next element of the tuple from the IO object + const size_t Idx = sizeof...(Ts); + auto r = obj.expect_element(make_tuple_element_name(), Tag>{}); + //recurse, append the new element to the pack of arguments + return deserialize_tuple_element(obj, tag, rs..., r); + } + else { + //end of recursion + //number of arguments in rs is the same as the size of the tuple + //no more elements to read, so finalize the object + return mio::apply( + obj, + [](const Ts&... ts) { + return Tup(ts...); + }, + rs...); + } } -//detect tuple-like types, e.g. std::tuple or std::pair -template -using tuple_size_value_t = decltype(std::tuple_size::value); } // namespace details /** @@ -576,9 +584,9 @@ using tuple_size_value_t = decltype(std::tuple_size::value); * @param io an IO context. * @param tup a tuple-like object to be serialized. */ -template ::value>> -void serialize_internal(IOContext& io, const Tup& tup) +template class Tup, class... T> + requires std::same_as, std::pair> || std::same_as, std::tuple> +void serialize_internal(IOContext& io, const Tup& tup) { auto obj = io.create_object("Tuple"); details::serialize_tuple_element<0>(obj, tup); @@ -592,9 +600,9 @@ void serialize_internal(IOContext& io, const Tup& tup) * @param tag define the type of the object to be deserialized. * @return a restored tuple */ -template ::value>> -IOResult deserialize_internal(IOContext& io, Tag tag) +template class Tup, class... T> + requires std::same_as, std::pair> || std::same_as, std::tuple> +IOResult> deserialize_internal(IOContext& io, Tag> tag) { auto obj = io.expect_object("Tuple"); return details::deserialize_tuple_element(obj, tag); @@ -626,7 +634,7 @@ void serialize_internal(IOContext& io, const Eigen::EigenBase& mat) * @param io an IO context. * @param tag defines the type of the matrix to be serialized. */ -template , M>::value, void*> = nullptr> +template IOResult deserialize_internal(IOContext& io, Tag /*tag*/) { auto obj = io.expect_object("Matrix"); @@ -704,7 +712,8 @@ IOResult> deserialize_internal(IOContext& io, Tag> * @param io an IO context * @param e an enum value to be serialized. */ -template ::value, void*> = nullptr> +template + requires std::is_enum_v void serialize_internal(IOContext& io, E e) { mio::serialize(io, std::underlying_type_t(e)); @@ -720,20 +729,14 @@ void serialize_internal(IOContext& io, E e) * @param tag defines the type of the enum to be deserialized * @return an enum value if succesful, an error otherwise. */ -template ::value, void*> = nullptr> +template + requires std::is_enum_v IOResult deserialize_internal(IOContext& io, Tag /*tag*/) { BOOST_OUTCOME_TRY(auto&& i, mio::deserialize(io, mio::Tag>{})); return success(E(i)); } -//detect a serialize member function -template -using serialize_t = decltype(std::declval().serialize(std::declval())); - -template -using has_serialize = is_expression_valid; - /** * serialize an object that has a serialize(io) member function. * @tparam IOContext a type that models the IOContext concept. @@ -741,20 +744,12 @@ using has_serialize = is_expression_valid; * @param io an IO context * @param t the object to be serialized. */ -template ::value, void*> = nullptr> +template T> void serialize_internal(IOContext& io, const T& t) { t.serialize(io); } -//detect a static deserialize member function -template -using deserialize_t = decltype(T::deserialize(std::declval())); - -template -using has_deserialize = is_expression_valid; - /** * deserialize an object that has a deserialize(io) static member function. * @tparam IOContext a type that models the IOContext concept. @@ -763,35 +758,25 @@ using has_deserialize = is_expression_valid; * @param tag defines the type of the object for overload resolution. * @return the restored object if succesful, an error otherwise. */ -template ::value, void*> = nullptr> +template T> IOResult deserialize_internal(IOContext& io, Tag /*tag*/) { return T::deserialize(io); } -//utilities for (de-)serializing STL containers -namespace details -{ -//detect stl container. -//don't check all requirements, since there are too many. Instead assume that if begin and end -//iterators are available, the other requirements are met as well, as they should be in any -//proper implementation. -template -using compare_iterators_t = decltype(std::declval().begin() != std::declval().end()); -} // namespace details - /** - * Is std::true_type if C is a STL compatible container. - * Is std::false_type otherwise. + * Concept to check whether C is a STL compatible container. * See https://en.cppreference.com/w/cpp/named_req/Container. * @tparam C any type. */ template -using is_container = - conjunction, - std::is_constructible().begin()), decltype(std::declval().end())>, - // Eigen types may pass as container, but we want to handle them separately - negation, C>>>; +concept IsContainer = + requires(C c, const C& cc) { + cc.begin() != cc.end(); + C(c.begin(), c.end()); + } + // Eigen types may pass as container, but we want to handle them separately + && !std::is_base_of_v, C>; /** * serialize an STL compatible container. @@ -800,14 +785,13 @@ using is_container = * @param io an IO context. * @param container a container to be serialized. */ -template , negation>>, - void*> = nullptr> +template + requires(!HasSerialize) void serialize_internal(IOContext& io, const Container& container) { auto obj = io.create_object("List"); obj.add_list("Items", container.begin(), container.end()); -} +} // namespace mio /** * deserialize an STL compatible container. @@ -817,10 +801,8 @@ void serialize_internal(IOContext& io, const Container& container) * @param tag defines the type of the container to be serialized for overload resolution. * @return restored container if successful, error otherwise. */ -template < - class IOContext, class Container, - std::enable_if_t<(is_container::value && !is_expression_valid::value), - void*> = nullptr> +template + requires(!HasSerialize) IOResult deserialize_internal(IOContext& io, Tag /*tag*/) { auto obj = io.expect_object("List"); @@ -912,4 +894,4 @@ bool file_exists(std::string const& rel_path, std::string& abs_path); } // namespace mio -#endif +#endif // MIO_IO_IO_H diff --git a/cpp/memilio/io/json_serializer.h b/cpp/memilio/io/json_serializer.h index 316e5406ae..7a42f7b8f0 100644 --- a/cpp/memilio/io/json_serializer.h +++ b/cpp/memilio/io/json_serializer.h @@ -17,20 +17,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef EPI_IO_JSON_SERIALIZER_H -#define EPI_IO_JSON_SERIALIZER_H +#ifndef MIO_IO_JSON_SERIALIZER_H +#define MIO_IO_JSON_SERIALIZER_H -#include "memilio/config.h" +#include "memilio/config.h" // IWYU pragma: keep +#include +#include #ifdef MEMILIO_HAS_JSONCPP #include "memilio/io/io.h" #include "memilio/io/serializer_base.h" #include "memilio/utils/metaprogramming.h" -#include "json/json.h" + +#include "json/json.h" // IWYU pragma: keep + #include -#include #include +#include namespace mio { @@ -44,7 +48,7 @@ namespace mio * @tparam T the type to be serialized. * @{ */ -template +template struct JsonType : std::false_type { }; //bool @@ -59,15 +63,15 @@ struct JsonType : std::true_type { } static Json::Value transform(bool b) { - return Json::Value(b); + return {b}; } }; -//all integers less than 32 bit must be stored as int -template -using is_small_integral = std::integral_constant::value && sizeof(T) <= 4)>; +// all integers less than 32 bit must be stored as int + //signed small ints template -struct JsonType, std::is_signed>>> : std::true_type { + requires(is_small_integral::value && std::is_signed_v) +struct JsonType : std::true_type { static IOResult transform(const Json::Value& js) { if (js.isInt()) { @@ -86,7 +90,8 @@ struct JsonType, std::is_ }; //unsigned small ints template -struct JsonType, std::is_unsigned>>> : std::true_type { + requires(is_small_integral::value && std::is_unsigned_v) +struct JsonType : std::true_type { static IOResult transform(const Json::Value& js) { if (js.isUInt()) { @@ -104,11 +109,10 @@ struct JsonType, std::is_ return Json::Value(Json::UInt(i)); } }; -template -using is_64bit_integral = std::integral_constant::value && sizeof(T) == 8)>; //signed big ints template -struct JsonType, std::is_signed>>> : std::true_type { + requires(is_64bit_integral::value && std::is_signed_v) +struct JsonType : std::true_type { static IOResult transform(const Json::Value& js) { if (js.isInt64()) { @@ -118,12 +122,13 @@ struct JsonType, std::is_ } static Json::Value transform(T i) { - return Json::Value(Json::Int64(i)); + return {Json::Int64(i)}; } }; //unsigned big ints template -struct JsonType, std::is_unsigned>>> : std::true_type { + requires(is_64bit_integral::value && std::is_unsigned_v) +struct JsonType : std::true_type { static IOResult transform(const Json::Value& js) { if (js.isUInt64()) { @@ -133,7 +138,7 @@ struct JsonType, std::is_ } static Json::Value transform(T i) { - return Json::Value(Json::UInt64(i)); + return {Json::UInt64(i)}; } }; //double @@ -149,7 +154,7 @@ struct JsonType : std::true_type { } static Json::Value transform(double d) { - return Json::Value(d); + return {d}; } }; //float @@ -168,7 +173,7 @@ struct JsonType : std::true_type { } static Json::Value transform(float f) { - return Json::Value(double(f)); + return {double(f)}; } }; //string @@ -183,7 +188,7 @@ struct JsonType : std::true_type { } static Json::Value transform(const std::string& s) { - return Json::Value(s); + return {s}; } }; //string literals @@ -192,11 +197,15 @@ struct JsonType : std::true_type { //cannot be read, but may be written (e.g. string literal), so only one way transform static Json::Value transform(const char* s) { - return Json::Value(s); + return {s}; } }; /**@}*/ +/// @brief Concept for checking if T is a json type. +template +concept IsJsonType = JsonType::value; + /** * Implementation of the IOObject concept for JSON format. */ @@ -222,9 +231,11 @@ class JsonObject : public SerializerBase * @param value value of the element. * @{ */ - template ::value, void*> = nullptr> + template + requires(IsJsonType) void add_element(const std::string& name, const T& value); - template ::value, void*> = nullptr> + template + requires(!IsJsonType) void add_element(const std::string& name, const T& value); /**@}*/ @@ -255,9 +266,11 @@ class JsonObject : public SerializerBase * @return retrieved element if succesful, error otherwise. * @{ */ - template ::value, void*> = nullptr> + template + requires(IsJsonType) IOResult expect_element(const std::string& name, Tag tag) const; - template ::value, void*> = nullptr> + template + requires(!IsJsonType) IOResult expect_element(const std::string& name, Tag tag) const; /**@}*/ @@ -319,9 +332,9 @@ class JsonContext : public SerializerBase * @param status status of serialization, shared with parent IO contexts and objects. * @param flags flags to determine behavior of serialization. */ - JsonContext(const Json::Value& value, const std::shared_ptr& status, int flags) + JsonContext(Json::Value value, const std::shared_ptr& status, int flags) : SerializerBase(status, flags) - , m_value(value) + , m_value(std::move(value)) { } @@ -352,7 +365,7 @@ class JsonContext : public SerializerBase if (!m_value.isObject()) { *m_status = IOStatus(StatusCode::InvalidType, "Json value must be an object."); } - return JsonObject(m_value, m_status, m_flags); + return {m_value, m_status, m_flags}; } /** @@ -379,7 +392,8 @@ class JsonContext : public SerializerBase * @param io reference JsonContext. * @param t value to be serialized. */ - template ::value, void*> = nullptr> + template + requires(IsJsonType) friend void serialize_internal(JsonContext& io, const T& t) { io.m_value = JsonType::transform(t); @@ -392,7 +406,8 @@ class JsonContext : public SerializerBase * @param io reference JsonContext. * @param t value to be serialized. */ - template ::value, void*> = nullptr> + template + requires(IsJsonType) friend IOResult deserialize_internal(JsonContext& io, Tag) { return JsonType::transform(io.m_value); @@ -402,9 +417,8 @@ class JsonContext : public SerializerBase * json specialization of serialization for containers. * Serialize containers as pure json array without a wrapping object. */ - template , negation>, - negation>>, - void*> = nullptr> + template + requires(!IsJsonType && !HasDeserialize) friend void serialize_internal(JsonContext& io, const Container& v) { if (io.m_status->is_ok()) { @@ -426,9 +440,8 @@ class JsonContext : public SerializerBase * json specialization of deserialization for containers. * Deserialize containers from pure json arrays without a wrapping object. */ - template , negation>, - negation>>, - void*> = nullptr> + template + requires(!IsJsonType && !HasDeserialize) friend IOResult deserialize_internal(JsonContext& io, Tag) { const auto& array = io.m_value; @@ -560,7 +573,8 @@ IOResult read_json(const std::string& path, Tag tag, int flags = IOF_None) //Implementations for JsonContext/Object member functions below// ///////////////////////////////////////////////////////////////// -template ::value, void*>> +template + requires(IsJsonType) void JsonObject::add_element(const std::string& name, const T& value) { if (m_status->is_ok()) { @@ -568,7 +582,8 @@ void JsonObject::add_element(const std::string& name, const T& value) } } -template ::value, void*>> +template + requires(!IsJsonType) void JsonObject::add_element(const std::string& name, const T& value) { if (m_status->is_ok()) { @@ -604,7 +619,8 @@ void JsonObject::add_list(const std::string& name, Iter b, Iter e) } } -template ::value, void*>> +template + requires(IsJsonType) IOResult JsonObject::expect_element(const std::string& name, Tag /*tag*/) const { if (m_status->is_error()) { @@ -624,7 +640,8 @@ IOResult JsonObject::expect_element(const std::string& name, Tag /*tag*/) r.error().message() + " (" + name + ")"); //annotate type error message with element name } -template ::value, void*>> +template + requires(!IsJsonType) IOResult JsonObject::expect_element(const std::string& name, Tag tag) const { if (m_status->is_error()) { @@ -683,6 +700,6 @@ IOResult> JsonObject::expect_list(const std::string& name, Tag } // namespace mio -#endif //MEMILIO_HAS_JSONCPP +#endif // MEMILIO_HAS_JSONCPP -#endif //EPI_IO_JSON_SERIALIZER_H +#endif // MIO_IO_JSON_SERIALIZER_H diff --git a/cpp/memilio/io/parameters_io.cpp b/cpp/memilio/io/parameters_io.cpp index 13807add81..c36beb13b7 100644 --- a/cpp/memilio/io/parameters_io.cpp +++ b/cpp/memilio/io/parameters_io.cpp @@ -23,8 +23,8 @@ #ifdef MEMILIO_HAS_JSONCPP #include "memilio/io/epi_data.h" -#include "memilio/io/result_io.h" -#include "json/value.h" + +#include #include #include @@ -43,7 +43,7 @@ read_population_data(const std::vector& population_data, co } //find region that this county belongs to //all counties belong to the country (id = 0) - auto it = std::find_if(vregion.begin(), vregion.end(), [&county_entry](auto r) { + auto it = std::ranges::find_if(vregion, [&county_entry](auto r) { return r == 0 || (county_entry.county_id && regions::StateId(r) == regions::get_state_id(int(*county_entry.county_id))) || diff --git a/cpp/memilio/io/parameters_io.h b/cpp/memilio/io/parameters_io.h index 0e4182f5e5..ad02409caf 100644 --- a/cpp/memilio/io/parameters_io.h +++ b/cpp/memilio/io/parameters_io.h @@ -17,8 +17,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef MEMILIO_IO_PARAMETER_H -#define MEMILIO_IO_PARAMETER_H +#ifndef MIO_IO_PARAMETERS_IO_H +#define MIO_IO_PARAMETERS_IO_H #include "memilio/config.h" @@ -26,7 +26,7 @@ #include "memilio/io/epi_data.h" #include "memilio/io/result_io.h" -#include "json/value.h" + #include #include @@ -45,9 +45,18 @@ namespace mio template int get_region_id(const EpiDataEntry& data_entry) { - return data_entry.county_id ? data_entry.county_id->get() - : (data_entry.state_id ? data_entry.state_id->get() - : (data_entry.district_id ? data_entry.district_id->get() : 0)); + if (data_entry.county_id) { + return data_entry.county_id->get(); + } + else if (data_entry.state_id) { + return data_entry.state_id->get(); + } + else if (data_entry.district_id) { + return data_entry.district_id->get(); + } + else { + return 0; + } } /** @@ -138,6 +147,6 @@ IOResult>> read_population_data(const std::s } // namespace mio -#endif //MEMILIO_HAS_JSONCPP +#endif // MEMILIO_HAS_JSONCPP -#endif //MEMILIO_IO_PARAMETER_H +#endif // MIO_IO_PARAMETERS_IO_H diff --git a/cpp/memilio/math/eigen_util.h b/cpp/memilio/math/eigen_util.h index e86a07225a..6228b9fdfe 100644 --- a/cpp/memilio/math/eigen_util.h +++ b/cpp/memilio/math/eigen_util.h @@ -17,12 +17,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#pragma once +#ifndef MIO_MATH_EIGEN_UTIL_H +#define MIO_MATH_EIGEN_UTIL_H + +#include "memilio/math/eigen.h" // IWYU pragma: keep -#include "memilio/math/eigen.h" -#include "memilio/utils/metaprogramming.h" #include -#include #include namespace mio @@ -49,21 +49,17 @@ struct Seq { * @brief check if Eigen::Matrix type M is a dynamic vector type. */ template -struct is_dynamic_vector { - static constexpr bool value = (std::remove_reference_t::RowsAtCompileTime == Eigen::Dynamic && - std::remove_reference_t::ColsAtCompileTime == 1) || - (std::remove_reference_t::RowsAtCompileTime == 1 && - std::remove_reference_t::ColsAtCompileTime == Eigen::Dynamic); -}; +concept IsDynamicVector = (std::remove_reference_t::RowsAtCompileTime == Eigen::Dynamic && + std::remove_reference_t::ColsAtCompileTime == 1) || + (std::remove_reference_t::RowsAtCompileTime == 1 && + std::remove_reference_t::ColsAtCompileTime == Eigen::Dynamic); /** * @brief check if Eigen::Matrix type M is a dynamic matrix type. */ template -struct is_dynamic_matrix { - static constexpr bool value = std::remove_reference_t::RowsAtCompileTime == Eigen::Dynamic && - std::remove_reference_t::ColsAtCompileTime == Eigen::Dynamic; -}; +concept IsDynamicMatrix = std::remove_reference_t::RowsAtCompileTime == Eigen::Dynamic && + std::remove_reference_t::ColsAtCompileTime == Eigen::Dynamic; /** * @brief number of rows (columns) of a row (column) major matrix. @@ -107,7 +103,7 @@ using CVPlainMatrixT = typename CVPlainMatrix::Type; * @param elems sequence of row or column indices * @returns vector expression with selected entries from the input vector */ -template ::value, int> = 0> +template auto slice(V&& v, Seq elems) { return Eigen::Map>, 0, Eigen::Stride>( @@ -124,7 +120,7 @@ auto slice(V&& v, Seq elems) * @param cols sequence of column indices * @returns matrix expression with selected entries from the input matrix */ -template ::value, int> = 0> +template auto slice(M&& m, Seq rows, Seq cols) { assert(rows.start + rows.stride * rows.n <= m.rows()); @@ -161,13 +157,9 @@ auto reshape(M&& m, Eigen::Index rows, Eigen::Index cols) return Eigen::Map>>(m.data(), rows, cols); } -/** - * template utility. - * Defines value = true if M is an Eigen matrix expression. - * Defines value = false, otherwise. - */ +/// @brief Concept to detect whether T is an Eigen matrix expression. template -using is_matrix_expression = std::is_base_of, M>; +concept IsMatrixExpression = std::is_base_of_v, M>; /** * coefficient wise maximum of two matrices. @@ -209,8 +201,8 @@ namespace details //true if elements returned by matrix(i, j) are references where matrix is of type M; //false if the elements are temporaries, e.g. for expressions like Eigen::MatrixXd::Constant(r, c, v). template -using IsElementReference = - std::is_reference()(std::declval(), std::declval()))>; +concept IsElementReference = + std::is_reference_v()(std::declval(), std::declval()))>; } // namespace details /** @@ -224,8 +216,7 @@ class RowMajorIterator public: using MatrixRef = std::conditional_t; using MatrixPtr = std::conditional_t; - static_assert(IsConst || details::IsElementReference::value, - "Iterator must be const if matrix is not in memory."); + static_assert(IsConst || details::IsElementReference, "Iterator must be const if matrix is not in memory."); using iterator_category = std::random_access_iterator_tag; using value_type = typename M::Scalar; @@ -243,7 +234,7 @@ class RowMajorIterator return &value; } }; - using pointer = std::conditional_t::value, + using pointer = std::conditional_t, std::conditional_t, Proxy>; /** @@ -354,13 +345,14 @@ class RowMajorIterator * The proxy stores a copy of the element and forwards the address of this copy. * @{ */ - template ::value, void*> = nullptr> pointer operator->() const + requires details::IsElementReference { return &(**this); } - template ::value, void*> = nullptr> + pointer operator->() const + requires(!details::IsElementReference) { return Proxy{**this}; } @@ -418,10 +410,9 @@ class RowMajorIterator * create a non-const iterator to first element of the matrix m. * only enabled if the matrix is evaluated in memory, i.e. elements can be modified. */ -template -std::enable_if_t, M>, details::IsElementReference>, - RowMajorIterator> -begin(M& m) +template + requires details::IsElementReference +RowMajorIterator begin(M& m) { return {m, 0}; } @@ -429,8 +420,8 @@ begin(M& m) /** * create a const iterator to first element of the matrix m. */ -template -std::enable_if_t, M>::value, RowMajorIterator> begin(const M& m) +template +RowMajorIterator begin(const M& m) { return {m, 0}; } @@ -438,8 +429,8 @@ std::enable_if_t, M>::value, RowMajorIterato /** * create a const iterator to first element of the matrix m. */ -template -std::enable_if_t, M>::value, RowMajorIterator> cbegin(const M& m) +template +RowMajorIterator cbegin(const M& m) { return {m, 0}; } @@ -447,10 +438,9 @@ std::enable_if_t, M>::value, RowMajorIterato /** * create a non-const end iterator for the matrix m. */ -template -std::enable_if_t, M>, details::IsElementReference>, - RowMajorIterator> -end(M& m) +template + requires details::IsElementReference +RowMajorIterator end(M& m) { return {m, m.size()}; } @@ -458,8 +448,8 @@ end(M& m) /** * create a const end iterator for the matrix m. */ -template -std::enable_if_t, M>::value, RowMajorIterator> end(const M& m) +template +RowMajorIterator end(const M& m) { return {m, m.size()}; } @@ -467,10 +457,12 @@ std::enable_if_t, M>::value, RowMajorIterato /** * create a non-const end iterator for the matrix m. */ -template -std::enable_if_t, M>::value, RowMajorIterator> cend(const M& m) +template +RowMajorIterator cend(const M& m) { return {m, m.size()}; } } // namespace mio + +#endif // MIO_MATH_EIGEN_UTIL_H diff --git a/cpp/memilio/math/euler_maruyama.h b/cpp/memilio/math/euler_maruyama.h index e1b84d68e8..6fae63379e 100644 --- a/cpp/memilio/math/euler_maruyama.h +++ b/cpp/memilio/math/euler_maruyama.h @@ -20,8 +20,8 @@ #ifndef MIO_MATH_EULER_MARUYAMA_H #define MIO_MATH_EULER_MARUYAMA_H +#include "memilio/math/eigen.h" // IWYU pragma: keep #include "memilio/math/integrator.h" -#include "memilio/math/eigen.h" #include "memilio/math/math_utils.h" #include "memilio/utils/logging.h" diff --git a/cpp/memilio/math/math_utils.h b/cpp/memilio/math/math_utils.h index d3afb80070..305d1010a9 100644 --- a/cpp/memilio/math/math_utils.h +++ b/cpp/memilio/math/math_utils.h @@ -22,7 +22,7 @@ #include "memilio/config.h" #include "memilio/io/io.h" -#include "memilio/math/eigen.h" +#include "memilio/math/eigen.h" // IWYU pragma: keep namespace mio { @@ -81,7 +81,7 @@ inline auto evaluate_intermediate(Intermediate&& x) return static_cast(x); } else { - return x; + return std::forward(x); } } diff --git a/cpp/memilio/math/matrix_shape.h b/cpp/memilio/math/matrix_shape.h index 4f99f5de13..e4d6cea0ec 100644 --- a/cpp/memilio/math/matrix_shape.h +++ b/cpp/memilio/math/matrix_shape.h @@ -29,11 +29,10 @@ * - equality comparable */ -#ifndef EPI_UTILS_MATRIX_SHAPE_H -#define EPI_UTILS_MATRIX_SHAPE_H +#ifndef MIO_MATH_MATRIX_SHAPE_H +#define MIO_MATH_MATRIX_SHAPE_H -#include "memilio/math/eigen.h" -#include "memilio/math/eigen_util.h" +#include "memilio/math/eigen.h" // IWYU pragma: keep #include "memilio/io/io.h" namespace mio @@ -338,4 +337,4 @@ class ColumnVectorShape } // namespace mio -#endif //EPI_UTILS_MATRIX_SHAPE_H +#endif // MIO_MATH_MATRIX_SHAPE_H diff --git a/cpp/memilio/math/smoother.h b/cpp/memilio/math/smoother.h index 396cae04e4..ea3a470ccc 100644 --- a/cpp/memilio/math/smoother.h +++ b/cpp/memilio/math/smoother.h @@ -17,11 +17,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef EPI_MATH_SMOOTHER_H -#define EPI_MATH_SMOOTHER_H +#ifndef MIO_MATH_SMOOTHER_H +#define MIO_MATH_SMOOTHER_H #include "memilio/config.h" #include "memilio/math/eigen.h" + #include #include @@ -78,4 +79,4 @@ auto smoother_cosine(FP x, FP xleft, FP xright, const Eigen::MatrixBase>&& table) - : TimeSeriesFunctor(type, TimeSeries{table}) + : TimeSeriesFunctor(type, TimeSeries{std::move(table)}) { } diff --git a/cpp/memilio/mobility/graph.h b/cpp/memilio/mobility/graph.h index 6a03f36929..1261939031 100644 --- a/cpp/memilio/mobility/graph.h +++ b/cpp/memilio/mobility/graph.h @@ -20,18 +20,17 @@ #ifndef GRAPH_H #define GRAPH_H -#include "memilio/utils/stl_util.h" #include "memilio/epidemiology/age_group.h" -#include "memilio/utils/date.h" -#include "memilio/utils/uncertain_value.h" -#include "memilio/utils/parameter_distributions.h" #include "memilio/epidemiology/damping.h" #include "memilio/geography/regions.h" +#include "memilio/utils/date.h" +#include "memilio/utils/parameter_distributions.h" +#include "memilio/utils/stl_util.h" +#include "memilio/utils/uncertain_value.h" + #include -#include #include #include -#include #include "boost/filesystem.hpp" @@ -97,13 +96,13 @@ struct Edge : public EdgeBase { /** * @brief comparison operator if node property type is equality comparable */ -template -std::enable_if_t::value, bool> operator==(const Node& n1, const Node& n2) +template +bool operator==(const Node& n1, const Node& n2) { return n1.id == n2.id && n1.property == n2.property; } -template -std::enable_if_t::value, bool> operator!=(const Node& n1, const Node& n2) +template +bool operator!=(const Node& n1, const Node& n2) { return !(n1 == n2); } @@ -111,13 +110,13 @@ std::enable_if_t::value, bool> operator!=(const Node& n1, const /** * @brief comparison operator if edge property type is equality comparable */ -template -std::enable_if_t::value, bool> operator==(const Edge& e1, const Edge& e2) +template +bool operator==(const Edge& e1, const Edge& e2) { return e1.start_node_idx == e2.start_node_idx && e1.end_node_idx == e2.end_node_idx && e1.property == e2.property; } -template -std::enable_if_t::value, bool> operator!=(const Edge& e1, const Edge& e2) +template +bool operator!=(const Edge& e1, const Edge& e2) { return !(e1 == e2); } @@ -126,7 +125,8 @@ std::enable_if_t::value, bool> operator!=(const Edge& e1, const * @brief out stream operator for edges if edge property type has stream operator defined */ template -std::enable_if_t::value, std::ostream&> operator<<(std::ostream& os, const Edge& e) + requires HasOstreamOperator +std::ostream& operator<<(std::ostream& os, const Edge& e) { os << e.start_node_idx << " > " << e.end_node_idx << " : " << e.property; return os; @@ -136,7 +136,8 @@ std::enable_if_t::value, std::ostream&> operator<<(std::ostrea * @brief out stream operator for edges if edge property type does not have stream operator defined */ template -std::enable_if_t::value, std::ostream&> operator<<(std::ostream& os, const Edge& e) + requires(!HasOstreamOperator) +std::ostream& operator<<(std::ostream& os, const Edge& e) { os << e.start_node_idx << " > " << e.end_node_idx; return os; @@ -148,8 +149,7 @@ std::enable_if_t::value, std::ostream&> operator<<(std::ostre template class Graph //ensure correct std::is_copy_constructible; it's not correct by default because the nodes and edges are stored in std::vector - : not_copyable_if_t< - !conjunction, std::is_copy_constructible>::value> + : not_copyable_if_t && std::is_copy_constructible_v)> { public: using NodeProperty = NodePropertyT; @@ -451,13 +451,15 @@ IOResult set_edges(const fs::path& mobility_data_file, Graph -std::enable_if_t::value, void> print_graph_object(std::ostream& os, size_t idx, const T&) + requires(!HasOstreamOperator) +void print_graph_object(std::ostream& os, size_t idx, const T&) { os << idx; } template -std::enable_if_t::value, void> print_graph_object(std::ostream& os, size_t idx, const T& o) + requires HasOstreamOperator +void print_graph_object(std::ostream& os, size_t idx, const T& o) { os << idx << " [" << o << "]"; } diff --git a/cpp/memilio/mobility/graph_builder.h b/cpp/memilio/mobility/graph_builder.h index 78f320d607..9a63f60802 100644 --- a/cpp/memilio/mobility/graph_builder.h +++ b/cpp/memilio/mobility/graph_builder.h @@ -22,11 +22,8 @@ #include "memilio/mobility/graph.h" #include "memilio/utils/logging.h" -#include "memilio/utils/stl_util.h" + #include -#include -#include -#include namespace mio { @@ -156,4 +153,4 @@ class GraphBuilder } // namespace mio -#endif // GRAPH_BUILDER_H \ No newline at end of file +#endif // GRAPH_BUILDER_H diff --git a/cpp/memilio/mobility/graph_simulation.h b/cpp/memilio/mobility/graph_simulation.h index ec49f4ad43..3835b72c5c 100644 --- a/cpp/memilio/mobility/graph_simulation.h +++ b/cpp/memilio/mobility/graph_simulation.h @@ -145,7 +145,7 @@ class GraphSimulationStochastic } GraphSimulationStochastic(FP t0, FP dt, Graph&& g, const node_function& node_func, const edge_function&& edge_func) - : Base(t0, dt, std::forward(g), node_func, std::move(edge_func)) + : Base(t0, dt, std::move(g), node_func, std::move(edge_func)) , m_rates(Base::m_graph.edges().size() * Base::m_graph.edges()[0].property.get_parameters().get_coefficients().get_shape().rows()) { diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index b152c4e714..8e44714e78 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -20,21 +20,15 @@ #ifndef METAPOPULATION_MOBILITY_INSTANT_H #define METAPOPULATION_MOBILITY_INSTANT_H -#include "memilio/mobility/graph_simulation.h" -#include "memilio/utils/time_series.h" +#include "memilio/compartments/simulation.h" +#include "memilio/epidemiology/contact_matrix.h" +#include "memilio/epidemiology/dynamic_npis.h" #include "memilio/math/eigen.h" +#include "memilio/math/euler.h" #include "memilio/math/eigen_util.h" -#include "memilio/utils/metaprogramming.h" +#include "memilio/mobility/graph_simulation.h" #include "memilio/utils/compiler_diagnostics.h" -#include "memilio/math/euler.h" -#include "memilio/epidemiology/contact_matrix.h" -#include "memilio/epidemiology/dynamic_npis.h" -#include "memilio/compartments/simulation.h" -#include "memilio/utils/date.h" - -#include "boost/filesystem.hpp" - -#include +#include "memilio/utils/time_series.h" namespace mio { @@ -48,7 +42,8 @@ class SimulationNode public: using Simulation = Sim; - template ::value, void>> + template + requires std::is_constructible_v SimulationNode(Args&&... args) : m_simulation(std::forward(args)...) , m_last_state(m_simulation.get_result().get_last_value()) @@ -463,7 +458,7 @@ void MobilityEdge::add_mobility_result_time_point(const FP t) * @param t time of mobility * @param dt time between mobility and return */ -template ::value>> +template Sim> void calculate_mobility_returns(Eigen::Ref::Vector> mobile_population, const Sim& sim, Eigen::Ref::Vector> total, FP t, FP dt) { @@ -476,13 +471,6 @@ void calculate_mobility_returns(Eigen::Ref::Vector> mobi y0, t, dt, y1); } -/** - * detect a get_infections_relative function for the Model type. - */ -template -using get_infections_relative_expr_t = decltype(get_infections_relative( - std::declval(), std::declval(), std::declval>&>())); - /** * get the percantage of infected people of the total population in the node * If dynamic NPIs are enabled, there needs to be an overload of get_infections_relative(model, y) @@ -495,7 +483,7 @@ using get_infections_relative_expr_t = decltype(get_infections_relative( template FP get_infections_relative(const SimulationNode& node, FP t, const Eigen::Ref>& y) { - if constexpr (is_expression_valid::value) { + if constexpr (requires { get_infections_relative(node.get_simulation(), t, y); }) { return get_infections_relative(node.get_simulation(), t, y); } else { @@ -506,13 +494,6 @@ FP get_infections_relative(const SimulationNode& node, FP t, const Eige } } -/** - * detect a get_mobility_factors function for the Model type. - */ -template -using get_mobility_factors_expr_t = decltype(get_mobility_factors( - std::declval(), std::declval(), std::declval>&>())); - /** * Get an additional mobility factor. * The absolute mobility for each compartment is computed by c_i * y_i * f_i, wher c_i is the coefficient set in @@ -527,7 +508,7 @@ using get_mobility_factors_expr_t = decltype(get_mobility_factors( template auto get_mobility_factors(const SimulationNode& node, FP t, const Eigen::Ref>& y) { - if constexpr (is_expression_valid::value) { + if constexpr (requires { get_mobility_factors(node.get_simulation(), t, y); }) { return get_mobility_factors(node.get_simulation(), t, y); } else { @@ -538,13 +519,6 @@ auto get_mobility_factors(const SimulationNode& node, FP t, const Eigen } } -/** - * detect a get_mobility_factors function for the Model type. - */ -template -using test_commuters_expr_t = decltype(test_commuters( - std::declval(), std::declval>>(), std::declval())); - /** * Test persons when moving from their source node. * May transfer persons between compartments, e.g., if an infection was detected. @@ -558,7 +532,7 @@ using test_commuters_expr_t = decltype(test_commuters( template void test_commuters(SimulationNode& node, Eigen::Ref> mobile_population, FP time) { - if constexpr (is_expression_valid::value) { + if constexpr (requires { test_commuters(node.get_simulation(), mobile_population, time); }) { test_commuters(node.get_simulation(), mobile_population, time); } else { diff --git a/cpp/memilio/mobility/metapopulation_mobility_stochastic.h b/cpp/memilio/mobility/metapopulation_mobility_stochastic.h index 89a38120ac..b6f0c672d8 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_stochastic.h +++ b/cpp/memilio/mobility/metapopulation_mobility_stochastic.h @@ -20,17 +20,10 @@ #ifndef METAPOPULATION_MOBILITY_STOCHASTIC_H #define METAPOPULATION_MOBILITY_STOCHASTIC_H -#include "memilio/compartments/simulation.h" -#include "memilio/utils/time_series.h" #include "memilio/epidemiology/contact_matrix.h" -#include "memilio/epidemiology/age_group.h" #include "memilio/mobility/graph_simulation.h" #include "memilio/mobility/metapopulation_mobility_instant.h" -#include "boost/filesystem.hpp" - -#include - namespace mio { diff --git a/cpp/memilio/timer/table_printer.h b/cpp/memilio/timer/table_printer.h index b3080b069a..e784230ad8 100644 --- a/cpp/memilio/timer/table_printer.h +++ b/cpp/memilio/timer/table_printer.h @@ -25,6 +25,7 @@ #include "memilio/utils/logging.h" // included for fmt #include +#include #include #include #include diff --git a/cpp/memilio/timer/timer_registrar.h b/cpp/memilio/timer/timer_registrar.h index 194a12b801..9bcb15ba14 100644 --- a/cpp/memilio/timer/timer_registrar.h +++ b/cpp/memilio/timer/timer_registrar.h @@ -67,7 +67,7 @@ class TimerRegistrar void add_timer(TimerRegistration&& registration) { m_registration_lock.lock(); - m_register.emplace_back(registration); + m_register.emplace_back(std::move(registration)); m_registration_lock.unlock(); } @@ -117,9 +117,6 @@ class TimerRegistrar // old value of m_printer (now stored in printer) is deleted at end of scope } -private: - /// @brief Instead of constructing a TimerRegistrar, use its static method `TimerRegistrar::get_instance()`. - TimerRegistrar() = default; /** * @brief TimerRegistrar must not be copied or moved, use `TimerRegistrar::get_instance()` to access it. * @{ @@ -130,6 +127,10 @@ class TimerRegistrar void operator=(TimerRegistrar&&) = delete; /** @} */ +private: + /// @brief Instead of constructing a TimerRegistrar, use its static method `TimerRegistrar::get_instance()`. + TimerRegistrar() = default; + /// @brief Specify a destructor to allow printing all timers after exit from main. ~TimerRegistrar() { diff --git a/cpp/memilio/utils/base_dir.h b/cpp/memilio/utils/base_dir.h index 72eab70fa9..4616ac7387 100644 --- a/cpp/memilio/utils/base_dir.h +++ b/cpp/memilio/utils/base_dir.h @@ -20,7 +20,7 @@ #ifndef MIO_BASE_DIR_H #define MIO_BASE_DIR_H -#include "memilio/config.h" +#include "memilio/config.h" // IWYU pragma: keep #include diff --git a/cpp/memilio/utils/compiler_diagnostics.h b/cpp/memilio/utils/compiler_diagnostics.h index dbc5ef4a66..73808ce69b 100644 --- a/cpp/memilio/utils/compiler_diagnostics.h +++ b/cpp/memilio/utils/compiler_diagnostics.h @@ -17,15 +17,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef EPI_UTILS_UNUSED_H -#define EPI_UTILS_UNUSED_H +#ifndef MIO_UTILS_COMPILER_DIAGNOSTICS_H +#define MIO_UTILS_COMPILER_DIAGNOSTICS_H namespace mio { /** -* does nothing, can be used to mark variables as not used. -* e.g. for avoiding compiler warnings/error about unused variables. -*/ + * @brief Does nothing, can be used to mark variables as not used. + * Intended for avoiding compiler warnings/error about unused variables. + */ template void unused(T&&...) { @@ -75,4 +75,4 @@ void unused(T&&...) #define MEMILIO_ENABLE_EBO #endif -#endif //EPI_UTILS_UNUSED_H +#endif // MIO_UTILS_COMPILER_DIAGNOSTICS_H diff --git a/cpp/memilio/utils/custom_index_array.h b/cpp/memilio/utils/custom_index_array.h index 2c1b74cd09..cbf414ffa0 100644 --- a/cpp/memilio/utils/custom_index_array.h +++ b/cpp/memilio/utils/custom_index_array.h @@ -17,12 +17,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef CUSTOMINDEXARRAY_H -#define CUSTOMINDEXARRAY_H +#ifndef MIO_UTILS_CUSTOM_INDEX_ARRAY_H +#define MIO_UTILS_CUSTOM_INDEX_ARRAY_H #include "memilio/math/eigen_util.h" #include "memilio/utils/index.h" -#include "memilio/utils/stl_util.h" +#include "memilio/utils/metaprogramming.h" #include @@ -30,17 +30,16 @@ namespace { //calculate the product of tuple elements -// std::apply or fold expression in C++17 +// TODO std::apply or fold expression in C++17; current version required by CustomIndexArray::Slice template class Index, class... Ts> -typename std::enable_if<(I == sizeof...(Ts)), size_t>::type product(Index const&) -{ - return 1; -} - -template class Index, class... Ts> -typename std::enable_if<(I < sizeof...(Ts)), size_t>::type product(Index const& t) +size_t product(Index const& t) { - return (size_t)mio::get(t) * product(t); + if constexpr (I < sizeof...(Ts)) { + return static_cast(mio::get(t)) * product(t); + } + else { + return 1; + } } template