]> git.mxchange.org Git - core.git/blob - inc/classes/main/stacker/file/class_BaseFileStack.php
Added debug lines.
[core.git] / inc / classes / main / stacker / file / class_BaseFileStack.php
1 <?php
2 /**
3  * A general file-based stack class
4  *
5  * @author              Roland Haeder <webmaster@ship-simu.org>
6  * @version             0.0.0
7  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2013 Core Developer Team
8  * @license             GNU GPL 3.0 or any newer version
9  * @link                http://www.ship-simu.org
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24 class BaseFileStack extends BaseStacker {
25         /**
26          * Magic for this stack
27          */
28         const STACK_MAGIC = 'STACKv0.1';
29
30         /**
31          * Separator magic->count
32          */
33         const SEPARATOR_MAGIC_COUNT = 0x00;
34
35         /**
36          * Separator position->entries
37          */
38         const SEPARATOR_SEEK_POS_ENTRIES = 0xff;
39
40         /**
41          * Separator hash->name
42          */
43         const SEPARATOR_HASH_NAME = 0x05;
44
45         /**
46          * Length of count
47          */
48         const COUNT_LENGTH = 20;
49
50         /**
51          * Length of position
52          */
53         const COUNT_POSITION = 20;
54
55         /**
56          * Counter for total entries
57          */
58         private $totalEntries = 0;
59
60         /**
61          * Current seek position
62          */
63         private $seekPosition = 0;
64
65         /**
66          * Protected constructor
67          *
68          * @param       $className      Name of the class
69          * @return      void
70          */
71         protected function __construct ($className) {
72                 // Call parent constructor
73                 parent::__construct($className);
74         }
75
76         /**
77          * Getter for total entries
78          *
79          * @return      $totalEntries   Total entries in this stack
80          */
81         private function getCounter () {
82                 // Get it
83                 return $this->totalEntries;
84         }
85
86         /**
87          * Increment counter
88          *
89          * @return      void
90          */
91         private function incrementCounter () {
92                 // Get it
93                 $this->totalEntries++;
94         }
95
96         /**
97          * Getter for seek position
98          *
99          * @return      $seekPosition   Current seek position (stored here in object)
100          */
101         private function getSeekPosition () {
102                 // Get it
103                 return $this->seekPosition;
104         }
105
106         /**
107          * Setter for seek position
108          *
109          * @param       $seekPosition   Current seek position (stored here in object)
110          * @return      void
111          */
112         private function setSeekPosition ($seekPosition) {
113                 // And set it
114                 $this->seekPosition = $seekPosition;
115         }
116
117         /**
118          * Updates seekPosition attribute from file to avoid to much access on file.
119          *
120          * @return      void
121          */
122         private function updateSeekPosition () {
123                 // Get key (= seek position)
124                 $seekPosition = $this->getIteratorInstance()->key();
125
126                 // And set it here
127                 $this->setSeekPosition($seekPosition);
128         }
129
130         /**
131          * Checks whether the file header is initialized
132          *
133          * @return      $isInitialized  Whether the file header is initialized
134          */
135         private function isFileHeaderInitialized () {
136                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
137                 // Default is not initialized
138                 $isInitialized = FALSE;
139
140                 // Is the file initialized?
141                 if ($this->isFileInitialized()) {
142                         // Some bytes has been written, so rewind to start of it.
143                         $rewindStatus = $this->getIteratorInstance()->rewind();
144                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] rewindStatus=%s', __METHOD__, __LINE__, $rewindStatus));
145
146                         // Read file header
147                         $this->readFileHeader();
148                 } // END - if
149
150                 // Return result
151                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] isInitialized=%d - EXIT!', __METHOD__, __LINE__, intval($isInitialized)));
152                 return $isInitialized;
153         }
154
155         /**
156          * Checks whether the file-based stack has been initialized
157          *
158          * @return      $isInitialized          Whether the file's size is zero
159          */
160         private function isFileInitialized () {
161                 // Get it from iterator which holds the pointer instance. If FALSE is returned
162                 $fileSize = $this->getIteratorInstance()->size();
163                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] fileSize=%s', __METHOD__, __LINE__, $fileSize));
164
165                 /*
166                  * The returned file size should not be FALSE or NULL as this means
167                  * that the pointer class does not work correctly.
168                  */
169                 assert(is_int($fileSize));
170
171                 // Is more than 0 returned?
172                 $isInitialized = ($fileSize > 0);
173
174                 // Return result
175                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] isInitialized=%d - EXIT!', __METHOD__, __LINE__, intval($isInitialized)));
176                 return $isInitialized;
177         }
178
179         /**
180          * Creates the file-stack's header
181          *
182          * @return      void
183          */
184         private function createFileHeader () {
185                 // The file's header should not be initialized here
186                 assert(!$this->isFileHeaderInitialized());
187
188                 // Flush file header
189                 $this->flushFileHeader();
190         }
191
192         /**
193          * Flushes the file header
194          *
195          * @return      void
196          */
197         private function flushFileHeader () {
198                 // Put all informations together
199                 $header = sprintf('%s%s%s%s%s',
200                         // Magic
201                         self::STACK_MAGIC,
202
203                         // Separator magic<->count
204                         chr(self::SEPARATOR_MAGIC_COUNT),
205
206                         // Total entries (will be zero) and pad it to 20 chars
207                         str_pad($this->dec2hex($this->getCounter()), self::COUNT_LENGTH, '0', STR_PAD_LEFT),
208
209                         // Position (will be zero)
210                         str_pad($this->dec2hex(0, 2), self::COUNT_POSITION, '0', STR_PAD_LEFT),
211
212                         // Separator position<->entries
213                         chr(self::SEPARATOR_SEEK_POS_ENTRIES)
214                 );
215
216                 // Write it to disk (header is always at seek position 0)
217                 $this->getIteratorInstance()->writeAtPosition(0, $header);
218
219                 // Update seek position
220                 $this->updateSeekPosition();
221         }
222
223         /**
224          * Initializes this file-based stack.
225          *
226          * @param       $fileName       File name of this stack
227          * @return      void
228          */
229         protected function initFileStack ($fileName) {
230                 // Get a file i/o pointer instance
231                 $pointerInstance = ObjectFactory::createObjectByConfiguredName('file_raw_input_output_class', array($fileName));
232
233                 // Get iterator instance
234                 $iteratorInstance = ObjectFactory::createObjectByConfiguredName('file_io_iterator_class', array($pointerInstance));
235
236                 // Is the instance implementing the right interface?
237                 assert($iteratorInstance instanceof SeekableWritableFileIterator);
238
239                 // Set iterator here
240                 $this->setIteratorInstance($iteratorInstance);
241
242                 // Is the file's header initialized?
243                 if ($this->isFileHeaderInitialized()) {
244                         // Then load it
245                         $this->loadFileHeader();
246                 } else {
247                         // No, then create it (which may pre-allocate the stack)
248                         $this->createFileHeader();
249
250                         // And pre-allocate a bit
251                         $this->preAllocateFile();
252                 }
253         }
254
255         /**
256          * Initializes given stacker
257          *
258          * @param       $stackerName    Name of the stack
259          * @param       $forceReInit    Force re-initialization
260          * @return      void
261          * @throws      AlreadyInitializedStackerException      If the stack is already initialized
262          */
263         public function initStack ($stackerName, $forceReInit = FALSE) {
264                 // Is the stack already initialized?
265                 if (($forceReInit === FALSE) && ($this->isStackInitialized($stackerName))) {
266                         // Then throw the exception
267                         throw new AlreadyInitializedStackerException(array($this, $stackerName, $forceReInit), self::EXCEPTION_STACKER_ALREADY_INITIALIZED);
268                 } // END - if
269
270                 // Initialize the given stack
271                 $this->partialStub('stackerName=' . $stackerName . ',forceReInit=' . intval($forceReInit));
272         }
273
274         /**
275          * Checks whether the given stack is initialized (set in array $stackers)
276          *
277          * @param       $stackerName    Name of the stack
278          * @return      $isInitialized  Whether the stack is initialized
279          */
280         public function isStackInitialized ($stackerName) {
281                 // Is is there?
282                 $this->partialStub('stackerName=' . $stackerName);
283                 $isInitialized = TRUE;
284
285                 // Return result
286                 return $isInitialized;
287         }
288
289         /**
290          * Getter for size of given stack (array count)
291          *
292          * @param       $stackerName    Name of the stack
293          * @return      $count                  Size of stack (array count)
294          * @throws      NoStackerException      If given stack is missing
295          */
296         public function getStackCount ($stackerName) {
297                 // Is the stack not yet initialized?
298                 if (!$this->isStackInitialized($stackerName)) {
299                         // Throw an exception
300                         throw new NoStackerException(array($this, $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
301                 } // END - if
302
303                 // Now, count the array of entries
304                 $this->partialStub('stackerName=' . $stackerName);
305                 $count = 0;
306
307                 // Return result
308                 return $count;
309         }
310
311         /**
312          * Adds a value to given stack
313          *
314          * @param       $stackerName    Name of the stack
315          * @param       $value                  Value to add to this stacker
316          * @return      void
317          * @throws      FullStackerException    Thrown if the stack is full
318          */
319         protected function addValue ($stackerName, $value) {
320                 // Is the stack not yet initialized or full?
321                 if (!$this->isStackInitialized($stackerName)) {
322                         // Then do it here
323                         $this->initStack($stackerName);
324                 } elseif ($this->isStackFull($stackerName)) {
325                         // Stacker is full
326                         throw new FullStackerException(array($this, $stackerName, $value), self::EXCEPTION_STACKER_IS_FULL);
327                 }
328
329                 // Now add the value to the stack
330                 $this->partialStub('stackerName=' . $stackerName . ',value[]=' . gettype($value));
331         }
332
333         /**
334          * Get last value from named stacker
335          *
336          * @param       $stackerName    Name of the stack
337          * @return      $value                  Value of last added value
338          * @throws      NoStackerException      If the named stacker was not found
339          * @throws      EmptyStackerException   If the named stacker is empty
340          */
341         protected function getLastValue ($stackerName) {
342                 // Is the stack not yet initialized or full?
343                 if (!$this->isStackInitialized($stackerName)) {
344                         // Throw an exception
345                         throw new NoStackerException(array($this, $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
346                 } elseif ($this->isStackEmpty($stackerName)) {
347                         // Throw an exception
348                         throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
349                 }
350
351                 // Now get the last value
352                 $this->partialStub('stackerName=' . $stackerName);
353                 $value = NULL;
354
355                 // Return it
356                 return $value;
357         }
358
359         /**
360          * Get first value from named stacker
361          *
362          * @param       $stackerName    Name of the stack
363          * @return      $value                  Value of last added value
364          * @throws      NoStackerException      If the named stacker was not found
365          * @throws      EmptyStackerException   If the named stacker is empty
366          */
367         protected function getFirstValue ($stackerName) {
368                 // Is the stack not yet initialized or full?
369                 if (!$this->isStackInitialized($stackerName)) {
370                         // Throw an exception
371                         throw new NoStackerException(array($this, $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
372                 } elseif ($this->isStackEmpty($stackerName)) {
373                         // Throw an exception
374                         throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
375                 }
376
377                 // Now get the first value
378                 $this->partialStub('stackerName=' . $stackerName);
379                 $value = NULL;
380
381                 // Return it
382                 return $value;
383         }
384
385         /**
386          * "Pops" last entry from stack
387          *
388          * @param       $stackerName    Name of the stack
389          * @return      $value                  Value "poped" from array
390          * @throws      NoStackerException      If the named stacker was not found
391          * @throws      EmptyStackerException   If the named stacker is empty
392          */
393         protected function popLast ($stackerName) {
394                 // Is the stack not yet initialized or full?
395                 if (!$this->isStackInitialized($stackerName)) {
396                         // Throw an exception
397                         throw new NoStackerException(array($this, $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
398                 } elseif ($this->isStackEmpty($stackerName)) {
399                         // Throw an exception
400                         throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
401                 }
402
403                 // Now, remove the last entry, we don't care about the return value here, see elseif() block above
404                 $this->partialStub('stackerName=' . $stackerName);
405                 return NULL;
406         }
407
408         /**
409          * "Pops" first entry from stack
410          *
411          * @param       $stackerName    Name of the stack
412          * @return      $value                  Value "shifted" from array
413          * @throws      NoStackerException      If the named stacker was not found
414          * @throws      EmptyStackerException   If the named stacker is empty
415          */
416         protected function popFirst ($stackerName) {
417                 // Is the stack not yet initialized or full?
418                 if (!$this->isStackInitialized($stackerName)) {
419                         // Throw an exception
420                         throw new NoStackerException(array($this, $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
421                 } elseif ($this->isStackEmpty($stackerName)) {
422                         // Throw an exception
423                         throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
424                 }
425
426                 // Now, remove the last entry, we don't care about the return value here, see elseif() block above
427                 $this->partialStub('stackerName=' . $stackerName);
428                 return NULL;
429         }
430 }
431
432 // [EOF]
433 ?>