joy

Dependencies:   mbed USBDevice USBJoystick_

buffer_builder.hpp

Committer:
gagarinlg
Date:
2021-08-01
Revision:
2:d9f806076779

File content as of revision 2:d9f806076779:

/*
 * buffer_builder.hpp
 *
 *  Created on: Nov 25, 2011
 *      Author: premmers
 */

#ifndef BUFFER_BUILDER_HPP_
#define BUFFER_BUILDER_HPP_

#include <vector>
#include <assert.h>
#include <stdint.h>
#include <string.h>

//#include "utilities.h"

class buffer_builder
{
public:
    static inline void put(uint8_t *&p, uint8_t &bitoffset, uint8_t fieldlen, uint32_t value) {

        assert(bitoffset < 8);
        assert(fieldlen <= 32);

        uint32_t mask = (1U<<fieldlen)-1;
        value &= mask;

        uint8_t b;

        // first byte
        if (bitoffset > 0)
        {
            uint8_t remaining_bits = 8-bitoffset;
            int8_t unused_bits = int8_t(remaining_bits - fieldlen);
            if (unused_bits > 0)
            {
                b = *p;
                b &= ~(mask << unused_bits);
                b |= value << unused_bits;
                *p = b;
                bitoffset += fieldlen;
                return;
            }

            // all the remaining bits in first byte are in use
            fieldlen -= remaining_bits;
            b = *p;
            b &= ~(mask >> fieldlen);
            b |= value >> fieldlen;
            *p++ = b;
            bitoffset = 0;
        }

        // middle section (whole bytes)
        while (fieldlen >= 8)
        {
            fieldlen -= 8;
            *p++ = (value >> fieldlen) & 0xFF;
        }

        // last byte
        if (fieldlen > 0)
        {
            b = *p;
            b &= 0xFFU >> fieldlen;
            b |= value << (8-fieldlen);
            *p = b;
            bitoffset = fieldlen;
        }
    }

    static inline void put_u8(uint8_t *&p, uint8_t b)
    {
        *p++ = b;
    }
    static inline void put_u16(uint8_t *&p, uint16_t w)
    {
        *p++ = (uint8_t)(w>> 8);
        *p++ = (uint8_t)(w);
    }
    static inline void put_u16le(uint8_t *&p, uint16_t w)
    {
        *p++ = (uint8_t)(w);
        *p++ = (uint8_t)(w>> 8);
    }
    static inline void put_u32(uint8_t *&p, uint32_t d)
    {
        *p++ = (uint8_t)(d>>24);
        *p++ = (uint8_t)(d>>16);
        *p++ = (uint8_t)(d>> 8);
        *p++ = (uint8_t)(d);
    }
    static inline void put_u32le(uint8_t *&p, uint32_t d)
    {
        *p++ = (uint8_t)(d);
        *p++ = (uint8_t)(d>> 8);
        *p++ = (uint8_t)(d>>16);
        *p++ = (uint8_t)(d>>24);
    }
    static inline void put_u64(uint8_t *&p, uint64_t d)
    {
        *p++ = (uint8_t)(d>>56);
        *p++ = (uint8_t)(d>>48);
        *p++ = (uint8_t)(d>>40);
        *p++ = (uint8_t)(d>>32);
        *p++ = (uint8_t)(d>>24);
        *p++ = (uint8_t)(d>>16);
        *p++ = (uint8_t)(d>> 8);
        *p++ = (uint8_t)(d);
    }
    static inline void put_u64le(uint8_t *&p, uint64_t d)
    {
        *p++ = (uint8_t)(d);
        *p++ = (uint8_t)(d>> 8);
        *p++ = (uint8_t)(d>>16);
        *p++ = (uint8_t)(d>>24);
        *p++ = (uint8_t)(d>>32);
        *p++ = (uint8_t)(d>>40);
        *p++ = (uint8_t)(d>>48);
        *p++ = (uint8_t)(d>>56);
    }
    static inline void put(uint8_t *&p, const uint8_t *data, size_t len)
    {
        memcpy(p, data, len);
        p += len;
    }

    static inline void put_u8(std::vector<uint8_t> &v, uint8_t b)
    {
        v.push_back(b);
    }
    static inline void put_u16(std::vector<uint8_t> &v, uint16_t w)
    {
        v.push_back((uint8_t)(w>> 8));
        v.push_back((uint8_t)(w));
    }
    static inline void put_u16le(std::vector<uint8_t> &v, uint16_t w)
    {
        v.push_back((uint8_t)(w));
        v.push_back((uint8_t)(w>> 8));
    }
    static inline void put_u32(std::vector<uint8_t> &v, uint32_t d)
    {
        v.push_back((uint8_t)(d>>24));
        v.push_back((uint8_t)(d>>16));
        v.push_back((uint8_t)(d>> 8));
        v.push_back((uint8_t)(d));
    }
    static inline void put_u32le(std::vector<uint8_t> &v, uint32_t d)
    {
        v.push_back((uint8_t)(d));
        v.push_back((uint8_t)(d>> 8));
        v.push_back((uint8_t)(d>>16));
        v.push_back((uint8_t)(d>>24));
    }
    static inline void put_u64(std::vector<uint8_t> &v, uint64_t d)
    {
        v.push_back((uint8_t)(d>>56));
        v.push_back((uint8_t)(d>>48));
        v.push_back((uint8_t)(d>>40));
        v.push_back((uint8_t)(d>>32));
        v.push_back((uint8_t)(d>>24));
        v.push_back((uint8_t)(d>>16));
        v.push_back((uint8_t)(d>> 8));
        v.push_back((uint8_t)(d));
    }
    static inline void put_u64le(std::vector<uint8_t> &v, uint64_t d)
    {
        v.push_back((uint8_t)(d));
        v.push_back((uint8_t)(d>> 8));
        v.push_back((uint8_t)(d>>16));
        v.push_back((uint8_t)(d>>24));
        v.push_back((uint8_t)(d>>32));
        v.push_back((uint8_t)(d>>40));
        v.push_back((uint8_t)(d>>48));
        v.push_back((uint8_t)(d>>56));
    }
    static inline void put(std::vector<uint8_t> &v, const uint8_t *data, size_t len)
    {
        v.insert(v.end(), data, data+len);
    }

    static inline void fill(std::vector<uint8_t> &v, uint8_t value, size_t len)
    {
        v.resize(v.size()+len, value);
    }

    explicit buffer_builder(std::vector<uint8_t> &v) : data(v), initial_size(v.size()) {}
    buffer_builder(const buffer_builder& rhs) : data(rhs.data), initial_size(rhs.data.size()) {}

    size_t written() const
    {
        return data.size() - initial_size;
    }
    void put_u8(uint8_t b)      { put_u8(data, b); }
    void put_u16(uint16_t w)    { put_u16(data, w); }
    void put_u16le(uint16_t w)  { put_u16le(data, w); }
    void put_u32(uint32_t w)    { put_u32(data, w); }
    void put_u32le(uint32_t w)  { put_u32le(data, w); }
    void put_u64(uint64_t w)    { put_u64(data,w); }
    void put_u64le(uint64_t w)  { put_u64le(data,w); }
#ifdef __ADSPBLACKFIN__
    void put_float(float f)     { put_u32(*(uint32_t*)&f); }
    void put_floatle(float f)   { put_u32le(*(uint32_t*)&f); }
    void put_double(double d)   { put_u64(*(uint64_t*)&d); }
    void put_doublele(double d) { put_u64le(*(uint64_t*)&d); }
    COMPILETIME_ASSERT(sizeof(double)==8);
    COMPILETIME_ASSERT(sizeof(float)==4);
#endif
    void put(const uint8_t *p, size_t len) { put(data, p, len); }
    void put(const void *p, size_t len) { put(data, (const uint8_t*)p, len); }
    void fill(uint8_t v, size_t len) { fill(data, v, len); }
    uint8_t* putptr(size_t len)
    {
        size_t s = data.size();
        data.insert(data.end(), len, uint8_t());
        return &data[s];
    }

    template<typename T, void (*F)(uint8_t *&, T)>
    class ref
    {
    public:
        void operator=(T d)
        {
            uint8_t* p = &data[index];
            F(p, d);
        }
    private:
        friend class buffer_builder;
        ref(std::vector<uint8_t> &data, size_t index) : data(data), index(index) {}
        std::vector<uint8_t> &data;
        size_t index;
    };

    typedef ref<uint8_t,  &buffer_builder::put_u8>    ref_u8;
    typedef ref<uint16_t, &buffer_builder::put_u16>   ref_u16;
    typedef ref<uint16_t, &buffer_builder::put_u16le> ref_u16le;
    typedef ref<uint32_t, &buffer_builder::put_u32>   ref_u32;
    typedef ref<uint32_t, &buffer_builder::put_u32le> ref_u32le;
    typedef ref<uint64_t, &buffer_builder::put_u64>   ref_u64;
    typedef ref<uint64_t, &buffer_builder::put_u64le> ref_u64le;

    ref_u8    put_ref_u8()    { ref_u8    r(data, data.size()); put_u8(0);    return r; }
    ref_u16   put_ref_u16()   { ref_u16   r(data, data.size()); put_u16(0);   return r; }
    ref_u16le put_ref_u16le() { ref_u16le r(data, data.size()); put_u16le(0); return r; }
    ref_u32   put_ref_u32()   { ref_u32   r(data, data.size()); put_u32(0);   return r; }
    ref_u32le put_ref_u32le() { ref_u32le r(data, data.size()); put_u32le(0); return r; }
    ref_u64   put_ref_u64()   { ref_u64   r(data, data.size()); put_u64(0);   return r; }
    ref_u64le put_ref_u64le() { ref_u64le r(data, data.size()); put_u64le(0); return r; }

    std::vector<uint8_t> &getData() { return data; }
private:
    buffer_builder();
    std::vector<uint8_t> &data;
    size_t initial_size;
};



#endif /* BUFFER_BUILDER_HPP_ */