{"id":19138360,"url":"https://github.com/rochet2/smallfolk_cpp","last_synced_at":"2025-05-06T20:46:46.927Z","repository":{"id":34215792,"uuid":"38073952","full_name":"Rochet2/smallfolk_cpp","owner":"Rochet2","description":"smallfolk serializer with C++","archived":false,"fork":false,"pushed_at":"2023-04-27T19:16:09.000Z","size":82,"stargazers_count":4,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-19T14:58:07.180Z","etag":null,"topics":["cpp","hacktoberfest","lua","serialization","serializer","smallfolk"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Rochet2.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-06-25T21:00:26.000Z","updated_at":"2023-04-23T17:21:24.000Z","dependencies_parsed_at":"2024-11-09T06:42:55.112Z","dependency_job_id":"e21dd10d-7630-4416-9acd-d9f4da54fb55","html_url":"https://github.com/Rochet2/smallfolk_cpp","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rochet2%2Fsmallfolk_cpp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rochet2%2Fsmallfolk_cpp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rochet2%2Fsmallfolk_cpp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rochet2%2Fsmallfolk_cpp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Rochet2","download_url":"https://codeload.github.com/Rochet2/smallfolk_cpp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252769134,"owners_count":21801373,"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":["cpp","hacktoberfest","lua","serialization","serializer","smallfolk"],"created_at":"2024-11-09T06:42:40.131Z","updated_at":"2025-05-06T20:46:46.907Z","avatar_url":"https://github.com/Rochet2.png","language":"C++","readme":"# smallfolk_cpp\n\nSmallfolk_cpp is a library for representing `Lua` values in `C++` and (de)serializing them. The serialization is made to work with smallfolk serializer made for lua. Most serializer logic is borrowed from gvx/Smallfolk. https://github.com/gvx/Smallfolk\n\nSmallfolk_cpp does not have dependencies other than `C++11` and it **does not need lua**. It simply uses same format and logic as gvx/Smallfolk for serialization.\n\nSmallfolk_cpp has its own type `LuaVal` to represent `Lua` values in `C++`.\nThey allow representing bool, number, string, nil and table.\n\nDue to implementation difficulties and security some features of gvx/Smallfolk are not supported. A version of smallfolk for lua with the unsupported features removed can be found at https://github.com/Rochet2/Smallfolk\n\nYou use, distribute and extend Smallfolk_cpp under the terms of the MIT license.\n\n## Usage\n\n```C++\n#include smallfolk.h\n\n// create a lua table and set some values to it\nLuaVal table = LuaVal::table();\ntable[1] = \"Hello\"; // the values is automatically converted to LuaVal\ntable[\"test\"] = \"world\";\ntable[67.5] = -234.5;\n\n// serialize the table\nstd::string serialized = table.dumps();\n\n// print the serialization, it should be rather human readable\n// Example output: {\"Hello\",\"test\":\"world\",67.5:-234.5}\nstd::cout \u003c\u003c serialized \u003c\u003c std::endl;\n\n// form lua values from the string\nLuaVal deserialized = LuaVal::loads(serialized);\n\n// print the values from deserialized result table\n// Example output: Hello world -234.5\nstd::cout \u003c\u003c deserialized[1].str() \u003c\u003c \" \";\nstd::cout \u003c\u003c deserialized[\"test\"].str() \u003c\u003c \" \";\nstd::cout \u003c\u003c deserialized[67.5].num() \u003c\u003c std::endl;\n```\n\n## Fast\n\nIts C++, duh!?\n\nSome poor benchmarking shows that plain serializing takes ~0.01ms. If creating, serializing and destroying created objects ~0.025ms. Deserializing takes ~0.05ms when destroying the created objects as well.\nThis is of course completely different depending on what data you serialize and deserialize.\nIn general it would seem that deserializing is ~50% slower.\n\nTo put this into any kind of perspective, here is the print of the serialized data:\n```lua\n{t,\"somestring\",123.456,t:-678,\"test\":123.45600128173828,f:268435455,\"subtable\":{1,2,3}}\n```\n\n## Table cycles\n\n__Note: This feature was disabled cause of difficult implementing in C++ and possibly unwanted infinite cycles. All table assigning create copies now in the C++ code and no @ notation is recognised for serializing or deserializing. Any such references are set to nil when deserializing. Any @ references are otherwise deep copies in the C++ code__\n\nFrom original smallfolk\n\u003e Sometimes you have strange, non-euclidean geometries in your table\n\u003e constructions. It happens, I don't judge. Smallfolk can deal with that, where\n\u003e some other serialization libraries (or anything that produces JSON) cry \"Iä!\n\u003e Iä! Cthulhu fhtagn!\" and give up \u0026mdash; or worse, silently produce incorrect\n\u003e data.\n\u003e\n\u003e ```C++\n\u003e #include smallfolk.h\n\u003e\n\u003e // Essentially {{},{},{}}\n\u003e LuaVal cthulhu(TTABLE);\n\u003e cthulhu[1] = LuaVal(TTABLE);\n\u003e cthulhu[2] = LuaVal(TTABLE);\n\u003e cthulhu[3] = LuaVal(TTABLE);\n\u003e cthulhu[\"fhtagn\"] = cthulhu;\n\u003e cthulhu[1][cthulhu[2]] = cthulhu[3];\n\u003e cthulhu[2][cthulhu[1]] = cthulhu[2];\n\u003e cthulhu[3][cthulhu[3]] = cthulhu;\n\u003e std::cout \u003c\u003c cthulhu.dumps() \u003c\u003c std::endl;\n\u003e // prints:\n\u003e // {\"fhtagn\":@1,1:{{@2:@3}:{@4:@1}},2:@3,3:@4}\n\u003e ```\n\n## Security\n\nI cannot guarantee that this code is secure. All I can give is that I have attempted to make it safe and implemented exceptions best I know to handle unexpected situations.\n\n## Tested\n\nAll tests can be seen in the main.cpp provided.\nThe code has been in use with a server-client C++-Lua communication system called AIO through which the API has been made more usable and critical issues have been addressed.\n- https://github.com/Rochet2/AIO\n- https://github.com/Rochet2/TrinityCore/tree/c_aio\n- https://github.com/SaiFi0102/TrinityCore/tree/CAIO-3.3.5\n\n## Reference\n\n### try-catch\nMost functions can throw `smallfolk_exception` and some string library errors and possibly more.\nOne method for try catching errors you can use is this:\n```C++\ntry {\n  // smallfolk_cpp code\n}\ncatch (smallfolk_exception\u0026 e) {\n    std::cout \u003c\u003c e.what() \u003c\u003c std::endl;\n}\n```\n\nYou need to catch exceptions mostly from incorrect handling of LuaVal. For example trying to access a number like a table will cause an exception.\n\n### serializing\nSerializing happens by calling the member function `std::string LuaVal::dumps(std::string* errmsg = nullptr)`. When an error occurs with the serialization an empty string is returned and if errmsg points to a string then it is filled with the error message.\nThis function does not throw.\n\n### deserializing\nDeserializing happens by calling the function `static LuaVal LuaVal::loads(std::string const \u0026 string, std::string* errmsg = nullptr)`. When an error occurs with the deserialization a LuaVal representing a nil is returned and if errmsg points to a string then it is filled with the error message.\nThis function does not throw.\n\n### LuaVal\nLuaVal is a type used to represent lua values in C++. LuaVal has a range of functions to access the underlying values and to construct LuaVal from different values. LuaVal is the input for serialization and output of deserialization.\n\n### LuaVal constructors\nConstructors allow implicitly constructing values.\nConstructors do not throw. Watch out for quirks with initializer list constructor: http://stackoverflow.com/questions/26947704/implicit-conversion-failure-from-initializer-list\n```C++\nLuaVal implicit_test = -123;\nLuaVal copy_test(implicit_test);\nLuaVal copy_test2 = implicit_test;\nLuaVal n = LuaVal::nil; // nil\nLuaVal n2(TNIL); // nil\nLuaVal b(true);\nLuaVal s(\"a string\");\nLuaVal d(123.456);\nLuaVal f(123.456f);\nLuaVal i(-678);\nLuaVal u(0xFFFFFFF);\nLuaVal t; // defaults to table\nLuaVal t2 = LuaVal::table();\nLuaVal t3 = { 1, 2, { 1,2,3 } };\nLuaVal t4 = {};\nLuaVal t5(TTABLE);\nLuaVal t6 = LuaVal::LuaTable{ { \"key\", \"value\" }, { 2, \"value2\" } }; // Table can be created with map table initializer list constructor also\n\n// You can mix and match a lot of different types and containers for creating tables.\n// For example vectors, lists, maps, arrays are supported for creating LuaVal.\nstd::vector\u003cstd::list\u003cstd::string\u003e\u003e vec = {{\"a\", \"b\"},{\"a\", \"b\"}};\nLuaVal t5 = {1,2, \"test\", vec};\n// Resulting table: {1,2,\"test\",{{\"a\",\"b\"},{\"a\",\"b\"}}}\n```\n\nCreating sequences is easy, but creating complex tables that contain different types of values can be difficult or take a lot of space in code. To avoid quirks and for conveience you can deserialize strings to create values in a compact way. Here two equivalent values are created with normal style and deserialization:\n```c++\nLuaVal val1 = { 1,2, LuaVal::mrg({3,4.5}, LuaVal::LuaTable({{\"ke\",\"test\"}})) };\nLuaVal val2 = LuaVal::loads(\"{1,2,{3,4.5,'ke':'test'}}\");\n```\n\n### static nil\nA static value `static const LuaVal LuaVal::nil` is a preconstructed nil object.\nIt can be used as a default value or return value when a const nil value reference is needed to avoid constructing unnecessary copies.\n\n### hash\nThe LuaVal class contains a hasher `LuaVal::LuaValHasher`. You need to use it when you use a LuaVal in a hash container for example: `std::unordered_set\u003cLuaVal, LuaVal::LuaValHasher\u003e myset;` or `std::unordered_map\u003cLuaVal, int, LuaVal::LuaValHasher\u003e mymap;`.\nCurrently there are no order operators implemented to be used for sorted sets and maps however.\nMay throw if LuaVal is not valid for some reason (which should not be possible).\n\n### typetag\nThere are definitions for typetags used to identify each value type. These can be used in the constructor of a LuaValue as well.\nFor example a table can be created with `LuaValue table(TTABLE)`. You can get the typetag of an object with the member function `LuaTypeTag LuaVal::typetag()`.\nGetTypeTag does not throw.\n```C++\nenum LuaTypeTag\n{\n    TNIL,\n    TSTRING,\n    TNUMBER,\n    TTABLE,\n    TBOOL,\n};\n```\n\n### tostring\nThe member function `std::string LuaVal::tostring()` returns a string representation of the object. This is similar to tostring in lua.\nYou can get a string representation of the typetag of a value with `value.type()`.\nYou can get a string representation of a typetag with `LuaVal::type(tag)`.\nAll of these may throw if LuaVal or tag is not valid for some reason (which should not be possible).\n\n### operators\nThe LuaVal class offers a few operators.  \nYou can use == and != operators to compare, however different table objects are copies so they are never equal unless you actually compare with the same object.\nLuaVal has the bool operator implemented so that nil and false will return false if a LuaVal is in a conditional statement. The assignment operator is also implemented and works as you would expect.\nMay throw if LuaVal is not valid for some reason (which should not be possible).\n\n### isvalue\nThere is a collection of member functions you can use to check whether the object is really of some type.\nThese functions do not throw.\n```C++\nluaval.isstring()\nluaval.isnumber()\nluaval.istable()\nluaval.isbool()\nluaval.isnil()\n```\n\n### LuaVal values\nLuaVal can represent different types of data like a string and a number. To access the underlying value you must use specific functions.\nThe functions will throw if you use them on the wrong type object, for example using the str function on a table will throw.\n```C++\nluaval.num()\nluaval.str()\nluaval.boolean()\nluaval.tbl()\n```\n\n### table access\nThere are several methods for accessing and editing a table.\n**Note Inserted values will be deep copies in all cases.**\n\nThe way of accessing and inserting map elements are the get and set member functions `luaval.get(key)`, `luaval.set(key, value)`.\nThe function `set` returns the accessed table itself, so you can chain it to set multiple values.\nWhen a value is attempted to be set as nil, it will be erased from the table instead.\nThese functions do not throw unless you use them on non table objects or with nil keys. `luaval.setignore(key, value)` works like `luaval.set(key, value)`, except it will not do anything if a value already exists in the table for that key.\n\nThe get method above will provide only const reference access to the table elements. For non const access to elements you must use the `[]` operator like so `luaval[key]`. If the accessed key does not exist in the accessed table then a table value is created to the table for that key. This means that accessing nonexisting elements will create clutter to the table. Setting a value to nil using brackets will store a nil value to the table instead of removing the key from the table.\nThis operator does not throw unless you use it on non table objects or with nil keys.\n\n`luaval.has(key)` can be used to check if a value can be found in a table.\nThis function do not throw unless you use it on non table objects or with nil keys.\n\nA method for erasing data with a key is `luaval.rem(key)` which also returns the accessed table.\nThis function do not throw unless you use it on non table objects or with nil keys.\n\nExample usage of the functions:\n```C++\nLuaVal table(TTABLE); // create an empty table\ntable.set(1, \"test\").set(2, 77.234).set(3, -324); // set multiple values\ntable.set(\"self copy\", table); // attempting to set a table into itself will create a deep copy\ntable.set(table, \"table as key?\"); // table will work as a key, but it will be a deep copy so you can not access it later\nstd::cout \u003c\u003c table.get(\"self copy\").get(3).num() \u003c\u003c std::endl; // get a value from a nested table\ntable[\"number\"] = 234; // Use table access operator to assign a value\nLuaVal \u0026 value = table[\"number\"]; // Use table access operator to get a value\ntable.set(e, LuaVal::nil).rem(\"number\"); // remove some values through set and rem functions\nif (table.has(100) and table[100].isstring())\n\tstd::cout \u003c\u003c table[100].str() \u003c\u003c std::end;\n```\n\nFor conveniency tables also have the methods `luaval.insert(value[, pos])`, `luaval.remove([pos])` and `luaval.len()`.\nThe len function returns the number of consecutive integer key elements in the table starting at index 1. It is similar to the # operator in lua.\nInsert and remove shift the values on the right side of the given position and insert or remove a value to or at the given position. If position is omitted, the value is inserted to the end of the list or the last element is removed.\nInsert and remove both return the accessed table.\nEach function throws if used on a non table object or pos is not valid.\n\n### table merging\nYou can merge two tables with `LuaVal::mrg(tbl1, tbl2)`. This will make a new table that contains values from both tables. If they have same keys then tbl2 will overwrite tbl1 value in the new table.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frochet2%2Fsmallfolk_cpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frochet2%2Fsmallfolk_cpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frochet2%2Fsmallfolk_cpp/lists"}