Stroika Library 3.0d24
 
Loading...
Searching...
No Matches
Foundation/Execution/Common.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Execution_Common_h_
5#define _Stroika_Foundation_Execution_Common_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <execution>
10
12
14
15 /**
16 * \brief equivalent which of 4 types being used std::execution::sequenced_policy, parallel_policy, etc...
17 *
18 * Much simpler to just have a single enum rather than these 4 classes. STL choice based on (probably more historical)
19 * C++ limitations with overloading (no constexpr) - not much point in that anymore, I don't think.
20 *
21 * \note 'eDEFAULT' is DEPRECATED, and there is deliberately no replacement enumerator. "I have no
22 * opinion, pick for me" is not a policy, and encoding it as one lies about what happens:
23 * eDEFAULT is an alias for eSeq, so a caller who meant 'you decide' silently pinned the
24 * implementation to sequential and left it no freedom at all.
25 *
26 * An API that wants to offer that choice provides an OVERLOAD taking no policy - see
27 * Iterable<T>::Apply (), Iterable<T>::Find (), Iterable<T>::OrderBy (). Not passing a policy is
28 * then genuinely different from passing one, the implementation is free to get smarter later,
29 * and no existing call site changes meaning when it does.
30 *
31 * \note HOW STROIKA DISPATCHES ON THIS - the rule for any code switching on a SequencePolicy:
32 * ONLY ePar selects a parallel std algorithm. Every other policy runs sequentially, and
33 * that fallthrough is DELIBERATE, not an unhandled case.
34 *
35 * We have no unsequenced implementation, and answering a request for eUnseq/eParUnseq with
36 * execution::par would substitute a DIFFERENT policy than the caller asked for: par permits
37 * locks and demands no vectorization-safety, while the unsequenced policies forbid locking
38 * and may interleave calls within a single thread. So a caller who wrote a correct lock-free
39 * SIMD-safe callable would silently get threads, and one who passed eUnseq while holding a
40 * mutex would get exactly the hazard the policy told them to avoid.
41 *
42 * Running sequentially is a legal execution of EVERY policy - a policy grants permission, it
43 * does not compel - so falling back is honest where substituting is not. Dispatch sites
44 * therefore read 'case ePar: <parallel>; default: <sequential>', never the inverse.
45 */
46 enum class SequencePolicy {
47 /**
48 * \brief default case - not parallelized
49 *
50 * Equivalent to std::seq, std::execution::sequenced_policy
51 *
52 * ..."a parallel algorithm's execution may not be parallelized.
53 * The invocations of element access functions in parallel algorithms invoked with this policy
54 * (usually specified as std::execution::seq) are indeterminately sequenced in the calling thread."
55 */
56 eSeq,
57
58 /**
59 * \brief must synchronize shared data, can use mutex (or atomics), cuz each parallel execution in real thread
60 *
61 * Equivalent to std::par, std::execution::parallel_policy
62 *
63 * ..."parallel algorithm's execution may be parallelized. The invocations of element access
64 * functions in parallel algorithms invoked with this policy (usually specified as std::execution::par)
65 * are permitted to execute in either the invoking thread or in a thread implicitly created by the
66 * library to support parallel algorithm execution. Any such invocations executing in the same
67 * thread are indeterminately sequenced with respect to each other.
68 */
69 ePar,
70
71 /**
72 * \brief Unclear how this differs from eUnseq, but no locks allowed
73 *
74 * Equivalent to std::par_unseq , std::execution::parallel_unsequenced_policy
75 *
76 * ..."a parallel algorithm's execution may be parallelized, vectorized,
77 * or migrated across threads (such as by a parent-stealing scheduler). The invocations of
78 * element access functions in parallel algorithms invoked with this policy are permitted
79 * to execute in an unordered fashion in unspecified threads, and unsequenced with respect
80 * to one another within each thread..
81 */
83
84 /**
85 * \brief SIMD, no locks allowed
86 *
87 * Equivalent to std::unseq, std::execution::unsequenced_policy
88 *
89 * ..."a parallel algorithm's execution may be parallelized, vectorized,
90 * or migrated across threads (such as by a parent-stealing scheduler). The invocations of
91 * element access functions in parallel algorithms invoked with this policy are permitted
92 * to execute in an unordered fashion in unspecified threads, and unsequenced with respect
93 * to one another within each thread..
94 */
95 eUnseq,
96
98
99 eDEFAULT [[deprecated ("Since Stroika v3.0d24 - call the overload taking no SequencePolicy to let the "
100 "implementation choose, or say eSeq if you require sequential")]] = eSeq,
101 };
102
103}
104
105/*
106 ********************************************************************************
107 ***************************** Implementation Details ***************************
108 ********************************************************************************
109 */
110
111#endif /*_Stroika_Foundation_Execution_Common_h_*/
#define Stroika_Define_Enum_Bounds(FIRST_ITEM, LAST_ITEM)
SequencePolicy
equivalent which of 4 types being used std::execution::sequenced_policy, parallel_policy,...
@ eParUnseq
Unclear how this differs from eUnseq, but no locks allowed.
@ ePar
must synchronize shared data, can use mutex (or atomics), cuz each parallel execution in real thread
@ eSeq
default case - not parallelized