From f927694fe168a805eecee8c83407e4aa3d3b5b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 25 Jan 2026 22:15:41 +0000 Subject: [PATCH 01/12] add a paper on task allocation --- docs/Makefile | 2 +- docs/P3941-affinity.md | 2 +- docs/P3980-allocation.md | 464 +++++++++++++++++++++++++++++++++++ docs/task-issues.md | 28 +++ examples/issue-affine_on.cpp | 2 - 5 files changed, 494 insertions(+), 4 deletions(-) create mode 100644 docs/P3980-allocation.md create mode 100644 docs/task-issues.md diff --git a/docs/Makefile b/docs/Makefile index 9594236..36b9db4 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -4,7 +4,7 @@ default: doc doc: doc-html -doc-html: P3552-task.html P3796-task-issues.html P3941-affinity.html +doc-html: P3552-task.html P3796-task-issues.html P3941-affinity.html P3980-allocation.html doc-pdf: P3552-task.pdf P3796-task-issues.pdf diff --git a/docs/P3941-affinity.md b/docs/P3941-affinity.md index d697289..c012a78 100644 --- a/docs/P3941-affinity.md +++ b/docs/P3941-affinity.md @@ -10,7 +10,7 @@ author: - name: Dietmar Kühl (Bloomberg) email: source: - - https://github.com/bemanproject/task/doc/issues.md + - https://github.com/bemanproject/task/doc/P3941-affinity.md toc: true --- diff --git a/docs/P3980-allocation.md b/docs/P3980-allocation.md new file mode 100644 index 0000000..b0b21cf --- /dev/null +++ b/docs/P3980-allocation.md @@ -0,0 +1,464 @@ +--- +title: Task's Allocator Use +document: D3980R0 +date: 2026-01-25 +audience: + - Library Evolution Working Group (LEWG) + - Library Working Group (LWG) +author: + - name: Dietmar Kühl (Bloomberg) + email: +source: + - https://github.com/bemanproject/task/doc/P3980-allocation.md +toc: true +--- + +

+There are different uses of allocators for `task`. The obvious use +is that the coroutine frame needs to be allocated and using an +allocator control where this coroutine frame gets allocated. In +addition, the environment used when `connect`ing a sender can provide +access to an allocator via the `get_allocator` query. The current +specification uses the same allocator for coroutine frame and the +child environments. At the Kona meeting the room preferred if these +were separated and the allocator for the environment were taken +from the environment of the receiver it gets `connect`ed to. In +doing so, the allocator for the coroutine frame becomes more flexible +and it should be brought more in line with `generator`'s allocator +use. This paper addresses +[US 254-385](https://github.com/cplusplus/nbballot/issues/960), +[US 253-386](https://github.com/cplusplus/nbballot/issues/961), +[US 255-384](https://github.com/cplusplus/nbballot/issues/959), +and [US 261-391](https://github.com/cplusplus/nbballot/issues/966). +

+ +# Change History + +## R0 Initial Revision + +# Overview of Changes + +

+There are a few NB comments about `task`'s use of allocators: +

+
    +
  • [US 254-385](https://github.com/cplusplus/nbballot/issues/960): Constraint `allocator_arg` argument to be the first argument
  • +
  • [US 253-386](https://github.com/cplusplus/nbballot/issues/961): Allow use of arbitrary allocators for coroutine frame
  • +
  • [US 255-384](https://github.com/cplusplus/nbballot/issues/959): Use allocator from receiver's environment
  • +
  • [US 261-391](https://github.com/cplusplus/nbballot/issues/966): Bad specification of parameter type
  • +
+

+The first issue +([US 254-385](https://github.com/cplusplus/nbballot/issues/960)) is +about where an allocator argument for the coroutine frame may go +on the coroutine function. The options are a fixed location (which +would first for consistency with existing use) and anywhere. The +status quo is anywhere and the request is to require that it goes +first. However, to support optionally passing an allocator having +it go anywhere is easier to do. +

+

+The allocator constraints for allocating the coroutine frame are +due to the use of the same allocator for the environment of child +senders. If the allocator for the environment of child senders uses +the allocator from the receiver's environment, these constraints +can be relaxed. Instead, there may be requirements on the result +of the `get_allocator` query from the receiver's environment. The +discussion in Kona favored this direction. This change can address +the second ([US 253-386](https://github.com/cplusplus/nbballot/issues/961)) +and the third +([US 255-384](https://github.com/cplusplus/nbballot/issues/959)) issues. +

+

+The forth issue ([US +261-391](https://github.com/cplusplus/nbballot/issues/966)) is +primarily a wording issue. However, some of the problematic paragraphs +will need some modifications to address the other issues, i.e., fixing +these wording issues in isolation isn't reasonable. +

+ +# Allocator Argument Position + +

+The combination of using `allocator_arg` followed by an allocator +object when invoking a function or a constructor is used in various +places throughout the standard C++ library. The `allocator_arg` +argument normally needs to be the first argument when present. The +definition of `task` makes the position of the `allocator_arg` more +flexible to allow easier support for optionally passing an allocator. +

+

+For coroutines, the arguments to the coroutine [factory] function +show up in three separate places: +

+
    +
  1. The parameters to the coroutine [factory] functions.
  2. +
  3. The constructor of the `promise_type` if there is a suitable matching overload.
  4. +
  5. the `operator new()` of the `promise_type` if there is a suitable matching overload.
  6. +
+

+This added flexibility doesn't introduce any constraints on how the coroutine +function is defined. It rather allows passing an `allocator_arg`/allocator +pair without requiring a specific location. The main benefit is that support +of an optional allocator can be supported by having a trailing `, auto&&...` +on the parameter list. Note that the allocator used for the coroutine frame +is normally not used in the body of the allocator. If it is needed, it can +in all cases be put into the first location. +

+::: cmptable + +### First +``` +task<> none(int x) +{ ... } +``` + +### Flexible +``` +task<> none(int x) +{ ... } +``` + +--- + +``` +task<> comes_first(allocator_arg_t, auto a, int x) +{ ... } +``` + +``` +task<> comes_first(allocator_arg_t, auto a, int x) +{ ... } +``` + +--- + +``` +task<> optional(allocator_arg_t, auto, int x) +{ ... } +task<> optional(int x) +{ return optional(allocator_arg, allocator(), x); } +``` + +``` +task<> optional(int x, auto&&...) +{ ... } +``` + +::: + +

+The comparison table above shows three separate cases the author of +a coroutine function may want to support: +

+
    +
  1. No allocator support (`none`): the use identical and just doesn't mention any allocator.
  2. +
  3. Mandate that the allocator is the first argument (`comes_first`): the use is identical.
  4. +
  5. + Support optionally passing an `allocator_arg`/allocator pair + (`optional`): the use can be identical but it can also be simplied + taking advantage of the flexible location. +
  6. +
+ +Below are three variations of the wording changes, only one can be picked: + +
    +
  1. Only support `allocator_arg` as the first argument and use the receiver's allocator for the environment.
  2. +
  3. Flexible position of the allocator arg and use allocator for the environment.
  4. +
  5. Flexible position of the allocator arg and use the receiver's allocator for the environment.
  6. +
+ +## Wording Change A: `allocator_arg` must be first argument + +::: ednote +Change the synopsis of `promise` type in [task.promise], modifying +the overloads of `operator new`: +::: + +``` +namespace std::execution { + template + class task::promise_type { + public: + ... + unspecified get_env() const noexcept; + + @[void*]{.add}@ @[operator]{.add}@ @[new(size_t]{.add}@ @[size);]{.add}@ + template<@[class Alloc,]{.add}@ class... Args> + void* operator new(size_t size, @[allocator_arg_t,]{.add}@ @[Alloc]{.add}@ @[alloc, ]{.add}@Args&&... @[args]{.rm}@); + + void operator delete(void* pointer, size_t size) noexcept; + + private: + ... + }; +} +``` + +::: ednote +Change [task.promise] paragraphs 17 and 18: +::: + +::: add + +``` +void* operator new(size_t size); +``` + +[??]{.pnum} _Returns_: `operator new(size, allocator_arg, allocator());` + +::: + +``` +template<@[class Alloc,]{.add}@ class... Args> + void* operator new(size_t size, @[allocator_arg_t,]{.add}@ @[Alloc]{.add}@ @[alloc, ]{.add}@Args&&... @[args]{.rm}@); +``` + +[17]{.pnum} [If there is no parameter with type `allocator_arg_t` +then let `alloc` be `allocator_type()`. Otherwise, let `arg_next` +be the parameter following the first `allocator_arg_t` parameter, +and let `alloc` be `allocator_type(arg_next)`]{.rm}. Let `PAlloc` +be `allocator_traits<@[allocator_type]{.rm}@@[Alloc]{.add}@>::template +rebind_alloc`, where `U` is an unspecified type whose size and +alignment are both `__STDCPP_DEFAULT_NEW_ALIGNMENT__`. + +::: rm + +[18]{.pnum} +_Mandates_: + +
    +
  • [18.1]{.pnum} The first parameter of type `allocator_arg_t` (if any) is not the last parameter.
  • +
  • [18.2]{.pnum} `allocator_type(arg_next)` is a valid expression if there is a parameter of type `allocator_arg_t`.
  • +
  • [18.3]{.pnum} `allocator_traits​::​pointer` is a pointer type.
  • +
+ +::: + +::: add + +[18]{.pnum} +_Mandates_: `allocator_traits​::​pointer` is a pointer type. + +::: + +[19]{.pnum} _Effects_: Initializes an allocator `palloc` of type +`PAlloc` with `alloc`. Uses `palloc` to allocate storage for the +smallest array of `U` sufficient to provide storage for a coroutine +state of size `size`, and unspecified additional state necessary to +ensure that `operator delete` can later deallocate this memory block +with an allocator equal to `palloc`. + +[20]{.pnum} _Returns_: A pointer to the allocated storage. + +## Wording Change B: Fix type names, allow flexible position, use for env + +::: ednote + +Change [task.promise] pargraph 17 and 18 to use the correct type: + +::: + +``` +template + void* operator new(size_t size, Args&&... args); +``` + +[17]{.pnum} If there is no parameter with type `@[allocator_arg_t]{.rm}@@[const]{.add}@ @[allocator_arg_t&]{.add}@` +then let `alloc` be `allocator_type()`. Otherwise, let `arg_next` +be the parameter following the first `@[allocator_arg_t]{.rm}@@[const]{.add}@ @[allocator_arg_t&]{.add}@` parameter, +and let `alloc` be `allocator_type(arg_next)`. Let `PAlloc` +be `allocator_traits::template +rebind_alloc`, where `U` is an unspecified type whose size and +alignment are both `__STDCPP_DEFAULT_NEW_ALIGNMENT__`. + +[18]{.pnum} +_Mandates_: + +
    +
  • [18.1]{.pnum} The first parameter of type `@[allocator_arg_t]{.rm}@@[const]{.add}@ @[allocator_arg_t&]{.add}@` (if any) is not the last parameter.
  • +
  • [18.2]{.pnum} `allocator_type(arg_next)` is a valid expression if there is a parameter of type `allocator_arg_t`.
  • +
  • [18.3]{.pnum} `allocator_traits​::​pointer` is a pointer type.
  • +
+ +[19]{.pnum} _Effects_: Initializes an allocator `palloc` of type +`PAlloc` with `alloc`. Uses `palloc` to allocate storage for the +smallest array of `U` sufficient to provide storage for a coroutine +state of size `size`, and unspecified additional state necessary to +ensure that `operator delete` can later deallocate this memory block +with an allocator equal to `palloc`. + +[20]{.pnum} _Returns_: A pointer to the allocated storage. + +## Wording Change C: Fix type names, allow flexible position, don't use for env + +::: ednote + +Change [task.promise] pargraph 17 and 18 to use the correct type and don't convert to `allocator_type`: + +::: + +``` +template + void* operator new(size_t size, Args&&... args); +``` + +[17]{.pnum} If there is no parameter with type `@[allocator_arg_t]{.rm}@@[const]{.add}@ @[allocator_arg_t&]{.add}@` +then let `alloc` be `@[allocator_type()]{.rm}@@[allocator()]{.add}@`. Otherwise, let `@[arg_next]{.rm}@@[alloc]{.add}@` +be the parameter following the first `@[allocator_arg_t]{.rm}@@[const]{.add}@ @[allocator_arg_t&]{.add}@` +parameter[, and let `alloc` be `allocator_type(arg_next)`]{.rm}. Let `PAlloc` +be `allocator_traits<@[allocator_type]{.rm}@@[remove_cvref_t]{.add}@>::template rebind_alloc`, where `U` is an unspecified type whose size and +alignment are both `__STDCPP_DEFAULT_NEW_ALIGNMENT__`. + +[18]{.pnum} +_Mandates_: + +
    +
  • [18.1]{.pnum} The first parameter of type `@[allocator_arg_t]{.rm}@@[const]{.add}@ @[allocator_arg_t&]{.add}@` (if any) is not the last parameter.
  • + +
  • +::: rm +[18.2]{.pnum} `allocator_type(arg_next)` is a valid expression if there is a parameter of type `allocator_arg_t`. +::: +
  • + +
  • [18.3]{.pnum} `allocator_traits​::​pointer` is a pointer type.
  • +
+ +[19]{.pnum} _Effects_: Initializes an allocator `palloc` of type +`PAlloc` with `alloc`. Uses `palloc` to allocate storage for the +smallest array of `U` sufficient to provide storage for a coroutine +state of size `size`, and unspecified additional state necessary to +ensure that `operator delete` can later deallocate this memory block +with an allocator equal to `palloc`. + +[20]{.pnum} _Returns_: A pointer to the allocated storage. + +# Use Allocator From Environment + +

+During the discussion at Kona the conclusion was that the allocator +forwarded by `task`'s environment to child senders should be the +allocator from `get_allocator` on the receiver `task` gets `connect`ed +to. Let `rcvr` be the receiver a `task` got `connect`ed to and let `ev` +be the result of `get_env(rcvr)`. The implication is that the `task`'s +`allocator_type` is compatible with the allocator of `ev`: +

+
    +
  • + If `get_allocator(ev)` is not defined, `allocator_type` has to + be default constructible. +
  • +
  • + Otherwise `allocator_type(get_allocator(ev))` has to be well-formed. +
  • +
  • + There is no need to store an alloc in the + `promise_type`: it can be obtained when requested from `ev` which, + in turn, can be obtained from `rcvr`. Thus, the ctor for `promise_type` + isn't needed. +
  • +
  • + The definition of `get_env` needs to be changed to get the allocator + when needed. +
  • +
+ +## Wording Changes + +::: ednote + +In [[task.members](https://wg21.link/task.members#3)] add a _Mandates_ to `connect`: + +::: + +``` +template + state connect(Rcvr&& recv) &&; +``` + +::: add + +[?]{.pnum} _Mandates_: `allocator_type(get_allocator(get_env(rcvr)))` is well-formed or `allocator_type()` is well-formed. + +::: + +[3]{.pnum} _Preconditions_: bool(handle) is `true`. + +[4]{.pnum} _Effects_: Equivalent to: +``` +return state(exchange(handle, {}), std::forward(recv)); +``` + +::: ednote + +In [[task.promise]](https://wg21.link/task.promise) in the synopsis remove the `promise_type` constructor and +the alloc exposition-only member. + +::: + +``` +namespace std::execution { + template + class task::promise_type { + public: + @[template]{.rm}@ + @[promise_type(const]{.rm}@ @[Args&...]{.rm}@ @[args);]{.rm}@ + + task get_return_object() noexcept; + + ... + private: + using error-variant = see below; // @_exposition only_@ + + @[allocator_type]{.rm}@ @[_alloc_;]{.rm}@ @[//]{.rm}@ @[_exposition_]{.rm}@ @[_only_]{.rm}@ + stop_source_type @_source_@; // @_exposition only_@ + stop_token_type @_token_@; // @_exposition only_@ + optional @_result_@; // @_exposition only_@; present only if is_void_v is false + error-variant @_errors_@; // @_exposition only_@ + }; +} +``` + +::: ednote + +Remove the ctor for `promise_type`, i.e., [[task.promise]](https://wg21.link/task.promise) paragraph [3](https://wg21.link/task.promise#3) and [4](https://wg21.link/task.promise#4): + +::: + +::: rm + +``` +template + promise_type(const Args&... args); +``` + +[3]{.pnum} _Mandates_: The first parameter of type `allocator_arg_t` +(if any) is not the last parameter. + +[4]{.pnum} _Effects_: If `Args` contains an element of type +`allocator_arg_t` then alloc is initialized +with the corresponding next element of `args`. Otherwise, +alloc is initialized with `allocator_type()`. + +::: + +::: ednote + +Change `get_env` to get the allocator from the receiver when needed +in [[task.promise] p16](https://wg21.link/task.pomise#16): + +::: + +``` +@_unspecified_@ get_env() const noexcept; +``` + +[16]{.pnum} _Returns_: An object `env` such that queries are forwarded as follows: +
    +
  • [16.1]{.pnum} `env.query(get_scheduler)` returns scheduler_type(SCHED(*this)).
  • +
  • [16.2]{.pnum} `env.query(get_allocator)` returns [alloc]{.rm}[allocator_type(get_allocator(get_env(RCVR(*this)))) if this expression is well-formed and `allocator_type()` otherwise]{.add}.
  • +
  • [16.3]{.pnum} `env.query(get_stop_token)` returns token.
  • +
  • [16.4]{.pnum} For any other query `q` and arguments `a...` a call to `env.query(q, a...)` returns STATE(*this).environment.query(q, a...) if this expression is well-formed and `forwarding_query(q)` is well-formed and is `true`. Otherwise `env.query(q, a...)` is ill-formed.
  • +
diff --git a/docs/task-issues.md b/docs/task-issues.md new file mode 100644 index 0000000..e67d6da --- /dev/null +++ b/docs/task-issues.md @@ -0,0 +1,28 @@ +# C++ task related issues + +NB Comment | LWG Issue | State | Section | Title +-----------|-----------|-------|---------|------ +[US 232-366](https://github.com/cplusplus/nbballot/issues/941) | [LWG4329](https://cplusplus.github.io/LWG/issue4329) [P3941](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3941r1.html) | open/SG1 | [33.13.3](https://wg21.link/exec.affine.on) | Specify customizations for `affine_on` when sender does not change scheduler +[US 233-365](https://github.com/cplusplus/nbballot/issues/940) | [LWG4330](https://cplusplus.github.io/LWG/issue4330) [P3941](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3941r1.html) | open/SG1 | [33.13.3](https://wg21.link/exec.affine.on) | Clarify `affine_on` vs. `continues_on` +[US 234-364](https://github.com/cplusplus/nbballot/issues/939) | [LWG4331](https://cplusplus.github.io/LWG/issue4331) [P3941](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3941r1.html) | open/LEWG | [33.13.3](https://wg21.link/exec.affine.on) | Remove scheduler parameter from `affine_on` +[US 235-363](https://github.com/cplusplus/nbballot/issues/938) | [LWG4332](https://cplusplus.github.io/LWG/issue4332) [P3941](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3941r1.html) | open/SG1 | [33.13.3](https://wg21.link/exec.affine.on) | `affine_on` should not forward the stop token to the scheduling operation +[US 236-362](https://github.com/cplusplus/nbballot/issues/937) | [LWG4344](https://cplusplus.github.io/LWG/issue4344) [P3941](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3941r1.html) | open/SG1 | [33.13.3](https://wg21.link/exec.affine.on) | Specify default implementation of `affine_on` +[US 237-369](https://github.com/cplusplus/nbballot/issues/944) | [LWG4342](https://cplusplus.github.io/LWG/issue4342) | closed | [33.13.5](https://wg21.link/exec.task.scheduler) | Add rvalue reference qualification to task_scheduler::ts-sender::connect +[US 238-368](https://github.com/cplusplus/nbballot/issues/943) | [LWG4336](https://cplusplus.github.io/LWG/issue4336) [P3927](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3927r0.html) | open/LEWG | [33.13.5](https://wg21.link/exec.task.scheduler) | Allow customizations when using `task_scheduler` +[US 239-367](https://github.com/cplusplus/nbballot/issues/942) | | closed | [33.13.5](https://wg21.link/exec.task.scheduler) | sch_ must not be in moved-from state +[US 242-372](https://github.com/cplusplus/nbballot/issues/947) | [LWG4339](https://cplusplus.github.io/LWG/issue4339) | open/LWG | [33.13.6](https://wg21.link/exec.task) | Timing of destruction of coroutine frame +[US 243-376](https://github.com/cplusplus/nbballot/issues/951) | | closed | [33.13.6.2](https://wg21.link/task.class) | Add default template arguments for `task` +[US 244-375](https://github.com/cplusplus/nbballot/issues/950) | [LWG4341](https://cplusplus.github.io/LWG/issue4341) | closed | [33.13.6.2](https://wg21.link/task.class) | Add rvalue reference qualifier for `task::connect()` +[US 245-374](https://github.com/cplusplus/nbballot/issues/949) | [LWG4338](https://cplusplus.github.io/LWG/issue4338) | rejected | [33.13.6.2](https://wg21.link/task.class) | Add `operator co_await` +[US 246-373](https://github.com/cplusplus/nbballot/issues/948) | [LWG4348](https://cplusplus.github.io/LWG/issue4348) | ⚠️open/SG1 | [33.13.6.2](https://wg21.link/task.class) | Support symmetric transfer +[US 249-379](https://github.com/cplusplus/nbballot/issues/954) | | ⚠️open/LWG | [33.13.6.4p4](https://wg21.link/task.state#4) | Move specification for `stop_token_type` +[US 250-389](https://github.com/cplusplus/nbballot/issues/964) | [LWG4346](https://cplusplus.github.io/LWG/issue4346) | closed | [33.13.6.5](https://wg21.link/task.promise) | Add specification for `return_void` and `return_value` +[US 251-388](https://github.com/cplusplus/nbballot/issues/963) | [LWG4345](https://cplusplus.github.io/LWG/issue4345) | closed | [33.13.6.5](https://wg21.link/task.promise) | Add default template argument for `return_value` +[US 252-387](https://github.com/cplusplus/nbballot/issues/962) | [LWG4340](https://cplusplus.github.io/LWG/issue4340) | closed | [33.13.6.5](https://wg21.link/task.promise) | `task::promise_type::unhandled_stopped()` should be `noexcept` +[US 253-386](https://github.com/cplusplus/nbballot/issues/961) | [LWG4333](https://cplusplus.github.io/LWG/issue4333) | ⚠️open/LEWG | [33.13.6.5](https://wg21.link/task.promise) | Allow use of arbitrary allocators for coroutine frame +[US 254-385](https://github.com/cplusplus/nbballot/issues/960) | [LWG4334](https://cplusplus.github.io/LWG/issue4334) | ⚠️open/LEWG | [33.13.6.5](https://wg21.link/task.promise) | Constraint `allocator_arg` argument to be the first argument +[US 255-384](https://github.com/cplusplus/nbballot/issues/959) | [LWG4335](https://cplusplus.github.io/LWG/issue4335) | ⚠️open/LEWG | [33.13.6.5](https://wg21.link/task.promise) | Use allocator from receiver's environment +[US 256-383](https://github.com/cplusplus/nbballot/issues/958) | [LWG4337](https://cplusplus.github.io/LWG/issue4337) | rejected | [33.13.6.5](https://wg21.link/task.promise) | Scheduler need not be assignable +[US 257-382](https://github.com/cplusplus/nbballot/issues/957) | [LWG4347](https://cplusplus.github.io/LWG/issue4347) | ⚠️open/LWG | [33.13.6.5](https://wg21.link/task.promise) | Respecify source and token members +[US 258-381](https://github.com/cplusplus/nbballot/issues/956) | [LWG4349](https://cplusplus.github.io/LWG/issue4349) | closed | [33.13.6.5](https://wg21.link/task.promise) | Clarify `task` is not eagerly started +[US 261-391](https://github.com/cplusplus/nbballot/issues/966) | | ⚠️open/LEWG | [33.13.6.5](https://wg21.link/task.promise) [p3](https://wg21.link/task.promise#3), [p16](https://wg21.link/task.promise#16), [p17](https://wg21.link/task.promise#17) | Bad specification of parameter type diff --git a/examples/issue-affine_on.cpp b/examples/issue-affine_on.cpp index 2b9b709..45fbd9f 100644 --- a/examples/issue-affine_on.cpp +++ b/examples/issue-affine_on.cpp @@ -15,10 +15,8 @@ ex::task<> test(Sender&& sender) { int main() { ex::sync_wait(test(ex::just())); ex::sync_wait(test(ex::read_env(ex::get_scheduler))); -#if 0 ex::sync_wait(test(ex::read_env(ex::get_scheduler) | ex::let_value([](auto sched) noexcept { return ex::just(); }))); ex::sync_wait(test(ex::read_env(ex::get_scheduler) | ex::let_value([](auto sched) { return ex::starts_on(sched, ex::just()); }))); -#endif } From a87856f11ed01f4341f4a70ac70555dc78044e60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 26 Jan 2026 20:58:31 +0000 Subject: [PATCH 02/12] updated the overview --- docs/task-issues.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/task-issues.md b/docs/task-issues.md index e67d6da..4bd3b74 100644 --- a/docs/task-issues.md +++ b/docs/task-issues.md @@ -19,10 +19,10 @@ NB Comment | LWG Issue | State | Section | Title [US 250-389](https://github.com/cplusplus/nbballot/issues/964) | [LWG4346](https://cplusplus.github.io/LWG/issue4346) | closed | [33.13.6.5](https://wg21.link/task.promise) | Add specification for `return_void` and `return_value` [US 251-388](https://github.com/cplusplus/nbballot/issues/963) | [LWG4345](https://cplusplus.github.io/LWG/issue4345) | closed | [33.13.6.5](https://wg21.link/task.promise) | Add default template argument for `return_value` [US 252-387](https://github.com/cplusplus/nbballot/issues/962) | [LWG4340](https://cplusplus.github.io/LWG/issue4340) | closed | [33.13.6.5](https://wg21.link/task.promise) | `task::promise_type::unhandled_stopped()` should be `noexcept` -[US 253-386](https://github.com/cplusplus/nbballot/issues/961) | [LWG4333](https://cplusplus.github.io/LWG/issue4333) | ⚠️open/LEWG | [33.13.6.5](https://wg21.link/task.promise) | Allow use of arbitrary allocators for coroutine frame -[US 254-385](https://github.com/cplusplus/nbballot/issues/960) | [LWG4334](https://cplusplus.github.io/LWG/issue4334) | ⚠️open/LEWG | [33.13.6.5](https://wg21.link/task.promise) | Constraint `allocator_arg` argument to be the first argument -[US 255-384](https://github.com/cplusplus/nbballot/issues/959) | [LWG4335](https://cplusplus.github.io/LWG/issue4335) | ⚠️open/LEWG | [33.13.6.5](https://wg21.link/task.promise) | Use allocator from receiver's environment +[US 253-386](https://github.com/cplusplus/nbballot/issues/961) | [LWG4333](https://cplusplus.github.io/LWG/issue4333) [D3980](https://isocpp.org/files/papers/D3980R0.html) | ✓open/LEWG | [33.13.6.5](https://wg21.link/task.promise) | Allow use of arbitrary allocators for coroutine frame +[US 254-385](https://github.com/cplusplus/nbballot/issues/960) | [LWG4334](https://cplusplus.github.io/LWG/issue4334) [D3980](https://isocpp.org/files/papers/D3980R0.html) | ✓open/LEWG | [33.13.6.5](https://wg21.link/task.promise) | Constraint `allocator_arg` argument to be the first argument +[US 255-384](https://github.com/cplusplus/nbballot/issues/959) | [LWG4335](https://cplusplus.github.io/LWG/issue4335) [D3980](https://isocpp.org/files/papers/D3980R0.html) | ✓open/LEWG | [33.13.6.5](https://wg21.link/task.promise) | Use allocator from receiver's environment [US 256-383](https://github.com/cplusplus/nbballot/issues/958) | [LWG4337](https://cplusplus.github.io/LWG/issue4337) | rejected | [33.13.6.5](https://wg21.link/task.promise) | Scheduler need not be assignable [US 257-382](https://github.com/cplusplus/nbballot/issues/957) | [LWG4347](https://cplusplus.github.io/LWG/issue4347) | ⚠️open/LWG | [33.13.6.5](https://wg21.link/task.promise) | Respecify source and token members [US 258-381](https://github.com/cplusplus/nbballot/issues/956) | [LWG4349](https://cplusplus.github.io/LWG/issue4349) | closed | [33.13.6.5](https://wg21.link/task.promise) | Clarify `task` is not eagerly started -[US 261-391](https://github.com/cplusplus/nbballot/issues/966) | | ⚠️open/LEWG | [33.13.6.5](https://wg21.link/task.promise) [p3](https://wg21.link/task.promise#3), [p16](https://wg21.link/task.promise#16), [p17](https://wg21.link/task.promise#17) | Bad specification of parameter type +[US 261-391](https://github.com/cplusplus/nbballot/issues/966) | [D3980](https://isocpp.org/files/papers/D3980R0.html) | ✓open/LEWG | [33.13.6.5](https://wg21.link/task.promise) [p3](https://wg21.link/task.promise#3), [p16](https://wg21.link/task.promise#16), [p17](https://wg21.link/task.promise#17) | Bad specification of parameter type From daacb3749b9710ad5f1078af9fd8c157fdbbfe8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Wed, 18 Feb 2026 21:08:04 +0000 Subject: [PATCH 03/12] added the missing member operator new --- docs/P3980-allocation.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/P3980-allocation.md b/docs/P3980-allocation.md index b0b21cf..ada2abf 100644 --- a/docs/P3980-allocation.md +++ b/docs/P3980-allocation.md @@ -187,6 +187,8 @@ namespace std::execution { @[void*]{.add}@ @[operator]{.add}@ @[new(size_t]{.add}@ @[size);]{.add}@ template<@[class Alloc,]{.add}@ class... Args> void* operator new(size_t size, @[allocator_arg_t,]{.add}@ @[Alloc]{.add}@ @[alloc, ]{.add}@Args&&... @[args]{.rm}@); + @[template]{.add}@ + @[void*]{.add}@ @[operator]{.add}@ @[new(size_t]{.add}@ @[size,]{.add}@ @[const]{.add}@ @[This&,]{.add}@ @[allocator_arg_t,]{.add}@ @[Alloc]{.add}@ @[alloc,]{.add}@ @[Args&&...);]{.add}@ void operator delete(void* pointer, size_t size) noexcept; @@ -213,6 +215,8 @@ void* operator new(size_t size); ``` template<@[class Alloc,]{.add}@ class... Args> void* operator new(size_t size, @[allocator_arg_t,]{.add}@ @[Alloc]{.add}@ @[alloc, ]{.add}@Args&&... @[args]{.rm}@); +@[template]{.add}@ + @[void*]{.add}@ @[operator]{.add}@ @[new(size_t]{.add}@ @[size,]{.add}@ @[const]{.add}@ @[This&,]{.add}@ @[allocator_arg_t,]{.add}@ @[Alloc]{.add}@ @[alloc,]{.add}@ @[Args&&...);]{.add}@ ``` [17]{.pnum} [If there is no parameter with type `allocator_arg_t` From 1930e4d1b96109c7c26b9ea102d2bef83c6ebc20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 22 Feb 2026 19:14:42 +0000 Subject: [PATCH 04/12] fix date and typos --- docs/P3980-allocation.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/P3980-allocation.md b/docs/P3980-allocation.md index ada2abf..d518e4b 100644 --- a/docs/P3980-allocation.md +++ b/docs/P3980-allocation.md @@ -1,7 +1,7 @@ --- title: Task's Allocator Use document: D3980R0 -date: 2026-01-25 +date: 2026-02-22 audience: - Library Evolution Working Group (LEWG) - Library Working Group (LWG) @@ -52,9 +52,9 @@ The first issue ([US 254-385](https://github.com/cplusplus/nbballot/issues/960)) is about where an allocator argument for the coroutine frame may go on the coroutine function. The options are a fixed location (which -would first for consistency with existing use) and anywhere. The -status quo is anywhere and the request is to require that it goes -first. However, to support optionally passing an allocator having +would fit first for consistency with existing use) and anywhere. The +status quo is anywhere, and the request is to require that it goes +first. However, to support optionally passing an allocator, having it go anywhere is easier to do.

@@ -70,7 +70,7 @@ and the third ([US 255-384](https://github.com/cplusplus/nbballot/issues/959)) issues.

-The forth issue ([US +The fourth issue ([US 261-391](https://github.com/cplusplus/nbballot/issues/966)) is primarily a wording issue. However, some of the problematic paragraphs will need some modifications to address the other issues, i.e., fixing From dbdf2c0223ff4b66f4911b25daf366080e161c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 22 Feb 2026 20:12:26 +0000 Subject: [PATCH 05/12] fixed a few issues, brought date up to date, and add LEWG outcome --- docs/P3980-allocation.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/P3980-allocation.md b/docs/P3980-allocation.md index d518e4b..fbb3230 100644 --- a/docs/P3980-allocation.md +++ b/docs/P3980-allocation.md @@ -169,6 +169,9 @@ Below are three variations of the wording changes, only one can be picked:

  • Flexible position of the allocator arg and use the receiver's allocator for the environment.
  • +At the LEWG meeting on 2026-02-03 the first approach (putting the `allocator_arg` first, Wording Change A) +was preferred ([notes](https://wiki.isocpp.org/2026-02-03_LEWG_Telecon)). It was identified that the original wording change did not support member functions returning a `task` (the wording was fixed accordingly). + ## Wording Change A: `allocator_arg` must be first argument ::: ednote From 31c2b475d0e787eac5cae4bb7792be435128faac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Tue, 24 Feb 2026 00:27:51 +0000 Subject: [PATCH 06/12] fix some typos and update the execution reference --- CMakeLists.txt | 2 +- docs/P3980-allocation.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6034d8..23158af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ FetchContent_Declare( execution # SOURCE_DIR ${CMAKE_SOURCE_DIR}/../execution GIT_REPOSITORY https://github.com/bemanproject/execution - GIT_TAG 66295d5 + GIT_TAG 3650634 SYSTEM FIND_PACKAGE_ARGS 0.2.0 diff --git a/docs/P3980-allocation.md b/docs/P3980-allocation.md index fbb3230..199882e 100644 --- a/docs/P3980-allocation.md +++ b/docs/P3980-allocation.md @@ -156,7 +156,7 @@ a coroutine function may want to support:
  • Mandate that the allocator is the first argument (`comes_first`): the use is identical.
  • Support optionally passing an `allocator_arg`/allocator pair - (`optional`): the use can be identical but it can also be simplied + (`optional`): the use can be identical but it can also be simplifed taking advantage of the flexible location.
  • @@ -263,7 +263,7 @@ with an allocator equal to `palloc`. ::: ednote -Change [task.promise] pargraph 17 and 18 to use the correct type: +Change [task.promise] paragraph 17 and 18 to use the correct type: ::: @@ -302,7 +302,7 @@ with an allocator equal to `palloc`. ::: ednote -Change [task.promise] pargraph 17 and 18 to use the correct type and don't convert to `allocator_type`: +Change [task.promise] paragraph 17 and 18 to use the correct type and don't convert to `allocator_type`: ::: @@ -454,7 +454,7 @@ with the corresponding next element of `args`. Otherwise, ::: ednote Change `get_env` to get the allocator from the receiver when needed -in [[task.promise] p16](https://wg21.link/task.pomise#16): +in [[task.promise] p16](https://wg21.link/task.promise#16): ::: From ab16c4a9f613ce4dfd0074ff1f0dc3833314045a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Tue, 24 Feb 2026 01:17:58 +0000 Subject: [PATCH 07/12] fixing a few more CI issues --- docs/P3980-allocation.md | 4 ++-- docs/task-issues.md | 2 +- examples/issue-affine_on.cpp | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/P3980-allocation.md b/docs/P3980-allocation.md index 199882e..ee6279a 100644 --- a/docs/P3980-allocation.md +++ b/docs/P3980-allocation.md @@ -156,7 +156,7 @@ a coroutine function may want to support:
  • Mandate that the allocator is the first argument (`comes_first`): the use is identical.
  • Support optionally passing an `allocator_arg`/allocator pair - (`optional`): the use can be identical but it can also be simplifed + (`optional`): the use can be identical but it can also be simplified taking advantage of the flexible location.
  • @@ -361,7 +361,7 @@ be the result of `get_env(rcvr)`. The implication is that the `task`'s Otherwise `allocator_type(get_allocator(ev))` has to be well-formed.
  • - There is no need to store an alloc in the + There is no need to store an alloc in the `promise_type`: it can be obtained when requested from `ev` which, in turn, can be obtained from `rcvr`. Thus, the ctor for `promise_type` isn't needed. diff --git a/docs/task-issues.md b/docs/task-issues.md index 4bd3b74..9da8013 100644 --- a/docs/task-issues.md +++ b/docs/task-issues.md @@ -21,7 +21,7 @@ NB Comment | LWG Issue | State | Section | Title [US 252-387](https://github.com/cplusplus/nbballot/issues/962) | [LWG4340](https://cplusplus.github.io/LWG/issue4340) | closed | [33.13.6.5](https://wg21.link/task.promise) | `task::promise_type::unhandled_stopped()` should be `noexcept` [US 253-386](https://github.com/cplusplus/nbballot/issues/961) | [LWG4333](https://cplusplus.github.io/LWG/issue4333) [D3980](https://isocpp.org/files/papers/D3980R0.html) | ✓open/LEWG | [33.13.6.5](https://wg21.link/task.promise) | Allow use of arbitrary allocators for coroutine frame [US 254-385](https://github.com/cplusplus/nbballot/issues/960) | [LWG4334](https://cplusplus.github.io/LWG/issue4334) [D3980](https://isocpp.org/files/papers/D3980R0.html) | ✓open/LEWG | [33.13.6.5](https://wg21.link/task.promise) | Constraint `allocator_arg` argument to be the first argument -[US 255-384](https://github.com/cplusplus/nbballot/issues/959) | [LWG4335](https://cplusplus.github.io/LWG/issue4335) [D3980](https://isocpp.org/files/papers/D3980R0.html) | ✓open/LEWG | [33.13.6.5](https://wg21.link/task.promise) | Use allocator from receiver's environment +[US 255-384](https://github.com/cplusplus/nbballot/issues/959) | [LWG4335](https://cplusplus.github.io/LWG/issue4335) [D3980](https://isocpp.org/files/papers/D3980R0.html) | ✓open/LEWG | [33.13.6.5](https://wg21.link/task.promise) | Use allocator from receiver's environment [US 256-383](https://github.com/cplusplus/nbballot/issues/958) | [LWG4337](https://cplusplus.github.io/LWG/issue4337) | rejected | [33.13.6.5](https://wg21.link/task.promise) | Scheduler need not be assignable [US 257-382](https://github.com/cplusplus/nbballot/issues/957) | [LWG4347](https://cplusplus.github.io/LWG/issue4347) | ⚠️open/LWG | [33.13.6.5](https://wg21.link/task.promise) | Respecify source and token members [US 258-381](https://github.com/cplusplus/nbballot/issues/956) | [LWG4349](https://cplusplus.github.io/LWG/issue4349) | closed | [33.13.6.5](https://wg21.link/task.promise) | Clarify `task` is not eagerly started diff --git a/examples/issue-affine_on.cpp b/examples/issue-affine_on.cpp index 45fbd9f..b5894dd 100644 --- a/examples/issue-affine_on.cpp +++ b/examples/issue-affine_on.cpp @@ -15,8 +15,7 @@ ex::task<> test(Sender&& sender) { int main() { ex::sync_wait(test(ex::just())); ex::sync_wait(test(ex::read_env(ex::get_scheduler))); - ex::sync_wait(test(ex::read_env(ex::get_scheduler) | - ex::let_value([](auto sched) noexcept { return ex::just(); }))); + ex::sync_wait(test(ex::read_env(ex::get_scheduler) | ex::let_value([](auto) noexcept { return ex::just(); }))); ex::sync_wait(test(ex::read_env(ex::get_scheduler) | ex::let_value([](auto sched) { return ex::starts_on(sched, ex::just()); }))); } From 520072ed6e09db012927e949f5b2b9efedb8cbb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 23 Mar 2026 02:48:25 +0000 Subject: [PATCH 08/12] changed the code to take the allocator from the environment --- include/beman/task/detail/awaiter.hpp | 7 +++++++ include/beman/task/detail/promise_type.hpp | 6 +----- include/beman/task/detail/state.hpp | 7 +++++++ include/beman/task/detail/state_base.hpp | 4 ++++ tests/beman/task/promise_base.test.cpp | 3 +++ tests/beman/task/promise_type.test.cpp | 3 +++ tests/beman/task/state_base.test.cpp | 3 +++ 7 files changed, 28 insertions(+), 5 deletions(-) diff --git a/include/beman/task/detail/awaiter.hpp b/include/beman/task/detail/awaiter.hpp index 4eff758..1bf1edb 100644 --- a/include/beman/task/detail/awaiter.hpp +++ b/include/beman/task/detail/awaiter.hpp @@ -48,6 +48,7 @@ struct awaiter_op_t { template class awaiter : public ::beman::task::detail::state_base { public: + using allocator_type = typename ::beman::task::detail::state_base::allocator_type; using stop_token_type = typename ::beman::task::detail::state_base::stop_token_type; using scheduler_type = typename ::beman::task::detail::state_base::scheduler_type; @@ -87,6 +88,12 @@ class awaiter : public ::beman::task::detail::state_base { auto actual_complete() -> std::coroutine_handle<> { return this->no_completion_set() ? this->parent.promise().unhandled_stopped() : ::std::move(this->parent); } + auto do_get_allocator() -> allocator_type override { + if constexpr (requires{ ::beman::execution::get_allocator(::beman::execution::get_env(this->parent)); }) + return ::beman::execution::get_allocator(::beman::execution::get_env(this->parent)); + else + return allocator_type{}; + } auto do_get_scheduler() -> scheduler_type override { return *this->scheduler; } auto do_set_scheduler(scheduler_type other) -> scheduler_type override { return ::std::exchange(*this->scheduler, other); diff --git a/include/beman/task/detail/promise_type.hpp b/include/beman/task/detail/promise_type.hpp index 27467a9..0c2f60d 100644 --- a/include/beman/task/detail/promise_type.hpp +++ b/include/beman/task/detail/promise_type.hpp @@ -50,9 +50,6 @@ class promise_type using stop_source_type = ::beman::task::detail::stop_source_of_t; using stop_token_type = decltype(std::declval().get_token()); - template - promise_type(const A&... a) : allocator(::beman::task::detail::find_allocator(a...)) {} - constexpr auto initial_suspend() noexcept -> ::std::suspend_always { return {}; } constexpr auto final_suspend() noexcept -> ::beman::task::detail::final_awaiter { return {}; } @@ -106,7 +103,7 @@ class promise_type } auto get_scheduler() const noexcept -> scheduler_type { return this->get_state()->get_scheduler(); } - auto get_allocator() const noexcept -> allocator_type { return this->allocator; } + auto get_allocator() const noexcept -> allocator_type { return this->get_state()->get_allocator(); } auto get_stop_token() const noexcept -> stop_token_type { return this->get_state()->get_stop_token(); } auto get_environment() const noexcept -> const Environment& { assert(this); @@ -117,7 +114,6 @@ class promise_type private: using env_t = ::beman::task::detail::promise_env; - allocator_type allocator{}; ::std::optional scheduler{}; }; } // namespace beman::task::detail diff --git a/include/beman/task/detail/state.hpp b/include/beman/task/detail/state.hpp index 714a077..10ff50c 100644 --- a/include/beman/task/detail/state.hpp +++ b/include/beman/task/detail/state.hpp @@ -20,6 +20,7 @@ struct state : ::beman::task::detail::state_base, ::beman::task::detail::s using operation_state_concept = ::beman::execution::operation_state_t; using promise_type = ::beman::task::detail::promise_type; using scheduler_type = typename ::beman::task::detail::state_base::scheduler_type; + using allocator_type = typename ::beman::task::detail::state_base::allocator_type; using stop_source_type = ::beman::task::detail::stop_source_of_t; using stop_token_type = decltype(std::declval().get_token()); using stop_token_t = @@ -46,6 +47,12 @@ struct state : ::beman::task::detail::state_base, ::beman::task::detail::s this->result_complete(::std::move(this->receiver)); return std::noop_coroutine(); } + auto do_get_allocator() -> allocator_type override { + if constexpr (requires{ ::beman::execution::get_allocator(this->receiver); }) + return ::beman::execution::get_allocator(this->receiver); + else + return allocator_type{}; + } auto do_get_scheduler() -> scheduler_type override { return this->scheduler; } auto do_set_scheduler(scheduler_type other) -> scheduler_type override { return ::std::exchange(this->scheduler, other); diff --git a/include/beman/task/detail/state_base.hpp b/include/beman/task/detail/state_base.hpp index 53c7096..e9c4765 100644 --- a/include/beman/task/detail/state_base.hpp +++ b/include/beman/task/detail/state_base.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -18,11 +19,13 @@ class state_base : public ::beman::task::detail::result_type<::beman::task::deta Value, ::beman::task::detail::error_types_of_t> { public: + using allocator_type = ::beman::task::detail::allocator_of_t; using stop_source_type = ::beman::task::detail::stop_source_of_t; using stop_token_type = decltype(std::declval().get_token()); using scheduler_type = ::beman::task::detail::scheduler_of_t; auto complete() -> std::coroutine_handle<> { return this->do_complete(); } + auto get_allocator() -> allocator_type { return this->do_get_allocator(); } auto get_stop_token() -> stop_token_type { return this->do_get_stop_token(); } auto get_environment() -> Environment& { assert(this); @@ -43,6 +46,7 @@ class state_base : public ::beman::task::detail::result_type<::beman::task::deta // NOLINTBEGIN(portability-template-virtual-member-function) virtual auto do_complete() -> std::coroutine_handle<> = 0; + virtual auto do_get_allocator() -> allocator_type = 0; virtual auto do_get_stop_token() -> stop_token_type = 0; virtual auto do_get_environment() -> Environment& = 0; virtual auto do_get_scheduler() -> scheduler_type = 0; diff --git a/tests/beman/task/promise_base.test.cpp b/tests/beman/task/promise_base.test.cpp index 77a7535..1ac9b13 100644 --- a/tests/beman/task/promise_base.test.cpp +++ b/tests/beman/task/promise_base.test.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include #include #include #include @@ -48,6 +49,7 @@ struct env { template struct state : bt::state_base> { using Environment = env; + using allocator_type = ::beman::task::detail::allocator_of_t; using stop_source_type = ::beman::task::detail::stop_source_of_t; using stop_token_type = decltype(std::declval().get_token()); using scheduler_type = ::beman::task::detail::scheduler_of_t; @@ -62,6 +64,7 @@ struct state : bt::state_base> { this->completed = true; return std::noop_coroutine(); } + allocator_type do_get_allocator() override { return allocator_type{}; } stop_token_type do_get_stop_token() override { this->token = true; return this->source.get_token(); diff --git a/tests/beman/task/promise_type.test.cpp b/tests/beman/task/promise_type.test.cpp index a6c002b..76beaa3 100644 --- a/tests/beman/task/promise_type.test.cpp +++ b/tests/beman/task/promise_type.test.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include #include #include #include @@ -129,6 +130,7 @@ struct test_error : std::exception { struct test_task : beman::task::detail::state_base { using promise_type = beman::task::detail::promise_type; + using allocator_type = ::beman::task::detail::allocator_of_t; beman::task::detail::handle handle; explicit test_task(beman::task::detail::handle h) : handle(std::move(h)) {} @@ -153,6 +155,7 @@ struct test_task : beman::task::detail::state_base { this->latch.count_down(); return std::noop_coroutine(); } + allocator_type do_get_allocator() override { return allocator_type{}; } stop_token_type do_get_stop_token() override { return this->source.get_token(); } environment& do_get_environment() override { return this->env; } auto do_get_scheduler() -> scheduler_type override { return scheduler_type(bt::inline_scheduler()); } diff --git a/tests/beman/task/state_base.test.cpp b/tests/beman/task/state_base.test.cpp index eae9623..02a16e0 100644 --- a/tests/beman/task/state_base.test.cpp +++ b/tests/beman/task/state_base.test.cpp @@ -3,6 +3,7 @@ #include #include +#include #ifdef NDEBUG #undef NDEBUG #endif @@ -16,6 +17,7 @@ namespace { struct environment {}; struct state : beman::task::detail::state_base { + using allocator_type = ::beman::task::detail::allocator_of_t; stop_source_type source; environment env; bool completed{}; @@ -26,6 +28,7 @@ struct state : beman::task::detail::state_base { this->completed = true; return std::noop_coroutine(); } + allocator_type do_get_allocator() override { return allocator_type{}; } stop_token_type do_get_stop_token() override { this->token = true; return this->source.get_token(); From 1bab4fb14b4fa440950a54b1c238387e57118429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 23 Mar 2026 02:49:42 +0000 Subject: [PATCH 09/12] clang-format --- include/beman/task/detail/awaiter.hpp | 4 ++-- include/beman/task/detail/state.hpp | 2 +- include/beman/task/detail/state_base.hpp | 2 +- tests/beman/task/promise_base.test.cpp | 2 +- tests/beman/task/promise_type.test.cpp | 4 ++-- tests/beman/task/state_base.test.cpp | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/beman/task/detail/awaiter.hpp b/include/beman/task/detail/awaiter.hpp index 1bf1edb..2225c5d 100644 --- a/include/beman/task/detail/awaiter.hpp +++ b/include/beman/task/detail/awaiter.hpp @@ -48,7 +48,7 @@ struct awaiter_op_t { template class awaiter : public ::beman::task::detail::state_base { public: - using allocator_type = typename ::beman::task::detail::state_base::allocator_type; + using allocator_type = typename ::beman::task::detail::state_base::allocator_type; using stop_token_type = typename ::beman::task::detail::state_base::stop_token_type; using scheduler_type = typename ::beman::task::detail::state_base::scheduler_type; @@ -89,7 +89,7 @@ class awaiter : public ::beman::task::detail::state_base { return this->no_completion_set() ? this->parent.promise().unhandled_stopped() : ::std::move(this->parent); } auto do_get_allocator() -> allocator_type override { - if constexpr (requires{ ::beman::execution::get_allocator(::beman::execution::get_env(this->parent)); }) + if constexpr (requires { ::beman::execution::get_allocator(::beman::execution::get_env(this->parent)); }) return ::beman::execution::get_allocator(::beman::execution::get_env(this->parent)); else return allocator_type{}; diff --git a/include/beman/task/detail/state.hpp b/include/beman/task/detail/state.hpp index 10ff50c..9825a23 100644 --- a/include/beman/task/detail/state.hpp +++ b/include/beman/task/detail/state.hpp @@ -48,7 +48,7 @@ struct state : ::beman::task::detail::state_base, ::beman::task::detail::s return std::noop_coroutine(); } auto do_get_allocator() -> allocator_type override { - if constexpr (requires{ ::beman::execution::get_allocator(this->receiver); }) + if constexpr (requires { ::beman::execution::get_allocator(this->receiver); }) return ::beman::execution::get_allocator(this->receiver); else return allocator_type{}; diff --git a/include/beman/task/detail/state_base.hpp b/include/beman/task/detail/state_base.hpp index e9c4765..6a43b42 100644 --- a/include/beman/task/detail/state_base.hpp +++ b/include/beman/task/detail/state_base.hpp @@ -19,7 +19,7 @@ class state_base : public ::beman::task::detail::result_type<::beman::task::deta Value, ::beman::task::detail::error_types_of_t> { public: - using allocator_type = ::beman::task::detail::allocator_of_t; + using allocator_type = ::beman::task::detail::allocator_of_t; using stop_source_type = ::beman::task::detail::stop_source_of_t; using stop_token_type = decltype(std::declval().get_token()); using scheduler_type = ::beman::task::detail::scheduler_of_t; diff --git a/tests/beman/task/promise_base.test.cpp b/tests/beman/task/promise_base.test.cpp index 1ac9b13..7e4e00b 100644 --- a/tests/beman/task/promise_base.test.cpp +++ b/tests/beman/task/promise_base.test.cpp @@ -64,7 +64,7 @@ struct state : bt::state_base> { this->completed = true; return std::noop_coroutine(); } - allocator_type do_get_allocator() override { return allocator_type{}; } + allocator_type do_get_allocator() override { return allocator_type{}; } stop_token_type do_get_stop_token() override { this->token = true; return this->source.get_token(); diff --git a/tests/beman/task/promise_type.test.cpp b/tests/beman/task/promise_type.test.cpp index 76beaa3..228a6a7 100644 --- a/tests/beman/task/promise_type.test.cpp +++ b/tests/beman/task/promise_type.test.cpp @@ -130,7 +130,7 @@ struct test_error : std::exception { struct test_task : beman::task::detail::state_base { using promise_type = beman::task::detail::promise_type; - using allocator_type = ::beman::task::detail::allocator_of_t; + using allocator_type = ::beman::task::detail::allocator_of_t; beman::task::detail::handle handle; explicit test_task(beman::task::detail::handle h) : handle(std::move(h)) {} @@ -155,7 +155,7 @@ struct test_task : beman::task::detail::state_base { this->latch.count_down(); return std::noop_coroutine(); } - allocator_type do_get_allocator() override { return allocator_type{}; } + allocator_type do_get_allocator() override { return allocator_type{}; } stop_token_type do_get_stop_token() override { return this->source.get_token(); } environment& do_get_environment() override { return this->env; } auto do_get_scheduler() -> scheduler_type override { return scheduler_type(bt::inline_scheduler()); } diff --git a/tests/beman/task/state_base.test.cpp b/tests/beman/task/state_base.test.cpp index 02a16e0..5f24109 100644 --- a/tests/beman/task/state_base.test.cpp +++ b/tests/beman/task/state_base.test.cpp @@ -17,7 +17,7 @@ namespace { struct environment {}; struct state : beman::task::detail::state_base { - using allocator_type = ::beman::task::detail::allocator_of_t; + using allocator_type = ::beman::task::detail::allocator_of_t; stop_source_type source; environment env; bool completed{}; @@ -28,7 +28,7 @@ struct state : beman::task::detail::state_base { this->completed = true; return std::noop_coroutine(); } - allocator_type do_get_allocator() override { return allocator_type{}; } + allocator_type do_get_allocator() override { return allocator_type{}; } stop_token_type do_get_stop_token() override { this->token = true; return this->source.get_token(); From a67dd565f8453f571ca43077d11565e011bbc582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 23 Mar 2026 02:52:02 +0000 Subject: [PATCH 10/12] fix formatting issue --- tests/beman/task/promise_type.test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/beman/task/promise_type.test.cpp b/tests/beman/task/promise_type.test.cpp index 228a6a7..eb8dc86 100644 --- a/tests/beman/task/promise_type.test.cpp +++ b/tests/beman/task/promise_type.test.cpp @@ -129,7 +129,7 @@ struct test_error : std::exception { struct test_task : beman::task::detail::state_base { - using promise_type = beman::task::detail::promise_type; + using promise_type = ::beman::task::detail::promise_type; using allocator_type = ::beman::task::detail::allocator_of_t; beman::task::detail::handle handle; From 89dd18e486fc842eb37e27fb37b624cd363c12e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 23 Mar 2026 02:59:02 +0000 Subject: [PATCH 11/12] fixed environment access in get_allocator --- include/beman/task/detail/awaiter.hpp | 4 ++-- include/beman/task/detail/state.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/beman/task/detail/awaiter.hpp b/include/beman/task/detail/awaiter.hpp index 2225c5d..2fbef7e 100644 --- a/include/beman/task/detail/awaiter.hpp +++ b/include/beman/task/detail/awaiter.hpp @@ -89,8 +89,8 @@ class awaiter : public ::beman::task::detail::state_base { return this->no_completion_set() ? this->parent.promise().unhandled_stopped() : ::std::move(this->parent); } auto do_get_allocator() -> allocator_type override { - if constexpr (requires { ::beman::execution::get_allocator(::beman::execution::get_env(this->parent)); }) - return ::beman::execution::get_allocator(::beman::execution::get_env(this->parent)); + if constexpr (requires { ::beman::execution::get_allocator(::beman::execution::get_env(this->parent.promise())); }) + return ::beman::execution::get_allocator(::beman::execution::get_env(this->parent.promise())); else return allocator_type{}; } diff --git a/include/beman/task/detail/state.hpp b/include/beman/task/detail/state.hpp index 9825a23..567fac0 100644 --- a/include/beman/task/detail/state.hpp +++ b/include/beman/task/detail/state.hpp @@ -48,8 +48,8 @@ struct state : ::beman::task::detail::state_base, ::beman::task::detail::s return std::noop_coroutine(); } auto do_get_allocator() -> allocator_type override { - if constexpr (requires { ::beman::execution::get_allocator(this->receiver); }) - return ::beman::execution::get_allocator(this->receiver); + if constexpr (requires { ::beman::execution::get_allocator(::beman::execution::get_env(this->receiver)); }) + return ::beman::execution::get_allocator(::beman::execution::get_env(this->receiver)); else return allocator_type{}; } From e657f74be038f97b6d0d379fa1330e22c4e17adf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 23 Mar 2026 03:00:17 +0000 Subject: [PATCH 12/12] clang-format again --- include/beman/task/detail/awaiter.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/beman/task/detail/awaiter.hpp b/include/beman/task/detail/awaiter.hpp index 2fbef7e..a6f4d9d 100644 --- a/include/beman/task/detail/awaiter.hpp +++ b/include/beman/task/detail/awaiter.hpp @@ -89,7 +89,9 @@ class awaiter : public ::beman::task::detail::state_base { return this->no_completion_set() ? this->parent.promise().unhandled_stopped() : ::std::move(this->parent); } auto do_get_allocator() -> allocator_type override { - if constexpr (requires { ::beman::execution::get_allocator(::beman::execution::get_env(this->parent.promise())); }) + if constexpr (requires { + ::beman::execution::get_allocator(::beman::execution::get_env(this->parent.promise())); + }) return ::beman::execution::get_allocator(::beman::execution::get_env(this->parent.promise())); else return allocator_type{};