* 23.11.2006: A small but significant step towards the true usability.
* 20.09.2006: Ported to Turbo Delphi.
* 13.09.2006: Resolved the conflict with Lazarus that prevented its code completion and Ctrl-click browsing from working.
* 01.09.2006: adressed one issue related to the usage convenience B).
* 31.08.2006: 4 bugs corrected, one of them severe ops:

Project page on SourceForge.net >>

It always irked me that every time you add a new data structure, you need to spend a lot of effort on the boring, non-creative background work of creating the save/load mechanism for it - if you wish it stay persistent. And the published properties are no help. Mainly because there is no mechanism to check if you forgot to include something.

I spent two months resolving exactly the problem of storing complex data structures and backward compatibility of data files. The main idea that all used types are registered, and divided to "binary" (which are saved/loaded as is) and "complex" (each has a custom loading/saving procedure). Then all fields are registered. While saving, all the adjacent "binary" fields are saved as a solid block of bytes, and for all the "complex" fields a corresponding procedure is called. For the string, for example, it first stores the length, then, if the string isn't empty, its contents - and so on.

Cross-links and circular object referencesa are resolved automatically.

Well, aood test example can say more than a thousand docs: feel free to play with it


Content of the Readme file:
Code:
1. This stuff was roughly cut from my game engine.
   Hence many extraneous stub functions.

2. The documentation is built into the mo_classes unit
   in the form of comments. See also the *.inc files
   it uses.

3. I should add that average saving/loading speed
   of 1.000.000 objects per second is quite real.
   This stuf is *fast*.

4. The {$minenumsize 4} directive in your program
   is ABSOLUTELY NECESSARY. Do not forget it, 
   or you'll get the corrupt data files that will give
   you free AVs instead of backward compatibility.

5. The AddLog() and Die() procedure variations
   in the mo_stubs_public.inc are a temporary stubs
   using  WriteLn(). You should replace these with
   your own code for displaying log/ error messages.

   The glUint and glFloat types are re defined in 
   mo_tmid_public.h - remove these if you plan 
   to use OpenGL.


6. The following files are taken directly from my
   engine (i.e. these are *shared* files) and thus
   are subject to modification without notice.
   Do not modify them if you want to keep your 
   version up to date (The updated versions may be
   "borrowed" from my CGE distributions, starting
   from the version included with the Test #13
   (NOT Test #12 or below!). As I write these lines,
   the Test #13 is not out yet.
   For example, my future plans include adding
   the compression of data files.

      cl_cfile_func.inc  
      cl_keys.inc
      mo_basket.inc
      mo_classes.pp
      mo_dyna.h
      mo_dyna.inc
      mo_dyna_1template.h
      mo_dyna_1template.inc
      mo_dyna_2template.h
      mo_registrator.inc
      mo_scenario.inc
      mo_trulypersistent.inc
      mo_typeprocs.inc

   the home of CGE is 
       http://chebmaster.narod.ru/cge/cge_e.html

7. The correct one approach is to use classes.
   The record types are not allowed (yet).

8. The mechanism of matching enumerated types by
   their value names is quite powerful, as you 
   can see. You can swap the valuse by places,
   add new ones at the beginning - the converter
   will always assign the correct one. Note, that
   if you *delete* the value, it will be replaced
   at loading with the value which ord() is 0.

9.The object structure can be cross-linked, 
   can contain circular references - the 
   processing mechanism will resolve everything
   automatically (although you may want to raise 
   the stack limit, because the alghoritm is
   recursive). 
   And do NOT touch the _BasketIndex field, or 
   things will go kaboom.

10.The built-in validator checks if the registered
   fields cover the entire instance, alsso if 
   there are any gaps between them, and gives
   comprehensible error messages, refusing to run
   if some clas is registered incorrectly.
[/b]