Skip to content

Instantly share code, notes, and snippets.

@bstaletic
Created June 20, 2020 19:31
Show Gist options
  • Save bstaletic/16f1118be9668584d9081ec9c25c5deb to your computer and use it in GitHub Desktop.
Save bstaletic/16f1118be9668584d9081ec9c25c5deb to your computer and use it in GitHub Desktop.
New nano::ranges algorithms
// nanorange/algorithm/clamp.hpp
//
// Copyright (c) 2020 Tristan Brindle (tcbrindle at gmail dot com)
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef NANORANGE_ALGORITHM_CLAMP_HPP_INCLUDED
#define NANORANGE_ALGORITHM_CLAMP_HPP_INCLUDED
#include <nanorange/ranges.hpp>
NANO_BEGIN_NAMESPACE
namespace detail {
struct clamp_fn {
private:
template <typename T, typename Proj, typename Comp>
static constexpr T&
impl(const T& value, const T& low, const T& high, Comp comp = {}, Proj proj = {})
{
auto projected_value = nano::invoke(proj, value);
if(nano::invoke(comp, projected_value, nano::invoke(proj, low))) {
return low;
} else if(nano::invoke(comp, nano::invoke(proj, high), projected_value)) {
return high;
} else {
return value;
}
}
public:
template <typename T, typename Proj = identity, typename Comp = nano::less>
constexpr std::enable_if_t<
input_iterator<T> &&
indirect_strict_weak_order<Comp, projected<const T*, Proj>>,
T&>
operator()(const T& value, const T& low, const T& high, Comp comp = {}, Proj proj = Proj{}) const
{
return clamp_fn::impl(value, low, high, comp, proj);
}
};
} // namespace detail
NANO_INLINE_VAR(detail::clamp_fn, clamp)
NANO_END_NAMESPACE
#endif
// nanorange/algorithm/for_each.hpp
//
// Copyright (c) 2020 Tristan Brindle (tcbrindle at gmail dot com)
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef NANORANGE_ALGORITHM_FOR_EACH_N_HPP_INCLUDED
#define NANORANGE_ALGORITHM_FOR_EACH_N_HPP_INCLUDED
#include <nanorange/ranges.hpp>
#include <nanorange/algorithm/for_each.hpp>
NANO_BEGIN_NAMESPACE
template <typename I, typename F>
using for_each_n_result = for_each_result<I, F>;
namespace detail {
struct for_each_n_fn {
private:
template <typename I, typename Proj, typename Fun>
static constexpr for_each_n_result<I, Fun>
impl(I first, iter_difference_t<I> n, Fun& fun, Proj& proj)
{
iter_difference_t<I> steps = 0;
while (steps < n) {
nano::invoke(fun, nano::invoke(proj, *first));
++first;
++steps;
}
return {first, std::move(fun)};
}
public:
template <typename I, typename S, typename Proj = identity, typename Fun>
constexpr std::enable_if_t<
input_iterator<I> &&
indirect_unary_invocable<Fun, projected<I, Proj>>,
for_each_n_result<I, Fun>>
operator()(I first, S last, Fun fun, Proj proj = Proj{}) const
{
return for_each_n_fn::impl(std::move(first), std::move(last),
fun, proj);
}
};
} // namespace detail
NANO_INLINE_VAR(detail::for_each_n_fn, for_each_n)
NANO_END_NAMESPACE
#endif
// nanorange/algorithm/shuffle.hpp
//
// Copyright (c) 2020 Tristan Brindle (tcbrindle at gmail dot com)
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef NANORANGE_ALGORITHM_SHUFFLE_HPP_INCLUDED
#define NANORANGE_ALGORITHM_SHUFFLE_HPP_INCLUDED
#include <nanorange/ranges.hpp>
#include <nanorange/random.hpp>
#include <nanorange/algorithm/min.hpp>
#include <random>
NANO_BEGIN_NAMESPACE
namespace detail {
struct sample_fn {
private:
template <typename I, typename S, typename O, typename Gen>
static O impl(I first, S last, O out, iter_difference_t<I> n, Gen&& g)
{
using diff_t = iter_difference_t<I>;
using distr_t = std::uniform_int_distribution<diff_t>;
using param_t = typename distr_t::param_type;
distr_t D;
auto unsampled_size = nano::distance(first, last);
for(n = nano::min(n, unsampled_size); n != 0; ++first) {
if(D(g, param_t(0, --unsampled_size)) < n) {
*out++ = *first;
--n;
}
}
return out;
}
public:
template <typename I, typename S, typename O, typename Gen>
std::enable_if_t<
input_iterator<I> &&
sentinel_for<S, I> &&
weakly_incrementable<O> &&
(forward_iterator<I> || random_access_iterator<O>) &&
indirectly_copyable<I, O> &&
uniform_random_bit_generator<std::remove_reference_t<Gen>>,
O>
operator()(I first, S last, O out, iter_difference_t<I> n, Gen&& gen) const
{
return sample_fn::impl(std::move(first), std::move(last),
std::move(out), std::move(n),
std::forward<Gen>(gen));
}
template <typename Rng, typename O, typename Gen>
std::enable_if_t<
input_range<Rng> &&
weakly_incrementable<O> &&
(forward_range<Rng> || random_access_iterator<O> ) &&
indirectly_copyable<iterator_t<Rng>, O> &&
uniform_random_bit_generator<std::remove_reference_t<Gen>>,
O>
operator()(Rng&& rng, O out, range_difference_t<Rng> n, Gen&& gen) const
{
return sample_fn::impl(nano::begin(rng), nano::end(rng),
std::move(out), std::move(n), std::forward<Gen>(gen));
}
};
}
NANO_INLINE_VAR(detail::sample_fn, sample)
NANO_END_NAMESPACE
#endif
@al-mission-2016
Copy link

Hi, bstaletic.
For comparison, you may take a look at my suggesion for ranges::for_each_n.
As Tristan said, pull/95, paraphrasing, there is no need in that static impl().
Have a look at gcc as well. : -)

template <typename I, typename F>
using for_each_n_result = for_each_result<I, F>;

namespace detail {

struct for_each_n_fn {
    template <typename I, typename Proj = identity, typename Fun>
    constexpr std::enable_if_t<
        input_iterator<I> &&
            indirect_unary_invocable<Fun, projected<I, Proj>>,
        for_each_n_result<I, Fun>>
    operator()(I first, iter_difference_t<I> n, Fun fun, Proj proj = Proj{}) const
    {
        while (n-- > 0) {
            nano::invoke(fun, std::invoke(proj, *first));
            ++first;
        }
        return {std::move(first), std::move(fun)};
    }
};

} // namespace detail

NANO_INLINE_VAR(detail::for_each_n_fn, for_each_n)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment