// Boost.Geometry Index // // Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland. // // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP //#include #include #include //#include // TODO // how about using the unsigned type capable of storing Max in compile-time versions? // TODO // - add wrappers for Point and Box and implement serialize for those wrappers instead of // raw geometries // PROBLEM: after implementing this, how Values would be set? // - store the name of the parameters to know how to load and detect errors // - in the header, once store info about the Indexable and Bounds types (geometry type, point CS, Dim, etc.) // each geometry save without this info // TODO - move to index/detail/serialization.hpp namespace boost { namespace geometry { namespace index { namespace detail { // TODO - use boost::move? template class serialization_storage { public: template serialization_storage(Archive & ar, unsigned int version) { boost::serialization::load_construct_data_adl(ar, this->address(), version); } ~serialization_storage() { this->address()->~T(); } T * address() { return static_cast(m_storage.address()); } private: boost::aligned_storage::value> m_storage; }; // TODO - save and load item_version? see: collections_load_imp and collections_save_imp // this should be done once for the whole container // versions of all used types should be stored template inline T serialization_load(const char * name, Archive & ar) { namespace bs = boost::serialization; serialization_storage storage(ar, bs::version::value); // load_construct_data ar >> boost::serialization::make_nvp(name, *storage.address()); // serialize //ar >> *storage.address(); // serialize return *storage.address(); } template inline void serialization_save(T const& t, const char * name, Archive & ar) { namespace bs = boost::serialization; bs::save_construct_data_adl(ar, boost::addressof(t), bs::version::value); // save_construct_data ar << boost::serialization::make_nvp(name, t); // serialize //ar << t; // serialize } }}}} // TODO - move to index/serialization/rtree.hpp namespace boost { namespace serialization { // boost::geometry::index::linear template void save_construct_data(Archive & ar, const boost::geometry::index::linear * params, unsigned int ) { size_t max = params->get_max_elements(), min = params->get_min_elements(); ar << boost::serialization::make_nvp("max", max); ar << boost::serialization::make_nvp("min", min); } template void load_construct_data(Archive & ar, boost::geometry::index::linear * params, unsigned int ) { size_t max, min; ar >> boost::serialization::make_nvp("max", max); ar >> boost::serialization::make_nvp("min", min); if ( max != params->get_max_elements() || min != params->get_min_elements() ) // TODO change exception type BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible")); // the constructor musn't be called for this type //::new(params)boost::geometry::index::linear(); } template void serialize(Archive &, boost::geometry::index::linear &, unsigned int) {} // boost::geometry::index::quadratic template void save_construct_data(Archive & ar, const boost::geometry::index::quadratic * params, unsigned int ) { size_t max = params->get_max_elements(), min = params->get_min_elements(); ar << boost::serialization::make_nvp("max", max); ar << boost::serialization::make_nvp("min", min); } template void load_construct_data(Archive & ar, boost::geometry::index::quadratic * params, unsigned int ) { size_t max, min; ar >> boost::serialization::make_nvp("max", max); ar >> boost::serialization::make_nvp("min", min); if ( max != params->get_max_elements() || min != params->get_min_elements() ) // TODO change exception type BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible")); // the constructor musn't be called for this type //::new(params)boost::geometry::index::quadratic(); } template void serialize(Archive &, boost::geometry::index::quadratic &, unsigned int) {} // boost::geometry::index::rstar template void save_construct_data(Archive & ar, const boost::geometry::index::rstar * params, unsigned int ) { size_t max = params->get_max_elements() , min = params->get_min_elements() , re = params->get_reinserted_elements() , oct = params->get_overlap_cost_threshold(); ar << boost::serialization::make_nvp("max", max); ar << boost::serialization::make_nvp("min", min); ar << boost::serialization::make_nvp("re", re); ar << boost::serialization::make_nvp("oct", oct); } template void load_construct_data(Archive & ar, boost::geometry::index::rstar * params, unsigned int ) { size_t max, min, re, oct; ar >> boost::serialization::make_nvp("max", max); ar >> boost::serialization::make_nvp("min", min); ar >> boost::serialization::make_nvp("re", re); ar >> boost::serialization::make_nvp("oct", oct); if ( max != params->get_max_elements() || min != params->get_min_elements() || re != params->get_reinserted_elements() || oct != params->get_overlap_cost_threshold() ) // TODO change exception type BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible")); // the constructor musn't be called for this type //::new(params)boost::geometry::index::rstar(); } template void serialize(Archive &, boost::geometry::index::rstar &, unsigned int) {} // boost::geometry::index::dynamic_linear template inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_linear * params, unsigned int ) { size_t max = params->get_max_elements(), min = params->get_min_elements(); ar << boost::serialization::make_nvp("max", max); ar << boost::serialization::make_nvp("min", min); } template inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_linear * params, unsigned int ) { size_t max, min; ar >> boost::serialization::make_nvp("max", max); ar >> boost::serialization::make_nvp("min", min); ::new(params)boost::geometry::index::dynamic_linear(max, min); } template void serialize(Archive &, boost::geometry::index::dynamic_linear &, unsigned int) {} // boost::geometry::index::dynamic_quadratic template inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_quadratic * params, unsigned int ) { size_t max = params->get_max_elements(), min = params->get_min_elements(); ar << boost::serialization::make_nvp("max", max); ar << boost::serialization::make_nvp("min", min); } template inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_quadratic * params, unsigned int ) { size_t max, min; ar >> boost::serialization::make_nvp("max", max); ar >> boost::serialization::make_nvp("min", min); ::new(params)boost::geometry::index::dynamic_quadratic(max, min); } template void serialize(Archive &, boost::geometry::index::dynamic_quadratic &, unsigned int) {} // boost::geometry::index::dynamic_rstar template inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_rstar * params, unsigned int ) { size_t max = params->get_max_elements() , min = params->get_min_elements() , re = params->get_reinserted_elements() , oct = params->get_overlap_cost_threshold(); ar << boost::serialization::make_nvp("max", max); ar << boost::serialization::make_nvp("min", min); ar << boost::serialization::make_nvp("re", re); ar << boost::serialization::make_nvp("oct", oct); } template inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_rstar * params, unsigned int ) { size_t max, min, re, oct; ar >> boost::serialization::make_nvp("max", max); ar >> boost::serialization::make_nvp("min", min); ar >> boost::serialization::make_nvp("re", re); ar >> boost::serialization::make_nvp("oct", oct); ::new(params)boost::geometry::index::dynamic_rstar(max, min, re, oct); } template void serialize(Archive &, boost::geometry::index::dynamic_rstar &, unsigned int) {} }} // boost::serialization // TODO - move to index/detail/serialization.hpp or maybe geometry/serialization.hpp namespace boost { namespace geometry { namespace index { namespace detail { template ::value> struct serialize_point { template static inline void save(Archive & ar, P const& p, unsigned int version) { typename coordinate_type

::type c = get(p); ar << boost::serialization::make_nvp("c", c); serialize_point::save(ar, p, version); } template static inline void load(Archive & ar, P & p, unsigned int version) { typename geometry::coordinate_type

::type c; ar >> boost::serialization::make_nvp("c", c); set(p, c); serialize_point::load(ar, p, version); } }; template struct serialize_point { template static inline void save(Archive &, P const&, unsigned int) {} template static inline void load(Archive &, P &, unsigned int) {} }; }}}} // TODO - move to index/detail/serialization.hpp or maybe geometry/serialization.hpp namespace boost { namespace serialization { template void save(Archive & ar, boost::geometry::model::point const& p, unsigned int version) { boost::geometry::index::detail::serialize_point< boost::geometry::model::point >::save(ar, p, version); } template void load(Archive & ar, boost::geometry::model::point & p, unsigned int version) { boost::geometry::index::detail::serialize_point< boost::geometry::model::point >::load(ar, p, version); } template inline void serialize(Archive & ar, boost::geometry::model::point & o, const unsigned int version) { split_free(ar, o, version); } template inline void serialize(Archive & ar, boost::geometry::model::box

& b, const unsigned int) { ar & boost::serialization::make_nvp("min", b.min_corner()); ar & boost::serialization::make_nvp("max", b.max_corner()); } }} // boost::serialization // TODO - move to index/detail/rtree/visitors/save.hpp namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace visitors { // TODO move saving and loading of the rtree outside the rtree, this will require adding some kind of members_view template class save : public rtree::visitor::type { public: typedef typename rtree::node::type node; typedef typename rtree::internal_node::type internal_node; typedef typename rtree::leaf::type leaf; save(Archive & archive, unsigned int version) : m_archive(archive), m_version(version) {} inline void operator()(internal_node const& n) { typedef typename rtree::elements_type::type elements_type; elements_type const& elements = rtree::elements(n); // CONSIDER: change to elements_type::size_type or size_type // or use fixed-size type like uint32 or even uint16? size_t s = elements.size(); m_archive << boost::serialization::make_nvp("s", s); for (typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it) { serialization_save(it->first, "b", m_archive); rtree::apply_visitor(*this, *it->second); } } inline void operator()(leaf const& l) { typedef typename rtree::elements_type::type elements_type; //typedef typename elements_type::size_type elements_size; elements_type const& elements = rtree::elements(l); // CONSIDER: change to elements_type::size_type or size_type // or use fixed-size type like uint32 or even uint16? size_t s = elements.size(); m_archive << boost::serialization::make_nvp("s", s); for (typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it) { serialization_save(*it, "v", m_archive); } } private: Archive & m_archive; unsigned int m_version; }; }}}}}} // boost::geometry::index::detail::rtree::visitors // TODO - move to index/detail/rtree/load.hpp namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { template class load { typedef typename MembersHolder::parameters_type parameters_type; typedef typename MembersHolder::translator_type translator_type; typedef typename MembersHolder::allocators_type allocators_type; typedef typename MembersHolder::node node; typedef typename MembersHolder::internal_node internal_node; typedef typename MembersHolder::leaf leaf; typedef typename allocators_type::node_pointer node_pointer; typedef typename allocators_type::size_type size_type; typedef rtree::subtree_destroyer subtree_destroyer; public: template inline static node_pointer apply(Archive & ar, unsigned int version, size_type leafs_level, size_type & values_count, parameters_type const& parameters, translator_type const& translator, allocators_type & allocators) { values_count = 0; return raw_apply(ar, version, leafs_level, values_count, parameters, translator, allocators); } private: template inline static node_pointer raw_apply(Archive & ar, unsigned int version, size_type leafs_level, size_type & values_count, parameters_type const& parameters, translator_type const& translator, allocators_type & allocators, size_type current_level = 0) { //BOOST_GEOMETRY_INDEX_ASSERT(current_level <= leafs_level, "invalid parameter"); typedef typename rtree::elements_type::type elements_type; typedef typename elements_type::value_type element_type; //typedef typename elements_type::size_type elements_size; // CONSIDER: change to elements_type::size_type or size_type // or use fixed-size type like uint32 or even uint16? size_t elements_count; ar >> boost::serialization::make_nvp("s", elements_count); if ( elements_count < parameters.get_min_elements() || parameters.get_max_elements() < elements_count ) BOOST_THROW_EXCEPTION(std::runtime_error("rtree loading error")); if ( current_level < leafs_level ) { node_pointer n = rtree::create_node::apply(allocators); // MAY THROW (A) subtree_destroyer auto_remover(n, allocators); internal_node & in = rtree::get(*n); elements_type & elements = rtree::elements(in); elements.reserve(elements_count); // MAY THROW (A) for ( size_t i = 0 ; i < elements_count ; ++i ) { typedef typename elements_type::value_type::first_type box_type; box_type b = serialization_load("b", ar); node_pointer n = raw_apply(ar, version, leafs_level, values_count, parameters, translator, allocators, current_level+1); // recursive call elements.push_back(element_type(b, n)); } auto_remover.release(); return n; } else { BOOST_GEOMETRY_INDEX_ASSERT(current_level == leafs_level, "unexpected value"); node_pointer n = rtree::create_node::apply(allocators); // MAY THROW (A) subtree_destroyer auto_remover(n, allocators); leaf & l = rtree::get(*n); typedef typename rtree::elements_type::type elements_type; typedef typename elements_type::value_type element_type; elements_type & elements = rtree::elements(l); values_count += elements_count; elements.reserve(elements_count); // MAY THROW (A) for ( size_t i = 0 ; i < elements_count ; ++i ) { element_type el = serialization_load("v", ar); // MAY THROW (C) elements.push_back(el); // MAY THROW (C) } auto_remover.release(); return n; } } }; }}}}} // boost::geometry::index::detail::rtree // TODO - move to index/detail/rtree/private_view.hpp namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { template class const_private_view { public: typedef typename Rtree::size_type size_type; typedef typename Rtree::translator_type translator_type; typedef typename Rtree::value_type value_type; typedef typename Rtree::options_type options_type; typedef typename Rtree::box_type box_type; typedef typename Rtree::allocators_type allocators_type; const_private_view(Rtree const& rt) : m_rtree(rt) {} typedef typename Rtree::members_holder members_holder; members_holder const& members() const { return m_rtree.m_members; } private: const_private_view(const_private_view const&); const_private_view & operator=(const_private_view const&); Rtree const& m_rtree; }; template class private_view { public: typedef typename Rtree::size_type size_type; typedef typename Rtree::translator_type translator_type; typedef typename Rtree::value_type value_type; typedef typename Rtree::options_type options_type; typedef typename Rtree::box_type box_type; typedef typename Rtree::allocators_type allocators_type; private_view(Rtree & rt) : m_rtree(rt) {} typedef typename Rtree::members_holder members_holder; members_holder & members() { return m_rtree.m_members; } members_holder const& members() const { return m_rtree.m_members; } private: private_view(private_view const&); private_view & operator=(private_view const&); Rtree & m_rtree; }; }}}}} // namespace boost::geometry::index::detail::rtree // TODO - move to index/serialization/rtree.hpp namespace boost { namespace serialization { template void save(Archive & ar, boost::geometry::index::rtree const& rt, unsigned int version) { namespace detail = boost::geometry::index::detail; typedef boost::geometry::index::rtree rtree; typedef detail::rtree::const_private_view view; typedef typename view::translator_type translator_type; typedef typename view::value_type value_type; typedef typename view::options_type options_type; typedef typename view::box_type box_type; typedef typename view::allocators_type allocators_type; view tree(rt); detail::serialization_save(tree.members().parameters(), "parameters", ar); ar << boost::serialization::make_nvp("values_count", tree.members().values_count); ar << boost::serialization::make_nvp("leafs_level", tree.members().leafs_level); if ( tree.members().values_count ) { BOOST_GEOMETRY_INDEX_ASSERT(tree.members().root, "root shouldn't be null_ptr"); detail::rtree::visitors::save save_v(ar, version); detail::rtree::apply_visitor(save_v, *tree.members().root); } } template void load(Archive & ar, boost::geometry::index::rtree & rt, unsigned int version) { namespace detail = boost::geometry::index::detail; typedef boost::geometry::index::rtree rtree; typedef detail::rtree::private_view view; typedef typename view::size_type size_type; typedef typename view::translator_type translator_type; typedef typename view::value_type value_type; typedef typename view::options_type options_type; typedef typename view::box_type box_type; typedef typename view::allocators_type allocators_type; typedef typename view::members_holder members_holder; typedef typename options_type::parameters_type parameters_type; typedef typename allocators_type::node_pointer node_pointer; typedef detail::rtree::subtree_destroyer subtree_destroyer; view tree(rt); parameters_type params = detail::serialization_load("parameters", ar); size_type values_count, leafs_level; ar >> boost::serialization::make_nvp("values_count", values_count); ar >> boost::serialization::make_nvp("leafs_level", leafs_level); node_pointer n(0); if ( 0 < values_count ) { size_type loaded_values_count = 0; n = detail::rtree::load ::apply(ar, version, leafs_level, loaded_values_count, params, tree.members().translator(), tree.members().allocators()); // MAY THROW subtree_destroyer remover(n, tree.members().allocators()); if ( loaded_values_count != values_count ) BOOST_THROW_EXCEPTION(std::runtime_error("unexpected number of values")); // TODO change exception type remover.release(); } tree.members().parameters() = params; tree.members().values_count = values_count; tree.members().leafs_level = leafs_level; subtree_destroyer remover(tree.members().root, tree.members().allocators()); tree.members().root = n; } template inline void serialize(Archive & ar, boost::geometry::index::rtree & rt, unsigned int version) { split_free(ar, rt, version); } template inline void serialize(Archive & ar, boost::geometry::index::rtree const& rt, unsigned int version) { split_free(ar, rt, version); } }} // boost::serialization #endif // BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP