Created
April 24, 2022 10:45
-
-
Save brokenprogrammer/3fdbd623186f4c7614b4cae27550644f to your computer and use it in GitHub Desktop.
Implementation of LBP Serializer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // This is a reference implementation that I wrote to understand and to keep my own archive of the LBP Serializer | |
| // as well as to try it out before using it within Brainroll. | |
| // Oswald Hurlem presents this in his article: https://yave.handmade.network/blog/p/2723-how_media_molecule_does_serialization | |
| // Credit goes to him and of course the people at Media Molecule. | |
| // | |
| // This implementation also briefly showcases the example use of CHECK_INTEGRITY which you can place in places | |
| // where it makes sense for you. | |
| // | |
| // Build with: cl.exe -nologo /Zi /FC LBPSerialization.cpp /link -opt:ref -incremental:no /Debug:full /out:lbp.exe | |
| #include <stdlib.h> | |
| #include <stdint.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <time.h> | |
| #include <assert.h> | |
| struct lbp_serializer | |
| { | |
| uint32_t DataVersion; | |
| FILE *FilePointer; | |
| bool IsWriting; | |
| int32_t Counter; | |
| }; | |
| enum serialization_versions : int32_t | |
| { | |
| SV_Initial = 1, | |
| SV_FirstRevision, | |
| SV_AddIntegrityChecks, | |
| // Keep this as the last element | |
| SV_LatestPlusOne, | |
| }; | |
| #define LATEST_VERSION (SV_LatestPlusOne - 1) | |
| #define ADD(_FieldAdded, _FieldName) \ | |
| if (LBPSerializer->DataVersion >= (_FieldAdded)) \ | |
| { \ | |
| Serialize(LBPSerializer, &(Datum->_FieldName)); \ | |
| } | |
| #define REM(_FieldAdded, _FieldRemoved, _Type, _FieldName, _DefaultValue) \ | |
| _Type _FieldName = (_DefaultValue); \ | |
| if (LBPSerializer->DataVersion >= (_FieldAdded) && \ | |
| LBPSerializer->DataVersion < (_FieldRemoved)) \ | |
| { \ | |
| Serialize(LBPSerializer, &(_FieldName)); \ | |
| } | |
| #define CHECK_INTEGRITY(_CheckAdded) \ | |
| if (LBPSerializer->DataVersion >= (_CheckAdded)) \ | |
| { \ | |
| int32_t Check = LBPSerializer->Counter; \ | |
| Serialize(LBPSerializer, &Check); \ | |
| assert(Check == LBPSerializer->Counter++); \ | |
| } | |
| static void | |
| Serialize(lbp_serializer *LBPSerializer, int32_t *Datum) | |
| { | |
| if (LBPSerializer->IsWriting) | |
| { | |
| fwrite(Datum, sizeof(uint32_t), 1, LBPSerializer->FilePointer); | |
| } | |
| else | |
| { | |
| fread(Datum, sizeof(uint32_t), 1, LBPSerializer->FilePointer); | |
| } | |
| } | |
| static void | |
| Serialize(lbp_serializer *LBPSerializer, uint32_t *Datum) | |
| { | |
| if (LBPSerializer->IsWriting) | |
| { | |
| fwrite(Datum, sizeof(uint32_t), 1, LBPSerializer->FilePointer); | |
| } | |
| else | |
| { | |
| fread(Datum, sizeof(uint32_t), 1, LBPSerializer->FilePointer); | |
| } | |
| } | |
| static void | |
| Serialize(lbp_serializer *LBPSerializer, int64_t *Datum) | |
| { | |
| if (LBPSerializer->IsWriting) | |
| { | |
| fwrite(Datum, sizeof(int64_t), 1, LBPSerializer->FilePointer); | |
| } | |
| else | |
| { | |
| fread(Datum, sizeof(int64_t), 1, LBPSerializer->FilePointer); | |
| } | |
| } | |
| static void | |
| Serialize(lbp_serializer *LBPSerializer, uint64_t *Datum) | |
| { | |
| if (LBPSerializer->IsWriting) | |
| { | |
| fwrite(Datum, sizeof(uint64_t), 1, LBPSerializer->FilePointer); | |
| } | |
| else | |
| { | |
| fread(Datum, sizeof(uint64_t), 1, LBPSerializer->FilePointer); | |
| } | |
| } | |
| struct my_state | |
| { | |
| int32_t Health; | |
| uint32_t Score; | |
| int64_t Weight; | |
| uint64_t DistanceTraveled; | |
| }; | |
| static void | |
| Serialize(lbp_serializer *LBPSerializer, my_state *Datum) | |
| { | |
| ADD(SV_Initial, Health); | |
| ADD(SV_Initial, Score); | |
| ADD(SV_FirstRevision, Weight); | |
| ADD(SV_FirstRevision, DistanceTraveled); | |
| CHECK_INTEGRITY(SV_AddIntegrityChecks); | |
| } | |
| static bool | |
| SerializeIncludingVersion(lbp_serializer *LBPSerializer, my_state *MyState) | |
| { | |
| if (LBPSerializer->IsWriting) | |
| { | |
| LBPSerializer->DataVersion = LATEST_VERSION; | |
| } | |
| Serialize(LBPSerializer, &LBPSerializer->DataVersion); | |
| if (LBPSerializer->DataVersion > (LATEST_VERSION)) | |
| { | |
| // NOTE(Oskar): Attempt to read from newer version. | |
| return false; | |
| } | |
| else | |
| { | |
| Serialize(LBPSerializer, MyState); | |
| return true; | |
| } | |
| } | |
| static void | |
| InitializeState(my_state *State) | |
| { | |
| State->Health = 0; | |
| State->Score = 0; | |
| State->Weight = (0x7fffffff) + 1; | |
| State->DistanceTraveled = (uint64_t) -1; | |
| } | |
| static void | |
| RandomizeState(my_state *State) | |
| { | |
| State->Health = rand(); | |
| State->Score = -1; | |
| State->Weight = (0x7fffffff) + rand(); | |
| State->DistanceTraveled = (uint64_t) -1; | |
| } | |
| static void | |
| PrintState(my_state *State) | |
| { | |
| printf("\nState:\n"); | |
| printf("Health: %d\n", State->Health); | |
| printf("Score: %ud\n", State->Score); | |
| printf("Weight: %lld\n", State->Weight); | |
| printf("DistanceTraveled: %I64u\n", State->DistanceTraveled); | |
| } | |
| int | |
| main(int argc, char **argv) | |
| { | |
| if (argc < 2) | |
| { | |
| printf("Error: Expected a filename. \nUsage: LBPSerialization.exe [filename]"); | |
| } | |
| char *FileName = argv[1]; | |
| FILE *FilePointer; | |
| srand(time(NULL)); | |
| my_state State = {0}; | |
| // NOTE(Oskar): Read or create new state file. | |
| if (FilePointer = fopen(FileName, "r")) | |
| { | |
| // NOTE(Oskar): Read in state | |
| lbp_serializer LBPSerializer = {0}; | |
| LBPSerializer.IsWriting = false; | |
| LBPSerializer.FilePointer = FilePointer; | |
| if (SerializeIncludingVersion(&LBPSerializer, &State)) | |
| { | |
| printf("Successfully read file %s.\n", FileName); | |
| PrintState(&State); | |
| } | |
| else | |
| { | |
| printf("Failed to open file for reading.\n"); | |
| return 0; | |
| } | |
| fclose(FilePointer); | |
| } | |
| else | |
| { | |
| // NOTE(Oskar): Couldn't open so build new state | |
| printf("No file exists so building new state.\n"); | |
| InitializeState(&State); | |
| } | |
| RandomizeState(&State); | |
| if (FilePointer = fopen(FileName, "w")) | |
| { | |
| lbp_serializer LBPSerializer = {0}; | |
| LBPSerializer.IsWriting = true; | |
| LBPSerializer.FilePointer = FilePointer; | |
| SerializeIncludingVersion(&LBPSerializer, &State); | |
| printf("Wrote serialized state to file\n"); | |
| fclose(FilePointer); | |
| } | |
| else | |
| { | |
| printf("Failed to open file for saving.\n"); | |
| return 0; | |
| } | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment