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

ConstantIterator #62

Open
wants to merge 19 commits into
base: master
Choose a base branch
from

Conversation

AntonReinhard
Copy link

  • Add ConstantIterator class
  • Yields the same value it was initialized with every time
  • Add testing for the class

example/reduce/src/reduce-main.cpp Outdated Show resolved Hide resolved
test/unit/iterator/src/ConstantIterator.cpp Outdated Show resolved Hide resolved

using namespace vikunja::mem::iterator;

TEMPLATE_TEST_CASE("Test Constant Iterator", "", int, double, uint64_t)
Copy link
Member

Choose a reason for hiding this comment

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

Please add also a test case to integ/transform. I think int operator()(int i) { return 2*i;} is a good functor for certificate the result (sum = size * 2 * constant).

@SimeonEhrig
Copy link
Member

@bernhardmgruber Can you please review it.

Copy link
Member

@bernhardmgruber bernhardmgruber left a comment

Choose a reason for hiding this comment

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

If the whole point of this iterator is to just return the same value whenever dereferences, I see no need to store an index. Then all iterator functions that move the iterator become noops. When do you need the index of the iterator?

You can probably make all member functions of ConstantIterator constexpr and noexcept.

Comment on lines 17 to 21
#if defined __has_include
# if __has_include(<version>)
# include <version>
# endif
# if __has_include(<compare>)
# include <compare>
# if defined(__cpp_lib_three_way_comparison) && defined(__cpp_impl_three_way_comparison)
# define USESPACESHIP
# endif
# endif
#endif
Copy link
Member

Choose a reason for hiding this comment

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

alpaka moved to C++17 recently. So maybe vikunja should be on C++17 as well. In this case you would not need the #if defined __has_include.

Furthermore, it seems you require only the language feature and not the library feature. In this case you can just test for __cpp_impl_three_way_comparison which is predefined by the compiler and does not require including the <version> header. See: https://en.cppreference.com/w/cpp/feature_test

Copy link
Member

Choose a reason for hiding this comment

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

After some discussion today, we decided to move to C++17. I want to provide a PR with the necessary changes this week.

Copy link
Author

Choose a reason for hiding this comment

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

Furthermore, it seems you require only the language feature and not the library feature. In this case you can just test for __cpp_impl_three_way_comparison

You're completely right, somehow I was under the impression that you always needed the header

include/vikunja/mem/iterator/ConstantIterator.hpp Outdated Show resolved Hide resolved
include/vikunja/mem/iterator/ConstantIterator.hpp Outdated Show resolved Hide resolved
include/vikunja/mem/iterator/ConstantIterator.hpp Outdated Show resolved Hide resolved
include/vikunja/mem/iterator/ConstantIterator.hpp Outdated Show resolved Hide resolved
include/vikunja/mem/iterator/ConstantIterator.hpp Outdated Show resolved Hide resolved
Comment on lines 185 to 164
/**
* @brief Spaceship operator for comparisons
*/
NODISCARD ALPAKA_FN_INLINE auto operator<=>(const ConstantIterator& other) const noexcept = default;
Copy link
Member

Choose a reason for hiding this comment

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

Such comments don't increase clarity of the code and only add noise. Try to avoid comments for the sake of comments, if they don't add any additional information the code is not already giving.

Copy link
Author

Choose a reason for hiding this comment

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

There is also the philosophy to have a doxygen comment for every function, even if it's fairly (or very) obvious what the function does. But I can also remove them if that's not the case for this project. Should I also remove them for the other straight forward arithmetic operators then?

Copy link
Member

Choose a reason for hiding this comment

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

To be honest, there is no real guide for the doxygen yet. The student who started this project, did it in some way. I don't believe, that he got some feedback. I want to overwork this in the near future, see #65 . But Bernhard is right, the function is already defined by the concept iterator. Therefore the one line which explains the obvious is not necessary.

Comment on lines 224 to 211
NODISCARD ALPAKA_FN_INLINE bool operator>(const ConstantIterator& other) const noexcept
{
if(v > other.v)
return true;
if(v < other.v)
return false;
return index > other.index;
}
Copy link
Member

Choose a reason for hiding this comment

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

When implementing comparison operators, you usually only implement operator< and operator==. The rest should be based on those:

Suggested change
NODISCARD ALPAKA_FN_INLINE bool operator>(const ConstantIterator& other) const noexcept
{
if(v > other.v)
return true;
if(v < other.v)
return false;
return index > other.index;
}
NODISCARD ALPAKA_FN_INLINE bool operator>(const ConstantIterator& other) const noexcept
{
return other < *this;
}

This way you can avoid accidentially only defining a partial order for your type. Or inconsistent comparions (e.g. a < b and a > b at the same time).

Applies to other operators below.

Copy link
Author

Choose a reason for hiding this comment

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

I know this can be done and reduces the probability to make mistakes, but I was trying to be explicit so I was sure the compiler wouldn't add unnecessary function calls. But I can change it anyways, if you think that this is unnecessary

Copy link
Member

Choose a reason for hiding this comment

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

Compiler inlining heuristics are quite good! I am certain, the compiler would inline the delegation to operator< inside operator>.

#pragma endregion comparisonoperators

private:
const DataType v;
Copy link
Member

Choose a reason for hiding this comment

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

By making v const, your type is not movable (which might not be a problem), but also not swapable. I would avoid it, but I leave the choice to you.

@SimeonEhrig
Copy link
Member

If the whole point of this iterator is to just return the same value whenever dereferences, I see no need to store an index. Then all iterator functions that move the iterator become noops. When do you need the index of the iterator?

You can probably make all member functions of ConstantIterator constexpr and noexcept.

The index is required for begin and end pointer:

ConstantIterator c_begin(10);
ConstantIterator c_end = c_begin + 4;

for(; c_begin < c_end; ++c_begin){
   std::cout << *c_begin << " "; // 10 10 10 10
}

Do you have a better idea?

@bernhardmgruber
Copy link
Member

The index is required for begin and end pointer:

ConstantIterator c_begin(10);
ConstantIterator c_end = c_begin + 4;

for(; c_begin < c_end; ++c_begin){
   std::cout << *c_begin << " "; // 10 10 10 10
}

No, makes perfect sense now :D Without the index you would have an infinite range.

@SimeonEhrig
Copy link
Member

@AntonReinhard Can you please rebase to the current master. I removed the C++ 14 support. New default is C++ 17.

@AntonReinhard
Copy link
Author

Ah, I knew you had to include for the spaceship operator: https://godbolt.org/z/soa55sP73
Apparently gcc somehow handles it without, but clang needs it, because the return type of the defaulted operator<=> is the std::strong_ordered type, which is defined in

@SimeonEhrig
Copy link
Member

Two points:

  • You need to rebase on the this commit, otherwise the constant iterator will not work on CPU: dbc5d3a
  • We cannot use the CI for benchmarking. All resources are virtualized and shared. Therefor the results are not reproduceable.

Can you execute your results on a local system or Taurus? If not, we have a Quadro V100 in our dev system. I can execute the benchmarks and send you the results.

@SimeonEhrig
Copy link
Member

By the way, I was aware about the wrong results on the serial backend in the reduce benchmark. I think, it is a precession problem of float and the many summations on a single value. But I had no time yet to investigate this.

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.

None yet

4 participants