From 997f19d6ce7817fa3afe5903a8bb90ad6974c8f2 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Fri, 20 Sep 2024 22:02:39 +0200 Subject: [PATCH 1/4] Fix potentially invalid use of C++20 input iterators as C++17 iterators. --- include/heyoka/detail/rng_to_vec.hpp | 51 ++++++++++++++++++++++++++++ include/heyoka/expression.hpp | 10 +++--- include/heyoka/llvm_state.hpp | 3 +- src/taylor_02.cpp | 5 +-- 4 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 include/heyoka/detail/rng_to_vec.hpp diff --git a/include/heyoka/detail/rng_to_vec.hpp b/include/heyoka/detail/rng_to_vec.hpp new file mode 100644 index 000000000..21b5e9c2a --- /dev/null +++ b/include/heyoka/detail/rng_to_vec.hpp @@ -0,0 +1,51 @@ +// Copyright 2020, 2021, 2022, 2023, 2024 Francesco Biscani (bluescarni@gmail.com), Dario Izzo (dario.izzo@gmail.com) +// +// This file is part of the heyoka library. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef HEYOKA_DETAIL_RNG_TO_VEC_HPP +#define HEYOKA_DETAIL_RNG_TO_VEC_HPP + +#include +#include +#include +#include + +#include + +HEYOKA_BEGIN_NAMESPACE + +namespace detail +{ + +// Helper to convert an input range R into a vector. +// The value type is deduced from the reference type of R. +template +auto rng_to_vec(R &&r) +{ + // Deduce the value type. + using value_type = std::remove_cvref_t>; + + // Prepare the return value, reserving the appropriate + // size if R is a sized range. + std::vector retval; + if constexpr (std::ranges::sized_range) { + retval.reserve(static_cast(std::ranges::size(r))); + } + + // Add r's values into retval. + for (auto &&val : r) { + retval.push_back(std::forward(val)); + } + + return retval; +} + +} // namespace detail + +HEYOKA_END_NAMESPACE + +#endif diff --git a/include/heyoka/expression.hpp b/include/heyoka/expression.hpp index 72b01683b..5bac58cd6 100644 --- a/include/heyoka/expression.hpp +++ b/include/heyoka/expression.hpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -461,8 +462,8 @@ class HEYOKA_DLL_PUBLIC dtens [[nodiscard]] size_type index_of(const iterator &) const; [[nodiscard]] auto get_derivatives(std::uint32_t) const -> decltype(std::ranges::subrange(begin(), end())); - [[nodiscard]] auto get_derivatives(std::uint32_t, - std::uint32_t) const -> decltype(std::ranges::subrange(begin(), end())); + [[nodiscard]] auto get_derivatives(std::uint32_t, std::uint32_t) const + -> decltype(std::ranges::subrange(begin(), end())); [[nodiscard]] std::vector get_gradient() const; [[nodiscard]] std::vector get_jacobian() const; [[nodiscard]] std::vector get_hessian(std::uint32_t) const; @@ -846,9 +847,8 @@ class HEYOKA_DLL_PUBLIC_INLINE_CLASS cfunc template static auto rng_to_vecex(R &&r) { - auto tv = r | std::views::transform([](U &&x) { return expression{std::forward(x)}; }); - - return std::vector(std::ranges::begin(tv), std::ranges::end(tv)); + return detail::rng_to_vec( + r | std::views::transform([](U &&x) { return expression{std::forward(x)}; })); } public: diff --git a/include/heyoka/llvm_state.hpp b/include/heyoka/llvm_state.hpp index a6fb77d52..07f26c9cf 100644 --- a/include/heyoka/llvm_state.hpp +++ b/include/heyoka/llvm_state.hpp @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -390,7 +391,7 @@ class HEYOKA_DLL_PUBLIC llvm_multi_state requires std::ranges::input_range && std::same_as>> explicit llvm_multi_state(R &&rng, bool parjit = detail::default_parjit) - : llvm_multi_state(std::vector(std::ranges::begin(rng), std::ranges::end(rng)), parjit) + : llvm_multi_state(detail::rng_to_vec(std::forward(rng)), parjit) { } llvm_multi_state(const llvm_multi_state &); diff --git a/src/taylor_02.cpp b/src/taylor_02.cpp index b5d4354d0..274634471 100644 --- a/src/taylor_02.cpp +++ b/src/taylor_02.cpp @@ -65,6 +65,7 @@ #include #include #include +#include #include #include #include @@ -1200,8 +1201,8 @@ std::vector taylor_compute_jet_multi(llvm_state &main_state, llvm::T // the custom transform: // // https://en.cppreference.com/w/cpp/ranges/as_rvalue_view - auto sview = states | std::views::transform([](auto &s) -> auto && { return std::move(s); }); - return std::vector(std::ranges::begin(sview), std::ranges::end(sview)); + auto sview = states | std::views::transform([](llvm_state &s) -> llvm_state && { return std::move(s); }); + return rng_to_vec(sview); } // Helper for the computation of a jet of derivatives in compact mode, From 8dcb630ad5b8d2da9a324ef023073442b046a5e1 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Fri, 20 Sep 2024 22:22:15 +0200 Subject: [PATCH 2/4] Tweaks. --- include/heyoka/detail/rng_to_vec.hpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/include/heyoka/detail/rng_to_vec.hpp b/include/heyoka/detail/rng_to_vec.hpp index 21b5e9c2a..40fb91d26 100644 --- a/include/heyoka/detail/rng_to_vec.hpp +++ b/include/heyoka/detail/rng_to_vec.hpp @@ -9,6 +9,7 @@ #ifndef HEYOKA_DETAIL_RNG_TO_VEC_HPP #define HEYOKA_DETAIL_RNG_TO_VEC_HPP +#include #include #include #include @@ -23,16 +24,28 @@ namespace detail // Helper to convert an input range R into a vector. // The value type is deduced from the reference type of R. +// +// NOTE: the need for this helper - as opposed to using directly +// the std::vector ctor from iterators - arises because the std::vector +// ctor requires C++17 input iterators, but C++20 input iterators +// are not necessarily C++17 input iterators. Thus, we go through +// a range-based for loop in which we push_back() the elements from +// the input range instead. template auto rng_to_vec(R &&r) { + static_assert(std::ranges::input_range); + // Deduce the value type. using value_type = std::remove_cvref_t>; // Prepare the return value, reserving the appropriate - // size if R is a sized range. + // size if R is a sized range whose size type is an integral type. std::vector retval; - if constexpr (std::ranges::sized_range) { + if constexpr (requires { + requires std::ranges::sized_range; + requires std::integral>; + }) { retval.reserve(static_cast(std::ranges::size(r))); } From a4bb436a7db9529dc9ed560bbdceb9fc2c94f237 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Fri, 20 Sep 2024 23:36:50 +0200 Subject: [PATCH 3/4] clang-tidy fixes. --- src/detail/llvm_helpers.cpp | 2 +- src/taylor_adaptive.cpp | 1 + src/taylor_adaptive_batch.cpp | 1 + src/var_ode_sys.cpp | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/detail/llvm_helpers.cpp b/src/detail/llvm_helpers.cpp index f808f1e2e..38ea055e0 100644 --- a/src/detail/llvm_helpers.cpp +++ b/src/detail/llvm_helpers.cpp @@ -1165,7 +1165,7 @@ llvm::Value *ext_gather_vector_from_memory(llvm_state &s, llvm::Type *tp, llvm:: auto &builder = s.builder(); #if defined(HEYOKA_HAVE_REAL) - if (const auto real_prec = llvm_is_real(tp->getScalarType())) { + if (llvm_is_real(tp->getScalarType()) != 0) { // LCOV_EXCL_START if (tp->isVectorTy()) { throw std::invalid_argument("Cannot gather from memory a vector of reals"); diff --git a/src/taylor_adaptive.cpp b/src/taylor_adaptive.cpp index 02e9ec15e..b4e8cb0a3 100644 --- a/src/taylor_adaptive.cpp +++ b/src/taylor_adaptive.cpp @@ -1005,6 +1005,7 @@ std::tuple taylor_adaptive::step_impl(T max_delta_t, bool // integration should continue). Otherwise, either the terminal event // has no callback or its callback returned false, meaning that the // integration must stop. + // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) return std::tuple{taylor_outcome{te_cb_ret ? ev_idx : (-ev_idx - 1)}, std::move(h)}; } } diff --git a/src/taylor_adaptive_batch.cpp b/src/taylor_adaptive_batch.cpp index eac130da4..60697e048 100644 --- a/src/taylor_adaptive_batch.cpp +++ b/src/taylor_adaptive_batch.cpp @@ -1877,6 +1877,7 @@ taylor_adaptive_batch::propagate_grid_impl(const std::vector &grid, std::s if (std::any_of(m_prop_res.begin(), m_prop_res.end(), [](const auto &t) { const auto t_oc = std::get<0>(t); + // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) return t_oc == taylor_outcome::cb_stop || (t_oc > taylor_outcome::success && t_oc < taylor_outcome{0}) || t_oc == taylor_outcome::step_limit; })) { diff --git a/src/var_ode_sys.cpp b/src/var_ode_sys.cpp index 02fe5d116..1a1043db3 100644 --- a/src/var_ode_sys.cpp +++ b/src/var_ode_sys.cpp @@ -56,6 +56,7 @@ namespace void validate_var_args(var_args a) { + // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) if (a == var_args{0} || a > var_args::all) [[unlikely]] { throw std::invalid_argument(fmt::format("Invalid var_args enumerator detected: the value of the enumerator " "must be in the [1, 7] range, but a value of {} was detected instead", From a52f19898d0463a52e2c1d9b9ba618d7580a4d31 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Sat, 21 Sep 2024 08:55:47 +0200 Subject: [PATCH 4/4] Minor. --- src/taylor_02.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/taylor_02.cpp b/src/taylor_02.cpp index 274634471..9d0add3a8 100644 --- a/src/taylor_02.cpp +++ b/src/taylor_02.cpp @@ -1201,8 +1201,7 @@ std::vector taylor_compute_jet_multi(llvm_state &main_state, llvm::T // the custom transform: // // https://en.cppreference.com/w/cpp/ranges/as_rvalue_view - auto sview = states | std::views::transform([](llvm_state &s) -> llvm_state && { return std::move(s); }); - return rng_to_vec(sview); + return rng_to_vec(states | std::views::transform([](llvm_state &s) -> llvm_state && { return std::move(s); })); } // Helper for the computation of a jet of derivatives in compact mode,