#include #include #include #include #include #include #include #include #include #include namespace mi = boost::multi_index; // Entries behave like filesystem paths: they have a derived "dirname" class Entry { public: Entry() : m_dirname(), m_file() {} Entry(const std::string &dirname, const std::string &file) : m_dirname(dirname), m_file(file) {} Entry(const Entry &entry) : m_dirname(entry.m_dirname), m_file(entry.m_file) {} std::string entry() const { return m_dirname + '/' + m_file; } const std::string & dirname() const { return m_dirname; } bool operator<(const Entry &entry) const { return m_dirname < entry.m_dirname || (m_dirname == entry.m_dirname && m_file < entry.m_file); } friend class boost::serialization::access; template void serialize(Archive & ar, const unsigned int version) { ar & m_dirname & m_file; } private: std::string m_dirname, m_file; }; // Mappings store multiple Entries, eg "entry" and "target", for this example they only store 1. struct Mapping { Entry entry; Mapping() : entry() {} Mapping(const Entry &entry) : entry(entry) {} // wrapper around entry.m_dirname for const_mem_fun index. only the reference needs serializing not the value. const std::string &getdirname() const { return entry.dirname(); } friend std::ostream& operator<<(std::ostream& os, const Mapping& mapping) { os << "entry `" << mapping.entry.entry() << "' with dirname `"<< mapping.getdirname() << "'." << std::endl; return os; } friend class boost::serialization::access; template void serialize(Archive & ar, const unsigned int version) { ar & entry; } }; // Mapping Entries can be accessed by entry (their main index) but also by containing dirname. struct by_entry {}; struct by_dirname {}; // a const_mem_fun non-unique index from the returned const reference. typedef mi::multi_index_container< Mapping, mi::indexed_by< mi::ordered_unique< mi::tag, BOOST_MULTI_INDEX_MEMBER(Mapping, Entry, entry) >, mi::ordered_non_unique< mi::tag, BOOST_MULTI_INDEX_CONST_MEM_FUN(Mapping, const std::string&, getdirname) > > > EntrySet; template void print_out(const MultiIndexContainer& s, const char *message) { const typename mi::index::type& i= mi::get(s); typedef typename MultiIndexContainer::value_type value_type; std::cout << message << std::endl; std::copy(i.begin(),i.end(),std::ostream_iterator(std::cout)); std::cout << std::endl; } void save_to_file(const EntrySet &entries, const char *file_name) { std::ofstream ofs(file_name); if( ofs.good() ) { boost::archive::text_oarchive oa(ofs); oa << boost::serialization::make_nvp("entries", entries); } } void load_from_file(EntrySet &entries, const char *file_name) { std::ifstream ifs(file_name); if( ifs.good() ) { boost::archive::text_iarchive ia(ifs); ia >> boost::serialization::make_nvp("entries", entries); } } int main() { EntrySet entries; entries.insert(Entry("", "")); entries.insert(Entry("", "doc")); entries.insert(Entry("/doc", "binutils-doc")); entries.insert(Entry("/doc/binutils-doc", "ld")); entries.insert(Entry("/doc/binutils-doc", "gas")); print_out(entries, "pre-serialization dump by entry"); print_out(entries, "pre-serialization dump by dirname. compare the order of dirnames with post-serialization"); save_to_file(entries, "mapping.db"); std::cout << std::endl << "** The dirname index is not reconstructed correctly after reloading from serialized file. **" << std::endl; load_from_file(entries, "mapping.db"); print_out(entries, "post-serialization dump by entry. ordered by entry as expected."); print_out(entries, "post-serialization dump by dirname. watch the broken position of '/doc', wrongly stuck between '/doc/ld' and '/doc/gas'"); return EXIT_SUCCESS; }