]> git.mxchange.org Git - core.git/blob - framework/main/classes/stacker/class_BaseStacker.php
Continued:
[core.git] / framework / main / classes / stacker / class_BaseStacker.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Stack;
4
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Bootstrap\FrameworkBootstrap;
7 use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem;
8
9 // Import SPL stuff
10 use \BadMethodCallException;
11 use \InvalidArgumentException;
12
13 /**
14  * A general Stacker
15  *
16  * @author              Roland Haeder <webmaster@shipsimu.org>
17  * @version             0.0.0
18  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2022 Core Developer Team
19  * @license             GNU GPL 3.0 or any newer version
20  * @link                http://www.shipsimu.org
21  *
22  * This program is free software: you can redistribute it and/or modify
23  * it under the terms of the GNU General Public License as published by
24  * the Free Software Foundation, either version 3 of the License, or
25  * (at your option) any later version.
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  * GNU General Public License for more details.
31  *
32  * You should have received a copy of the GNU General Public License
33  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
34  */
35 abstract class BaseStacker extends BaseFrameworkSystem {
36         // Exception codes
37         const EXCEPTION_STACKER_ALREADY_INITIALIZED = 0x050;
38         const EXCEPTION_STACKER_IS_FULL             = 0x051;
39         const EXCEPTION_NO_STACKER_FOUND            = 0x052;
40         const EXCEPTION_STACKER_IS_EMPTY            = 0x053;
41
42         /**
43          * Array "caches" configuration entries for saving "expensive" method
44          * invocations
45          */
46         private $cachedMaxStackSizes = [];
47
48         /**
49          * Protected constructor
50          *
51          * @param       $className      Name of the class
52          * @return      void
53          */
54         protected function __construct (string $className) {
55                 // Call parent constructor
56                 parent::__construct($className);
57         }
58
59         /**
60          * Initializes given stacker
61          *
62          * @param       $stackerName    Name of the stack
63          * @param       $forceReInit    Force re-initialization
64          * @return      void
65          * @throws      InvalidArgumentException        If a parameter is invalid
66          * @throws      BadMethodCallException  If the stack is already initialized
67          */
68         public function initStack (string $stackerName, bool $forceReInit = false) {
69                 // Validate parameter
70                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s,forceReInit=%d - CALLED!', $stackerName, intval($forceReInit)));
71                 if (empty($stackerName)) {
72                         // No empty stack name
73                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
74                 } elseif (($forceReInit === false) && ($this->isStackInitialized($stackerName))) {
75                         // Then throw the exception
76                         throw new BadMethodCallException(array($this, $stackerName, $forceReInit), self::EXCEPTION_STACKER_ALREADY_INITIALIZED);
77                 }
78
79                 // Initialize the given stack and "cache" configuration entry
80                 $this->initGenericArrayKey('stacks', $stackerName, 'entries', $forceReInit);
81                 $this->cachedMaxStackSizes[$stackerName] = FrameworkBootstrap::getConfigurationInstance()->getConfigEntry(sprintf('stacker_%s_max_size', $stackerName));
82
83                 // Trace message
84                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-STACKER: EXIT!');
85         }
86
87         /**
88          * Initializes all stacks
89          *
90          * @return      void
91          * @throws      InvalidArgumentException        If a parameter is invalid
92          */
93         public function initStacks (array $stacks, bool $forceReInit = false) {
94                 // Validate parameter
95                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stacks()=%d,forceReInit=%d - CALLED!', count($stacks), intval($forceReInit)));
96                 if (count($stacks) == 0) {
97                         // No empty stack name
98                         throw new InvalidArgumentException('Array "stacks" is empty');
99                 }
100
101                 // "Walk" through all (more will be added as needed
102                 foreach ($stacks as $stackerName) {
103                         // Init this stack
104                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: Calling this->initStack(%s,%d) ...', $stackerName, intval($forceReInit)));
105                         $this->initStack($stackerName, $forceReInit);
106                 }
107
108                 // Trace message
109                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-STACKER: EXIT!');
110         }
111
112         /**
113          * Checks whether the given stack is initialized (set in array $stackers)
114          *
115          * @param       $stackerName    Name of the stack
116          * @return      $isInitialized  Whether the stack is initialized
117          * @throws      InvalidArgumentException        If a parameter is invalid
118          */
119         public function isStackInitialized (string $stackerName) {
120                 // Validate parameter
121                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
122                 if (empty($stackerName)) {
123                         // No empty stack name
124                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
125                 }
126
127                 // Is is there?
128                 $isInitialized = ($this->isValidGenericArrayKey('stacks', $stackerName, 'entries'));
129
130                 // Return result
131                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: isInitialized=%d - EXIT!', intval($isInitialized)));
132                 return $isInitialized;
133         }
134
135         /**
136          * Checks whether the given stack is full
137          *
138          * @param       $stackerName    Name of the stack
139          * @return      $isFull                 Whether the stack is full
140          * @throws      InvalidArgumentException        If a parameter is invalid
141          * @throws      BadMethodCallException  If given stack is missing
142          */
143         protected function isStackFull (string $stackerName) {
144                 // Validate parameter
145                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
146                 if (empty($stackerName)) {
147                         // No empty stack name
148                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
149                 } elseif (!$this->isStackInitialized($stackerName)) {
150                         // Throw an exception
151                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
152                 }
153
154                 // So, is the stack full?
155                 $isFull = (($this->getStackCount($stackerName)) == $this->cachedMaxStackSizes[$stackerName]);
156
157                 // Return result
158                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: isFull=%d - EXIT!', intval($isFull)));
159                 return $isFull;
160         }
161
162         /**
163          * Checks whether the given stack is empty
164          *
165          * @param       $stackerName            Name of the stack
166          * @return      $isEmpty                        Whether the stack is empty
167          * @throws      InvalidArgumentException        If a parameter is invalid
168          * @throws      BadMethodCallException  If given stack is missing
169          */
170         public function isStackEmpty (string $stackerName) {
171                 // Validate parameter
172                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
173                 if (empty($stackerName)) {
174                         // No empty stack name
175                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
176                 } elseif (!$this->isStackInitialized($stackerName)) {
177                         // Throw an exception
178                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
179                 }
180
181                 // So, is the stack empty?
182                 $isEmpty = (($this->getStackCount($stackerName)) == 0);
183
184                 // Return result
185                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: isEmpty=%d - EXIT!', intval($isEmpty)));
186                 return $isEmpty;
187         }
188
189         /**
190          * Getter for size of given stack (array count)
191          *
192          * @param       $stackerName    Name of the stack
193          * @return      $count                  Size of stack (array count)
194          * @throws      InvalidArgumentException        If a parameter is invalid
195          * @throws      BadMethodCallException  If given stack is missing
196          */
197         public function getStackCount (string $stackerName) {
198                 // Validate parameter
199                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
200                 if (empty($stackerName)) {
201                         // No empty stack name
202                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
203                 } elseif (!$this->isStackInitialized($stackerName)) {
204                         // Throw an exception
205                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
206                 }
207
208                 // Now, count the array of entries
209                 $count = $this->countGenericArrayElements('stacks', $stackerName, 'entries');
210
211                 // Return result
212                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: count=%d - EXIT!', $count));
213                 return $count;
214         }
215
216         /**
217          * Adds a value to given stack
218          *
219          * @param       $stackerName    Name of the stack
220          * @param       $value                  Value to add to this stacker
221          * @return      void
222          * @throws      InvalidArgumentException        If a parameter is invalid
223          * @throws      BadMethodCallException  If given stack is missing
224          * @throws      FullStackerException    Thrown if the stack is full
225          */
226         protected function addValueToStack (string $stackerName, $value) {
227                 // Validate parameter
228                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s,value[]=%s - CALLED!', $stackerName, gettype($value)));
229                 if (empty($stackerName)) {
230                         // No empty stack name
231                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
232                 } elseif (!$this->isStackInitialized($stackerName)) {
233                         // Throw an exception
234                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
235                 } elseif ($this->isStackFull($stackerName)) {
236                         // Stacker is full
237                         throw new FullStackerException([$this, $stackerName, $value], self::EXCEPTION_STACKER_IS_FULL);
238                 }
239
240                 // Now add the value to the stack
241                 $this->pushValueToGenericArrayKey('stacks', $stackerName, 'entries', $value);
242
243                 // Trace message
244                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-STACKER: EXIT!');
245         }
246
247         /**
248          * Get last value from named stacker
249          *
250          * @param       $stackerName    Name of the stack
251          * @return      $value                  Value of last added value
252          * @throws      InvalidArgumentException        If a parameter is invalid
253          * @throws      BadMethodCallException  If the named stacker was not found
254          * @throws      BadMethodCallException  If the named stacker is empty
255          */
256         protected function getLastValue (string $stackerName) {
257                 // Validate parameter
258                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
259                 if (empty($stackerName)) {
260                         // No empty stack name
261                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
262                 } elseif (!$this->isStackInitialized($stackerName)) {
263                         // Throw an exception
264                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
265                 } elseif ($this->isStackEmpty($stackerName)) {
266                         // Throw an exception
267                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
268                 }
269
270                 // Now get the last value
271                 $value = $this->getGenericArrayElement('stacks', $stackerName, 'entries', $this->getStackCount($stackerName) - 1);
272
273                 // Return it
274                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
275                 return $value;
276         }
277
278         /**
279          * Get first value from named stacker
280          *
281          * @param       $stackerName    Name of the stack
282          * @return      $value                  Value of last added value
283          * @throws      InvalidArgumentException        If a parameter is invalid
284          * @throws      BadMethodCallException  If the named stacker was not found
285          * @throws      BadMethodCallException  If the named stacker is empty
286          */
287         protected function getFirstValue (string $stackerName) {
288                 // Validate parameter
289                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
290                 if (empty($stackerName)) {
291                         // No empty stack name
292                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
293                 } elseif (!$this->isStackInitialized($stackerName)) {
294                         // Throw an exception
295                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
296                 } elseif ($this->isStackEmpty($stackerName)) {
297                         // Throw an exception
298                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
299                 }
300
301                 // Now get the first value
302                 $value = $this->getGenericArrayElement('stacks', $stackerName, 'entries', 0);
303
304                 // Return it
305                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
306                 return $value;
307         }
308
309         /**
310          * "Pops" last entry from stack
311          *
312          * @param       $stackerName    Name of the stack
313          * @return      $value                  Value "poped" from array
314          * @throws      InvalidArgumentException        If a parameter is invalid
315          * @throws      BadMethodCallException  If the named stacker was not found
316          * @throws      BadMethodCallException  If the named stacker is empty
317          */
318         protected function popLast (string $stackerName) {
319                 // Validate parameter
320                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
321                 if (empty($stackerName)) {
322                         // No empty stack name
323                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
324                 } elseif (!$this->isStackInitialized($stackerName)) {
325                         // Throw an exception
326                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
327                 } elseif ($this->isStackEmpty($stackerName)) {
328                         // Throw an exception
329                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
330                 }
331
332                 // Now, remove the last entry, we don't care about the return value here, see elseif() block above
333                 $value = $this->popGenericArrayElement('stacks', $stackerName, 'entries');
334
335                 // Return it
336                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
337                 return $value;
338         }
339
340         /**
341          * "Pops" first entry from stack
342          *
343          * @param       $stackerName    Name of the stack
344          * @return      $value                  Value "shifted" from array
345          * @throws      InvalidArgumentException        If a parameter is invalid
346          * @throws      BadMethodCallException  If the named stacker was not found
347          * @throws      BadMethodCallException  If the named stacker is empty
348          */
349         protected function popFirst (string $stackerName) {
350                 // Validate parameter
351                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
352                 if (empty($stackerName)) {
353                         // No empty stack name
354                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
355                 } elseif (!$this->isStackInitialized($stackerName)) {
356                         // Throw an exception
357                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
358                 } elseif ($this->isStackEmpty($stackerName)) {
359                         // Throw an exception
360                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
361                 }
362
363                 // Now, remove the last entry, we don't care about the return value here, see elseif() block above
364                 $value = $this->shiftGenericArrayElement('stacks', $stackerName, 'entries');
365
366                 // Return it
367                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
368                 return $value;
369         }
370
371 }