Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX-#690: any_of basics #694

Merged
merged 3 commits into from
May 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions include/eve/algo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ The main model is `unaligned_ptr_iterator`

iterator that can represent any position in the underlying range.

### iteration pattern (concept)

A reusable component to do `while(f != l) ++f;`.
Given traits, f, l, delegate calls the delegate for each piece with (f, ignore).
The specific api of the delegate varies by iteration pattern.

Main one is `for_each_iteration`.
However for some algorithms, like `reverse` and maybe `partition` it's not a good.

### concepts

* `unaligned_t` -> a convinience to get the unaligned type.
Expand All @@ -56,3 +65,23 @@ iterator that can represent any position in the underlying range.
* `unaligned_ptr_iterator`

A pointer + cardinal with the `iterator` interface.

### preprocess_range

* `preprocess_range`

Given a more general notion of a range + traits returns enhanced traits +
iterator/sentinel pair that is understood by eve.

### for_each_iteration

`for_each_iteration(traits, f, l)`

_TODO_: we need some way to know where the iteration pattern starts from before actually doing anything. Example is `remove` it needs the base of where to start writing and it has to be there at the time of delegate creation.

The basic iteration pattern. A simd version of `while (f != l)`.
Delegate needs to implement `step(iterator, relative_condtional_expr)` and
_TODO_ `step_unrolled(iterator)` if the `unroll` trait is bigger than 1.
`iterator` type from steps is not guarantied to match `decltype(f)` (for when we know we can align the input for example).

`step` returns `true` if it wants to break or `false` to continue.
58 changes: 58 additions & 0 deletions include/eve/algo/any_of.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//==================================================================================================
/**
EVE - Expressive Vector Engine
Copyright : EVE Contributors & Maintainers
SPDX-License-Identifier: MIT
**/
//==================================================================================================
#pragma once

#include <eve/algo/preprocess_range.hpp>
#include <eve/algo/for_each_iteration.hpp>

#include <eve/function/any.hpp>



namespace eve::algo
{
struct any_of_
{
struct default_traits {};

template <typename P>
struct delegate
{
explicit delegate(P p) : p(p) {}

bool step(auto it, eve::relative_conditional_expr auto ignore)
{
auto test = p(eve::load[ignore](it));
res = eve::any[ignore](test);
return res;
}

P p;
bool res = false;
};

template <typename Traits, typename I, typename S, typename P>
bool operator()(Traits _traits, I _f, S _l, P p) const
{
if (_f == _l) return false;

delegate d{p};

auto [traits, f, l] = preprocess_range(_traits, _f, _l);
for_each_iteration(traits, f, l, d);
return d.res;
}

template <typename I, typename S, typename P>
bool operator()(I f, S l, P p) const
{
return operator()(default_traits{}, f, l, p);
}

} inline constexpr any_of;
}
33 changes: 33 additions & 0 deletions include/eve/algo/for_each_iteration.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//==================================================================================================
/**
EVE - Expressive Vector Engine
Copyright : EVE Contributors & Maintainers
SPDX-License-Identifier: MIT
**/
//==================================================================================================
#pragma once

#include <eve/assert.hpp>
#include <eve/conditional.hpp>

namespace eve::algo
{
struct for_each_iteration_
{
template <typename Traits, typename I, typename S, typename Delegate>
void operator()(Traits, I f, S l, Delegate& delegate) const
{
static constexpr std::ptrdiff_t step = typename I::cardinal{}();

I precise_l = f + ((l - f) / step * step);

while (f != precise_l) {
if (delegate.step(f, eve::ignore_none)) return;
f += step;
}

eve::keep_first ignore{l - precise_l};
delegate.step(f, ignore);
}
} inline constexpr for_each_iteration;
}
57 changes: 57 additions & 0 deletions include/eve/algo/preprocess_range.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//==================================================================================================
/**
EVE - Expressive Vector Engine
Copyright : EVE Contributors & Maintainers
SPDX-License-Identifier: MIT
**/
//==================================================================================================
#pragma once

#include <eve/algo/ptr_iterator.hpp>

#include <eve/assert.hpp>

#include <iterator>
#include <type_traits>

namespace eve::algo
{
namespace detail
{
template <typename Traits, typename I, typename S>
struct preprocess_range_result
{
Traits traits;
I f;
S l;
};

template <typename Traits, typename I, typename S>
preprocess_range_result(Traits, I, S) -> preprocess_range_result<Traits, I, S>;
}

struct preprocess_range_
{
template <typename Traits, std::contiguous_iterator I, typename S>
auto operator()(Traits traits, I f, S l) const
{
EVE_ASSERT(f != l, "preprocess_range requires a non-empty range");

auto* raw_f = &*f;
auto* raw_l = raw_f + (l - f);
using T = std::remove_reference_t<decltype(*raw_f)>;
using it = unaligned_ptr_iterator<T, eve::fixed<eve::expected_cardinal_v<T>>>;

return detail::preprocess_range_result{traits, it{raw_f}, it{raw_l}};
}

// Base case. Should validate that I, S are a valid iterator pair
template <typename Traits, typename I, typename S>
auto operator()(Traits traits, I f, S l) const
{
EVE_ASSERT(f != l, "preprocess_range requires a non-empty range");
return detail::preprocess_range_result{traits, f, l};
}

} inline constexpr preprocess_range;
}
110 changes: 53 additions & 57 deletions include/eve/algo/ptr_iterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace eve::algo
struct unaligned_ptr_iterator : operations_with_distance
{
using cardinal = Cardinal;
using wide_value_type = eve::wide<std::remove_const_t<T>, cardinal>;

unaligned_ptr_iterator() = default;
explicit unaligned_ptr_iterator(T* ptr) : ptr(ptr) {}
Expand All @@ -30,13 +31,40 @@ namespace eve::algo

auto operator<=>(unaligned_ptr_iterator const&) const = default;

template <relative_conditional_expr C>
friend wide_value_type tagged_dispatch( eve::tag::load_, C cond, unaligned_ptr_iterator self )
{
return eve::load[cond](self.ptr, cardinal{});
}

friend wide_value_type tagged_dispatch( eve::tag::load_, unaligned_ptr_iterator self )
{
return eve::load(self.ptr, cardinal{});
}

template <relative_conditional_expr C>
friend void tagged_dispatch(
eve::tag::store_, C cond, wide_value_type v, unaligned_ptr_iterator self )
requires (!std::is_const_v<T>)
{
eve::store[cond](v, self.ptr);
}

friend void tagged_dispatch( eve::tag::store_, wide_value_type v, unaligned_ptr_iterator self )
requires ( !std::is_const_v<T> )
{
eve::store(v, self.ptr);
}

T* ptr;
};

template <typename T, typename Cardinal>
struct aligned_ptr_iterator : operations_with_distance, forward_to_unaligned
{
using cardinal = Cardinal;
using wide_value_type = eve::wide<std::remove_const_t<T>, cardinal>;

using aligned_ptr_type = eve::aligned_ptr<T, Cardinal{}() * sizeof(T)>;

aligned_ptr_iterator();
Expand All @@ -45,63 +73,31 @@ namespace eve::algo
auto unaligned() const { return unaligned_ptr_iterator<T, Cardinal>{ptr.get()}; }
aligned_ptr_iterator& operator+=(std::ptrdiff_t n) { ptr += n; return *this; }

template <relative_conditional_expr C>
friend wide_value_type tagged_dispatch( eve::tag::load_, C cond, aligned_ptr_iterator self )
{
return eve::load[cond](self.ptr, cardinal{});
}

friend wide_value_type tagged_dispatch( eve::tag::load_, aligned_ptr_iterator self )
{
return eve::load(self.ptr, cardinal{});
}

template <relative_conditional_expr C>
friend void tagged_dispatch(
eve::tag::store_, C cond, wide_value_type v, aligned_ptr_iterator self )
requires ( !std::is_const_v<T> )
{
return eve::store[cond](v, self.ptr);
}

friend void tagged_dispatch( eve::tag::store_, wide_value_type v, aligned_ptr_iterator self )
requires ( !std::is_const_v<T> )
{
return eve::store(v, self.ptr);
}

aligned_ptr_type ptr;
};
}

// TODO: after #683 replace with a proper hook
namespace eve::detail
{
template <relative_conditional_expr C, typename T, typename N>
EVE_FORCEINLINE auto load_(EVE_SUPPORTS(cpu_), C cond, algo::aligned_ptr_iterator<T, N> it) {
return eve::load[cond](it.ptr, N{});
}

template <typename T, typename N>
EVE_FORCEINLINE auto load_(EVE_SUPPORTS(cpu_), algo::aligned_ptr_iterator<T, N> it) {
return eve::load(it.ptr, N{});
}


template <relative_conditional_expr C, typename T, typename N>
EVE_FORCEINLINE auto load_(EVE_SUPPORTS(cpu_), C cond, algo::unaligned_ptr_iterator<T, N> it) {
return eve::load[cond](it.ptr, N{});
}

template <typename T, typename N>
EVE_FORCEINLINE auto load_(EVE_SUPPORTS(cpu_), algo::unaligned_ptr_iterator<T, N> it) {
return eve::load(it.ptr, N{});
}

// ---------------------------
// store, we need to restrict the wide type but we can do that when the customization
// is avaliable.
template <relative_conditional_expr C, typename Wide, typename T, typename N>
requires std::invocable<decltype(eve::store),
C,
Wide,
typename algo::aligned_ptr_iterator<T, N>::aligned_ptr_type>
EVE_FORCEINLINE auto store_(EVE_SUPPORTS(cpu_), C cond, Wide wide, algo::aligned_ptr_iterator<T, N> it) {
return eve::store[cond](wide, it.ptr);
}

template <typename Wide, typename T, typename N>
requires std::invocable<decltype(eve::store),
Wide,
typename algo::aligned_ptr_iterator<T, N>::aligned_ptr_type>
EVE_FORCEINLINE auto store_(EVE_SUPPORTS(cpu_), Wide wide, algo::aligned_ptr_iterator<T, N> it) {
return eve::store(wide, it.ptr);
}

template <relative_conditional_expr C, typename Wide, typename T, typename N>
requires std::invocable<decltype(eve::store), C, Wide, T*>
EVE_FORCEINLINE auto store_(EVE_SUPPORTS(cpu_), C cond, Wide wide, algo::unaligned_ptr_iterator<T, N> it) {
return eve::store[cond](wide, it.ptr);
}

template <typename Wide, typename T, typename N>
requires std::invocable<decltype(eve::store), Wide, T*>
EVE_FORCEINLINE auto store_(EVE_SUPPORTS(cpu_), Wide wide, algo::unaligned_ptr_iterator<T, N> it) {
return eve::store(wide, it.ptr);
}
}
5 changes: 5 additions & 0 deletions test/unit/algo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,9 @@ add_custom_target(unit.algo.simd.exe )

##==================================================================================================
## ALGO tests
# Helpers
make_unit("unit.algo" preprocess_range.cpp)
make_unit("unit.algo" ptr_iterator.cpp)

# Algorithms
make_unit("unit.algo" any_of.cpp)
23 changes: 23 additions & 0 deletions test/unit/algo/any_of.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//==================================================================================================
/**
EVE - Expressive Vector Engine
Copyright : EVE Contributors & Maintainers
SPDX-License-Identifier: MIT
**/
//==================================================================================================

#include "algo_test.hpp"

#include <eve/algo/any_of.hpp>

#include "find_generic_test.hpp"

EVE_TEST_TYPES("Check any_of", algo_test::selected_types)
<typename T>(eve::as_<T> as_t)
{
algo_test::find_generic_test(as_t, [](auto f, auto l, auto res) {
bool actual = eve::algo::any_of(f, l, [](auto x) { return x != 0; });
bool expected = (res != l);
TTS_EQUAL(actual, expected);
});
};
Loading