Data shared among processes could be limited to integers and strings. Other types could be present with these two types.
1. A floating value could be presented in the form of mantissa and exponent, both could be int type.
2. Composed types are built upon integers and strings
Keys:
1. A string is a sequence of bytes leading its length
2. An integer is in the form of a sequence of bytes. For each byte, the highest byte is an indicator showing whether more bytes followed; the lower 7bits of all bytes compose that integer. The 1th byte is for 0-6th bit of the integer, the 2nd byte is for 7-13th bit of that integer, etc. Why we do this way? It's independent of the byte order of the system. And it could also save memory. e.g., an int of 56 normally occupies 4 bytes for a 32-bit system. Encode it with our tool, only 1 byte is needed. As long as we have a well-designed protocol, we could save a lot of network bandwidth.
The code is attached bellow. Comments are welcomed via emails. Enjoy :-).
//feel free to use it in your project with nothing guaranteed
//mail to: bruceadi(at)hotmail.com
#include <iostream>
#include <fstream>
class encoder
{
public:
encoder(std::ostream& os): os_(os)
{
}
encoder& operator <<(int val)
{
return *this << (unsigned int)(val);
}
encoder& operator <<(unsigned int val)
{
do
{
unsigned char b = val & 0x7f;
val >>= 7;
if(val) b |= 0x80;
os_.write((char*)&b, 1);
}while(val);
return *this;
}
encoder& operator <<(char val)
{
os_.write(&val, 1);
return *this;
}
encoder& operator <<(unsigned char val)
{
os_.write((char*)&val, 1);
return *this;
}
encoder& operator <<(signed char val)
{
os_.write((char*)&val, 1);
return *this;
}
encoder& operator <<(char const* val)
{
size_t len = strlen(val);
*this << len;
os_.write(val, len);
return *this;
}
private:
encoder& operator=(encoder const&);
encoder(encoder const&);
std::ostream& os_;
};
class decoder
{
public:
decoder(std::istream& is): is_(is)
{
}
decoder& operator >> (int& val)
{
unsigned int v;
*this >> v;
val = (int)v;
return *this;
}
decoder& operator >> (unsigned int& val)
{
val = 0;
unsigned char ch, cnt = 0;
do
{
is_.read((char*)&ch, 1);
val += (ch & 0x7f) << cnt;
cnt += 7;
}while(ch & 0x80);
return *this;
}
decoder& operator >> (char& val)
{
is_.read(&val, 1);
return *this;
}
decoder& operator >> (unsigned char& val)
{
is_.read((char*)&val, 1);
return *this;
}
decoder& operator >> (signed char& val)
{
is_.read((char*)&val, 1);
return *this;
}
decoder& operator >> (char* val)
{
size_t len;
*this >> len;
is_.read(val, len);
val[len] = 0;
return *this;
}
private:
decoder& operator=(decoder const&);
decoder(decoder const&);
std::istream& is_;
};
//the following code is only for demostration, not part of the library
struct Float
{
int exp;
int man;
};
encoder& operator<<(encoder & en,Float const& f)
{
return en << f.man << f.exp;
}
decoder& operator >> (decoder & de, Float& f)
{
return de >> f.man >> f.exp;
}
struct Message
{
char c;
short s;
int i;
unsigned char str[2];
char name[4];
};
encoder& operator<<(encoder & en,Message const& msg)
{
en << msg.c << (int)msg.s << msg.i;
for(size_t i = 0; i < sizeof(msg.str); ++i)
{
en << msg.str[i];
}
en << msg.name;
return en;
}
decoder& operator >> (decoder & de,Message & msg)
{
de >> msg.c;
int s;
de >> s >> msg.i;
msg.s = (short)s;
for(size_t i = 0; i < sizeof(msg.str); ++i)
{
de >> msg.str[i];
}
de >> msg.name;
return de;
}
std::ostream& operator<<(std::ostream& os, Message const& msg)
{
return os << msg.c << " " << msg.s << " " << msg.i << " " << (int)msg.str[0] << " "<< (int)msg.str[1] << " "
<< (unsigned int)msg.name[0] << " "<< (unsigned int)msg.name[1] << " "
<< (unsigned int)msg.name[2] << " "<< (unsigned int)msg.name[3] << std::endl;
}
std::ostream& operator<<(std::ostream& os, Float const& f)
{
return os << f.exp << " " << f.man;
}
template <typename T>
void test(T const& a )
{
{
std::cout << "before: " << std::endl << a << std::endl;
std::ofstream ofs("bin");
encoder en(ofs);
en << a;
}
{
T msg;
std::ifstream ifs("bin");
decoder de(ifs);
de >> msg;
std::cout << "after: " << std::endl << msg << std::endl;
}
}
int main ()
{
test(7867);
test(90U);
Message msg;
strncpy(msg.name, "yello ass", sizeof(msg.name) -1 );
test(msg);
Float f;
test(f);
return 0;
}