Skip to content

Commit

Permalink
Merge pull request #456 from bluescarni/pr/ranges_fixes
Browse files Browse the repository at this point in the history
Fix potential compilation failure with C++20 input iterators
  • Loading branch information
bluescarni authored Sep 21, 2024
2 parents cde3faf + a52f198 commit 2ecadd9
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 9 deletions.
64 changes: 64 additions & 0 deletions include/heyoka/detail/rng_to_vec.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2020, 2021, 2022, 2023, 2024 Francesco Biscani ([email protected]), Dario Izzo ([email protected])
//
// 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 <concepts>
#include <ranges>
#include <type_traits>
#include <utility>
#include <vector>

#include <heyoka/config.hpp>

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.
//
// 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 <typename R>
auto rng_to_vec(R &&r)
{
static_assert(std::ranges::input_range<R>);

// Deduce the value type.
using value_type = std::remove_cvref_t<std::ranges::range_reference_t<R>>;

// Prepare the return value, reserving the appropriate
// size if R is a sized range whose size type is an integral type.
std::vector<value_type> retval;
if constexpr (requires {
requires std::ranges::sized_range<R>;
requires std::integral<std::ranges::range_size_t<R>>;
}) {
retval.reserve(static_cast<decltype(retval.size())>(std::ranges::size(r)));
}

// Add r's values into retval.
for (auto &&val : r) {
retval.push_back(std::forward<decltype(val)>(val));
}

return retval;
}

} // namespace detail

HEYOKA_END_NAMESPACE

#endif
10 changes: 5 additions & 5 deletions include/heyoka/expression.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include <heyoka/detail/fwd_decl.hpp>
#include <heyoka/detail/igor.hpp>
#include <heyoka/detail/llvm_fwd.hpp>
#include <heyoka/detail/rng_to_vec.hpp>
#include <heyoka/detail/type_traits.hpp>
#include <heyoka/detail/visibility.hpp>
#include <heyoka/func.hpp>
Expand Down Expand Up @@ -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<expression> get_gradient() const;
[[nodiscard]] std::vector<expression> get_jacobian() const;
[[nodiscard]] std::vector<expression> get_hessian(std::uint32_t) const;
Expand Down Expand Up @@ -846,9 +847,8 @@ class HEYOKA_DLL_PUBLIC_INLINE_CLASS cfunc
template <typename R>
static auto rng_to_vecex(R &&r)
{
auto tv = r | std::views::transform([]<typename U>(U &&x) { return expression{std::forward<U>(x)}; });

return std::vector(std::ranges::begin(tv), std::ranges::end(tv));
return detail::rng_to_vec(
r | std::views::transform([]<typename U>(U &&x) { return expression{std::forward<U>(x)}; }));
}

public:
Expand Down
3 changes: 2 additions & 1 deletion include/heyoka/llvm_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

#include <heyoka/detail/fwd_decl.hpp>
#include <heyoka/detail/llvm_fwd.hpp>
#include <heyoka/detail/rng_to_vec.hpp>
#include <heyoka/detail/type_traits.hpp>
#include <heyoka/detail/visibility.hpp>
#include <heyoka/kw.hpp>
Expand Down Expand Up @@ -390,7 +391,7 @@ class HEYOKA_DLL_PUBLIC llvm_multi_state
requires std::ranges::input_range<R>
&& std::same_as<llvm_state, std::remove_cvref_t<std::ranges::range_reference_t<R>>>
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<R>(rng)), parjit)
{
}
llvm_multi_state(const llvm_multi_state &);
Expand Down
2 changes: 1 addition & 1 deletion src/detail/llvm_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
4 changes: 2 additions & 2 deletions src/taylor_02.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
#include <heyoka/detail/llvm_helpers.hpp>
#include <heyoka/detail/llvm_vector_type.hpp>
#include <heyoka/detail/logging_impl.hpp>
#include <heyoka/detail/rng_to_vec.hpp>
#include <heyoka/detail/string_conv.hpp>
#include <heyoka/detail/type_traits.hpp>
#include <heyoka/detail/visibility.hpp>
Expand Down Expand Up @@ -1200,8 +1201,7 @@ std::vector<llvm_state> 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));
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,
Expand Down
1 change: 1 addition & 0 deletions src/taylor_adaptive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,7 @@ std::tuple<taylor_outcome, T> taylor_adaptive<T>::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)};
}
}
Expand Down
1 change: 1 addition & 0 deletions src/taylor_adaptive_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1877,6 +1877,7 @@ taylor_adaptive_batch<T>::propagate_grid_impl(const std::vector<T> &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;
})) {
Expand Down
1 change: 1 addition & 0 deletions src/var_ode_sys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit 2ecadd9

Please sign in to comment.