Skip to content

Adding concept to a part of the code #2842

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

Merged
merged 6 commits into from
Apr 11, 2025

Conversation

alexandrehoffmann
Copy link
Contributor

@alexandrehoffmann alexandrehoffmann commented Apr 9, 2025

Checklist

  • [ X] The title and commit message(s) are descriptive.
  • [ X] Small commits made to fix your PR have been squashed to avoid history pollution.
  • [ X] Tests have been added for new features or bug fixes.
  • [ X] API of new functions and classes are documented.

Description

This PR C++20's concept and C++17's if constexpr to a moderatly large chunk of xtensor.

Copy link
Member

@JohanMabille JohanMabille left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When all the enable_if have been replaced, I think we can start removing most of the metafunction used in the concept definitinos, and defined the concept with specific C++20 syntax:

template <class E>
concept has_simd_interface = requires(R e, size_t i)
{
    e.load_simd(i);
    e.store_simd(i, E::vaue_type());
};

That should be done in a dedicated PR.

@@ -64,7 +56,7 @@ namespace xt
explicit uvector(size_type count, const allocator_type& alloc = allocator_type());
uvector(size_type count, const_reference value, const allocator_type& alloc = allocator_type());

template <class InputIt, class = detail::require_input_iter<InputIt>>
template <input_iterator_concept InputIt>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use std::input_iterator instead ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed in commit 4809115



template<class E>
concept is_xscalar_concept = is_xscalar<std::decay_t<E>>::value;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpicking: xscalar_concept would be more consistent with the other names.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed in last commit #4809115

@gouarin
Copy link
Member

gouarin commented Apr 9, 2025

#2839 must be merged for the CI

@alexandrehoffmann
Copy link
Contributor Author

Git pre-commit tends to switch requires and inline keywords . Is it possible to amand the git .pre-commit-config.yaml so that it does not happens ?

@spectre-ns
Copy link
Contributor

spectre-ns commented Apr 9, 2025

@alexandrehoffmann @JohanMabille Great work! Concept are a great match for this library! When looking into views I found that the concepts of linear assignment and data interface (has_data_interface) are conflated in places. This means that views of functions are much slower than functions of views even though they are the same operations and commutative. Hopefully, we can come up with better logic for these properties once the code base is ported to C++20. :)

@alexandrehoffmann
Copy link
Contributor Author

alexandrehoffmann commented Apr 10, 2025

Ok so, as for now, clang doesn't allow to implement methods outside of the class scope if said method uses concepts.
As an example:

    template <class CT, class... S>
    template <class T>
        requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
    auto xview<CT, S...>::linear_begin() -> linear_iterator
    {
        return m_e.storage().begin() + data_offset();
    }

does not compile with clang but

template <class CT, class... S>
class xview
{
[...]
        template <class T = xexpression_type>
            requires has_data_interface_concept<T> and strided_view_concept<CT, S...>
        const_linear_iterator linear_begin() const { return m_e.storage().begin() + data_offset(); } 
[...]       
};

does.

To me the two options are
a) wait for proper concept implementation in clang or upgrade to a newer version
b) declare all the method that rely on concepts within the class's scope.

@JohanMabille
Copy link
Member

JohanMabille commented Apr 10, 2025

Does the trailing requires syntax work ? I.e. something like

    template <class CT, class... S>
    template <class T>
    auto xview<CT, S...>::linear_begin() -> linear_iterator
        requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
    {
        return m_e.storage().begin() + data_offset();
    }

@alexandrehoffmann
Copy link
Contributor Author

alexandrehoffmann commented Apr 10, 2025

Does the trailing requires syntax work ? I.e. something like

    template <class CT, class... S>
    template <class T>
    auto xview<CT, S...>::linear_begin() -> linear_iterator
        requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
    {
        return m_e.storage().begin() + data_offset();
    }

Unfortunately is does not, at least on my side:

/home/alex/Desktop/xtensor/include/xtensor/generators/../views/xview.hpp:1175:27: error: out-of-line definition of 'linear_begin' does not match any declaration in 'xview<CT, S...>'
 1175 |     auto xview<CT, S...>::linear_begin() -> linear_iterator

A possible solution would be to forward declare and then fully declare within the class e.g. :

template <class CT, class... S>
class xview
{
/////////// declaration zone
[...]
        template <class T = xexpression_type>
            requires has_data_interface_concept<T> and strided_view_concept<CT, S...>
        const_linear_iterator linear_begin() const;
[...]       
/////////// definition zone
        template <class T = xexpression_type>
            requires has_data_interface_concept<T> and strided_view_concept<CT, S...>
        const_linear_iterator linear_begin() const { return m_e.storage().begin() + data_offset(); } 
};

@JohanMabille
Copy link
Member

JohanMabille commented Apr 10, 2025

A possible solution would be to forward declare and then fully declare within the class e.g

I think it's a good compromise.

@alexandrehoffmann
Copy link
Contributor Author

So using the trailing requires works for most compilers but not clang-17 and 18

@JohanMabille
Copy link
Member

Awesome, thanks!

@JohanMabille JohanMabille merged commit 6705ba7 into xtensor-stack:master Apr 11, 2025
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants