From c38abef50ccfc7a42eaff6f54ac5a88c52b0f9d1 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Sun, 14 Jul 2013 01:59:26 +0000 Subject: [PATCH] [geometry][index]: experimental rtree serialization support added. [SVN r85026] --- .../index/detail/rtree/node/node_auto_ptr.hpp | 2 + .../geometry/index/detail/serialization.hpp | 396 ++++++++++++++++++ include/boost/geometry/index/rtree.hpp | 53 +++ 3 files changed, 451 insertions(+) create mode 100644 include/boost/geometry/index/detail/serialization.hpp diff --git a/include/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp b/include/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp index 359d4380d..c19e123b6 100644 --- a/include/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp +++ b/include/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp @@ -17,6 +17,8 @@ namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { +// TODO - change the name to node_scoped_ptr + template class node_auto_ptr { diff --git a/include/boost/geometry/index/detail/serialization.hpp b/include/boost/geometry/index/detail/serialization.hpp new file mode 100644 index 000000000..d043114f8 --- /dev/null +++ b/include/boost/geometry/index/detail/serialization.hpp @@ -0,0 +1,396 @@ +// Boost.Geometry Index +// +// Copyright (c) 2011-2013 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 - 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(Archive & ar) +{ + namespace bs = boost::serialization; + serialization_storage storage(ar, bs::version::value); // load_construct_data + //ar >> boost::serialization::make_nvp("name", *storage.address()); + ar >> *storage.address(); // serialize + return *storage.address(); +} + +template inline +void serialization_save(T const& t, 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); + ar << t; // serialize +} + +}}}} + +// TODO - move to index/serialization.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 << max << min; +} +template +void load_construct_data(Archive & ar, boost::geometry::index::linear * params, unsigned int ) +{ + size_t max, min; + ar >> max >> 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 << max << min; +} +template +void load_construct_data(Archive & ar, boost::geometry::index::quadratic * params, unsigned int ) +{ + size_t max, min; + ar >> max >> 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 << max << min << re << oct; +} +template +void load_construct_data(Archive & ar, boost::geometry::index::rstar * params, unsigned int ) +{ + size_t max, min, re, oct; + ar >> max >> min; + 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 << max << min; +} +template +inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_linear * params, unsigned int ) +{ + size_t max, min; + ar >> max >> 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 << max << min; +} +template +inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_quadratic * params, unsigned int ) +{ + size_t max, min; + ar >> max >> 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 << max << min; +} +template +inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_rstar * params, unsigned int ) +{ + size_t max, min, re, oct; + ar >> max >> min >> re >> 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 << c; + serialize_point::save(ar, p, version); + } + + template + static inline void load(Archive & ar, P & p, unsigned int version) + { + typename traits::coordinate_type

::type c; + ar >> 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 & b.min_corner(); + ar & 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); + + char t = 'i'; + size_t s = elements.size(); + m_archive << t << s; + + for (typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it) + { + serialization_save(it->first, m_archive); + + rtree::apply_visitor(*this, *it->second); + } + } + + inline void operator()(leaf const& l) + { + typedef typename rtree::elements_type::type elements_type; + elements_type const& elements = rtree::elements(l); + + char t = 'l'; + size_t s = elements.size(); + m_archive << t << s; + + for (typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it) + { + serialization_save(*it, 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 rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef typename Options::parameters_type parameters_type; + + typedef typename Allocators::node_pointer node_pointer; + typedef rtree::node_auto_ptr node_auto_ptr; + typedef typename Allocators::size_type size_type; + +public: + template inline static + node_pointer apply(Archive & ar, unsigned int version, parameters_type const& parameters, Translator const& translator, Allocators & allocators) + { + char t; + ar >> t; + + if ( t == 'n' ) + return node_pointer(0); + + size_t elements_count; + ar >> 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 ( t == 'i' ) + { + node_pointer n = rtree::create_node::apply(allocators); // MAY THROW (A) + node_auto_ptr auto_remover(n, allocators); + internal_node & in = rtree::get(*n); + + typedef typename rtree::elements_type::type elements_type; + typedef typename elements_type::value_type element_type; + 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(ar); + node_pointer n = apply(ar, version, parameters, translator, allocators); // recursive call + elements.push_back(element_type(b, n)); + } + + auto_remover.release(); + return n; + } + else if ( t == 'l' ) + { + node_pointer n = rtree::create_node::apply(allocators); // MAY THROW (A) + node_auto_ptr 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); + + elements.reserve(elements_count); // MAY THROW (A) + + for ( size_t i = 0 ; i < elements_count ; ++i ) + { + element_type el = serialization_load(ar); // MAY THROW (C) + elements.push_back(el); // MAY THROW (C) + } + + auto_remover.release(); + return n; + } + + BOOST_THROW_EXCEPTION(std::runtime_error("rtree loading error")); + //return node_pointer(0); + } +}; + +}}}}} // boost::geometry::index::detail::rtree + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP diff --git a/include/boost/geometry/index/rtree.hpp b/include/boost/geometry/index/rtree.hpp index 018d508f6..26e7883ae 100644 --- a/include/boost/geometry/index/rtree.hpp +++ b/include/boost/geometry/index/rtree.hpp @@ -62,10 +62,14 @@ #include #ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL +// query iterators #include #ifdef BOOST_GEOMETRY_INDEX_DETAIL_ENABLE_TYPE_ERASED_ITERATORS +// type-erased iterators #include #endif +// serialization +#include #endif // TODO change the name to bounding_tree @@ -166,6 +170,7 @@ private: typedef typename allocators_type::node_pointer node_pointer; typedef ::boost::container::allocator_traits allocator_traits_type; + typedef detail::rtree::node_auto_ptr node_auto_ptr; friend class detail::rtree::utilities::view; @@ -1155,6 +1160,7 @@ private: dst.m_members.parameters() = src.m_members.parameters(); } + // TODO use node_auto_ptr if ( dst.m_members.root ) { detail::rtree::visitors::destroy @@ -1211,6 +1217,53 @@ private: return distance_v.finish(); } +#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + + friend class boost::serialization::access; + + template + void save(Archive & ar, unsigned int version) const + { + detail::serialization_save(m_members.parameters(), ar); + + ar << m_members.values_count; // might be removed + ar << m_members.leafs_level; // might be removed + if ( m_members.root ) + { + detail::rtree::visitors::save save_v(ar, version); + detail::rtree::apply_visitor(save_v, *m_members.root); + } + else + { + char t = 'n'; + ar << t; + } + } + + template + void load(Archive & ar, unsigned int version) + { + parameters_type params = detail::serialization_load(ar); + + size_type values_count, leafs_level; + ar >> values_count; // might be removed + ar >> leafs_level; // might be removed + + node_pointer n = detail::rtree::load + ::apply(ar, version, params, m_members.translator(), m_members.allocators()); // MAY THROW + + m_members.parameters() = params; + m_members.values_count = values_count; + m_members.leafs_level = leafs_level; + + node_auto_ptr remover(m_members.root, m_members.allocators()); + m_members.root = n; + } + + BOOST_SERIALIZATION_SPLIT_MEMBER() + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL + struct members_holder : public translator_type , public Parameters