Stroika Library 3.0d18
 
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_{nullptr};
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 Checks if CaptureCurrentActivities() would produce a non-empty stack (but faster)
113 */
114 bool AnyCurrentActivities ();
115
116 /**
117 * \brief Returns a copyable preservable version of the current activities stack.
118 *
119 * 'render' each current activity on the current threads activity stack as a Activity<> (so String based), and return the full
120 * list as a copyable stack of activities.
121 *
122 * \note the intended purpose of this is to provide better 'context' for default exception messages, when exceptions are
123 * created/thrown.
124 *
125 * \note the TOP of the static is the most specific activity, and the bottom of the stack is the initial, outermost task.
126 */
128
129 /**
130 * Push the argument Activity onto the current thread's Activity stack in the constructor, and pop it off in the destructor.
131 *
132 * \par Example Usage
133 * \code
134 * static constexpr Activity kBuildingThingy_ {"building thingy"sv };
135 * try {
136 * DeclareActivity declareActivity { &kBuildingThingy_ };
137 * doBuildThing (); // throw any exception (that inherits from Exception<>)
138 * }
139 * catch (...) {
140 * String exceptionMsg = Characters::ToString (current_exception ());
141 * Assert (exceptionMsg.Contains (kBuildingThingy_.AsString ()); // exception e while building thingy...
142 * }
143 * \endcode
144 *
145 * \note these activities are captured via CaptureCurrentActivities() - when an ExceptionStringHelper subclass (any of the Stroika Exception classes)
146 * is constructed. For 3rd-party exceptions, consider wrapping with NestedException.
147 */
148 template <typename ACTIVITY>
150 public:
151 /**
152 * The caller must always declare an Activity object whose address can be taken,
153 * and whose lifetime exceeds that of the DeclareActivity object.
154 *
155 * \note the Activity* argument MAY be nullptr, in which case this does nothing.
156 *
157 * This is allowed to facilitate examples like:
158 * \code
159 * DeclareActivity declareActivity { flag? &kSomeActivity_? nullptr }; // so we only conditionally declare the activity
160 * \endcode
161 *
162 * I considered using optional<ACTIVITY> - but tricky since we pass in pointer - and really not much point. This has practically zero
163 * overhead, and is easy enough to understand and use.
164 */
165 DeclareActivity () = delete;
166 DeclareActivity (const DeclareActivity&) = delete;
167 DeclareActivity (const ACTIVITY* activity) noexcept;
169
170 private:
171 Private_::Activities_::StackElt_ fNewTopOfStackElt_;
172 };
173
174}
175
176/*
177 ********************************************************************************
178 ***************************** Implementation Details ***************************
179 ********************************************************************************
180 */
181#include "Activity.inl"
182
183#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
bool AnyCurrentActivities()
Checks if CaptureCurrentActivities() would produce a non-empty stack (but faster)
Definition Activity.cpp:39