Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Activity.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Execution_Activity_h_
5#define _Stroika_Foundation_Execution_Activity_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
11
12/*
13 *
14 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
15 *
16 *
17 * Notes:
18 *
19 *
20 *
21 */
22
24
25 namespace Private_ {
26 namespace Activities_ {
27 /**
28 * \note intentionally omit virtual DTOR because then the subclasses cannot be constexpr (at least it appears so in c++17).
29 * And they are never destroyed by ptr to a base class type, so this isn't needed.
30 */
31 struct AsStringObj_ {
32 constexpr AsStringObj_ () noexcept = default;
33 virtual Characters::String AsString () const = 0;
34 };
35 struct StackElt_ {
36 const AsStringObj_* fActivity{};
37 const StackElt_* fPrev{};
38 };
39 thread_local inline const StackElt_* sTop_;
40 }
41 }
42
43 /**
44 * An Activity is typically a static const or sometimes even constexpr object which contains a description of
45 * an ongoing activity. They are generally not meant to be stored or copied, but REFERENCED with DeclareActivity
46 * to form a 'current activity stack'.
47 *
48 * \par Example Usage
49 * \code
50 * static constexpr Activity kBuildingThingy_{ "building thingy"sv };
51 * static const auto kOtherActivity = Activity<String>{ "abc" };
52 * // automatic variable activity OK as long as it's lifetime longer than reference in DeclareActivity
53 * auto otherActivity = Activity<String> { "abc" + argument }; // activities can be stack based, but these cost more to define
54 * auto lazyEvalActivity = LazyEvalActivity ([&] () -> String { return argument.Repeat (5) + "x"; });
55 * // then for how to use activity object - see DeclareActivity
56 * \endcode
57 *
58 * \note the intended purpose of this is to provide better 'context' for default exception messages, when exceptions are
59 * created/thrown. @see CaptureCurrentActivities
60 *
61 * \note for now, constexpr Activity<wstring_view> kActivity; // FAILS
62 * This is because AsStringObj_ has a virtual destructor (necessary for other types). That's crazy
63 * because constexpr objects are never destroyed, so its crazy to care that they have a virtual DTOR.
64 * Still, g++ and msvc both agree on this; I think this MAYBE fixed in C++20 (not yet tested) - because
65 * there they at least allow virtual constexpr methods. That might impact (indirectly) whether an object
66 * can be constexpr (having a virtual dtor).
67 */
68 template <typename STRINGISH_T = Characters::String>
70 public:
71 constexpr Activity (const STRINGISH_T& arg);
72 Activity (const Activity& src) = default;
73
74 public:
75 virtual Characters::String AsString () const override;
76
77 private:
78 STRINGISH_T fArg_;
79 };
80
81 /**
82 */
83 template <typename CTOR_ARG>
84 Activity (const CTOR_ARG& b) -> Activity<CTOR_ARG>;
85
86 /**
87 * When creating the activity would be expensive, just capture it in a lambda, and only convert that lambda to
88 * an actual string if/when CaptureCurrentActivities is called.
89 *
90 * \note would LIKE to know how to do this as a template specialization of Activity, but haven't figured that out yet.
91 *
92 * \par Example Usage
93 * \code
94 * auto scanningThisAddress = LazyEvalActivity ([&] () -> String { return "scanning ports on {}"_f (ia); });
95 * DeclareActivity da{&scanningThisAddress};
96 * \endcode
97 */
98 template <typename CTOR_ARG>
100 public:
101 constexpr LazyEvalActivity (const CTOR_ARG& arg)
102 requires (is_invocable_r_v<Characters::String, CTOR_ARG>);
103
104 public:
105 virtual Characters::String AsString () const override;
106
107 private:
108 [[no_unique_address]] CTOR_ARG fArg_;
109 };
110
111 /**
112 * \brief Returns a copyable preservable version of the current activities stack.
113 *
114 * 'render' each current activity on the current threads activity stack as a Activity<> (so String based), and return the full
115 * list as a copyable stack of activities.
116 *
117 * \note the intended purpose of this is to provide better 'context' for default exception messages, when exceptions are
118 * created/thrown.
119 *
120 * \note the TOP of the static is the most specific activity, and the bottom of the stack is the initial, outermost task.
121 */
123
124 /**
125 * Push the argument Activity onto the current thread's Activity stack in the constructor, and pop it off in the destructor.
126 *
127 * \par Example Usage
128 * \code
129 * static constexpr Activity kBuildingThingy_ {"building thingy"sv };
130 * try {
131 * DeclareActivity declareActivity { &kBuildingThingy_ };
132 * doBuildThing (); // throw any exception (that inherits from Exception<>)
133 * }
134 * catch (...) {
135 * String exceptionMsg = Characters::ToString (current_exception ());
136 * Assert (exceptionMsg.Contains (kBuildingThingy_.AsString ()); // exception e while building thingy...
137 * }
138 * \endcode
139 */
140 template <typename ACTIVITY>
142 public:
143 /**
144 * The caller must always declare an Activity object whose address can be taken,
145 * and whose lifetime exceeds that of the DeclareActivity object.
146 *
147 * \note the Activity* argument MAY be nullptr, in which case this does nothing.
148 *
149 * This is allowed to facilitate examples like:
150 * \code
151 * DeclareActivity declareActivity { flag? &kSomeActivity_? nullptr }; // so we only conditionally declare the activity
152 * \endcode
153 *
154 * I considered using optional<ACTIVITY> - but tricky since we pass in pointer - and really not much point. This has practically zero
155 * overhead, and is easy enough to understand and use.
156 */
157 DeclareActivity () = delete;
158 DeclareActivity (const DeclareActivity&) = delete;
159 DeclareActivity (const ACTIVITY* activity) noexcept;
161
162 private:
163 Private_::Activities_::StackElt_ fNewTopOfStackElt_;
164 };
165
166}
167
168/*
169 ********************************************************************************
170 ***************************** Implementation Details ***************************
171 ********************************************************************************
172 */
173#include "Activity.inl"
174
175#endif /*_Stroika_Foundation_Execution_Activity_h_*/
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
Containers::Stack< Activity<> > CaptureCurrentActivities()
Returns a copyable preservable version of the current activities stack.
Definition Activity.cpp:19