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