1 /*
2 
3 *************************************************************************
4 
5 ArmageTron -- Just another Tron Lightcycle Game in 3D.
6 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
7 
8 **************************************************************************
9 
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23 
24 ***************************************************************************
25 
26 */
27 
28 #ifndef     TRECORDER_H_INCLUDED
29 #define     TRECORDER_H_INCLUDED
30 
31 #ifdef DEBUG
32 #ifndef DEBUG_DIFFERENCE
33 #define DEBUG_DIFFERENCE
34 #endif
35 #endif
36 
37 // self include
38 #ifndef     TRECORDER_H_INCLUDED
39 #include    "tRecorder.h"
40 #endif
41 
42 #include    "tString.h"
43 
44 // #include    "tRecorderInternal.h"
45 
46 // *****************************************************************************
47 // Helpers required to work around VisualC's iability to handle out-of-line
48 // template members. Just ignore them.
49 // *****************************************************************************
50 
51 //! recording funtions that take one piece of data
52 template< class BLOCK >
53 class tRecorderTemplate1
54 {
55 public:
56     static bool Archive( bool strict, char const * section );                  //!< Archives an empty section
57 };
58 
59 //! recording funtions that take two pieces of data
60 template< class BLOCK, typename DATA >
61 class tRecorderTemplate2
62 {
63 public:
64     static bool Archive( bool strict, char const * section, DATA data );                  //!< Archives a section with one piece of data
65 };
66 
67 //! recording funtions that take two pieces of data and a block
68 template< class BLOCK, typename DATA1, typename DATA2 >
69 class tRecorderTemplate3
70 {
71 public:
72     static bool Archive( bool strict, char const * section, DATA1 data1, DATA2 data2 );  //!< Archives a section with two pieces of data
73 };
74 
75 // *****************************************************************************
76 // tRecorder: simple recording interface. Most users will only need this.
77 // *****************************************************************************
78 
79 class tRecordingBlock;
80 class tPlaybackBlock;
81 
82 //! non-templated base class of recorder
83 class tRecorderBase
84 {
85 public:
86     static bool IsRecording();                          //!< returns whether there is a recording running
87     static bool IsPlayingBack();                        //!< returns whether there is a playback running
88     static bool IsRunning();                            //!< returns whether recording or playback are running
89 };
90 
91 //! simple interface to recording functionality
92 class tRecorder: public tRecorderBase
93 {
94 public:
95     static bool Record( char const * section );         //!< Records an empty section
96     static bool Playback( char const * section );       //!< Plays back an empty section
97     static bool PlaybackStrict( char const * section ); //!< Plays back an empty section, making sure it exists in the recording
98 
99     //! Records a section with one piece of data
100     template< class DATA >
Record(char const * section,DATA const & data)101     static bool Record  ( char const * section, DATA const & data )
102     { return tRecorderTemplate2< tRecordingBlock, DATA const & >::Archive( false, section, data ); }
103 
104     //! Plays back a section with one piece of data
105     template< class DATA >
Playback(char const * section,DATA & data)106     static bool Playback( char const * section, DATA & data )
107     { return tRecorderTemplate2< tPlaybackBlock, DATA & >::Archive( false, section, data ); }
108 
109     //! Plays back a section with one piece of data, making sure it exists in the recording
110     template< class DATA >
PlaybackStrict(char const * section,DATA & data)111     static bool PlaybackStrict( char const * section, DATA & data )
112     { return tRecorderTemplate2< tPlaybackBlock, DATA & >::Archive( true, section, data ); }
113 
114     //! Records a section with two pieces of data
115     template< class DATA1, class DATA2 >
Record(char const * section,DATA1 const & data1,DATA2 const & data2)116     static bool Record( char const * section, DATA1 const & data1, DATA2 const & data2 )
117     { return tRecorderTemplate3< tRecordingBlock, DATA1 const & , DATA2 const & >::Archive( false, section, data1, data2 ); }
118 
119     //!< Plays back a section with two pieces of data
120     template< class DATA1, class DATA2 >
Playback(char const * section,DATA1 & data1,DATA2 & data2)121     static bool Playback( char const * section, DATA1 & data1, DATA2 & data2 )
122     { return tRecorderTemplate3< tPlaybackBlock, DATA1 &, DATA2 & >::Archive( false, section, data1, data2 ); }
123 
124     //! Plays back a section with two pieces of data, making sure it exists in the recording
125     template< class DATA1, class DATA2 >
PlaybackStrict(char const * section,DATA1 & data1,DATA2 & data2)126     static bool PlaybackStrict( char const * section, DATA1 & data1, DATA2 & data2 )
127     { return tRecorderTemplate3< tPlaybackBlock, DATA1 &, DATA2 & >::Archive( true, section, data1, data2 ); }
128 };
129 
130 class tPath;
131 
132 //! text file loading recorder
133 class tTextFileRecorder: public tRecorderBase
134 {
135 public:
136     tTextFileRecorder();
137     ~tTextFileRecorder();
138 
139     //! opens a text file for reading
140     bool Open( tPath const & searchPath, char const * fileName );
141 
142     //! constructor, opening a file directly (status can be queried later with EndOfFile)
143     tTextFileRecorder( tPath const & searchPath, char const * fileName );
144 
145     //! end of file query
146     bool EndOfFile() const;
147 
148     //! read one line, give it back as a stream
149     std::string GetLine();
150 private:
151     // disable copying
152     tTextFileRecorder(tTextFileRecorder const &);
153     tTextFileRecorder & operator = (tTextFileRecorder const &);
154 
155     std::ifstream * stream_; //! the real stream to read from
156     bool eof_;               //! flag indicating end of file
157 };
158 
159 //! typedef for easier handling
160 // typedef tRecorderTemplate<int> tRecorder;
161 
162 // *****************************************************************************
163 // helper classes for converting data before it gets archived
164 // *****************************************************************************
165 
166 //! type modifying class mapping types in memory to types to stream
167 template< class T > struct tTypeToStream
168 {
169     typedef T TOSTREAM;             //!< type to put into the stream
170     typedef int DUMMYREQUIRED;      //!< change this type to "int *" to indicate the conversion is required
171 };
172 
173 //! macro declaring that type TYPE should be converted to type STREAM before
174 // recording (and back after playback) by specializing the tTypeToStream class template
175 #define tRECORD_AS( TYPE, STREAM ) \
176 template<> struct tTypeToStream< TYPE > \
177 { \
178     typedef STREAM TOSTREAM; \
179   typedef int * DUMMYREQUIRED; \
180 } \
181 
182 //! macro for recording enums: convert them to int.
183 #define tRECORDING_ENUM( TYPE ) tRECORD_AS( TYPE, int )
184 
185 // record chars as ints for human readability
186 tRECORD_AS( char, int );
187 tRECORD_AS( unsigned char, int );
188 
189 //! persistable string class
190 class tLineString: public tString
191 {
192 public:
193     tLineString( tString const & ); //! copy constructor
194     tLineString();                  //! default constructor
195     ~tLineString();                 //! destructor
196 };
197 
198 //! persistent string writing operator
199 std::ostream & operator << ( std::ostream & s, tLineString const & line );
200 
201 //! persistent string reading operator
202 std::istream & operator >> ( std::istream & s, tLineString & line );
203 
204 //! record strings as line strings
205 tRECORD_AS( tString, tLineString );
206 
207 // *****************************************************************************
208 // support for debugging only recording (for intermediate data)
209 // *****************************************************************************
210 
211 //! debug recording synchronization test class
212 class tRecorderSyncBase
213 {
214 public:
215     //! returns the current debug level of the playback
216     static int GetDebugLevelPlayback();
217 
218     //! returns the current debug level of the recording
219     static int GetDebugLevelRecording();
220 };
221 
222 //! debug recording synchronization test class
223 template< class DATA >
224 class tRecorderSync: public tRecorderSyncBase
225 {
226 public:
227     //! Archives a bit of data for reference
228     static void Archive( char const * section, int debugLevel, DATA & data );
229 
230 private:
231     //! Calculates a suitable difference between two bits of data
232     static float GetDifference( DATA const & a, DATA const & b );
233 };
234 
235 // *****************************************************************************
236 // another helper class
237 // *****************************************************************************
238 
239 //! class taking the ugly implementation part of tRecordingBlock and tPlaybackBlock
240 template < class DATA > class tRecorderBlockHelper
241 {
242 public:
243     static void Write ( std::ostream & stream, DATA const & data, int nodummyrequired );        //!< writes a piece of data using a dummy
244     static void Write ( std::ostream & stream, DATA const & data, int * dummyrequired );        //!< writes a piece of data using a dummy
245 
246     static void Read  ( std::istream & stream, DATA & data, int nodummyrequired );        //!< reads a piece of data using a dummy
247     static void Read  ( std::istream & stream, DATA & data, int * dummyrequired );        //!< reads a piece of data using a dummy
248 };
249 
250 // *****************************************************************************
251 // recording blocks for stuffing more data inside a section than two elements
252 // *****************************************************************************
253 
254 class tRecording;
255 
256 //! a block of data to record (for more advanced data storage ), base class
257 class tRecordingBlockBase
258 {
259 public:
260     bool Initialize( char const * section, tRecording * recording );  //!< initializes this for recording
261     bool Initialize( char const * section );                          //!< initializes this for recording
262 
263     void Separator();                                                 //!< separates two recorded elements (more than usual)
264     static tRecording * GetArchive();                                 //!< returns the active recording
265 protected:
266     tRecordingBlockBase();                                            //!< default constructor
267     ~tRecordingBlockBase();                                           //!< ends a recording block
268 
269     std::ostream & GetRecordingStream() const;                        //!< returns the stream to record to
270 
271     bool separate_;                                                   //!< flag indicating whether a separation is needed before the next data element
272 private:
273     tRecording * recording_;                                          //!< the recording to record to
274 };
275 
276 //! a block of data to record (for more advanced data storage ), implementation
277 class tRecordingBlock: public tRecordingBlockBase
278 {
279 public:
280     tRecordingBlock();                                                     //!< default constructor
281     ~tRecordingBlock();                                                    //!< ends a recording block
282 
283     //! writes a piece of data
284     template< class T > tRecordingBlock & operator << ( T const & data ) { return Write( data ); }
285 
286     //! writes a piece of data
Archive(T const & data)287     template< class T > tRecordingBlock & Archive     ( T const & data ) { return Write( data ); }
288 
289     //! writes a piece of data
Write(T const & data)290     template< class T > tRecordingBlock & Write       ( T const & data )
291     {
292         // get stream
293         std::ostream & stream = GetRecordingStream();
294 
295         // add separator
296         if ( separate_ )
297             stream << ' ';
298         separate_ = true;
299 
300         // delegate to dummy using or dummyless function
301         typename tTypeToStream< T >::DUMMYREQUIRED dummyRequired = 0;
302         tRecorderBlockHelper< T >::Write( stream, data, dummyRequired );
303 
304         return *this;
305     }
306 };
307 
308 // *****************************************************************************
309 
310 class tPlayback;
311 
312 //! a block of data to play back.
313 class tPlaybackBlockBase
314 {
315 public:
316     bool Initialize( char const * section, tPlayback * playback );    //!< initializes this for recording
317     bool Initialize( char const * section );                          //!< initializes this for recording
318 
319     void Separator() const;                                           //!< separate output (Nothing done here while playing back)
320     static tPlayback * GetArchive();                                  //!< returns the active playback
321 protected:
322     tPlaybackBlockBase();                                             //!< default constructor
323     ~tPlaybackBlockBase();                                            //!< ends a playback block
324 
325     std::istream & GetPlaybackStream() const;                         //!< returns the stream to playback from
326 
327 private:
328     tPlayback * playback_;                                             //!< the playback to read from
329 };
330 
331 //! a block of data to play back.
332 class tPlaybackBlock: public tPlaybackBlockBase
333 {
334 public:
335     tPlaybackBlock();                                         //!< default constructor
336     ~tPlaybackBlock();                                        //!< ends a playback block
337 
338     //!< reads a piece of data
339     template< class T > tPlaybackBlock & operator >> ( T & data ){ return Read( data ); }
340 
341     //!< reads a piece aof data
Archive(T & data)342     template< class T > tPlaybackBlock & Archive     ( T & data ){ return Read( data ); }
343 
344     //!< reads a piece of data
Read(T & data)345     template< class T > tPlaybackBlock & Read        ( T & data )
346     {
347         // delegate to dummy using or dummyless function
348         typename tTypeToStream< T >::DUMMYREQUIRED dummyrequired = 0;
349         tRecorderBlockHelper< T >::Read( GetPlaybackStream(), data, dummyrequired );
350 
351         return *this;
352     }
353 };
354 
355 //! typedefs for easier handling
356 // typedef tRecordingBlockTemplate< int > tRecordingBlock;
357 // typedef tPlaybackBlockTemplate< int > tPlaybackBlock;
358 
359 // Note: both tRecordingBlock and tPlaybackBlock share common mebe fuctions. See uInputQueue.cpp
360 // (or the tRecorderTemplate::Archive implementation) how to
361 // exploit this with templates to make sure you read exaclty the same data as you write.
362 
363 // *****************************************************************************
364 // * Implementation
365 // *****************************************************************************
366 
367 /*
368 
369 // *******************************************************************************************
370 // *
371 // *    Record
372 // *
373 // *******************************************************************************************
374 //!
375 //!     @param  section the name of the section to record or play back
376 //!     @param  data            the data to archive
377 //!     @return   true on success
378 //!
379 // *******************************************************************************************
380 
381 template< class DUMMY  >
382 template<  class DATA >
383 bool tRecorderTemplate< DUMMY >::Record( char const * section, DATA const & data )
384 {
385     // delegate
386     return Archive< tRecordingBlock >( false, section, data );
387 }
388 
389 // *******************************************************************************************
390 // *
391 // *    Playback
392 // *
393 // *******************************************************************************************
394 //!
395 //!     @param  section the name of the section to record or play back
396 //!     @param  data            the data to archive
397 //!     @return   true on success
398 //!
399 // *******************************************************************************************
400 
401 template< class DUMMY  >
402 template<  class DATA >
403 bool tRecorderTemplate< DUMMY >::Playback( char const * section, DATA & data )
404 {
405     // delegate
406     return Archive< tPlaybackBlock >( false, section, data );
407 }
408 
409 // *******************************************************************************************
410 // *
411 // *    PlaybackStrict
412 // *
413 // *******************************************************************************************
414 //!
415 //!     @param  section the name of the section to record or play back
416 //!     @param  data            the data to archive
417 //!     @return   true on success
418 //!
419 // *******************************************************************************************
420 
421 template< class DUMMY  >
422 template<  class DATA >
423 bool tRecorderTemplate< DUMMY >::PlaybackStrict( char const * section, DATA & data )
424 {
425     // delegate
426     return Archive< tPlaybackBlock >( true, section, data );
427 }
428 
429 // *******************************************************************************************
430 // *
431 // *    Record
432 // *
433 // *******************************************************************************************
434 //!
435 //!     @param  section the name of the section to record or play back
436 //!     @param  data1    first bit of data to archive
437 //!     @param  data2    second bit of data to archive
438 //!     @return   true on success
439 //!
440 // *******************************************************************************************
441 
442 template< class DUMMY  >
443 template<  class DATA1, class DATA2 >
444 bool tRecorderTemplate< DUMMY >::Record( char const * section, DATA1 const & data1, DATA2 const & data2 )
445 {
446     // delegate
447     return Archive< tRecordingBlock >( false, section, data1, data2 );
448 }
449 
450 // *******************************************************************************************
451 // *
452 // *    Playback
453 // *
454 // *******************************************************************************************
455 //!
456 //!     @param  section the name of the section to record or play back
457 //!     @param  data1    first bit of data to archive
458 //!     @param  data2    second bit of data to archive
459 //!     @return   true on success
460 //!
461 // *******************************************************************************************
462 
463 template< class DUMMY  >
464 template<  class DATA1, class DATA2 >
465 bool tRecorderTemplate< DUMMY >::Playback( char const * section, DATA1 & data1, DATA2 & data2 )
466 {
467     // delegate
468     return Archive< tPlaybackBlock >( false, section, data1, data2 );
469 }
470 
471 // *******************************************************************************************
472 // *
473 // *    PlaybackStrict
474 // *
475 // *******************************************************************************************
476 //!
477 //!     @param  section the name of the section to record or play back
478 //!     @param  data1    first bit of data to archive
479 //!     @param  data2    second bit of data to archive
480 //!     @return   true on success
481 //!
482 // *******************************************************************************************
483 
484 template< class DUMMY  >
485 template<  class DATA1, class DATA2 >
486 bool tRecorderTemplate< DUMMY >::PlaybackStrict( char const * section, DATA1 & data1, DATA2 & data2 )
487 {
488     // delegate
489     return Archive< tPlaybackBlock >( true, section, data1, data2 );
490 }
491 
492 // *******************************************************************************************
493 // *
494 // *    Archive
495 // *
496 // *******************************************************************************************
497 //!
498 //!     @param  strict
499 //!     @param  section the name of the section to record or play back
500 //!     @return   true on success
501 //!
502 // *******************************************************************************************
503 
504 template< class DUMMY  >
505 template<  class BLOCK >
506 bool tRecorderTemplate< DUMMY >::Archive( bool strict, char const * section )
507 {
508     // create recording/playback block
509     BLOCK block;
510 
511     // initialize
512     if ( block.Initialize( section ) )
513     {
514         // return success
515         return true;
516     }
517 
518     // report failure
519     tASSERT( !strict  || !BLOCK::GetArchive() );
520     return false;
521 }
522 
523 // *******************************************************************************************
524 // *
525 // *    Archive
526 // *
527 // *******************************************************************************************
528 //!
529 //!     @param  strict
530 //!     @param  section the name of the section to record or play back
531 //!     @param  data
532 //!     @return   true on success
533 //!
534 // *******************************************************************************************
535 
536 template< class DUMMY  >
537 template<  class BLOCK, class DATA >
538 bool tRecorderTemplate< DUMMY >::Archive( bool strict, char const * section, DATA & data )
539 {
540     // create recording/playback block
541     BLOCK block;
542 
543     // initialize
544     if ( block.Initialize( section ) )
545     {
546         // successfully initialized: archive data
547         block.Archive( data );
548 
549         // return success
550         return true;
551     }
552 
553     // report failure
554     tASSERT( !strict || !BLOCK::GetArchive() );
555     return false;
556 }
557 
558 // *******************************************************************************************
559 // *
560 // *    Archive
561 // *
562 // *******************************************************************************************
563 //!
564 //!     @param  strict
565 //!     @param  section the name of the section to record or play back
566 //!     @param  data1    first bit of data to archive
567 //!     @param  data2    second bit of data to archive
568 //!     @return   true on success
569 //!
570 // *******************************************************************************************
571 
572 template< class DUMMY  >
573 template<  class BLOCK, class DATA1, class DATA2 >
574 bool tRecorderTemplate< DUMMY >::Archive( bool strict, char const * section, DATA1 & data1, DATA2 & data2 )
575 {
576     // create recording/playback block
577     BLOCK block;
578 
579     // initialize
580     if ( block.Initialize( section ) )
581     {
582         // successfully initialized: archive data
583         block.Archive( data1 ).Archive( data2 );
584 
585         // return success
586         return true;
587     }
588 
589     // report failure
590     tASSERT( !strict  || !BLOCK::GetArchive() );
591     return false;
592 }
593 
594 // *******************************************************************************************
595 // *******************************************************************************************
596 // *******************************************************************************************
597 // *******************************************************************************************
598 
599 // *******************************************************************************************
600 // *
601 // *    tRecordingBlockTemplate
602 // *
603 // *******************************************************************************************
604 //!
605 //!
606 // *******************************************************************************************
607 
608 template< class DUMMY >
609 tRecordingBlockTemplate< DUMMY >::tRecordingBlockTemplate( void )
610 {
611 }
612 
613 // *******************************************************************************************
614 // *
615 // *    ~tRecordingBlockTemplate
616 // *
617 // *******************************************************************************************
618 //!
619 //!
620 // *******************************************************************************************
621 
622 template< class DUMMY >
623 tRecordingBlockTemplate< DUMMY >::~tRecordingBlockTemplate( void )
624 {
625 }
626 
627 // *******************************************************************************************
628 // *
629 // *    operator <<
630 // *
631 // *******************************************************************************************
632 //!
633 //!     @param  data            the data to archive
634 //!     @return     reference to this for chaining
635 //!
636 // *******************************************************************************************
637 
638 template< class DUMMY  >
639 template<  class T >
640 tRecordingBlockTemplate< DUMMY > & tRecordingBlockTemplate< DUMMY >::operator <<( T const & data )
641 {
642     // delegate
643     return Write( data );
644 }
645 
646 // *******************************************************************************************
647 // *
648 // *    Archive
649 // *
650 // *******************************************************************************************
651 //!
652 //!     @param  data            the data to archive
653 //!     @return     reference to this for chaining
654 //!
655 // *******************************************************************************************
656 
657 template< class DUMMY  >
658 template<  class T >
659 tRecordingBlockTemplate< DUMMY > & tRecordingBlockTemplate< DUMMY >::Archive( T const & data )
660 {
661     // delegate
662     return Write( data );
663 }
664 
665 // *******************************************************************************************
666 // *
667 // *    Write
668 // *
669 // *******************************************************************************************
670 //!
671 //!     @param  data            the data to archive
672 //!     @return     reference to this for chaining
673 //!
674 // *******************************************************************************************
675 
676 template< class DUMMY  >
677 template<  class T >
678 tRecordingBlockTemplate< DUMMY > & tRecordingBlockTemplate< DUMMY >::Write( T const & data )
679 {
680     // get stream
681     std::ostream & stream = GetRecordingStream();
682 
683     // add small separator
684     if (separate_)
685         stream << ' ';
686     separate_ = true;
687 
688     // delegate to dummy using or dummyless function
689     typename tTypeToStream< T >::DUMMYREQUIRED dummyrequired = 0;
690     Write( data, dummyrequired );
691 
692     return *this;
693 }
694 
695 // *******************************************************************************************
696 // *
697 // *    Write
698 // *
699 // *******************************************************************************************
700 //!
701 //!     @param  data            the data to archive
702 //!     @param  nodummyrequired dummy parameter indicating by type that no conversion is required
703 //!
704 // *******************************************************************************************
705 
706 template< class DUMMY  >
707 template<  class T >
708 void tRecordingBlockTemplate< DUMMY >::Write( T const & data, int nodummyrequired )
709 {
710     // get stream
711     std::ostream & stream = GetRecordingStream();
712 
713     // add small separator
714     stream << ' ';
715 
716     // write
717     stream << data;
718 
719 }
720 
721 // *******************************************************************************************
722 // *
723 // *    Write
724 // *
725 // *******************************************************************************************
726 //!
727 //!     @param  data            the data to archive
728 //!     @param  dummyrequired   dummy parameter indicating by type that conversion is required
729 //!
730 // *******************************************************************************************
731 
732 template< class DUMMY  >
733 template<  class T >
734 void tRecordingBlockTemplate< DUMMY >::Write( T const & data, int * dummyrequired )
735 {
736     // get stream
737     std::ostream & stream = GetRecordingStream();
738 
739     // write ( converted )
740     typedef typename tTypeToStream< T >::TOSTREAM TOSTREAM;
741     TOSTREAM dummy = static_cast< TOSTREAM >( data );
742     stream << dummy;
743 }
744 
745 // *******************************************************************************************
746 // *******************************************************************************************
747 // *******************************************************************************************
748 // *******************************************************************************************
749 
750 // *******************************************************************************************
751 // *
752 // *    tPlaybackBlockTemplate
753 // *
754 // *******************************************************************************************
755 //!
756 //!
757 // *******************************************************************************************
758 
759 template< class DUMMY >
760 tPlaybackBlockTemplate< DUMMY >::tPlaybackBlockTemplate( void )
761 {
762 }
763 
764 // *******************************************************************************************
765 // *
766 // *    ~tPlaybackBlockTemplate
767 // *
768 // *******************************************************************************************
769 //!
770 //!
771 // *******************************************************************************************
772 
773 template< class DUMMY >
774 tPlaybackBlockTemplate< DUMMY >::~tPlaybackBlockTemplate( void )
775 {
776 }
777 
778 // *******************************************************************************************
779 // *
780 // *    operator >>
781 // *
782 // *******************************************************************************************
783 //!
784 //!     @param  data            the data to archive
785 //!     @return     reference to this for chaining
786 //!
787 // *******************************************************************************************
788 
789 template< class DUMMY  >
790 template<  class T >
791 tPlaybackBlockTemplate< DUMMY > & tPlaybackBlockTemplate< DUMMY >::operator >>( T & data )
792 {
793     // delegate
794     return Read( data );
795 }
796 
797 // *******************************************************************************************
798 // *
799 // *    Archive
800 // *
801 // *******************************************************************************************
802 //!
803 //!     @param  data            the data to archive
804 //!     @return     reference to this for chaining
805 //!
806 // *******************************************************************************************
807 
808 template< class DUMMY  >
809 template<  class T >
810 tPlaybackBlockTemplate< DUMMY > & tPlaybackBlockTemplate< DUMMY >::Archive( T & data )
811 {
812     // delegate
813     return Read( data );
814 }
815 
816 // *******************************************************************************************
817 // *
818 // *    Read
819 // *
820 // *******************************************************************************************
821 //!
822 //!     @param  data            the data to archive
823 //!     @return     reference to this for chaining
824 //!
825 // *******************************************************************************************
826 
827 template< class DUMMY  >
828 template<  class T >
829 tPlaybackBlockTemplate< DUMMY > & tPlaybackBlockTemplate< DUMMY >::Read( T & data )
830 {
831     // delegate to dummy using or dummyless function
832     typename tTypeToStream< T >::DUMMYREQUIRED dummyrequired = 0;
833     Read( data, dummyrequired );
834 
835     return *this;
836 }
837 
838 // *******************************************************************************************
839 // *
840 // *    Read
841 // *
842 // *******************************************************************************************
843 //!
844 //!     @param  data            the data to archive
845 //!     @param  nodummyrequired dummy parameter indicating by type that no conversion is required
846 //!
847 // *******************************************************************************************
848 
849 template< class DUMMY  >
850 template<  class T >
851 void tPlaybackBlockTemplate< DUMMY >::Read( T & data, int nodummyrequired )
852 {
853     // get stream
854     std::istream & stream = GetPlaybackStream();
855     tASSERT( stream.good() );
856 
857     // read
858     stream >> data;
859 }
860 
861 // *******************************************************************************************
862 // *
863 // *    Read
864 // *
865 // *******************************************************************************************
866 //!
867 //!     @param  data            the data to archive
868 //!     @param  dummyrequired   dummy parameter indicating by type that conversion is required
869 //!
870 // *******************************************************************************************
871 
872 template< class DUMMY  >
873 template<  class T >
874 void tPlaybackBlockTemplate< DUMMY >::Read( T & data, int * dummyrequired )
875 {
876     // get stream
877     std::istream & stream = GetPlaybackStream();
878     tASSERT( stream.good() );
879 
880     // read ( with conversion )
881     typedef typename tTypeToStream< T >::TOSTREAM TOSTREAM;
882     TOSTREAM dummy ;
883     stream >> dummy;
884     data = static_cast< T >( dummy );
885 }
886 
887 */
888 
889 // ******************************************************************************************
890 // *
891 // *	Archive
892 // *
893 // ******************************************************************************************
894 //!
895 //!		@param	section	    section to archive to
896 //!		@param	level  	    debug level of the data (lower levels get archived sooner)
897 //!		@param	data	    data to archive
898 //!
899 // ******************************************************************************************
900 
901 template< class DATA >
Archive(char const * section,int level,DATA & data)902 void tRecorderSync< DATA >::Archive( char const * section, int level, DATA & data )
903 {
904     // see if it is really a DEBUG only section
905     tASSERT( section && *section == '_' );
906 
907     if ( level <= GetDebugLevelPlayback() )
908     {
909         DATA copy = data;
910 
911         // read data from archive
912         if ( tRecorder::PlaybackStrict( section, copy ) )
913         {
914 #ifdef DEBUG_DIFFERENCE
915             // determine difference
916             REAL diff = GetDifference( data, copy );
917 
918             static REAL alarmDiff = EPS;
919             if ( diff > alarmDiff )
920             {
921                 alarmDiff = diff * 2;
922                 REAL st_GetDifference( REAL a, REAL b);
923                 REAL st_GetDifference( int a, int b);
924                 REAL st_GetDifference( tString const & a, tString const & b );
925                 std::cout << "Syncing difference found: " << data << "!=" << copy << " by " << diff << "\n";
926                 st_Breakpoint();
927             }
928 #endif
929 
930             // restore data, hoping that the playback can take the little bump
931             if ( level <= GetDebugLevelRecording() )
932             {
933                 data = copy;
934             }
935         }
936         else if ( tRecorder::IsPlayingBack() )
937         {
938             std::cout << "Syncing difference found: expected " << section << ".\n";
939 
940             st_Breakpoint();
941         }
942     }
943 
944     // archive data
945     if ( level <= GetDebugLevelRecording() )
946         tRecorder::Record( section, data );
947 }
948 
949 REAL st_GetDifference( REAL a, REAL b);
950 REAL st_GetDifference( int a, int b);
951 REAL st_GetDifference( unsigned int a, unsigned int b);
952 REAL st_GetDifference( long unsigned int a, long unsigned int b);
953 REAL st_GetDifference( tString const & a, tString const & b );
954 
955 // ******************************************************************************************
956 // *
957 // *	GetDifference
958 // *
959 // ******************************************************************************************
960 //!
961 //!		@param	a	        object a
962 //!		@param	b	        object b
963 //!		@return		        |a-b|, interpreted as appropriate
964 //!
965 // ******************************************************************************************
966 
967 template< class DATA >
GetDifference(DATA const & a,DATA const & b)968 float tRecorderSync< DATA >::GetDifference( DATA const & a, DATA const & b )
969 {
970     return st_GetDifference( a, b );
971 }
972 
973 // ******************************************************************************************
974 // *
975 // *	Archive
976 // *
977 // ******************************************************************************************
978 //!
979 //!     @param  strict  true if the success should be asserted
980 //!     @param  section the name of the section to record or play back
981 //!     @return         true on success
982 //!
983 // ******************************************************************************************
984 
985 template< class BLOCK >
Archive(bool strict,char const * section)986 bool tRecorderTemplate1< BLOCK >::Archive( bool strict, char const * section )
987 {
988     // create recording/playback block
989     BLOCK block;
990 
991     // initialize
992     if ( block.Initialize( section ) )
993     {
994         // return success
995         return true;
996     }
997 
998     // report failure
999     tASSERT( !strict  || !BLOCK::GetArchive() );
1000     return false;
1001 }
1002 
1003 // ******************************************************************************************
1004 // *
1005 // *	Archive
1006 // *
1007 // ******************************************************************************************
1008 //!
1009 //!     @param  strict  true if the success should be asserted
1010 //!     @param  section the name of the section to record or play back
1011 //!     @param  data    bit of data to archive
1012 //!     @return   true on success
1013 //!
1014 // ******************************************************************************************
1015 
1016 template< class BLOCK, typename DATA >
Archive(bool strict,char const * section,DATA data)1017 bool tRecorderTemplate2< BLOCK, DATA >::Archive( bool strict, char const * section, DATA data )
1018 {
1019     // create recording/playback block
1020     BLOCK block;
1021 
1022     // initialize
1023     if ( block.Initialize( section ) )
1024     {
1025         // successfully initialized: archive data
1026         block.Archive( data );
1027 
1028         // return success
1029         return true;
1030     }
1031 
1032     // report failure
1033     tASSERT( !strict || !BLOCK::GetArchive() );
1034     return false;
1035 }
1036 
1037 // ******************************************************************************************
1038 // *
1039 // *	Archive
1040 // *
1041 // ******************************************************************************************
1042 //!
1043 //!     @param  strict  true if the success should be asserted
1044 //!     @param  section the name of the section to record or play back
1045 //!     @param  data1    first bit of data to archive
1046 //!     @param  data2    second bit of data to archive
1047 //!     @return   true on success
1048 //!
1049 // ******************************************************************************************
1050 
1051 template< class BLOCK, typename DATA1, typename DATA2 >
Archive(bool strict,char const * section,DATA1 data1,DATA2 data2)1052 bool tRecorderTemplate3< BLOCK, DATA1, DATA2 >::Archive( bool strict, char const * section, DATA1 data1, DATA2 data2 )
1053 {
1054     // create recording/playback block
1055     BLOCK block;
1056 
1057     // initialize
1058     if ( block.Initialize( section ) )
1059     {
1060         // successfully initialized: archive data
1061         block.Archive( data1 ).Archive( data2 );
1062 
1063         // return success
1064         return true;
1065     }
1066 
1067     // report failure
1068     tASSERT( !strict  || !BLOCK::GetArchive() );
1069     return false;
1070 }
1071 
1072 // ******************************************************************************************
1073 // *
1074 // *	Write
1075 // *
1076 // ******************************************************************************************
1077 //!
1078 //!		@param	stream	        the stream to write to
1079 //!     @param  data            the data to archive
1080 //!     @param  nodummyrequired dummy parameter indicating by type that no conversion is required
1081 //!
1082 // ******************************************************************************************
1083 
1084 template< class DATA >
Write(std::ostream & stream,DATA const & data,int nodummyrequired)1085 void tRecorderBlockHelper< DATA >::Write( std::ostream & stream, DATA const & data, int nodummyrequired )
1086 {
1087     // write
1088     stream << data;
1089 }
1090 
1091 // ******************************************************************************************
1092 // *
1093 // *	Write
1094 // *
1095 // ******************************************************************************************
1096 //!
1097 //!		@param	stream	        the stream to write to
1098 //!     @param  data            the data to archive
1099 //!     @param  dummyrequired   dummy parameter indicating by type that conversion is required
1100 //!
1101 // ******************************************************************************************
1102 
1103 template< class DATA >
Write(std::ostream & stream,DATA const & data,int * dummyrequired)1104 void tRecorderBlockHelper< DATA >::Write( std::ostream & stream, DATA const & data, int * dummyrequired )
1105 {
1106     // write ( converted )
1107     typedef typename tTypeToStream< DATA >::TOSTREAM TOSTREAM;
1108     TOSTREAM dummy = static_cast< TOSTREAM >( data );
1109     stream << dummy;
1110 }
1111 
1112 // ******************************************************************************************
1113 // *
1114 // *	Read
1115 // *
1116 // ******************************************************************************************
1117 //!
1118 //!		@param	stream	        the stream to read from
1119 //!     @param  data            the data to archive
1120 //!     @param  nodummyrequired dummy parameter indicating by type that no conversion is required
1121 //!
1122 // ******************************************************************************************
1123 
1124 template< class DATA >
Read(std::istream & stream,DATA & data,int nodummyrequired)1125 void tRecorderBlockHelper< DATA >::Read( std::istream & stream, DATA & data, int nodummyrequired )
1126 {
1127     tASSERT( stream.good() );
1128 
1129     // read
1130     stream >> data;
1131 }
1132 
1133 // ******************************************************************************************
1134 // *
1135 // *	Read
1136 // *
1137 // ******************************************************************************************
1138 //!
1139 //!		@param	stream	        the stream to read from
1140 //!     @param  data            the data to archive
1141 //!     @param  dummyrequired   dummy parameter indicating by type that conversion is required
1142 //!
1143 // ******************************************************************************************
1144 
1145 template< class DATA >
Read(std::istream & stream,DATA & data,int * dummyrequired)1146 void tRecorderBlockHelper< DATA >::Read( std::istream & stream, DATA & data, int * dummyrequired )
1147 {
1148     tASSERT( stream.good() );
1149 
1150     // read ( with conversion )
1151     typedef typename tTypeToStream< DATA >::TOSTREAM TOSTREAM;
1152     TOSTREAM dummy ;
1153     stream >> dummy;
1154     data = static_cast< DATA >( dummy );
1155 }
1156 
1157 #endif // TRECORDING_H_INCLUDED
1158