eirrepo Explanation

The code of eirrepo is a tiny SDK. There are multiple purposes each of which I grant a category. We are mainly talking about the common/ subfolder.

Memory Management

The sliceOfData class (MemoryRaw.h) is meant to be a model representation of memory occupation. It is used to intersect data against each other to prevent overlapping memory. For that we have the intersectWith method. By passing another sliceOfData instance you can check for multiple intersection states. Let’s assume a call A.intersectWith( B )

  • INTERSECT_EQUAL: both slices are the same
  • INTERSECT_INSIDE: A is inside B
  • INTERSECT_BORDER_START: starting point of A is being overlapped by B
  • INTERSECT_BORDER_END: ending point of A is being overlapped by B
  • INTERSECT_ENCLOSING: A is enclosing B
  • INTERSECT_FLOATING_START: A is before B
  • INTERSECT_FLOATING_END: A is after B

The FirstPassAllocationSemantics class (MemoryUtils.h) uses sliceOfData to implement overlapping-free allocation logic. Using FindSpace method you can locate a spot to put data at. Using ObtainSpaceAt you can verify if a certain location is free for taking. Note that the class is entirely made of static methods. This is because the storage of allocation information is left for the user. A typical implementation is the CollisionlessBlockAllocator class which stores the data in a linked-list.

The StaticPluginClassFactory class (MemoryUtils.h) allows you to create instances of a C++ struct that can be extended by third-party logic. It is done by increasing the struct instance size and registering offsets into the extended data. This way implementation specific variables can be hidden from global code. Plugin data is managed by the AnonymousPluginStructRegistry class.

DynamicTypeSystem

The DynamicTypeSystem class (in its own header) is a RTTI implementation. The advantage over compiler-given RTTI is that DTS supports plugins for types. Just like for StaticPluginClassFactory this can be used to add logic whose implementation should be hidden from general code. Another typical use is trimming down struct size by not allocating threading-support variables in a single-threaded configuration.

Supported features are checking for type equality, creating a type hierarchy, extending types with plugins and object creation/cloning/destruction. DTS can be sophistically configured to allow per-object size by runtime configuration during creation, by using the conditionalStructRegistryFlavor class.

Stream logic

The BoundedBufferOperations class (MemoryUtils.stream.h) is used to simulate a seek-able memory block that can be dynamically truncated. It is used by the memoryBufferStream class which is a basic implementation. By providing it with a stream memory manager of custom type you can perform filestream-like logic on the memory. In the BasicMemStream namespace you can find an implementation that uses CRT heap memory.

Paging

The NativePageAllocator class (OSUtils.h) is a OS-specific implementation of virtual memory management. Given an endless virtual memory space this class can create handles into it aligned by pages so that smaller memory can be allocated into those pages. This is the foundation of every heap memory allocator. It does not depend on the CRT.

It is necessary to use this class because virtual memory implementation of operating systems are not trivial. In general an allocation granularity of 1024bytes is desired but on Windows memory is served in 16KB chunks on modern systems.

Double-linked list

The RwList class (rwlist.hpp) is an sentinel-based implementation of linked lists. This has been used inside RenderWare and Savage: The Battle for Newerth. The macros LIST_APPEND, LIST_INSERT, LIST_REMOVE, LIST_CLEAR and LIST_EMPTY are commonly used with it. Please note that appending means adding before a node, inserting means adding after a node (i.e. node being the sentinel).

Endianness

The endian::little_endian and endian::big_endian template structs (Endian.h) are used to handle processor integers of a certain byte ordering. It makes sense to use native numbers in program code but serialize things using correct endianess. The moving of data is optimized using compiler intrinsics.

Unicode

The character_env class (UniChar.h) is used to parse character streams by unicode code points. This is a numeric value that undoubtedly describes an Unicode character (32bit). The codepoint_exception class is thrown if any parsing error occurs. Unicode code points can also be re-encoded into either UTF-typed or ANSI-typed strings.