ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
scopestore.cpp
1// #################################################################################################
2// alib::lox::detail - ALox Logging Library
3//
4// Copyright 2013-2024 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6// #################################################################################################
8
9#if !DOXYGEN
10# include "alib/alox/alox.hpp"
12# define HPP_ALIB_LOX_PROPPERINCLUDE
15# undef HPP_ALIB_LOX_PROPPERINCLUDE
16#endif // !DOXYGEN
17
18using namespace alib;
19
20namespace alib { namespace lox { namespace detail {
21
22#define CMD_INSERT 0
23#define CMD_REMOVE 1
24#if ALIB_THREADS
25# define CMD_GET 2
26#endif
27
28
29// #################################################################################################
30// Constructor/Destructor
31// #################################################################################################
32
33template<typename T, bool TStackedThreadValues>
35 MonoAllocator& monoAllocator )
36 : globalStore ( nullptr )
37 , languageStore( monoAllocator , '/' )
38 IF_ALIB_THREADS(, threadStore ( monoAllocator ) )
39 , scopeInfo ( pScopeInfo )
40{
41 #if ALIB_DEBUG_CRITICAL_SECTIONS
42 languageStore.DbgSetDCSName("ScopeStore");
43 #endif
45}
46
47template<typename T, bool TStackedThreadValues>
49{
50 languageStore.DestructRootValue();
51}
52
53
54// #################################################################################################
55// Methods
56// #################################################################################################
57template<typename T, bool TStackedThreadValues>
58void ScopeStore<T,TStackedThreadValues>::InitWalk( Scope startScope, T localObject )
59{
60 actScope= startScope;
61 walkLocalObject= localObject;
62 actPathLevel= 0;
63 walkNextThreadIdx= -2;
64 lazyLanguageNode= true;
65 walking= true;
66}
67
68#if !DOXYGEN
69
70template<typename T>
72{
73 while ( self.walking ) switch( self.actScope )
74 {
75 case Scope::ThreadInner:
76 {
77 // initialize
78 if ( self.walkNextThreadIdx == -2 )
79 {
80 self.walkNextThreadIdx= -1;
81 #if ALIB_THREADS
82 if ( self.threadStore.Size() != 0 )
83 {
84 auto it= self.threadStore.Find( typename ScopeStore<T, true>::ThreadMapKey(true, self.scopeInfo.GetThreadID()) );
85 if ( it != self.threadStore.end() )
86 {
87 self.walkThreadValues= &it->second;
88 self.walkNextThreadIdx= 1;
89 }
90 }
91 #endif
92 }
93
94 // return next inner thread object (traversalNextScope keeps being ThreadInner)
95 if ( self.walkNextThreadIdx > 0 )
96 {
97 --self.walkNextThreadIdx;
98 return (*self.walkThreadValues);
99 }
100
101 // next scope is Method
102 self.actScope= Scope::Method;
103
104 // if we have a valid 'local object' return this first
105 if ( self.walkLocalObject != nullptr )
106 return self.walkLocalObject;
107 }
108 break;
109
110 case Scope::Method:
111 case Scope::Filename:
112 case Scope::Path:
113 {
114 if( self.lazyLanguageNode )
115 self.initCursor( false );
116
117 while( self.actStringTreeNode.IsValid() )
118 {
119 T actValue= *self.actStringTreeNode;
120 self.actStringTreeNode.GoToParent();
121 if( actValue != nullptr )
122 return actValue;
123 }
124
125 self.actScope= Scope::ThreadOuter;
126 self.walkNextThreadIdx= -2;
127 }
128 break;
129
130 case Scope::ThreadOuter:
131 {
132 // initialize
133 if ( self.walkNextThreadIdx == -2 )
134 {
135 #if ALIB_THREADS
136 if ( self.threadStore.Size() != 0 )
137 {
138 auto it= self.threadStore.Find( typename ScopeStore<T, true>::ThreadMapKey(false, self.scopeInfo.GetThreadID()) );
139 if ( it != self.threadStore.end() )
140 {
141 self.walkThreadValues= &it->second;
142 self.walkNextThreadIdx= 1;
143
144 }
145 }
146 #endif
147 }
148
149 // return next outer thread object (walkNext keeps being THREAD_OUTER)
150 if ( self.walkNextThreadIdx > 0 )
151 {
152 --self.walkNextThreadIdx;
153 return (*self.walkThreadValues);
154 }
155
156 // next scope is Global
157 self.actScope= Scope::Global;
158 }
159 break;
160
161 case Scope::Global:
162 {
163 self.walking= false;
164 return self.globalStore;
165 }
166 break;
167
168 default: ALIB_ERROR("Illegal switch state.") break;
169 }
170
171 return nullptr;
172}
173
174template<typename T>
175T ScopeStoreHelper<T, false>::doAccess( ScopeStore<T, false>& self, int cmd, T value )
176{
177 T oldValue= nullptr;
178
179 // --------- global scope ---------
180 if( self.actScope == Scope::Global )
181 {
182 oldValue= self.globalStore;
183 if ( cmd == CMD_INSERT )
184 self.globalStore= value;
185 else if ( cmd == CMD_REMOVE )
186 self.globalStore= nullptr;
187
188 return oldValue;
189 }
190
191#if ALIB_THREADS
192 // --------- thread-related scopes ---------
193 if( self.actScope == Scope::ThreadOuter
194 || self.actScope == Scope::ThreadInner )
196 // choose outer/inner store
197 bool isInner= self.actScope == Scope::ThreadInner;
198
199 // check if empty (to avoid key creation/thread detection )
200 if ( cmd != CMD_INSERT && self.threadStore.Size() == 0 )
201 return oldValue;
202
203 // thread given?
204 if ( self.actThreadID == threads::UNDEFINED )
205 self.actThreadID= self.scopeInfo.GetThreadID();
206
207 // --- implementation for non-stacked values (values stored in a ma) ---
208 ALIB_ASSERT( cmd != CMD_REMOVE ) // no remove implemented (needed)
209
210 // 'get'
211 auto key = typename ScopeStore<T, true>::ThreadMapKey(isInner, self.actThreadID);
212 auto hash= typename decltype(self.threadStore)::HashType ()( key );
213 if ( cmd == CMD_GET )
215 auto it= self.threadStore.Find( key, hash );
216 if ( it != self.threadStore.end() )
217 return it->second;
218
219 return oldValue;
220 }
221
222 // insert is simple, we do not even return an 'oldValue'
223 ALIB_ASSERT( cmd == CMD_INSERT )
224 self.threadStore.InsertUnique( std::make_pair( key, value), hash );
225
226 return oldValue;
227
228 }
229#endif
230
231 // --------- language-related scopes ---------
232 {
233 if ( cmd == CMD_INSERT && value == nullptr )
234 cmd= CMD_REMOVE;
235
236 if ( self.lazyLanguageNode
237 || ( self.actStringTreeNode.IsInvalid() && cmd == CMD_INSERT ) )
238 self.initCursor( true ); // always create
239
240 oldValue= *self.actStringTreeNode;
241 if ( cmd == CMD_INSERT ) *self.actStringTreeNode= value;
242 else if ( cmd == CMD_REMOVE ) *self.actStringTreeNode= nullptr;
243
244 return oldValue;
245 }
246}
247
248template<typename T> T ScopeStoreHelper<T, true>::doWalk( ScopeStore<T, true>& self )
249{
250 while ( self.walking ) switch( self.actScope )
251 {
252 case Scope::ThreadInner:
253 {
254 // initialize
255 if ( self.walkNextThreadIdx == -2 )
256 {
257 self.walkNextThreadIdx= -1;
258 #if ALIB_THREADS
259 if ( self.threadStore.Size() != 0 )
260 {
261 auto it= self.threadStore.Find( typename ScopeStore<T, true>::ThreadMapKey(true, self.scopeInfo.GetThreadID()) );
262 if ( it != self.threadStore.end() )
263 {
264 self.walkThreadValues= &it.Mapped();
265 self.walkNextThreadIdx= static_cast<int>( self.walkThreadValues->size() );
266 }
267 }
268 #endif
269 }
270
271 // return next inner thread object (traversalNextScope keeps being ThreadInner)
272 if ( self.walkNextThreadIdx > 0 )
274 --self.walkNextThreadIdx;
275 return (*self.walkThreadValues)[size_t(self.walkNextThreadIdx)];
276 }
277
278 // next scope is Method
279 self.actScope= Scope::Method;
280
281 // if we have a valid 'local object' return this first
282 if ( self.walkLocalObject != nullptr )
283 return self.walkLocalObject;
284 }
285 break;
286
287 case Scope::Method:
288 case Scope::Filename:
289 case Scope::Path:
290 {
291 if( self.lazyLanguageNode )
292 self.initCursor( false );
293
294 while( self.actStringTreeNode.IsValid() )
295 {
296 T actValue= *self.actStringTreeNode;
297 self.actStringTreeNode.GoToParent();
298 if( actValue != nullptr )
299 return actValue;
300 }
301
302 self.actScope= Scope::ThreadOuter;
303 self.walkNextThreadIdx= -2;
304 }
305 break;
306
307 case Scope::ThreadOuter:
308 {
309 // initialize
310 if ( self.walkNextThreadIdx == -2 )
311 {
312 #if ALIB_THREADS
313 if ( self.threadStore.Size() != 0 )
314 {
315 auto it= self.threadStore.Find( typename ScopeStore<T, true>::ThreadMapKey(false, self.scopeInfo.GetThreadID()) );
316 if ( it != self.threadStore.end() )
317 {
318 self.walkThreadValues= &it.Mapped();
319 self.walkNextThreadIdx= static_cast<int>( self.walkThreadValues->size() );
320 }
321 }
322 #endif
323 }
324
325 // return next outer thread object (walkNext keeps being THREAD_OUTER)
326 if ( self.walkNextThreadIdx > 0 )
327 {
328 --self.walkNextThreadIdx;
329 return (*self.walkThreadValues)[size_t(self.walkNextThreadIdx)];
330 }
331
332 // next scope is Global
333 self.actScope= Scope::Global;
334 }
335 break;
336
337 case Scope::Global:
338 {
339 self.walking= false;
340 return self.globalStore;
341 }
342 break;
343
344 default: ALIB_ERROR("Illegal switch state.") break;
345 }
346
347 return nullptr;
348}
349
350
351template<typename T> T ScopeStoreHelper<T, true>::doAccess( ScopeStore<T, true>& self, int cmd, T value )
352{
353 T oldValue= nullptr;
354
355 // --------- global scope ---------
356 if( self.actScope == Scope::Global )
357 {
358 oldValue= self.globalStore;
359 if ( cmd == CMD_INSERT ) self.globalStore= value;
360 else if ( cmd == CMD_REMOVE ) self.globalStore= nullptr;
361
362 return oldValue;
363 }
364
365#if ALIB_THREADS
366 // --------- thread-related scopes ---------
367 if( self.actScope == Scope::ThreadOuter
368 || self.actScope == Scope::ThreadInner )
369 {
370 // choose outer/inner store
371 bool isInner= self.actScope == Scope::ThreadInner;
372
373 // check if empty (to avoid key creation/thread detection )
374 if ( cmd != CMD_INSERT && self.threadStore.Size() == 0 )
375 return oldValue;
376
377 // thread given?
378 if ( self.actThreadID == threads::UNDEFINED )
379 self.actThreadID= self.scopeInfo.GetThreadID();
380
381 // --- implementation for stacked values ---
382 // find (create) the vector of values
383 StdVectorMono<T>* values;
384 {
385 values= &self.threadStore.EmplaceIfNotExistent(
386 typename ScopeStore<T, true>::ThreadMapKey(isInner, self.actThreadID),
387 self.threadStore.GetAllocator() ).first.Mapped();
388 }
389
390 // 'get'
391 if ( cmd == CMD_GET )
392 return ( values->size() > 0) ? (*values)[ values->size() -1 ] : nullptr;
393
394 // insert is simple, we do not even return an 'oldValue'
395 if ( cmd == CMD_INSERT )
396 {
397 values->emplace_back( value );
398 return oldValue; // if multiple values are allowed we do not return an 'oldValue'
399 }
400
401 // remove has two options: the last or, if given, a specific one
402 if ( cmd == CMD_REMOVE && values->size() > 0)
403 {
404 // remove the last
405 if ( value == nullptr )
406 {
407 oldValue= values->back();
408 values->pop_back();
409 }
410
411 // remove a specific one.
412 else
413 for ( auto rem= values->begin() ; rem != values->end(); ++rem )
414 if ( (*rem) == value )
415 {
416 // If found, we return the value, otherwise we don't do anything
417 oldValue= *rem;
418 values->erase( rem );
419 break;
420 }
421 }
422
423 return oldValue;
424 }
425#endif
426
427 // --------- language-related scopes ---------
428 {
429 if ( cmd == CMD_INSERT && value == nullptr )
430 cmd= CMD_REMOVE;
431
432 if ( self.lazyLanguageNode
433 || ( self.actStringTreeNode.IsInvalid() && cmd == CMD_INSERT ) )
434 self.initCursor( true ); // always create
435
436 oldValue= *self.actStringTreeNode;
437 if ( cmd == CMD_INSERT ) *self.actStringTreeNode= value;
438 else if ( cmd == CMD_REMOVE ) *self.actStringTreeNode= nullptr;
439
440 return oldValue;
441 }
442}
443
444#endif
445
446// #################################################################################################
447// internals
448// #################################################################################################
449template<typename T, bool TStackedThreadValues>
451{
452 lazyLanguageNode= false;
453 actStringTreeNode= languageStore.Root();
454
455 // path key for the StringTree
456 String512 path;
457 scopeInfo.GetTrimmedPath( path );
458 #if defined( _WIN32 )
459 path.SearchAndReplace( '\\', '/' );
460 #endif
461
462 // read-only mode
463 if( !create )
464 {
465 // in non-creation mode, it is always scope Method
466 ALIB_ASSERT( actScope == Scope::Method )
467
468 // in read only mode, we can leave as soon as a portion was not read
469 auto remainingPath= actStringTreeNode.GoTo( path );
470 if ( remainingPath.IsNotEmpty() )
471 return;
472
473 // filename: append '#' to distinguish from directories
474 if ( !actStringTreeNode.GoToChild( path.Reset<NC>( scopeInfo.GetFileNameWithoutExtension() )._( '#' ) ) )
475 return;
476
477 // method: prepend '#' to distinguish from filenames
478 actStringTreeNode.GoToChild( path.Reset<NC>( '#' )._<NC>( scopeInfo.GetMethod() ) );
479
480 return;
481 }
482
483 // create mode:
484 actStringTreeNode.GoToCreatedPathIfNotExistent( path );
485 if ( actScope == Scope::Path )
486 {
487 // subtract folders at the back
488 int pathLevel= actPathLevel;
489 while ( --pathLevel >= 0 && !actStringTreeNode.IsRoot() )
490 actStringTreeNode.GoToParent();
491 return;
492 }
493
494 // filename: append '#' to distinguish from directories
495 path.Reset( scopeInfo.GetFileNameWithoutExtension() )._( '#' );
496
497 // method: prepend '#' to distinguish from filenames
498 if ( actScope == Scope::Method )
499 path._( "/#" )._( scopeInfo.GetMethod() );
500
501 actStringTreeNode.GoToCreatedPathIfNotExistent( path );
502}
503
504template<typename T, bool TStackedThreadValues>
506{
507 actScope= scope;
508 actPathLevel= pathLevel;
509#if ALIB_THREADS
510 actThreadID= threadID;
511#else
512 (void) threadID;
513#endif
514
515 lazyLanguageNode= true;
516}
517
518
519// #################################################################################################
520// template instantiations
521// #################################################################################################
522
523//! @cond NO_DOX
524
526template class ScopeStore <NString , true>;
527
529template class ScopeStore <PrefixLogable* , true>;
530
531template struct ScopeStoreHelper<SSMap<int>*, false>;
532template class ScopeStore <SSMap<int>*, false>;
533
534template struct ScopeStoreHelper<SSMap<Box>*, false>;
535template class ScopeStore <SSMap<Box>*, false>;
536
537//! @endcond
538
539}}} // namespace [alib::lox::detail]
540
void ConstructRootValue(TArgs &&... args)
void DbgSetDCSName(const char *name) const
threads::ThreadID GetThreadID()
TLanguageStore::Cursor actStringTreeNode
The actual language related scope's map node.
ALIB_API void InitWalk(Scope startScope, const T localObject)
bool lazyLanguageNode
Flag used to lazily create the key to language-related scope values.
ALIB_API void InitAccess(Scope scope, int pathLevel, threads::ThreadID threadID)
TThreadMapValue * walkThreadValues
The list of values of Scope::ThreadOuter/Inner during a walk.
int walkNextThreadIdx
The next value of a walk during Scope::ThreadInner/Outer.
T walkLocalObject
The 'local object' returned by a walk after Scope::ThreadInner and before Scope::Method.
TLanguageStore languageStore
StringTree to store data for language-related scopes (path,source,method).
bool walking
Indicates if currently a scope walk is active.
Scope actScope
The actual scope of a walk.
std::pair< bool, threads::ThreadID > ThreadMapKey
Key type for the thread store.
ALIB_API ScopeStore(ScopeInfo &scopeInfo, MonoAllocator &monoAllocator)
ScopeInfo & scopeInfo
ScopeInfo of 'our' lox.
HashMap< MonoAllocator, ThreadMapKey, TThreadMapValue, BoolThreadIDHash > threadStore
T globalStore
The value of the global scope.
ALIB_API ~ScopeStore()
Destructor.
ALIB_API integer SearchAndReplace(TChar needle, TChar replacement, integer startIdx=0, integer endIdx=strings::MAX_LEN)
TAString & _(const TString< TChar > &src, integer regionStart, integer regionLength=MAX_LEN)
#define IF_ALIB_THREADS(...)
Definition alib.hpp:352
#define ALIB_ERROR(...)
Definition alib.hpp:1267
#define ALIB_ASSERT(cond)
Definition alib.hpp:1270
#define ALIB_THREADS
Definition alib.hpp:213
integer ThreadID
The ALib thread identifier type.
Definition loxpimpl.inl:28
Definition alib.cpp:69
T doWalk(ScopeStore< T, TStackedThreadValues > &self)