1 // Boost.Geometry Index
3 // Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland.
5 // This file was modified by Oracle on 2021.
6 // Modifications copyright (c) 2021 Oracle and/or its affiliates.
7 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
9 // Use, modification and distribution is subject to the Boost Software License,
10 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
13 #ifndef BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP
14 #define BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP
16 #include <boost/type_traits/alignment_of.hpp>
17 #include <boost/type_traits/aligned_storage.hpp>
19 //#include <boost/serialization/serialization.hpp>
20 #include <boost/serialization/split_member.hpp>
21 #include <boost/serialization/version.hpp>
22 //#include <boost/serialization/nvp.hpp>
24 #include <boost/geometry/geometries/point.hpp>
25 #include <boost/geometry/geometries/box.hpp>
27 #include <boost/geometry/index/parameters.hpp>
28 #include <boost/geometry/index/detail/rtree/node/concept.hpp>
29 #include <boost/geometry/index/detail/rtree/node/subtree_destroyer.hpp>
32 // how about using the unsigned type capable of storing Max in compile-time versions?
35 // - add wrappers for Point and Box and implement serialize for those wrappers instead of
37 // PROBLEM: after implementing this, how Values would be set?
38 // - store the name of the parameters to know how to load and detect errors
39 // - in the header, once store info about the Indexable and Bounds types (geometry type, point CS, Dim, etc.)
40 // each geometry save without this info
42 // TODO - move to index/detail/serialization.hpp
43 namespace boost { namespace geometry { namespace index {
45 // Forward declaration
46 template <typename Value, typename Options, typename IndexableGetter, typename EqualTo, typename Allocator>
51 // TODO - use boost::move?
53 class serialization_storage
56 template <typename Archive>
57 serialization_storage(Archive & ar, unsigned int version)
59 boost::serialization::load_construct_data_adl(ar, this->address(), version);
61 ~serialization_storage()
63 this->address()->~T();
67 return static_cast<T*>(m_storage.address());
70 boost::aligned_storage<sizeof(T), boost::alignment_of<T>::value> m_storage;
73 // TODO - save and load item_version? see: collections_load_imp and collections_save_imp
74 // this should be done once for the whole container
75 // versions of all used types should be stored
77 template <typename T, typename Archive> inline
78 T serialization_load(const char * name, Archive & ar)
80 namespace bs = boost::serialization;
81 serialization_storage<T> storage(ar, bs::version<T>::value); // load_construct_data
82 ar >> boost::serialization::make_nvp(name, *storage.address()); // serialize
83 //ar >> *storage.address(); // serialize
84 return *storage.address();
87 template <typename T, typename Archive> inline
88 void serialization_save(T const& t, const char * name, Archive & ar)
90 namespace bs = boost::serialization;
91 bs::save_construct_data_adl(ar, boost::addressof(t), bs::version<T>::value); // save_construct_data
92 ar << boost::serialization::make_nvp(name, t); // serialize
93 //ar << t; // serialize
98 // TODO - move to index/serialization/rtree.hpp
99 namespace boost { namespace serialization {
101 // boost::geometry::index::linear
103 template<class Archive, size_t Max, size_t Min>
104 void save_construct_data(Archive & ar, const boost::geometry::index::linear<Max, Min> * params, unsigned int )
106 size_t max = params->get_max_elements(), min = params->get_min_elements();
107 ar << boost::serialization::make_nvp("max", max);
108 ar << boost::serialization::make_nvp("min", min);
110 template<class Archive, size_t Max, size_t Min>
111 void load_construct_data(Archive & ar, boost::geometry::index::linear<Max, Min> * params, unsigned int )
114 ar >> boost::serialization::make_nvp("max", max);
115 ar >> boost::serialization::make_nvp("min", min);
116 if ( max != params->get_max_elements() || min != params->get_min_elements() )
117 // TODO change exception type
118 BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible"));
119 // the constructor musn't be called for this type
120 //::new(params)boost::geometry::index::linear<Max, Min>();
122 template<class Archive, size_t Max, size_t Min> void serialize(Archive &, boost::geometry::index::linear<Max, Min> &, unsigned int) {}
124 // boost::geometry::index::quadratic
126 template<class Archive, size_t Max, size_t Min>
127 void save_construct_data(Archive & ar, const boost::geometry::index::quadratic<Max, Min> * params, unsigned int )
129 size_t max = params->get_max_elements(), min = params->get_min_elements();
130 ar << boost::serialization::make_nvp("max", max);
131 ar << boost::serialization::make_nvp("min", min);
133 template<class Archive, size_t Max, size_t Min>
134 void load_construct_data(Archive & ar, boost::geometry::index::quadratic<Max, Min> * params, unsigned int )
137 ar >> boost::serialization::make_nvp("max", max);
138 ar >> boost::serialization::make_nvp("min", min);
139 if ( max != params->get_max_elements() || min != params->get_min_elements() )
140 // TODO change exception type
141 BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible"));
142 // the constructor musn't be called for this type
143 //::new(params)boost::geometry::index::quadratic<Max, Min>();
145 template<class Archive, size_t Max, size_t Min> void serialize(Archive &, boost::geometry::index::quadratic<Max, Min> &, unsigned int) {}
147 // boost::geometry::index::rstar
149 template<class Archive, size_t Max, size_t Min, size_t RE, size_t OCT>
150 void save_construct_data(Archive & ar, const boost::geometry::index::rstar<Max, Min, RE, OCT> * params, unsigned int )
152 size_t max = params->get_max_elements()
153 , min = params->get_min_elements()
154 , re = params->get_reinserted_elements()
155 , oct = params->get_overlap_cost_threshold();
156 ar << boost::serialization::make_nvp("max", max);
157 ar << boost::serialization::make_nvp("min", min);
158 ar << boost::serialization::make_nvp("re", re);
159 ar << boost::serialization::make_nvp("oct", oct);
161 template<class Archive, size_t Max, size_t Min, size_t RE, size_t OCT>
162 void load_construct_data(Archive & ar, boost::geometry::index::rstar<Max, Min, RE, OCT> * params, unsigned int )
164 size_t max, min, re, oct;
165 ar >> boost::serialization::make_nvp("max", max);
166 ar >> boost::serialization::make_nvp("min", min);
167 ar >> boost::serialization::make_nvp("re", re);
168 ar >> boost::serialization::make_nvp("oct", oct);
169 if ( max != params->get_max_elements() || min != params->get_min_elements() ||
170 re != params->get_reinserted_elements() || oct != params->get_overlap_cost_threshold() )
171 // TODO change exception type
172 BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible"));
173 // the constructor musn't be called for this type
174 //::new(params)boost::geometry::index::rstar<Max, Min, RE, OCT>();
176 template<class Archive, size_t Max, size_t Min, size_t RE, size_t OCT>
177 void serialize(Archive &, boost::geometry::index::rstar<Max, Min, RE, OCT> &, unsigned int) {}
179 // boost::geometry::index::dynamic_linear
181 template<class Archive>
182 inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_linear * params, unsigned int )
184 size_t max = params->get_max_elements(), min = params->get_min_elements();
185 ar << boost::serialization::make_nvp("max", max);
186 ar << boost::serialization::make_nvp("min", min);
188 template<class Archive>
189 inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_linear * params, unsigned int )
192 ar >> boost::serialization::make_nvp("max", max);
193 ar >> boost::serialization::make_nvp("min", min);
194 ::new(params)boost::geometry::index::dynamic_linear(max, min);
196 template<class Archive> void serialize(Archive &, boost::geometry::index::dynamic_linear &, unsigned int) {}
198 // boost::geometry::index::dynamic_quadratic
200 template<class Archive>
201 inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_quadratic * params, unsigned int )
203 size_t max = params->get_max_elements(), min = params->get_min_elements();
204 ar << boost::serialization::make_nvp("max", max);
205 ar << boost::serialization::make_nvp("min", min);
207 template<class Archive>
208 inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_quadratic * params, unsigned int )
211 ar >> boost::serialization::make_nvp("max", max);
212 ar >> boost::serialization::make_nvp("min", min);
213 ::new(params)boost::geometry::index::dynamic_quadratic(max, min);
215 template<class Archive> void serialize(Archive &, boost::geometry::index::dynamic_quadratic &, unsigned int) {}
217 // boost::geometry::index::dynamic_rstar
219 template<class Archive>
220 inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_rstar * params, unsigned int )
222 size_t max = params->get_max_elements()
223 , min = params->get_min_elements()
224 , re = params->get_reinserted_elements()
225 , oct = params->get_overlap_cost_threshold();
226 ar << boost::serialization::make_nvp("max", max);
227 ar << boost::serialization::make_nvp("min", min);
228 ar << boost::serialization::make_nvp("re", re);
229 ar << boost::serialization::make_nvp("oct", oct);
231 template<class Archive>
232 inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_rstar * params, unsigned int )
234 size_t max, min, re, oct;
235 ar >> boost::serialization::make_nvp("max", max);
236 ar >> boost::serialization::make_nvp("min", min);
237 ar >> boost::serialization::make_nvp("re", re);
238 ar >> boost::serialization::make_nvp("oct", oct);
239 ::new(params)boost::geometry::index::dynamic_rstar(max, min, re, oct);
241 template<class Archive> void serialize(Archive &, boost::geometry::index::dynamic_rstar &, unsigned int) {}
243 }} // boost::serialization
245 // TODO - move to index/detail/serialization.hpp or maybe geometry/serialization.hpp
246 namespace boost { namespace geometry { namespace index { namespace detail {
248 template <typename P, size_t I = 0, size_t D = geometry::dimension<P>::value>
249 struct serialize_point
251 template <typename Archive>
252 static inline void save(Archive & ar, P const& p, unsigned int version)
254 typename coordinate_type<P>::type c = get<I>(p);
255 ar << boost::serialization::make_nvp("c", c);
256 serialize_point<P, I+1, D>::save(ar, p, version);
259 template <typename Archive>
260 static inline void load(Archive & ar, P & p, unsigned int version)
262 typename geometry::coordinate_type<P>::type c;
263 ar >> boost::serialization::make_nvp("c", c);
265 serialize_point<P, I+1, D>::load(ar, p, version);
269 template <typename P, size_t D>
270 struct serialize_point<P, D, D>
272 template <typename Archive> static inline void save(Archive &, P const&, unsigned int) {}
273 template <typename Archive> static inline void load(Archive &, P &, unsigned int) {}
278 // TODO - move to index/detail/serialization.hpp or maybe geometry/serialization.hpp
279 namespace boost { namespace serialization {
281 template<class Archive, typename T, size_t D, typename C>
282 void save(Archive & ar, boost::geometry::model::point<T, D, C> const& p, unsigned int version)
284 boost::geometry::index::detail::serialize_point< boost::geometry::model::point<T, D, C> >::save(ar, p, version);
286 template<class Archive, typename T, size_t D, typename C>
287 void load(Archive & ar, boost::geometry::model::point<T, D, C> & p, unsigned int version)
289 boost::geometry::index::detail::serialize_point< boost::geometry::model::point<T, D, C> >::load(ar, p, version);
291 template<class Archive, typename T, size_t D, typename C>
292 inline void serialize(Archive & ar, boost::geometry::model::point<T, D, C> & o, const unsigned int version) { split_free(ar, o, version); }
294 template<class Archive, typename P>
295 inline void serialize(Archive & ar, boost::geometry::model::box<P> & b, const unsigned int)
297 ar & boost::serialization::make_nvp("min", b.min_corner());
298 ar & boost::serialization::make_nvp("max", b.max_corner());
301 }} // boost::serialization
303 // TODO - move to index/detail/rtree/visitors/save.hpp
304 namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace visitors {
306 // TODO move saving and loading of the rtree outside the rtree, this will require adding some kind of members_view
308 template <typename Archive, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
310 : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
313 typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
314 typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
315 typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
317 save(Archive & archive, unsigned int version)
318 : m_archive(archive), m_version(version)
321 inline void operator()(internal_node const& n)
323 typedef typename rtree::elements_type<internal_node>::type elements_type;
324 elements_type const& elements = rtree::elements(n);
326 // CONSIDER: change to elements_type::size_type or size_type
327 // or use fixed-size type like uint32 or even uint16?
328 size_t s = elements.size();
329 m_archive << boost::serialization::make_nvp("s", s);
331 for (typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it)
333 serialization_save(it->first, "b", m_archive);
335 rtree::apply_visitor(*this, *it->second);
339 inline void operator()(leaf const& l)
341 typedef typename rtree::elements_type<leaf>::type elements_type;
342 //typedef typename elements_type::size_type elements_size;
343 elements_type const& elements = rtree::elements(l);
345 // CONSIDER: change to elements_type::size_type or size_type
346 // or use fixed-size type like uint32 or even uint16?
347 size_t s = elements.size();
348 m_archive << boost::serialization::make_nvp("s", s);
350 for (typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it)
352 serialization_save(*it, "v", m_archive);
358 unsigned int m_version;
361 }}}}}} // boost::geometry::index::detail::rtree::visitors
363 // TODO - move to index/detail/rtree/load.hpp
364 namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree {
366 template <typename MembersHolder>
369 typedef typename MembersHolder::parameters_type parameters_type;
370 typedef typename MembersHolder::translator_type translator_type;
371 typedef typename MembersHolder::allocators_type allocators_type;
373 typedef typename MembersHolder::node node;
374 typedef typename MembersHolder::internal_node internal_node;
375 typedef typename MembersHolder::leaf leaf;
377 typedef typename allocators_type::node_pointer node_pointer;
378 typedef typename allocators_type::size_type size_type;
380 typedef rtree::subtree_destroyer<MembersHolder> subtree_destroyer;
383 template <typename Archive> inline static
384 node_pointer apply(Archive & ar, unsigned int version, size_type leafs_level,
385 size_type & values_count,
386 parameters_type const& parameters,
387 translator_type const& translator,
388 allocators_type & allocators)
391 return raw_apply(ar, version, leafs_level, values_count, parameters, translator, allocators);
395 template <typename Archive> inline static
396 node_pointer raw_apply(Archive & ar, unsigned int version, size_type leafs_level,
397 size_type & values_count,
398 parameters_type const& parameters,
399 translator_type const& translator,
400 allocators_type & allocators,
401 size_type current_level = 0)
403 //BOOST_GEOMETRY_INDEX_ASSERT(current_level <= leafs_level, "invalid parameter");
405 typedef typename rtree::elements_type<internal_node>::type elements_type;
406 typedef typename elements_type::value_type element_type;
407 //typedef typename elements_type::size_type elements_size;
409 // CONSIDER: change to elements_type::size_type or size_type
410 // or use fixed-size type like uint32 or even uint16?
411 size_t elements_count;
412 ar >> boost::serialization::make_nvp("s", elements_count);
414 // root may contain count < min but shouldn't contain count > max
415 if ( (elements_count < parameters.get_min_elements() && current_level > 0)
416 || parameters.get_max_elements() < elements_count )
418 BOOST_THROW_EXCEPTION(std::runtime_error("rtree loading error"));
421 if ( current_level < leafs_level )
423 node_pointer n = rtree::create_node<allocators_type, internal_node>::apply(allocators); // MAY THROW (A)
424 subtree_destroyer auto_remover(n, allocators);
425 internal_node & in = rtree::get<internal_node>(*n);
427 elements_type & elements = rtree::elements(in);
429 elements.reserve(elements_count); // MAY THROW (A)
431 for ( size_t i = 0 ; i < elements_count ; ++i )
433 typedef typename elements_type::value_type::first_type box_type;
434 box_type b = serialization_load<box_type>("b", ar);
435 node_pointer n = raw_apply(ar, version, leafs_level, values_count, parameters, translator, allocators, current_level+1); // recursive call
436 elements.push_back(element_type(b, n));
439 auto_remover.release();
444 BOOST_GEOMETRY_INDEX_ASSERT(current_level == leafs_level, "unexpected value");
446 node_pointer n = rtree::create_node<allocators_type, leaf>::apply(allocators); // MAY THROW (A)
447 subtree_destroyer auto_remover(n, allocators);
448 leaf & l = rtree::get<leaf>(*n);
450 typedef typename rtree::elements_type<leaf>::type elements_type;
451 typedef typename elements_type::value_type element_type;
452 elements_type & elements = rtree::elements(l);
454 values_count += elements_count;
456 elements.reserve(elements_count); // MAY THROW (A)
458 for ( size_t i = 0 ; i < elements_count ; ++i )
460 element_type el = serialization_load<element_type>("v", ar); // MAY THROW (C)
461 elements.push_back(el); // MAY THROW (C)
464 auto_remover.release();
470 }}}}} // boost::geometry::index::detail::rtree
472 // TODO - move to index/detail/rtree/private_view.hpp
473 namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree {
475 template <typename Rtree>
476 class const_private_view
479 typedef typename Rtree::size_type size_type;
481 typedef typename Rtree::translator_type translator_type;
482 typedef typename Rtree::value_type value_type;
483 typedef typename Rtree::options_type options_type;
484 typedef typename Rtree::box_type box_type;
485 typedef typename Rtree::allocators_type allocators_type;
487 const_private_view(Rtree const& rt) : m_rtree(rt) {}
489 typedef typename Rtree::members_holder members_holder;
491 members_holder const& members() const { return m_rtree.m_members; }
494 const_private_view(const_private_view const&);
495 const_private_view & operator=(const_private_view const&);
497 Rtree const& m_rtree;
500 template <typename Rtree>
504 typedef typename Rtree::size_type size_type;
506 typedef typename Rtree::translator_type translator_type;
507 typedef typename Rtree::value_type value_type;
508 typedef typename Rtree::options_type options_type;
509 typedef typename Rtree::box_type box_type;
510 typedef typename Rtree::allocators_type allocators_type;
512 private_view(Rtree & rt) : m_rtree(rt) {}
514 typedef typename Rtree::members_holder members_holder;
516 members_holder & members() { return m_rtree.m_members; }
517 members_holder const& members() const { return m_rtree.m_members; }
520 private_view(private_view const&);
521 private_view & operator=(private_view const&);
526 }}}}} // namespace boost::geometry::index::detail::rtree
528 // TODO - move to index/serialization/rtree.hpp
529 namespace boost { namespace serialization {
531 template<class Archive, typename V, typename P, typename I, typename E, typename A>
532 void save(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> const& rt, unsigned int version)
534 namespace detail = boost::geometry::index::detail;
536 typedef boost::geometry::index::rtree<V, P, I, E, A> rtree;
537 typedef detail::rtree::const_private_view<rtree> view;
538 typedef typename view::translator_type translator_type;
539 typedef typename view::value_type value_type;
540 typedef typename view::options_type options_type;
541 typedef typename view::box_type box_type;
542 typedef typename view::allocators_type allocators_type;
546 detail::serialization_save(tree.members().parameters(), "parameters", ar);
548 ar << boost::serialization::make_nvp("values_count", tree.members().values_count);
549 ar << boost::serialization::make_nvp("leafs_level", tree.members().leafs_level);
551 if ( tree.members().values_count )
553 BOOST_GEOMETRY_INDEX_ASSERT(tree.members().root, "root shouldn't be null_ptr");
555 detail::rtree::visitors::save<Archive, value_type, options_type, translator_type, box_type, allocators_type> save_v(ar, version);
556 detail::rtree::apply_visitor(save_v, *tree.members().root);
560 template<class Archive, typename V, typename P, typename I, typename E, typename A>
561 void load(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> & rt, unsigned int version)
563 namespace detail = boost::geometry::index::detail;
565 typedef boost::geometry::index::rtree<V, P, I, E, A> rtree;
566 typedef detail::rtree::private_view<rtree> view;
567 typedef typename view::size_type size_type;
568 typedef typename view::translator_type translator_type;
569 typedef typename view::value_type value_type;
570 typedef typename view::options_type options_type;
571 typedef typename view::box_type box_type;
572 typedef typename view::allocators_type allocators_type;
573 typedef typename view::members_holder members_holder;
575 typedef typename options_type::parameters_type parameters_type;
576 typedef typename allocators_type::node_pointer node_pointer;
577 typedef detail::rtree::subtree_destroyer<members_holder> subtree_destroyer;
581 parameters_type params = detail::serialization_load<parameters_type>("parameters", ar);
583 size_type values_count, leafs_level;
584 ar >> boost::serialization::make_nvp("values_count", values_count);
585 ar >> boost::serialization::make_nvp("leafs_level", leafs_level);
588 if ( 0 < values_count )
590 size_type loaded_values_count = 0;
591 n = detail::rtree::load<members_holder>
592 ::apply(ar, version, leafs_level, loaded_values_count, params, tree.members().translator(), tree.members().allocators()); // MAY THROW
594 subtree_destroyer remover(n, tree.members().allocators());
595 if ( loaded_values_count != values_count )
596 BOOST_THROW_EXCEPTION(std::runtime_error("unexpected number of values")); // TODO change exception type
600 tree.members().parameters() = params;
601 tree.members().values_count = values_count;
602 tree.members().leafs_level = leafs_level;
604 subtree_destroyer remover(tree.members().root, tree.members().allocators());
605 tree.members().root = n;
608 template<class Archive, typename V, typename P, typename I, typename E, typename A> inline
609 void serialize(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> & rt, unsigned int version)
611 split_free(ar, rt, version);
614 template<class Archive, typename V, typename P, typename I, typename E, typename A> inline
615 void serialize(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> const& rt, unsigned int version)
617 split_free(ar, rt, version);
620 }} // boost::serialization
622 #endif // BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP