Skip to content

Commit

Permalink
Adding environmental query CPOs
Browse files Browse the repository at this point in the history
- flyby: fixing global_fixture linking problems with MSVC
  • Loading branch information
hkaiser committed Jan 23, 2022
1 parent af206bb commit 3423b5d
Show file tree
Hide file tree
Showing 21 changed files with 943 additions and 98 deletions.
3 changes: 2 additions & 1 deletion libs/core/config/include/hpx/config/compiler_specific.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,5 @@
# endif
#endif
// clang-format on
#endif

#endif // defined(DOXYGEN)
2 changes: 1 addition & 1 deletion libs/core/execution/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2019-2021 The STE||AR-Group
# Copyright (c) 2019-2022 The STE||AR-Group
#
# SPDX-License-Identifier: BSL-1.0
# Distributed under the Boost Software License, Version 1.0. (See accompanying
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,7 @@ namespace hpx { namespace execution { namespace experimental {
using value_types = hpx::util::detail::unique_t<
hpx::util::detail::concat_pack_of_packs_t<hpx::util::detail::
transform_t<successor_sender_types<Tuple, Variant>,
value_types<Tuple, Variant>::template apply
#if defined(HPX_CLANG_VERSION) && HPX_CLANG_VERSION < 110000
>
//
>>;
#else
>>>;
#endif
value_types<Tuple, Variant>::template apply> /**/>>;

// hpx::util::pack acts as a concrete type in place of Tuple. It is
// required for computing successor_sender_types, but disappears
Expand Down
10 changes: 8 additions & 2 deletions libs/core/execution_base/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2019-2020 The STE||AR-Group
# Copyright (c) 2019-2022 The STE||AR-Group
#
# SPDX-License-Identifier: BSL-1.0
# Distributed under the Boost Software License, Version 1.0. (See accompanying
Expand All @@ -8,11 +8,17 @@ set(execution_base_headers
hpx/execution_base/agent_base.hpp
hpx/execution_base/agent_ref.hpp
hpx/execution_base/any_sender.hpp
hpx/execution_base/completion_scheduler.hpp
hpx/execution_base/context_base.hpp
hpx/execution_base/detail/spinlock_deadlock_detection.hpp
hpx/execution_base/execution.hpp
hpx/execution_base/completion_scheduler.hpp
hpx/execution_base/get_allocator.hpp
hpx/execution_base/get_env.hpp
hpx/execution_base/get_scheduler.hpp
hpx/execution_base/get_delegatee_scheduler.hpp
hpx/execution_base/get_stop_token.hpp
hpx/execution_base/operation_state.hpp
hpx/execution_base/read.hpp
hpx/execution_base/receiver.hpp
hpx/execution_base/resource_base.hpp
hpx/execution_base/sender.hpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2022 Hartmut Kaiser
//
// SPDX-License-Identifier: BSL-1.0
// 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)

#pragma once

#include <hpx/config.hpp>
#include <hpx/execution_base/get_env.hpp>
#include <hpx/execution_base/read.hpp>
#include <hpx/functional/detail/tag_fallback_invoke.hpp>

namespace hpx::execution::experimental {

// 1. execution::get_allocator is used to ask an object for its associated
// allocator.
//
// 2. The name execution::get_allocator denotes a customization point object.
// For some subexpression r, if the type of r is (possibly cv-qualified)
// no_env, then execution::get_allocator(r) is ill-formed.
// Otherwise, it is expression equivalent to:
//
// 1. tag_invoke(execution::get_allocator, as_const(r)), if this expression
// is well formed.
// Mandates: The tag_invoke expression above is not potentially-
// throwing and its type satisfies Allocator.
//
// 2. Otherwise, execution::get_allocator(r) is ill-formed.
//
// 3. execution::get_allocator() (with no arguments) is expression-equivalent
// to execution::read(execution::get_allocator).
//
inline constexpr struct get_allocator_t final
: hpx::functional::detail::tag_fallback<get_allocator_t>
{
friend inline constexpr auto tag_fallback_invoke(
get_allocator_t) noexcept;

} get_allocator{};

constexpr auto tag_fallback_invoke(get_allocator_t) noexcept
{
return hpx::execution::experimental::read(get_allocator);
}
} // namespace hpx::execution::experimental
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) 2022 Hartmut Kaiser
//
// SPDX-License-Identifier: BSL-1.0
// 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)

#pragma once

#include <hpx/config.hpp>
#include <hpx/execution_base/get_env.hpp>
#include <hpx/execution_base/read.hpp>
#include <hpx/functional/detail/tag_fallback_invoke.hpp>

namespace hpx::execution::experimental {

// 1. execution::get_delegatee_scheduler is used to ask an object for a
// scheduler that may be used to delegate work to for the purpose of
// forward progress delegation.
//
// 2. The name execution::get_scheduler denotes a customization point
// object.
// For some subexpression r, if the type of r is (possibly cv-qualified)
// no_env, then execution::get_delegatee_scheduler(r) is ill-formed.
// Otherwise, it is expression equivalent to:
//
// 1. tag_invoke(execution::get_delegatee_scheduler, as_const(r)), if
// this expression is well formed.
// Mandates: The tag_invoke expression above is not potentially-
// throwing and its type satisfies execution::scheduler.
//
// 2. Otherwise, execution::get_delegatee_scheduler(r) is ill-formed.
//
// 3. execution::get_delegatee_scheduler() (with no arguments) is expression-
// equivalent to execution::read(execution::get_delegatee_scheduler).
//
inline constexpr struct get_delegatee_scheduler_t final
: hpx::functional::detail::tag_fallback<get_delegatee_scheduler_t>
{
friend inline constexpr auto tag_fallback_invoke(
get_delegatee_scheduler_t) noexcept;

} get_delegatee_scheduler{};

constexpr auto tag_fallback_invoke(get_delegatee_scheduler_t) noexcept
{
return hpx::execution::experimental::read(get_delegatee_scheduler);
}
} // namespace hpx::execution::experimental
180 changes: 180 additions & 0 deletions libs/core/execution_base/include/hpx/execution_base/get_env.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// Copyright (c) 2022 Hartmut Kaiser
//
// SPDX-License-Identifier: BSL-1.0
// 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)

#pragma once

#include <hpx/config.hpp>
#include <hpx/functional/detail/tag_fallback_invoke.hpp>
#include <hpx/type_support/hide_from_adl.hpp>
#include <hpx/type_support/unwrap_ref.hpp>

#include <type_traits>
#include <utility>

namespace hpx::execution::experimental {

// 1. An execution environment contains state associated with the
// completion of an asynchronous operation. Every receiver has an
// associated execution environment, accessible with the get_env
// receiver query. The state of an execution environment is accessed
// with customization point objects. An execution environment may
// respond to any number of these environment queries.
//
// 2. An environment query is a customization point object that accepts
// as its first argument an execution environment. For an environment
// query EQ and an object e of type no_env, the expression EQ(e) shall
// be ill-formed.
//
namespace exec_envs {

// no_env is a special environment used by the sender concept and by
// the get_completion_signatures customization point when the user
// has specified no environment argument.
//
// [Note: A user may choose to not specify an environment in order
// to see if a sender knows its completion signatures
// independent of any particular execution environment.
// -- end note]
struct no_env
{
template <typename Tag, typename Env>
friend void tag_invoke(Tag, Env,
std::enable_if_t<std::is_same_v<no_env, std::decay_t<Env>>,
int*> = nullptr) = delete;
};

struct empty_env
{
};

template <typename Tag, typename Value,
typename BaseEnvId = util::hide_from_adl<empty_env>>
struct env
{
using BaseEnv = util::hidden_from_adl_t<BaseEnvId>;

HPX_NO_UNIQUE_ADDRESS util::unwrap_reference_t<Value> value_;
HPX_NO_UNIQUE_ADDRESS BaseEnv base_env_{};

// Forward only the receiver queries
template <typename Tag2, typename... Args,
typename = std::enable_if_t<functional::is_tag_invocable_v<Tag2,
BaseEnv const&, Args...>>>
friend constexpr auto tag_invoke(
Tag2 tag, env const& self, Args&&... args) noexcept
-> functional::tag_invoke_result_t<Tag2, BaseEnv const&,
Args...>
{
return HPX_FORWARD(Tag2, tag)(
self.base_env_, HPX_FORWARD(Args, args)...);
}

template <typename... Args>
friend constexpr auto
tag_invoke(Tag, env const& self, Args&&...) noexcept(
std::is_nothrow_copy_constructible_v<
util::unwrap_reference_t<Value>>)
-> util::unwrap_reference_t<Value>
{
return self.value_;
}
};

template <typename Tag>
struct make_env_t
{
template <typename Value>
constexpr auto operator()(Value&& value) const
noexcept(std::is_nothrow_copy_constructible_v<
util::unwrap_reference_t<std::decay_t<Value>>>)
-> env<Tag, std::decay_t<Value>>
{
return {HPX_FORWARD(Value, value)};
}

template <typename Value, typename BaseEnv>
constexpr auto operator()(Value&& value, BaseEnv&& base_env) const
-> env<Tag, std::decay_t<Value>,
util::hide_from_adl<std::decay_t<BaseEnv>>>
{
return {
HPX_FORWARD(Value, value), HPX_FORWARD(BaseEnv, base_env)};
}
};

// For making an evaluation environment from a key/value pair, and
// optionally another environment.
template <typename Tag>
inline constexpr exec_envs::make_env_t<Tag> make_env{};

} // namespace exec_envs

using exec_envs::empty_env;
using exec_envs::env;
using exec_envs::make_env;
using exec_envs::no_env;

template <typename Env>
struct is_no_env : std::is_same<std::decay_t<Env>, no_env>
{
};

template <typename Env>
inline constexpr bool is_no_env_v = is_no_env<Env>::value;

// get_env is a customization point object. For some subexpression r,
// get_env(r) is expression-equivalent to:
//
// 1. tag_invoke(execution::get_env, r) if that expression is well-formed.
// 2. Otherwise, empty_env{}.
//
inline constexpr struct get_env_t final
: hpx::functional::detail::tag_fallback<get_env_t>
{
template <typename EnvProvider>
friend constexpr HPX_FORCEINLINE auto tag_fallback_invoke(
get_env_t, EnvProvider&&) noexcept
{
return empty_env{};
}
} get_env{};

template <typename T>
using env_of_t = decltype(get_env(std::declval<T>()));

template <typename Tag, typename Value, typename BaseEnv = empty_env>
using make_env_t =
decltype(make_env<Tag>(std::declval<Value>(), std::declval<BaseEnv>()));

// execution::forwarding_env_query is used to ask a customization point
// object whether it is an environment query that should be forwarded
// through environment adaptors.
//
// The name execution::forwarding_env_query denotes a customization point
// object. For some subexpression t, execution::forwarding_env_query(t)
// is expression equivalent to:
//
// 1. tag_invoke(execution::forwarding_env_query, t), contextually
// converted to bool, if the tag_invoke expression is well formed.
// Mandates: The tag_invoke expression is indeed contextually
// convertible to bool, that expression and the contextual conversion
// are not potentially-throwing and are core constant expressions if t
// is a core constant expression.
// 2. Otherwise, false.
//
inline constexpr struct forwarding_env_query_t final
: hpx::functional::detail::tag_fallback<forwarding_env_query_t>
{
template <typename T>
friend constexpr HPX_FORCEINLINE auto tag_fallback_invoke(
forwarding_env_query_t, T&&) noexcept
{
return true;
}

} forwarding_env_query{};

} // namespace hpx::execution::experimental
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) 2022 Hartmut Kaiser
//
// SPDX-License-Identifier: BSL-1.0
// 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)

#pragma once

#include <hpx/config.hpp>
#include <hpx/execution_base/get_env.hpp>
#include <hpx/execution_base/read.hpp>
#include <hpx/functional/detail/tag_fallback_invoke.hpp>

namespace hpx::execution::experimental {

// 1. execution::get_scheduler is used to ask an object for its associated
// scheduler.
//
// 2. The name execution::get_scheduler denotes a customization point object.
// For some subexpression r, if the type of r is (possibly cv-qualified)
// no_env, then execution::get_scheduler(r) is ill-formed.
//
// Otherwise, it is expression equivalent to:
//
// 1. tag_invoke(execution::get_scheduler, as_const(r)), if this expression
// is well formed.
//
// Mandates: The tag_invoke expression above is not potentially-
// throwing and its type satisfies execution::scheduler.
//
// 2. Otherwise, execution::get_scheduler(r) is ill-formed.
//
// 3. execution::get_scheduler() (with no arguments) is expression-equivalent
// to execution::read(execution::get_scheduler).
//
inline constexpr struct get_scheduler_t final
: hpx::functional::detail::tag_fallback<get_scheduler_t>
{
friend inline constexpr auto tag_fallback_invoke(
get_scheduler_t) noexcept;

} get_scheduler{};

constexpr auto tag_fallback_invoke(get_scheduler_t) noexcept
{
return hpx::execution::experimental::read(get_scheduler);
}
} // namespace hpx::execution::experimental
Loading

0 comments on commit 3423b5d

Please sign in to comment.