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