feat(util/serializer): simple serialization infrastructure

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-12-27 16:45:40 -08:00
parent 73cd48cb13
commit b72937c02c
6 changed files with 272 additions and 1 deletions

View file

@ -61,3 +61,6 @@ add_test(optional ${CMAKE_CURRENT_BINARY_DIR}/optional)
add_executable(stackinfo stackinfo.cpp) add_executable(stackinfo stackinfo.cpp)
target_link_libraries(stackinfo ${EXTRA_LIBS}) target_link_libraries(stackinfo ${EXTRA_LIBS})
add_test(stackinfo ${CMAKE_CURRENT_BINARY_DIR}/stackinfo) add_test(stackinfo ${CMAKE_CURRENT_BINARY_DIR}/stackinfo)
add_executable(serializer serializer.cpp)
target_link_libraries(serializer ${EXTRA_LIBS})
add_test(serializer ${CMAKE_CURRENT_BINARY_DIR}/serializer)

View file

@ -0,0 +1,128 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include <iostream>
#include <sstream>
#include <string>
#include <cstring>
#include <vector>
#include <functional>
#include "util/test.h"
#include "util/object_serializer.h"
#include "util/debug.h"
#include "util/list.h"
using namespace lean;
template<typename T>
struct list_ptr_hash { unsigned operator()(list<T> const & l) const { return std::hash<typename list<T>::cell*>()(l.raw()); } };
template<typename T>
struct list_ptr_eq { bool operator()(list<T> const & l1, list<T> const & l2) const { return l1.raw() == l2.raw(); } };
class list_int_serializer : public object_serializer<list<int>, list_ptr_hash<int>, list_ptr_eq<int>> {
typedef object_serializer<list<int>, list_ptr_hash<int>, list_ptr_eq<int>> super;
public:
void write(list<int> const & l) {
super::write(l, [&]() {
serializer & s = get_owner();
if (l) {
s.write_bool(true);
s.write_int(head(l));
write(tail(l));
} else {
s.write_bool(false);
}
});
}
};
class list_int_deserializer : public object_deserializer<list<int>> {
typedef object_deserializer<list<int>> super;
public:
list<int> read() {
return super::read([&]() {
deserializer & d = get_owner();
if (d.read_bool()) {
int h = d.read_int();
list<int> t = read();
return list<int>(h, t);
} else {
return list<int>();
}
});
}
};
struct list_int_initializer {
unsigned m_serializer_extid;
unsigned m_deserializer_extid;
list_int_initializer() {
m_serializer_extid = serializer::register_extension([](){ return std::unique_ptr<serializer::extension>(new list_int_serializer()); });
m_deserializer_extid = deserializer::register_extension([](){ return std::unique_ptr<deserializer::extension>(new list_int_deserializer()); });
}
};
static list_int_initializer g_list_int_initializer;
serializer & operator<<(serializer & s, list<int> const & l) {
s.get_extension<list_int_serializer>(g_list_int_initializer.m_serializer_extid).write(l);
return s;
}
deserializer & operator>>(deserializer & d, list<int> & l) {
l = d.get_extension<list_int_deserializer>(g_list_int_initializer.m_deserializer_extid).read();
return d;
}
static void tst1() {
std::ostringstream out;
serializer s(out);
s.write_int(10); s.write_int(20); s.write_bool(false); s.write_string("hello"); s.write_int(30);
std::istringstream in(out.str());
deserializer d(in);
lean_assert(d.read_int() == 10);
lean_assert(d.read_int() == 20);
lean_assert(!d.read_bool());
lean_assert(d.read_string() == "hello");
lean_assert(d.read_int() == 30);
}
static void tst2() {
std::ostringstream out;
serializer s(out);
list<int> l1{1, 2, 3, 4};
list<int> l2;
l2 = cons(10, l1);
list<int> l3;
l3 = cons(20, cons(30, l2));
s << l1 << l2 << l3 << l2 << l3;
std::cout << "OUT: ";
auto str = out.str();
for (auto c : str) {
std::cout << static_cast<int>(c) << " ";
}
std::cout << "\n";
std::istringstream in(out.str());
deserializer d(in);
list<int> new_l1, new_l2, new_l3, new_l4, new_l5;
d >> new_l1 >> new_l2 >> new_l3 >> new_l4 >> new_l5;
lean_assert_eq(l1, new_l1);
lean_assert_eq(l2, new_l2);
lean_assert_eq(l3, new_l3);
lean_assert_eq(l2, new_l4);
lean_assert_eq(l3, new_l5);
lean_assert(is_eqp(new_l1, tail(new_l2)));
lean_assert(is_eqp(new_l2, tail(tail(new_l3))));
lean_assert(is_eqp(new_l4, new_l2));
lean_assert(is_eqp(new_l5, new_l3));
}
int main() {
tst1();
tst2();
return has_violations() ? 1 : 0;
}

View file

@ -8,6 +8,6 @@ add_library(util trace.cpp debug.cpp name.cpp name_set.cpp
exception.cpp interrupt.cpp hash.cpp escaped.cpp bit_tricks.cpp exception.cpp interrupt.cpp hash.cpp escaped.cpp bit_tricks.cpp
safe_arith.cpp ascii.cpp memory.cpp shared_mutex.cpp realpath.cpp safe_arith.cpp ascii.cpp memory.cpp shared_mutex.cpp realpath.cpp
script_state.cpp script_exception.cpp splay_map.cpp lua.cpp script_state.cpp script_exception.cpp splay_map.cpp lua.cpp
luaref.cpp stackinfo.cpp lean_path.cpp ${THREAD_CPP}) luaref.cpp stackinfo.cpp lean_path.cpp serializer.cpp ${THREAD_CPP})
target_link_libraries(util ${LEAN_LIBS}) target_link_libraries(util ${LEAN_LIBS})

View file

@ -0,0 +1,61 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include <unordered_map>
#include <vector>
#include "util/serializer.h"
#ifndef LEAN_OBJECT_SERIALIZER_BUCKET_SIZE
#define LEAN_OBJECT_SERIALIZER_BUCKET_SIZE 8
#endif
namespace lean {
/**
\brief Helper class for serializing objects.
*/
template<class T, class HashFn, class EqFn>
class object_serializer : public serializer::extension {
std::unordered_map<T, unsigned, HashFn, EqFn> m_table;
public:
object_serializer(HashFn const & h = HashFn(), EqFn const & e = EqFn()):m_table(LEAN_OBJECT_SERIALIZER_BUCKET_SIZE, h, e) {}
template<typename F>
void write(T const & v, F && f) {
auto it = m_table.find(v);
serializer & s = get_owner();
if (it == m_table.end()) {
s.write_bool(true);
f();
m_table.insert(std::make_pair(v, m_table.size()));
} else {
s.write_bool(false);
s.write_unsigned(it->second);
}
}
};
/**
\brief Helper class for deserializing objects.
*/
template<class T>
class object_deserializer : public deserializer::extension {
std::vector<T> m_table;
public:
template<typename F>
T read(F && f) {
deserializer & d = get_owner();
if (d.read_bool()) {
T r = f();
m_table.push_back(r);
return r;
} else {
unsigned i = d.read_unsigned();
lean_assert(i < m_table.size());
return m_table[i];
}
}
};
}

21
src/util/serializer.cpp Normal file
View file

@ -0,0 +1,21 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include <string>
#include "util/serializer.h"
namespace lean {
std::string deserializer_core::read_string() {
std::string r;
while (true) {
char c = m_in.get();
if (c == 0)
break;
r += c;
}
return r;
}
}

58
src/util/serializer.h Normal file
View file

@ -0,0 +1,58 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include <iostream>
#include <string>
#include <sstream>
#include <cstring>
#include "util/extensible_object.h"
namespace lean {
/**
\brief Low-tech serializer.
The actual functionality is implemented using extensions.
*/
class serializer_core {
std::ostream & m_out;
public:
serializer_core(std::ostream & out):m_out(out) {}
void write_string(char const * str) { m_out.write(str, strlen(str) + 1); }
void write_string(std::string const & str) { m_out.write(str.c_str(), str.size() + 1); }
void write_unsigned(unsigned i) { m_out.write(reinterpret_cast<char*>(&i), sizeof(i)); }
void write_int(int i) { m_out.write(reinterpret_cast<char*>(&i), sizeof(i)); }
void write_bool(bool b) { m_out.put(b ? 1 : 0); }
};
typedef extensible_object<serializer_core> serializer;
inline serializer & operator<<(serializer & s, char const * str) { s.write_string(str); return s; }
inline serializer & operator<<(serializer & s, std::string const & str) { s.write_string(str); return s; }
inline serializer & operator<<(serializer & s, unsigned i) { s.write_unsigned(i); return s; }
inline serializer & operator<<(serializer & s, int i) { s.write_int(i); return s; }
inline serializer & operator<<(serializer & s, bool b) { s.write_bool(b); return s; }
/**
\brief Low-tech serializer.
The actual functionality is implemented using extensions.
*/
class deserializer_core {
std::istream & m_in;
public:
deserializer_core(std::istream & in):m_in(in) {}
std::string read_string();
int read_int() { int r; m_in.read(reinterpret_cast<char*>(&r), sizeof(r)); return r; }
unsigned read_unsigned() { unsigned r; m_in.read(reinterpret_cast<char*>(&r), sizeof(r)); return r; }
bool read_bool() { return m_in.get() != 0; }
};
typedef extensible_object<deserializer_core> deserializer;
inline deserializer & operator>>(deserializer & d, std::string & str) { str = d.read_string(); return d; }
inline deserializer & operator>>(deserializer & d, unsigned & i) { i = d.read_unsigned(); return d; }
inline deserializer & operator>>(deserializer & d, int & i) { i = d.read_int(); return d; }
inline deserializer & operator>>(deserializer & d, bool & b) { b = d.read_bool(); return d; }
}