VariableLengthSerialise.h

// VariableLengthSerialise.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2009

#pragma once
#ifndef Ceda_cxUtils_VariableLengthSerialise_H
#define Ceda_cxUtils_VariableLengthSerialise_H

#include "cxUtils.h"
#include "BasicTypeSizes.h"

/*
Overflow version
----------------

Allows for sending of unsigned integer values in the range 0..2^29-1 (0..536870911) - i.e. 
up to about 500 million, using less bytes for smaller numbers if possible.

Byte order : Send the most significant byte first

    Range           Num bytes          Format
                      to send
    --------------------------------------------------
    0..2^7-1        send 1 byte     0 + 7 bits
    2^7..2^14-1     send 2 bytes    10 + 14=6+8  bits
    2^14..2^21-1    send 3 bytes    110 + 21=5+8+8 bits
    2^21..2^28-1    send 4 bytes    111 + 29=5+8+8+8 bits

2^7     =                                 1000 0000     =   0x00000080
2^14    =                       0100 0000 0000 0000     =   0x00004000
2^21    =            0010 0000  0000 0000 0000 0000     =   0x00200000
2^29    =  0010 0000 0000 0000  0000 0000 0000 0000     =   0x20000000

           1110 0000 0000 0000  0000 0000 0000 0000     =   0xE0000000

No overflow version
-------------------

Similar to the above except we allow for 5 bytes to be written to the archive to accomodate 
the full range of an unsigned int32.

Byte order : Send the most significant byte first

    Range           Num bytes          Format
                      to send
    --------------------------------------------------
    0..2^7-1        send 1 byte     0 + 7 bits
    2^7..2^14-1     send 2 bytes    10 + 14=6+8  bits
    2^14..2^21-1    send 3 bytes    110 + 21=5+8+8 bits
    2^21..2^28-1    send 4 bytes    1110 + 28=4+8+8+8 bits
    2^28..2^32-1    send 5 bytes    11110000 + 32=8+8+8+8 bits
    
Escape code support
-------------------

The no overflow version can represent up to 15 "escape codes" that only take up a single byte
In binary representation these are of the form

    1111XXXX
    
where XXXX is not equal to 0000 (since 0xF0 is reserved for sending the 5 byte sequence)

An implementation could use these for efficient "escape codes", that cannot be confused with values
in the range 0..2^32-1
*/

namespace ceda
{
const ssize_t MAX_VARIABLE_LENGTH_UINT_SIZE = 5;

/////////// uint32

// Calculates the number of bytes uses for the variable length representation of v
// Returns a value in range 1..5 inclusive
cxUtils_API ssize_t GetSizeVariableLengthUint32(uint32 v);

// Write the variable length representation of v at memory address p and returns the 
// next memory address write position, which is p+n where 1 <= n <= 5
cxUtils_API octet_t* SerialiseVariableLengthUint32(octet_t* p, uint32 v);

// Reads a variable length integer at memory address p into out-parameter v.  
// Returns the next memory read position which is p+n where 1 <= n <= 5.
cxUtils_API const octet_t* DeserialiseVariableLengthUint32(const octet_t* p, uint32& v);

// Version that allows for escape codes
cxUtils_API const octet_t* DeserialiseVariableLengthUint32(const octet_t* p, uint32& v, bool& escape);

/////////// T

template<typename T>
inline ssize_t GetSizeVariableLengthInteger(T v)
{
    return GetSizeVariableLengthUint32( (uint32) v );
}

template<typename T>
inline octet_t* SerialiseVariableLengthInteger(octet_t* p, T v)
{
    return SerialiseVariableLengthUint32(p, (uint32) v);
}

template<typename T>
inline const octet_t* DeserialiseVariableLengthInteger(const octet_t* p, T& v)
{
    uint32 v32;
    p = DeserialiseVariableLengthUint32(p,v32);
    v = (T) v32;
    return p;
}

template<typename T>
inline const octet_t* DeserialiseVariableLengthInteger(const octet_t* p, T& v, bool& escape)
{
    uint32 v32;
    p = DeserialiseVariableLengthUint32(p,v32,escape);
    v = (T) v32;
    return p;
}

} // namespace ceda

#endif // include guard