Skip to content

Instantly share code, notes, and snippets.

@tomerfiliba
Created February 25, 2014 19:54
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomerfiliba/9216420 to your computer and use it in GitHub Desktop.
Save tomerfiliba/9216420 to your computer and use it in GitHub Desktop.
Consturct++: Pickler combinators in C++11
#include <iostream>
#include <sstream>
#include <cstdint>
#include <cstddef>
#include <string>
#include <memory>
#include <vector>
#include <tuple>
#include <utility>
#include <type_traits>
template<typename T> typename std::enable_if<std::is_integral<T>::value || std::is_floating_point<T>::value>::type
pack(std::ostream& stream, const T& value) {
stream.write((char*)&value, sizeof(T));
}
template<typename T> typename std::enable_if<std::is_integral<T>::value || std::is_floating_point<T>::value>::type
unpack(std::istream& stream, T &value) {
stream.read((char*)&value, sizeof(T));
}
template<typename T> typename std::enable_if<std::is_enum<T>::value>::type
pack(std::ostream& stream, const T& val) {
typename std::underlying_type<T>::type tmp = (typename std::underlying_type<T>::type)val;
pack(stream, tmp);
}
template<typename T> typename std::enable_if<std::is_enum<T>::value>::type
unpack(std::istream& stream, T &val) {
typename std::underlying_type<T>::type tmp;
unpack(stream, tmp);
val = (T)tmp;
}
void pack(std::ostream& stream, const bool& value) {
pack(stream, (uint8_t)value);
}
void unpack(std::istream& stream, bool& value) {
uint8_t tmp;
unpack(stream, tmp);
value = (tmp != 0);
}
typedef uint8_t length_type;
template<typename L=length_type> void pack(std::ostream& stream, const std::string& str) {
L length = (L)str.size();
pack(stream, length);
stream.write(str.data(), length);
}
template<typename L=length_type> void unpack(std::istream& stream, std::string& str) {
L length;
unpack(stream, length);
str.resize(length);
stream.read(const_cast<char*>(str.data()), length);
}
template<typename T, typename L=length_type> void pack(std::ostream& stream, const std::vector<T>& vec) {
L length = (L)vec.size();
pack(stream, length);
for (int i = 0; i < length; i++) {
pack(stream, vec[i]);
}
}
template<typename T, typename L=length_type> void unpack(std::istream& stream, std::vector<T>& vec) {
L length;
unpack(stream, length);
vec.resize(length);
for (int i = 0; i < length; i++) {
unpack(stream, vec[i]);
}
}
template<typename T, std::size_t N> void pack(std::ostream& stream, const T (&arr)[N]) {
for (int i = 0; i < N; i++) {
pack(stream, arr[i]);
}
}
template<typename T, std::size_t N> void unpack(std::istream& stream, T (&arr)[N]) {
for (int i = 0; i < N; i++) {
unpack(stream, arr[i]);
}
}
template<typename TUPLE, unsigned N, unsigned Last>
struct _tuple_packer {
static void tup_pack(std::ostream& stream, const TUPLE& tup) {
pack(stream, std::get<N>(tup));
_tuple_packer<TUPLE, N + 1, Last>::tup_pack(stream, tup);
}
static void tup_unpack(std::istream& stream, TUPLE& tup) {
unpack(stream, std::get<N>(tup));
_tuple_packer<TUPLE, N + 1, Last>::tup_unpack(stream, tup);
}
};
template<typename TUPLE, unsigned N>
struct _tuple_packer<TUPLE, N, N> {
static void tup_pack(std::ostream& stream, const TUPLE& tup) {
pack(stream, std::get<N>(tup));
}
static void tup_unpack(std::istream& stream, TUPLE& tup) {
unpack(stream, std::get<N>(tup));
}
};
template<typename... Types> void pack(std::ostream& stream, const std::tuple<Types...>& tup) {
_tuple_packer<std::tuple<Types...>, 0, sizeof...(Types) - 1>::tup_pack(stream, tup);
}
template<typename... Types> void pack(std::istream& stream, const std::tuple<Types&...>& tup) {
_tuple_packer<std::tuple<Types&...>, 0, sizeof...(Types) - 1>::tup_pack(stream, tup);
}
template<typename... Types> void unpack(std::ostream& stream, std::tuple<Types...>& tup) {
_tuple_packer<std::tuple<Types...>, 0, sizeof...(Types) - 1>::tup_unpack(stream, tup);
}
template<typename... Types> void unpack(std::istream& stream, std::tuple<Types&...>& tup) {
_tuple_packer<std::tuple<Types&...>, 0, sizeof...(Types) - 1>::tup_unpack(stream, tup);
}
struct packable {
virtual void _pack_self(std::ostream& stream) const = 0;
virtual void _unpack_self(std::istream& stream) = 0;
};
template<typename T> typename std::enable_if<std::is_base_of<packable, T>::value>::type
pack(std::ostream& stream, const T& pkd) {
pkd._pack_self(stream);
}
template<typename T> typename std::enable_if<std::is_base_of<packable, T>::value>::type
unpack(std::istream& stream, T &pkd) {
pkd._unpack_self(stream);
}
#define PACKED(...) \
void _pack_self(std::ostream& stream) const override { \
auto tmp = std::tie(__VA_ARGS__); \
pack(stream, tmp); \
} \
void _unpack_self(std::istream& stream) override { \
auto tmp = std::tie(__VA_ARGS__); \
unpack(stream, tmp); \
}
struct first_struct : packable {
uint8_t x;
uint16_t y;
PACKED(x, y);
};
struct second_struct : packable {
uint8_t a;
std::string b;
int16_t c[3][2];
first_struct d;
enum : uint16_t {
A = 1,
B = 2,
C = 3
} e;
PACKED(a, b, c, d, e)
};
int main(int argc, const char ** argv) {
std::stringstream ss;
ss << "A\x05helloa0b0c0d0e0f0Bg0\x02\x00XXXXXXXXXX";
second_struct x = {};
unpack(ss, x);
std::cout
<< "a=" << (int)x.a << ","
<< "b=" << x.b << ","
<< "c=" << x.c[0][0] << ".." << x.c[2][1] << ","
<< "d=(" << x.d.x << "," << x.d.y << "),"
<< "e=" << x.e
<< std::endl;
return 0;
}
a=65,b=hello,c=12385..12390,d=(B,12391),e=2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment