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
Add a synchronous mapping API #2704
Conversation
struct my_mapper | ||
{ | ||
template <typename T, | ||
typename std::enable_if<std::is_same<T, int>::value>::type* = nullptr> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just out of curiosity, what's the purpose of using SFINAE here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using SFINAE over operator()(int)
has the benefits that wer can reject arguments that are convertible to int
too.
This makes it possible to reject float
values by this mapper.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, so rejecting then means to discard the input value? I would have expected a compile failure in case of a missing overload. What's the rationale here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation works as following: if the mapper doesn't accept a particular type, the type isn't remapped or traversed and thus effectively routed through.
Hence, there will be no compile-time error when an overload is missing or the argument type was rejected.
One of the reasons to implement it like that is, that I looked for a convenient way of routing some types through while remapping others and this approach works well with lambdas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense.
I am not sure if this won't lead to subtle bugs though. On the other hand, those types of bugs should be caught at compile already...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may still add an accept all overload, that triggers a static_assert
on instantiation to implement the behaviour that only known types are valid in a mapped or traversed pack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you planning on moving the customization points out of the detail namespace? It would be great if those were put more prominently for others to hook in them.
hpx/util/pack_traversal.hpp
Outdated
|
||
namespace hpx { | ||
namespace util { | ||
namespace detail { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably avoid having doxygen to generate docs for this, the detail namespace is not for public consumption anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was improved through one of my previous PR's already (8f71f2a).
As of now, doxygen doesn't generate docs for symbols declared inside a detail
namespace.
hpx/util/pack_traversal.hpp
Outdated
std::forward<Mapper>(mapper)); | ||
return helper.init_traverse(strategy, std::forward<T>(pack)...); | ||
} | ||
} // end namespace detail |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it make sense to move the stuff in detail into a seperate file? That way users could directly see the functions to use and not get hung up with all the implementation details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, good idea. I'll change that.
hpx/util/pack_traversal.hpp
Outdated
/// Calls the traversal method for every element in the pack, | ||
/// and returns a tuple containing the remapped content. | ||
template <typename First, typename Second, typename... T> | ||
auto init_traverse(strategy_remap_tag strategy, First&& first, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is first and second spelled out here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GCC has issues with prioritizing the deduction of the function taking only one argument over this one that accepts two or more arguments. This causes endless recursive instantiations.
In order to fix this I spelled both arguments out here.
@sithhell First of all thanks for your review, I highly appreciate that. As of now, I don't have any plans on making this API more customizable than it is, mainly due to the circumstance that this API does provide enough features to implement my project and possible future requirements are not known for me. However, the API is really adaptable in the way that we can map or traverse arbitrary types (this isn't tied to futures like in Additionally, the API can be easily refactored and extended through adapting the |
Makes sense. Are you planning on doing the unchecked TODO items within that PR or will you submit following ones? If the latter, I would like to ask you to move the missing TODOs into a separate issue so that we are able to track process. |
I plan to resolve the outstanding ToDo list items before this PR gets merged (the allocator issue will be resolved by tomorrow and for the capability macro I need some help from the maintainers, since I don't know how to solve it while keeping the conformance to the current practices). |
Did you have a look at this: This test is compiled during the CMake configuration run. If compiled successful, the define |
Sadly On stackoverflow I found an example case that still fails: https://stackoverflow.com/questions/35669239/the-c-detection-idiom-is-not-working-as-expected-in-visual-studio-2015-update however, I don't think that we can reduce the issue I have in this API to a minimalistic example. Also I can't take the example over because it's MIT licensed (stackoverflow TOS). Probably the best way to test the capability would be to try out, whether we can compile the API with |
Sure this would be a viable feature test. |
@hkaiser, @sithhell: Today, I tried to add a feature test like described above, however I'm facing two major issues:
Do you have any suggestions how I could solve this? Another really simple solution for this partuclar issue would be to just check the compiler and its version, but that violates the current principle of automatic feature tests. |
@Naios: inspect is still unhappy with this: https://7080-4455628-gh.circle-artifacts.com/0/tmp/circle-artifacts.B1i3Bir/hpx_inspect_report.html |
1046beb
to
c8c854d
Compare
@hkaiser Thanks for noticing, I corrected this. Also the two outstanding points are fixed now:
From my side this PR finished and thus ready for the final review and merge. |
hpx/config.hpp
Outdated
#include <hpx/config/version.hpp> | ||
#endif // HPX_CONFIG_NO_INTERNAL_LINK |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be better if this #if
/#endif
went into the header file hpx/config/version.hpp
, instead of wrapping the include outside of it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm now using HPX_NO_VERSION_CHECK
instead of the custom macro which made it possible to drop the conditional inclusion completely (hpx/config.hpp
wasn't touched then).
tests/unit/util/pack_traversal.cpp
Outdated
// 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) | ||
|
||
#include <algorithm> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my experience, for MSVC, including the HPX headers first avoids various warnings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually I try to stick to the Google C++
style guide (https://google.github.io/styleguide/cppguide.html#Names_and_Order_of_Includes) which requests to include standard library headers first for the reason:
With the preferred ordering, if dir2/foo2.h omits any necessary includes, the build of dir/foo.cc or dir/foo_test.cc will break. Thus, this rule ensures that build breaks show up first for the people working on these files, not for innocent people in other packages.
But I will reorder the includes to keep the conformance to the existing code.
hpx/util/pack_traversal.hpp
Outdated
#ifndef HPX_UTIL_PACK_TRAVERSAL_HPP | ||
#define HPX_UTIL_PACK_TRAVERSAL_HPP | ||
|
||
#include <utility> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, please include the HPX headers first.
#ifndef HPX_UTIL_DETAIL_PACK_TRAVERSAL_IMPL_HPP | ||
#define HPX_UTIL_DETAIL_PACK_TRAVERSAL_IMPL_HPP | ||
|
||
#include <cstddef> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here as well, please include the HPX headers first.
* add_hpx_in_framework_config_test makes HPX and its dependencies available to the corresponding feature test.
* Can be used to traverse or map elements contained in any nested container or tuple-like type. * Meant for replacing the internal API of hpx::util::unwrapped and some functions which are used to wait on futures.
* Tests whether the compiler provides full expression SFINAE supports so all parts of HPX can be compiled. * Currently MSVC is the only compiler that doesn't implement it.
@hkaiser Thank you for your feedback, I corrected all mentioned points. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks a lot!
in any nested container or tuple-like type.
hpx::util::unwrapped and some functions
which are used to wait on futures.
This is the first PR for my GSoC project, which implements the unified (synchronous) internal API
for re-implementing unwrapped as well as providing helper methods for synchronous functions
that wait on futures like
wait_all
.ToDo:
but only working for trivially constructible allocators as of now.
HPX_HAVE_EXPRESSION_SFINAE
macro accordingly.The issue is that I can't find a particular minimalistic example which could be used to detect the
capability of the compiler to compile the API.
All I know is, that Visual Studio isn't capable as of now to evaluate the expression SFINAE correctly.
This leads to a less performant implementation on Windows which traverses elements although they
contain no element, which is effectively accepted by the mapper.
Tested Compilers:
HPX_HAVE_EXPRESSION_SFINAE
)HPX_HAVE_EXPRESSION_SFINAE
)HPX_HAVE_EXPRESSION_SFINAE
)HPX_HAVE_EXPRESSION_SFINAE
)HPX_HAVE_EXPRESSION_SFINAE
)