{"id":21515702,"url":"https://github.com/goblinhack/c-plus-plus-serializer","last_synced_at":"2025-07-06T04:35:11.709Z","repository":{"id":49448218,"uuid":"206885308","full_name":"goblinhack/c-plus-plus-serializer","owner":"goblinhack","description":"A minimal C++11 header only serializer. Can serialize basic types, strings, containers, maps and custom classes. No suppprt yet for pointer types.","archived":false,"fork":false,"pushed_at":"2025-02-25T19:01:15.000Z","size":475,"stargazers_count":52,"open_issues_count":2,"forks_count":9,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-09T20:12:39.087Z","etag":null,"topics":["c-plus-plus","c-plus-plus-11","serialization"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/goblinhack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-09-06T22:52:29.000Z","updated_at":"2025-03-16T15:00:32.000Z","dependencies_parsed_at":"2022-09-06T01:30:14.039Z","dependency_job_id":null,"html_url":"https://github.com/goblinhack/c-plus-plus-serializer","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goblinhack%2Fc-plus-plus-serializer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goblinhack%2Fc-plus-plus-serializer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goblinhack%2Fc-plus-plus-serializer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goblinhack%2Fc-plus-plus-serializer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/goblinhack","download_url":"https://codeload.github.com/goblinhack/c-plus-plus-serializer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248103872,"owners_count":21048245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c-plus-plus","c-plus-plus-11","serialization"],"created_at":"2024-11-23T23:56:27.672Z","updated_at":"2025-04-09T20:12:46.262Z","avatar_url":"https://github.com/goblinhack.png","language":"C++","readme":"Simple C++ 11 header-only serializer\n====================================\n\nHave you ever wanted a really minimal header-only C++11 serializer? Of course\nyou have! Having tried some other implementations I found them too hard to\nmaintain and grok when they inevitably failed to compile under the latest\ng++ version. Hopefully this one is simple enough to avoid such issues. All you\nneed to do is add\n\n\u003cpre\u003e\n#include \"c_plus_plus_serializer.h\"\n\u003c/pre\u003e\n\nin your project for any files that need to do serialization.\n\nThe data is saved in raw binary format, hence this is only loadable on the\nsame architecture that it was saved in.\n\nCredits\n=======\n\nThis work was based on some of the ideas in [this link](https://stackoverflow.com/questions/1559254/are-there-binary-memory-streams-in-c), specifically,\nthose by Samuel Powell.\n\nTested types\n============\n\n- POD types (char, wchar_t, int, float, double etc...)\n- std::array (multidimensional works too)\n- std::list\n- std::map\n- std::deque\n- std::multiset\n- std::pair\n- std::set\n- std::string, std::wstring\n- std::unordered_map\n- std::vector\n- custom class\n- nested types e.g. std::map\u003c std::string, std::list\u003e\n\nPOD serialization\n=================\n\n```C++\n#include \"c_plus_plus_serializer.h\"\n\n    static void serialize (std::ofstream out)\n    {\n        char           a = 42;\n        unsigned short b = 65535;\n        int            c = 123456;\n        float          d = std::numeric_limits\u003cfloat\u003e::max();\n        double         e = std::numeric_limits\u003cdouble\u003e::max();\n        std::string    f(\"hello\");\n        wchar_t        g = L'💩';\n        std::wstring   h(L\"wide string 💩\");\n\n        out \u003c\u003c bits(a) \u003c\u003c bits(b) \u003c\u003c bits(c) \u003c\u003c bits(d);\n        out \u003c\u003c bits(e) \u003c\u003c bits(f) \u003c\u003c bits(g) \u003c\u003c bits(h);\n    }\n\n    static void deserialize (std::ifstream in)\n    {\n        char           a;\n        unsigned short b;\n        int            c;\n        float          d;\n        double         e;\n        std::string    f;\n        wchar_t        g;\n        std::wstring   h;\n\n        in \u003e\u003e bits(a) \u003e\u003e bits(b) \u003e\u003e bits(c) \u003e\u003e bits(d);\n        in \u003e\u003e bits(e) \u003e\u003e bits(f) \u003e\u003e bits(g) \u003e\u003e bits(h);\n    }\n```\n\nContainer serialization\n=======================\n\n```C++\n#include \"c_plus_plus_serializer.h\"\n\n    static void serialize (std::ofstream out)\n    {\n        std::initializer_list\u003c std::string \u003e d1 = {\"vec-elem1\", \"vec-elem2\"};\n        std::vector\u003c std::string \u003e a(d1);\n\n        std::initializer_list\u003c std::string \u003e d2 = {\"list-elem1\", \"list-elem2\"};\n        std::list\u003c std::string \u003e b(d2);\n\n        std::array\u003c std::string, 2\u003e c = {\"arr-elem1\", \"arr-elem2\"};\n\n        //\n        // 2d array\n        //\n        std::array\u003c std::array\u003cchar, 2\u003e, 3\u003e d;\n        d[0][0] = '0'; d[0][1] = '1';\n        d[1][0] = '2'; d[1][1] = '3';\n        d[2][0] = '4'; d[2][1] = '5';\n\n        //\n        // 3d array\n        //\n        std::array\u003c std::array\u003c std::array\u003cchar, 2\u003e, 3\u003e, 4\u003e ddd;\n        ddd[0][0][0] = 'a'; ddd[0][0][1] = 'b';\n        ddd[0][1][0] = 'c'; ddd[0][1][1] = 'd';\n        ddd[0][2][0] = 'e'; ddd[0][2][1] = 'f';\n        ddd[1][0][0] = 'g'; ddd[1][0][1] = 'h';\n        ddd[1][1][0] = 'i'; ddd[1][1][1] = 'j';\n        ddd[1][2][0] = 'k'; ddd[1][2][1] = 'l';\n        ddd[2][0][0] = 'm'; ddd[2][0][1] = 'n';\n        ddd[2][1][0] = 'o'; ddd[2][1][1] = 'p';\n        ddd[2][2][0] = 'q'; ddd[2][2][1] = 'r';\n        ddd[3][0][0] = 's'; ddd[3][0][1] = 't';\n        ddd[3][1][0] = 'u'; ddd[3][1][1] = 'v';\n        ddd[3][2][0] = 'w'; ddd[3][2][1] = 'x';\n\n        out \u003c\u003c bits(a) \u003c\u003c bits(b) \u003c\u003c bits(c) \u003c\u003c bits(dd) \u003c\u003c bits(ddd);\n    }\n\n    static void deserialize (std::ifstream in)\n    {\n        std::string f;\n        std::vector\u003c std::string \u003e a;\n        std::list\u003c std::string \u003e b;\n        std::array\u003c std::string, 2\u003e c;\n        std::array\u003c std::array\u003cchar, 2\u003e, 3\u003e d;\n        std::array\u003c std::array\u003c std::array\u003cchar, 2\u003e, 3\u003e, 4\u003e ddd;\n\n        in \u003e\u003e bits(a) \u003e\u003e bits(b) \u003e\u003e bits(c) \u003e\u003e bits(dd) \u003e\u003e bits(ddd);\n    }\n```\n\nMap serialization\n=================\n\n```C++\n    static void serialize (std::ofstream out)\n    {\n        std::map\u003c std::string, std::string \u003e m;\n        m.insert(std::make_pair(std::string(\"key1\"), std::string(\"value1\")));\n        m.insert(std::make_pair(std::string(\"key2\"), std::string(\"value2\")));\n        m.insert(std::make_pair(std::string(\"key3\"), std::string(\"value3\")));\n        m.insert(std::make_pair(std::string(\"key4\"), std::string(\"value4\")));\n        out \u003c\u003c bits(m);\n    }\n\n    static void deserialize (std::ifstream in)\n    {\n        std::map\u003c std::string, std::string \u003e m;\n        in \u003e\u003e bits(m);\n    }\n```\n\nUnordered map serialization\n===========================\n\n```C++\n    static void serialize (std::ofstream out)\n    {\n        std::unordered_map\u003c std::string, std::string \u003e m;\n        m.insert(std::make_pair(std::string(\"key1\"), std::string(\"value1\")));\n        m.insert(std::make_pair(std::string(\"key2\"), std::string(\"value2\")));\n        m.insert(std::make_pair(std::string(\"key3\"), std::string(\"value3\")));\n        m.insert(std::make_pair(std::string(\"key4\"), std::string(\"value4\")));\n        out \u003c\u003c bits(m);\n    }\n\n    static void deserialize (std::ifstream in)\n    {\n        std::unordered_map\u003c std::string, std::string \u003e m;\n        in \u003e\u003e bits(m);\n    }\n```\n\nstd::map\u003c std::string, std::list \u003e example\n========================================\n\n```C++\n    static void serialize (std::ofstream out)\n    {\n        std::map\u003c std::string, std::list\u003c std::string \u003e \u003e m;\n\n        std::initializer_list\u003c std::string \u003e L1 = {\"list-elem1\", \"list-elem2\"};\n        std::list\u003c std::string \u003e l1(L1);\n        std::initializer_list\u003c std::string \u003e L2 = {\"list-elem3\", \"list-elem4\"};\n        std::list\u003c std::string \u003e l2(L2);\n\n        m.insert(std::make_pair(std::string(\"key1\"), l1));\n        m.insert(std::make_pair(std::string(\"key2\"), l2));\n\n        out \u003c\u003c bits(m);\n    }\n\n    static void deserialize (std::ifstream in)\n    {\n        std::map\u003c std::string, std::list\u003c std::string \u003e \u003e m;\n\n        in \u003e\u003e bits(m);\n    }\n```\n\nSet serialization\n=================\n\n```C++\n    static void serialize (std::ofstream out)\n    {\n        std::set\u003c std::string \u003e m;\n        m.insert(std::string(\"key1\"));\n        m.insert(std::string(\"key2\"));\n        m.insert(std::string(\"key3\"));\n        m.insert(std::string(\"key4\"));\n        out \u003c\u003c bits(m);\n    }\n\n    static void deserialize (std::ifstream in)\n    {\n        std::set\u003c std::string \u003e m;\n        in \u003e\u003e bits(m);\n    }\n```\n\nMultiset serialization\n======================\n\n```C++\n    static void serialize (std::ofstream out)\n    {\n        std::multiset\u003c std::string \u003e m;\n        m.insert(std::string(\"key1\"));\n        m.insert(std::string(\"key1\"));\n        m.insert(std::string(\"key1\"));\n        m.insert(std::string(\"key1\"));\n        m.insert(std::string(\"key2\"));\n        m.insert(std::string(\"key3\"));\n        m.insert(std::string(\"key4\"));\n        out \u003c\u003c bits(m);\n    }\n\n    static void deserialize (std::ifstream in)\n    {\n        std::multiset\u003c std::string \u003e m;\n        in \u003e\u003e bits(m);\n    }\n```\n\nDeque serialization\n===================\n\n```C++\n    static void serialize (std::ofstream out)\n    {\n        std::deque\u003c std::string \u003e m;\n        m.push_front(std::string(\"key1\"));\n        m.push_front(std::string(\"key2\"));\n        m.push_back(std::string(\"key3\"));\n        m.push_back(std::string(\"key4\"));\n        out \u003c\u003c bits(m);\n    }\n\n    static void deserialize (std::ifstream in)\n    {\n        std::deque\u003c std::string \u003e m;\n        in \u003e\u003e bits(m);\n    }\n```\n\nUser defined class serialization\n================================\n\n```C++\n    class Custom {\n    public:\n        int a;\n        std::string b;\n        std::vector\u003c std::string \u003e c;\n\n        friend std::ostream\u0026 operator\u003c\u003c(std::ostream \u0026out,\n                                        Bits\u003cclass Custom \u0026 \u003e my)\n        {\n            out \u003c\u003c bits(my.t.a) \u003c\u003c bits(my.t.b) \u003c\u003c bits(my.t.c);\n            return (out);\n        }\n\n        friend std::istream\u0026 operator\u003e\u003e(std::istream \u0026in,\n                                        Bits\u003cclass Custom \u0026\u003e my)\n        {\n            in \u003e\u003e bits(my.t.a) \u003e\u003e bits(my.t.b) \u003e\u003e bits(my.t.c);\n            return (in);\n        }\n    };\n```\n\nSerializing a custom template class\n===================================\n\n```C++\n    template\u003cclass T \u003e class MyPoint\n    {\n    public:\n        T x {};\n        T y {};\n\n        MyPoint (void) : x(0), y(0) {};\n\n        MyPoint (T x, T y) : x(x), y(y) { }\n\n        friend std::ostream\u0026 operator\u003c\u003c(std::ostream \u0026out,\n                                        Bits\u003cconst MyPoint \u0026 \u003e const my)\n        {\n            out \u003c\u003c bits(my.t.x) \u003c\u003c bits(my.t.y);\n            return (out);\n        }\n\n        friend std::istream\u0026 operator\u003e\u003e(std::istream \u0026in, Bits\u003cMyPoint \u0026\u003e my)\n        {\n            in \u003e\u003e bits(my.t.x) \u003e\u003e bits(my.t.y);\n            return (in);\n        }\n\n        friend std::ostream\u0026 operator \u003c\u003c (std::ostream \u0026out, const MyPoint \u0026my)\n        {\n            out \u003c\u003c \"(\" \u003c\u003c my.x \u003c\u003c \", \" \u003c\u003c my.y \u003c\u003c \")\";\n            return (out);\n        }\n    };\n\n    typedef MyPoint\u003cint \u003e IntPoint;\n    typedef MyPoint\u003cfloat \u003e FloatPoint;\n    typedef MyPoint\u003cdouble \u003e DoublePoint;\n\n    static void serialize (std::ofstream out)\n    {\n        out \u003c\u003c bits(IntPoint(1, 2));\n        out \u003c\u003c bits(FloatPoint(1.1, 2.2));\n        out \u003c\u003c bits(DoublePoint(3.3, 4.4));\n    }\n\n    static void deserialize (std::ifstream in)\n    {\n        IntPoint a;\n        FloatPoint b;\n        DoublePoint c;\n\n        in \u003e\u003e bits(a);\n        in \u003e\u003e bits(b);\n        in \u003e\u003e bits(c);\n    }\n```\n\nUser defined class serialization (more complex one, a map of classes)\n=====================================================================\n\n```C++\n    class Custom {\n    public:\n        int a;\n        std::string b;\n        std::vector\u003c std::string \u003e c;\n\n        friend std::ostream\u0026 operator\u003c\u003c(std::ostream \u0026out,\n                                        Bits\u003cclass Custom \u0026 \u003e my)\n        {\n            out \u003c\u003c bits(my.t.a) \u003c\u003c bits(my.t.b) \u003c\u003c bits(my.t.c);\n            return (out);\n        }\n\n        friend std::istream\u0026 operator\u003e\u003e(std::istream \u0026in,\n                                        Bits\u003cclass Custom \u0026\u003e my)\n        {\n            in \u003e\u003e bits(my.t.a) \u003e\u003e bits(my.t.b) \u003e\u003e bits(my.t.c);\n            return (in);\n        }\n\n        friend std::ostream\u0026 operator\u003c\u003c(std::ostream \u0026out,\n                                        class Custom \u0026my)\n        {\n            out \u003c\u003c \"a:\" \u003c\u003c my.a \u003c\u003c \" b:\" \u003c\u003c my.b;\n\n            out \u003c\u003c \" c:[\" \u003c\u003c my.c.size() \u003c\u003c \" elems]:\";\n            for (auto v : my.c) {\n                out \u003c\u003c v \u003c\u003c \" \";\n            }\n            out \u003c\u003c std::endl;\n\n            return (out);\n        }\n    };\n\n    static void serialize (...)\n    {\n        std::map\u003c std::string, class Custom \u003e m;\n\n        auto c1 = Custom();\n        c1.a = 1;\n        c1.b = \"hello\";\n        std::initializer_list\u003c std::string \u003e L1 = {\"vec-elem1\", \"vec-elem2\"};\n        std::vector\u003c std::string \u003e l1(L1);\n        c1.c = l1;\n\n        auto c2 = Custom();\n        c2.a = 2;\n        c2.b = \"there\";\n        std::initializer_list\u003c std::string \u003e L2 = {\"vec-elem3\", \"vec-elem4\"};\n        std::vector\u003c std::string \u003e l2(L2);\n        c2.c = l2;\n\n        m.insert(std::make_pair(std::string(\"key1\"), c1));\n        m.insert(std::make_pair(std::string(\"key2\"), c2));\n\n        out \u003c\u003c bits(m);\n    }\n\n    static void deserialize (...)\n    {\n        std::cout \u003c\u003c \"read from \" \u003c\u003c filename \u003c\u003c std::endl;\n        std::ifstream in(filename);\n\n        std::map\u003c std::string, class Custom \u003e m;\n\n        in \u003e\u003e bits(m);\n        std::cout \u003c\u003c std::endl;\n\n        std::cout \u003c\u003c \"m = \" \u003c\u003c m.size() \u003c\u003c \" list-elems { \" \u003c\u003c std::endl;\n        for (auto i : m) {\n            std::cout \u003c\u003c \"    [\" \u003c\u003c i.first \u003c\u003c \"] = \" \u003c\u003c i.second;\n        }\n        std::cout \u003c\u003c \"}\" \u003c\u003c std::endl;\n    }\n```\n\nBitfield serialization (C and C++ style)\n========================================\n\n```C++\n    class BitsetClass {\n    public:\n        std::bitset\u003c1\u003e a;\n        std::bitset\u003c2\u003e b;\n        std::bitset\u003c3\u003e c;\n\n        unsigned int d:1; // need c++20 for default initializers for bitfields\n        unsigned int e:2;\n        unsigned int f:3;\n        BitsetClass(void) { d = 0; e = 0; f = 0; }\n\n        friend std::ostream\u0026 operator\u003c\u003c(std::ostream \u0026out,\n                                        Bits\u003cconst class BitsetClass \u0026 \u003e const my)\n        {\n            out \u003c\u003c bits(my.t.a);\n            out \u003c\u003c bits(my.t.b);\n            out \u003c\u003c bits(my.t.c);\n\n            std::bitset\u003c6\u003e s(my.t.d | my.t.e \u003c\u003c 1 | my.t.f \u003c\u003c 3);\n            out \u003c\u003c bits(s);\n\n            return (out);\n        }\n\n        friend std::istream\u0026 operator\u003e\u003e(std::istream \u0026in,\n                                        Bits\u003cclass BitsetClass \u0026\u003e my)\n        {\n            std::bitset\u003c1\u003e a;\n            in \u003e\u003e bits(a);\n            my.t.a = a;\n\n            in \u003e\u003e bits(my.t.b);\n            in \u003e\u003e bits(my.t.c);\n            std::bitset\u003c6\u003e s;\n            in \u003e\u003e bits(s);\n\n            unsigned long raw_bits = static_cast\u003cunsigned long\u003e(s.to_ulong());\n            my.t.d = raw_bits \u0026 0b000001;\n            my.t.e = (raw_bits \u0026 0b000110) \u003e\u003e 1;\n            my.t.f = (raw_bits \u0026 0b111000) \u003e\u003e 3;\n\n            return (in);\n        }\n    };\n```\n\nRaw memory\n==========\n```C++\n#include \"hexdump.h\"\n\n    auto elems = 128;\n\n    static void serialize (std::ofstream out)\n    {\n        auto a = new char[elems];\n        for (auto i = 0; i \u003c elems; i++) {\n            a[i] = i;\n        }\n        out \u003c\u003c bits(a);\n    }\n\n    static void deserialize (std::ifstream in)\n    {\n        auto a = new char[elems];\n        in \u003e\u003e bits(a);\n\n        hexdump(a, elems);\n    }\n```\n\nOutput:\n\n```C++\n    128 bytes:\n    0000 00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f |................|\n    0010 10 11 12 13 14 15 16 17  18 19 1a 1b 1c 1d 1e 1f |................|\n    0020 20 21 22 23 24 25 26 27  28 29 2a 2b 2c 2d 2e 2f | !\"#$%\u0026'()*+,-./|\n    0030 30 31 32 33 34 35 36 37  38 39 3a 3b 3c 3d 3e 3f |0123456789:;\u003c=\u003e?|\n    0040 40 41 42 43 44 45 46 47  48 49 4a 4b 4c 4d 4e 4f |@ABCDEFGHIJKLMNO|\n    0050 50 51 52 53 54 55 56 57  58 59 5a 5b 5c 5d 5e 5f |PQRSTUVWXYZ[\\]^_|\n    0060 60 61 62 63 64 65 66 67  68 69 6a 6b 6c 6d 6e 6f |`abcdefghijklmno|\n    0070 70 71 72 73 74 75 76 77  78 79 7a 7b 7c 7d 7e 7f |pqrstuvwxyz{|}~.|\n```\n\nCompression\n===========\n\nFor compression, look at the following which uses [quicklz](http://www.quicklz.com/download.html)\n\n\u003cpre\u003e\n    zipped_container_example.cpp\n\u003c/pre\u003e\n\nBuilding\n========\n\nDo\n\n\u003cpre\u003e\n    sh ./RUNME\n\u003c/pre\u003e\n\nOr, if that fails, manual build:\n\n\u003cpre\u003e\n    c++ -std=c++11 -Werror -O2 -Wall -c -o .o/main.o main.cpp\n    c++ .o/main.o -o c_plus_plus_serializer\n\u003c/pre\u003e\n\nTo test:\n\n\u003cpre\u003e\n    ./c_plus_plus_serializer\n\u003c/pre\u003e\n\nTo debug, uncomment this line in Makefile.base, and then rerun RUNME:\n\n\u003cpre\u003e\n#EXTRA_CFLAGS += -DDEBUG_C_PLUS_PLUS_SERIALIZER\n\u003c/pre\u003e\n\nTo use 64-bit size_t when saving vectors, uncomment in Makefile.base and then\nrerun RUNME:\n\n\u003cpre\u003e\n#EXTRA_CFLAGS += -DUSE_SIZE_T\n\u003c/pre\u003e\n\nNote, no sanity checking is performed on the data when it is read back in, so\nmake sure your serializer and deserializers match perfectly.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoblinhack%2Fc-plus-plus-serializer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoblinhack%2Fc-plus-plus-serializer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoblinhack%2Fc-plus-plus-serializer/lists"}