Bare minimal header-only binary stream based on C++ file streams where the stream operator can be overloaded for your custom type.
#include<iostream>
#include"SimpleBinStream.h"// Testing memory streamvoidTestMem()
{
simple::mem_ostream out;
out << 23 << 24 << "Hello world!";
simple::mem_istream in(out.get_internal_vec());
int num1 = 0, num2 = 0;
std::string str;
in >> num1 >> num2 >> str;
cout << num1 << "," << num2 << "," << str << endl;
}
// Testing file streamvoidTestFile()
{
simple::file_ostream out("file.bin", std::ios_base::out | std::ios_base::binary);
out << 23 << 24 << "Hello world!";
out.flush();
out.close();
simple::file_istream in("file.bin", std::ios_base::in | std::ios_base::binary);
int num1 = 0, num2 = 0;
std::string str;
in >> num1 >> num2 >> str;
cout << num1 << "," << num2 << "," << str << endl;
}Requires C++11 compiler and standard library now.
The classes are templates now.
template<typename same_endian_type>
classfile_istream {...}template<typename same_endian_type>
classmem_istream {...}template<typename same_endian_type>
classptr_istream {...}template<typename same_endian_type>
classfile_ostream {...}template<typename same_endian_type>
classmem_ostream {...}How to pass in same_endian_type to the class? Use std::is_same<>.
// 1st parameter is data endian and 2 parameter is platform endian, if they are different, swap.using same_endian_type = std::is_same<simple::BigEndian, simple::LittleEndian>;
simple::mem_ostream<same_endian_type> out;
out << (int64_t)23 << (int64_t)24 << "Hello world!";
simple::ptr_istream<same_endian_type> in(out.get_internal_vec());
int64_t num1 = 0, num2 = 0;
std::string str;
in >> num1 >> num2 >> str;
cout << num1 << "," << num2 << "," << str << endl;If your data and platform shares the same endianness, you can skip the test by specifying std::true_type directly.
simple::mem_ostream<std::true_type> out;
out << (int64_t)23 << (int64_t)24 << "Hello world!";
simple::ptr_istream<std::true_type> in(out.get_internal_vec());
int64_t num1 = 0, num2 = 0;
std::string str;
in >> num1 >> num2 >> str;
cout << num1 << "," << num2 << "," << str << endl;- For same_endian_type = true_type, the swap function is a empty function which is optimised away.
- For same_endian_type = false_type, the swapping is done without any prior runtime check cost.
- Cannot parse file/data which is sometime different endian. I believe this scenario is rare.
Swap functions are listed below.
enumclassEndian
{
Big,
Little
};
using BigEndian = std::integral_constant<Endian, Endian::Big>;
using LittleEndian = std::integral_constant<Endian, Endian::Little>;
template<typename T>
voidswap(T& val, std::true_type)
{
// same endian so do nothing.
}
template<typename T>
voidswap(T& val, std::false_type)
{
std::is_arithmetic<T> is_integral_type;
swap_if_arithmetic(val, is_integral_type);
}
template<typename T>
voidswap_if_arithmetic(T& val, std::false_type)
{
// T is not arithmetic so do nothing
}
template<typename T>
voidswap_if_arithmetic(T& val, std::true_type)
{
swap_endian<T, sizeof(T)>()(val);
}
template<typename T, size_t N>
structswap_endian
{
voidoperator()(T& ui)
{
}
};
template<typename T>
structswap_endian<T, 8>
{
voidoperator()(T& ui)
{
union EightBytes
{
T ui;
uint8_t arr[8];
};
EightBytes fb;
fb.ui = ui;
// swap the endianstd::swap(fb.arr[0], fb.arr[7]);
std::swap(fb.arr[1], fb.arr[6]);
std::swap(fb.arr[2], fb.arr[5]);
std::swap(fb.arr[3], fb.arr[4]);
ui = fb.ui;
}
};
template<typename T>
structswap_endian<T, 4>
{
voidoperator()(T& ui)
{
union FourBytes
{
T ui;
uint8_t arr[4];
};
FourBytes fb;
fb.ui = ui;
// swap the endianstd::swap(fb.arr[0], fb.arr[3]);
std::swap(fb.arr[1], fb.arr[2]);
ui = fb.ui;
}
};
template<typename T>
structswap_endian<T, 2>
{
voidoperator()(T& ui)
{
union TwoBytes
{
T ui;
uint8_t arr[2];
};
TwoBytes fb;
fb.ui = ui;
// swap the endianstd::swap(fb.arr[0], fb.arr[1]);
ui = fb.ui;
}
};Benchmark of 0.9.7 against 0.9.5
# File streams
old::file_ostream: 359ms
old::file_istream: 416ms
new::file_ostream: 216ms
new::file_istream: 328ms
new::memfile_ostream: 552ms
new::memfile_istream: 12ms
# In-memory streams
new::mem_ostream: 534ms
new::mem_istream: 16ms
new::ptr_istream: 15ms