I am trying to serialize an icu::UnicodeString with the boost serialization library but am having trouble.
The icu::UnicodeString does not have the required serialize function to serialize it. So I tried to create it, but I am not sure how to make these. Example code:
#include <map>
#include <sstream>
#include <fstream>
#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <boost/serialization/map.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
namespace boost {
namespace serialization {
template<class Archive>
inline void save(
Archive & ar,
const icu_55::UnicodeString& str,
const unsigned int /* file_version */
){
}
template<class Archive>
inline void load(
Archive & ar,
icu_55::UnicodeString& str,
const unsigned int /* file_version */
){
}
// split non-intrusive serialization function member into separate
// non intrusive save/load member functions
template<class Archive>
inline void serialize(
Archive & ar,
icu_55::UnicodeString& str,
const unsigned int file_version
){
boost::serialization::split_free(ar, str, file_version);
}
} // serialization
} // namespace boost
int main()
{
std::map<icu::UnicodeString, int> map = {{"asssdasd",2}, {"qwe",1}, {"Zxc",55}};
std::stringstream ss;
boost::archive::text_oarchive oarch(ss);
oarch << map;
std::map<icu::UnicodeString, int> new_map;
boost::archive::text_iarchive iarch(ss);
iarch >> new_map;
std::cout << (map == new_map) << std::endl;
}
Compile with something like g++ -o new new.cpp -std=c++11 -lboost_serialization -licuuc
Currently the "save" and "load" functions are not implemented. I tried doing just the ar & str;
statements that are used in the boost manuals, but I am getting a segmentation fault with that that I am also unable to fix.
I've never worked with LibICU directly, so probably someone can review this code.
However, from my experience using Boost Serialization I think this should be helpful:
template <class Archive>
inline void save(Archive &ar, icu_55::UnicodeString const &str, const unsigned int) {
auto sz = str.getCapacity();
auto len = str.length();
auto buf = str.getBuffer();
if (!buf) throw std::invalid_argument("str");
ar & sz & len & boost::serialization::make_array(buf, sz);
}
template <class Archive>
inline void load(Archive &ar, icu_55::UnicodeString &str, const unsigned int)
{
size_t sz, len;
ar & sz & len;
auto buf = str.getBuffer(sz);
if (!buf) throw std::invalid_argument("str");
try {
ar & boost::serialization::make_array(buf, sz);
}
catch(...) {
str.releaseBuffer(len);
throw;
}
str.releaseBuffer(len);
}
It works for the simple test case provided:
#include <fstream>
#include <map>
#include <sstream>
#include <iostream>
#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/map.hpp>
namespace boost { namespace serialization {
template <class Archive>
inline void save(Archive &ar, icu_55::UnicodeString const &str, const unsigned int) {
auto sz = str.getCapacity();
auto len = str.length();
auto buf = str.getBuffer();
if (!buf) throw std::invalid_argument("str");
ar & sz & len & boost::serialization::make_array(buf, sz);
}
template <class Archive>
inline void load(Archive &ar, icu_55::UnicodeString &str, const unsigned int)
{
size_t sz, len;
ar & sz & len;
auto buf = str.getBuffer(sz);
if (!buf) throw std::invalid_argument("str");
try {
ar & boost::serialization::make_array(buf, sz);
}
catch(...) {
str.releaseBuffer(len);
throw;
}
str.releaseBuffer(len);
}
// split non-intrusive serialization function member into separate
// non intrusive save/load member functions
template <class Archive>
inline void serialize(Archive &ar, icu_55::UnicodeString &str, const unsigned int file_version) {
boost::serialization::split_free(ar, str, file_version);
}
} } // serialization // namespace boost
int main() {
std::map<icu::UnicodeString, int> const map = { { "asssdasd", 2 }, { "qwe", 1 }, { "Zxc", 55 } };
std::stringstream ss;
{
boost::archive::text_oarchive oarch(ss);
oarch << map;
}
{
std::map<icu::UnicodeString, int> new_map;
boost::archive::text_iarchive iarch(ss);
iarch >> new_map;
std::cout << (map == new_map) << std::endl;
}
}
Prints
1