r-lyeh / tinybits

Tiny bits and useful snippets that I keep using everywhere (C, C++)
The Unlicense
313 stars 23 forks source link

tinyserialize #3

Open RandyGaul opened 5 years ago

RandyGaul commented 5 years ago

Here's one you might like! It's endian agnostic since it reads or writes one byte at the time. The underlying CPU architecture handles endianness within the bitshift operators. No need for byteswap stuff. I use these functions all the time. Very copy + pasteable.

#ifdef _WIN32
#   define TINYBITS_RESTRICT __restrict
#else
#   define TINYBITS_RESTRICT __restrict__
#endif

#include <stdint.h>

inline uint8_t read_uint8(const uint8_t** TINYBITS_RESTRICT p)
{
    uint8_t value = **p;
    ++(*p);
    return value;
}

inline uint32_t read_uint32(const uint8_t** TINYBITS_RESTRICT p)
{
    uint32_t value;
    value  = (*p)[0];
    value |= (((uint32_t)((*p)[1])) << 8);
    value |= (((uint32_t)((*p)[2])) << 16);
    value |= (((uint32_t)((*p)[3])) << 24);
    *p += 4;
    return value;
}

inline float read_float(const uint8_t** TINYBITS_RESTRICT p)
{
    union
    {
        uint32_t auint32;
        float afloat;
    } val;
    val.auint32 = read_uint32(p);
    return val.afloat;
}

inline v3 read_v3(const uint8_t** TINYBITS_RESTRICT p)
{
    float x = read_float(p);
    float y = read_float(p);
    float z = read_float(p);
    return v3(x, y, z);
}

void read_fourcc(const uint8_t** TINYBITS_RESTRICT p, uint8_t* TINYBITS_RESTRICT fourcc)
{
    fourcc[0] = read_uint8(p);
    fourcc[1] = read_uint8(p);
    fourcc[2] = read_uint8(p);
    fourcc[3] = read_uint8(p);
}

inline void write_uint8(uint8_t** TINYBITS_RESTRICT p, uint8_t value)
{
    **p = value;
    ++(*p);
}

inline void write_uint32(uint8_t** TINYBITS_RESTRICT p, uint32_t value)
{
    (*p)[0] = value & 0xFF;
    (*p)[1] = (value >> 8 ) & 0xFF;
    (*p)[2] = (value >> 16) & 0xFF;
    (*p)[3] = value >> 24;
    *p += 4;
}

inline void write_float(uint8_t** TINYBITS_RESTRICT p, float value)
{
    union
    {
        uint32_t auint32;
        float afloat;
    } val;
    val.afloat = value;
    write_uint32(p, val.auint32);
}

inline void write_v3(uint8_t** TINYBITS_RESTRICT p, v3 value)
{
    write_float(p, value.x());
    write_float(p, value.y());
    write_float(p, value.z());
}

inline void write_fourcc(uint8_t** TINYBITS_RESTRICT p, const char* TINYBITS_RESTRICT fourcc)
{
    write_uint8(p, fourcc[0]);
    write_uint8(p, fourcc[1]);
    write_uint8(p, fourcc[2]);
    write_uint8(p, fourcc[3]);
}
r-lyeh commented 5 years ago

Cool thx. I think this topic is a interesting addition! I also have small msgpack and json/json5 parsers/writers lying around! :D

RandyGaul commented 5 years ago

Oh great. I've been interested in JSON parsers lately. The more the better. It's nice to see a wide variety of styles to get ideas from. In my own game I'm using something really similar to JSON and spent a lot of energy to make sure that code is easy to re-learn later when I need to modify it... Most parsers I've seen were not written with code maturation in mind.

r-lyeh commented 5 years ago

I've extracted tinyjson5 from AVA engine. It is a JSON5/SJSON/JSON parser and JSON writer, which happens to be small and fast enough (parses 55 MiB JSON file at 230 ms in my computer). Hope it helps or serves as a good base :D Feedback welcome!

cl tinyjson5.c -DJSON5_C -DJSON5_BENCH /O2 /Oy /MT /DNDEBUG
cl tinyjson5.c -DJSON5_C -DJSON5_DEMO /O2 /Oy /MT /DNDEBUG

PS: Dunno if tinydixy or tinyini+ could also satisfy your needs. Is it for config files maybe?

RandyGaul commented 5 years ago

That JSON parser does look pretty well written. Thanks! I'll be coming back in the future and probably referencing it :P

I took a look at ini, but actually have no idea how to use it. Can it save ini files? Can it add sections? Or is it only for loading ini files?

Personally I would look for something like ini_parse(buffer, sz), and then ini_get(key, &char_ptr) and that sort of thing. Otherwise it looks complicated to figure out how to use.

r-lyeh commented 5 years ago

tinyini only load files and provide a list of pairs {key:value}. The point is that it parses a superset of ini which includes a few more options to work with.

r-lyeh commented 5 years ago

in the tinyini demo, rather than printf'ing pairs, you could add them to a map<string,string> for further lookups and that would be enough for an end-user, I guess.