• Stars
    star
    102
  • Rank 334,066 (Top 7 %)
  • Language
    C++
  • License
    MIT License
  • Created over 3 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Zmeya is a header-only C++11 binary serialization library designed for games and performance-critical applications

Zmeya Build Status Build status codecov MIT

Zmeya is a header-only C++11 binary serialization library designed for games and performance-critical applications. Zmeya is not even a serialization library in the usual sense but rather a set of STL-like containers that entirely agnostic for their memory location and movable. As long as you use Zmeya data structures + other trivially_copyable, everything just works, and there is no deserialization cost. You can memory-map a serialized file and immediately start using your data. There are no pointers fixup, nor any other parsing/decoding needed. You can also serialize your data and send it over the network, there is no deserialization cost on the receiver side, or you can even use Zmeya for interprocess communication.

Features

  • Cross-platform compatible
  • Single header library (~550 lines of code for deserialization and extra 750 lines of code with serialization support enabled)
  • No code generation required: no IDL or metadata, just use your types directly
  • No macros
  • Heavily optimized for performance
  • No dependencies
  • Zmeya pointers are always 32-bits (configurable) regardless of the target platform pointer size

Zmeya library offering the following memory movable types

  • Pointer<T>
  • Array<T>
  • String
  • HashSet<Key>
  • HashMap<Key, Value>

Usage

Include the header file, and you are all set.

Usage example

Here is a simple usage example.

#include "Zmeya.h"

struct Test
{
  uint32_t someVar;
  zm::String name;
  zm::Pointer<Test> ptr;
  zm::Array<zm::String> arr;
  zm::HashMap<zm::String, float> hashMap;
};

int main()
{
   // load binary file to memory (using fread, mmap, etc)
   // no parsing/decoding needed
   const Test* test = (const Test*)loadBytesFromDisk("binaryFile.zm");  
   
   // use your loaded data
   printf("%s\n", test->name.c_str());
   for(const zm::String& str : test->arr)
   {
     printf("%s\n",str.c_str());
   }
   printf("key = %3.2f\n", test->hashMap.find("key", 0.0f));
   return 0;
}

You can always find more usage examples looking into unit test files. They are organized in a way to covers all Zmeya features and shows common usage patterns.

How it works

Zmeya movable containers' key idea is to use self-relative pointers instead of using “absolute” pointers provided by C++ by default. The idea is pretty simple; instead of using the absolute address, we are using offset relative to the pointer's memory address. i.e., target_address = uintptr_t(this) + offset

Which is perfectly representable by one of x86/ARM addressing modes addr = reg+reg Here is an example of generated assembly code https://godbolt.org/z/aTTW9E7o9 https://godbolt.org/z/xEqTYe44j

One of the problems of such offset-based addressing is the representation of the null pointer. The null pointer can't be safely represented like an offset since the absolute address 0 is always outside of the mapped region. So we decided to use offset 0 (pointer to self) as a special magic value that encodes null pointer.

#include <stdint.h>

template<typename T>
struct OffsetPtr {
    int32_t offset;
    T* get() const noexcept {
        return reinterpret_cast<T*>(uintptr_t(this) + offset);
    }
};

template<typename T>
struct Ptr {
    T* ptr;
    T* get() const noexcept {
        return ptr;
    }
};

int test1(const OffsetPtr<int>& ptr) {
    return *ptr.get();
}

int test2(const Ptr<int>& ptr) {
    return *ptr.get();
}
test1(OffsetPtr<int> const&):
        movsx   rax, DWORD PTR [rdi]
        mov     eax, DWORD PTR [rax+rdi]
        ret
        
test2(Ptr<int> const&):
        mov     rax, QWORD PTR [rdi]
        mov     eax, DWORD PTR [rax]
        ret

So there is no extra overhead from using such pointers in comparison with traditional pointers.

All other Zmeya containers are pretty much based on the same principles. i.e. zm::String is a self-relative pointer to const char* zm::Array<T> is a self-relative pointer to data + size zm::HashSet<Key> is made using two arrays (buckets and values) etc...

The only requirement is that we have to have all the data tightly packed in a single memory region or binary blob. Zmeya provides a convenient mechanism to build such a binary blob called zm::BlobBuilder. Blob builder is capable of convert all the standard STL containers to appropriate Zmeya movable containers. Blob builder also provides a mechanism to convert all the inner types (e.g., std::vector<std::string>) to Zmeya compatible type. And by default, Zmeya offers convertors/template specializations for all commonly used cases.

References

Boost::offset_ptr
https://www.boost.org/doc/libs/1_75_0/doc/html/interprocess/offset_ptr.html

Handmade Hero forum thread
https://hero.handmade.network/forums/code-discussion/t/487-serialization_techniques_with_memory_pooling

Relative Pointers article by Ginger Bill
https://www.gingerbill.org/article/2020/05/17/relative-pointers/

"The Blob and I" by Niklas Gray
https://bitsquid.blogspot.com/2010/02/blob-and-i.html

FlatBuffers by Google
https://google.github.io/flatbuffers/

Physics Optimization Strategies by Sergiy Migdalskiy (slides 56-68)
http://media.steampowered.com/apps/valve/2015/Migdalskiy_Sergiy_Physics_Optimization_Strategies.pdf

https://youtu.be/Nsf2_Au6KxU?t=1542

Relative Pointers by Jonathan Blow
https://www.youtube.com/watch?v=Z0tsNFZLxSU

More Repositories

1

TaskScheduler

Cross-platform, fiber-based, multi-threaded task scheduler designed for video games.
C++
549
star
2

ArcadeCarPhysics

Arcade Car Physics - Vehicle Simulation for Unity3D
C#
327
star
3

slot_map

A slot map is a high-performance associative container with persistent unique 32/64 bit keys to access stored values.
C++
246
star
4

smmalloc

Blazing fast memory allocator designed for video games
C++
239
star
5

ecs

Thoughts about entity-component-system
C++
183
star
6

Goofy

Goofy - Realtime DXT1/ETC1 encoder
C++
70
star
7

Quaternions-Revisited

Sample code for a 'Quaternions revisited' article from GPU Pro 5
C++
31
star
8

Sandworm

Embeddable preprocessor based on clang. Created to compile ubershaders, but can preprocess anything you like.
C++
20
star
9

GpuZen2

Sample code for the article 'Real-Time Layered Materials Compositing Using Spatial Clustering Encoding'
C#
17
star
10

z8

Z8 : fantasy 8-bit system
JavaScript
11
star
11

Ninja-Ripper-Maya-Importer-

Ninja Ripper Importer for Autodesk Maya
Python
11
star
12

tony-mc-mapface-fuse

A cool-headed display transform - ported to DaVinci Resolve
10
star
13

FastFiberIdea

C++
9
star
14

StaticVector

C++
5
star
15

sm_hash_map

C++
5
star
16

AimExplorer

Aim Acceleration Explorer in FPS games
HTML
4
star
17

DxtSplitter

C++
3
star
18

RobloxAvatarExporter

Python
3
star
19

FixMultimonWindows

C++
3
star
20

CellularAutomata

GPU Cellular Automata fun
C++
3
star
21

ECalc

Expression Calculator (Similar to Far Manager plugin)
HTML
2
star
22

DominantColorsExtractor

Python
2
star
23

Sputnik

Python
2
star
24

GitCheatSheet

2
star
25

BuildConfigurationTool

C#
1
star
26

AT-Linker

C++
1
star
27

MOD_XMQ

Custom extension for XMPP protocol to provide message broker features.
Erlang
1
star
28

sergeymakeev.github.io

github pages
JavaScript
1
star
29

ExcaliburHash

C++
1
star
30

XMQ_Client

Example of XMQ client.
C++
1
star