inline void split(Node & n) const { typedef rtree::split<Value, Options, Translator, Box, Allocators, typename Options::split_tag> split_algo; typename split_algo::nodes_container_type additional_nodes; Box n_box; split_algo::apply(additional_nodes, n, n_box, m_parameters, m_translator, m_allocators); // MAY THROW (V, E: alloc, copy, N:alloc) BOOST_GEOMETRY_INDEX_ASSERT(additional_nodes.size() == 1, "unexpected number of additional nodes"); // TODO add all additional nodes // For kmeans algorithm: // elements number may be greater than node max elements count // split and reinsert must take node with some elements count // and container of additional elements (std::pair<Box, node*>s or Values) // and translator + allocators // where node_elements_count + additional_elements > node_max_elements_count // What with elements other than std::pair<Box, node*> ? // Implement template <node_tag> struct node_element_type or something like that // for exception safety node_auto_ptr additional_node_ptr(additional_nodes[0].second, m_allocators); // node is not the root - just add the new node if ( !m_traverse_data.current_is_root() ) { // update old node's box m_traverse_data.current_element().first = n_box; // add new node to parent's children m_traverse_data.parent_elements().push_back(additional_nodes[0]); // MAY THROW, STRONG (V, E: alloc, copy) } // node is the root - add level else { BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<Node>(*m_root_node), "node should be the root"); // create new root and add nodes node_auto_ptr new_root(rtree::create_node<Allocators, internal_node>::apply(m_allocators), m_allocators); // MAY THROW, STRONG (N:alloc) BOOST_TRY { rtree::elements(rtree::get<internal_node>(*new_root)).push_back(rtree::make_ptr_pair(n_box, m_root_node)); // MAY THROW, STRONG (E:alloc, copy) rtree::elements(rtree::get<internal_node>(*new_root)).push_back(additional_nodes[0]); // MAY THROW, STRONG (E:alloc, copy) } BOOST_CATCH(...) { // clear new root to not delete in the ~node_auto_ptr() potentially stored old root node rtree::elements(rtree::get<internal_node>(*new_root)).clear(); BOOST_RETHROW // RETHROW } BOOST_CATCH_END m_root_node = new_root.get(); ++m_leafs_level; new_root.release(); }
static inline void apply(nodes_container_type & additional_nodes, Node & n, Box & n_box, parameters_type const& parameters, Translator const& translator, Allocators & allocators) { // TODO - consider creating nodes always with sufficient memory allocated // create additional node, use auto ptr for automatic destruction on exception node_auto_ptr second_node(rtree::create_node<Allocators, Node>::apply(allocators), allocators); // MAY THROW, STRONG (N: alloc) // create reference to the newly created node Node & n2 = rtree::get<Node>(*second_node); // NOTE: thread-safety // After throwing an exception by redistribute_elements the original node may be not changed or // both nodes may be empty. In both cases the tree won't be valid r-tree. // The alternative is to create 2 (or more) additional nodes here and store backup info // in the original node, then, if exception was thrown, the node would always have more than max // elements. // The alternative is to use moving semantics in the implementations of redistribute_elements, // it will be possible to throw from boost::move() in the case of e.g. static size nodes. // redistribute elements Box box2; redistribute_elements< Value, Options, Translator, Box, Allocators, typename Options::redistribute_tag >::apply(n, n2, n_box, box2, parameters, translator, allocators); // MAY THROW (V, E: alloc, copy, copy) // check numbers of elements BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= rtree::elements(n).size() && rtree::elements(n).size() <= parameters.get_max_elements(), "unexpected number of elements"); BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= rtree::elements(n2).size() && rtree::elements(n2).size() <= parameters.get_max_elements(), "unexpected number of elements"); // return the list of newly created nodes (this algorithm returns one) additional_nodes.push_back(rtree::make_ptr_pair(box2, second_node.get())); // MAY THROW, STRONG (alloc, copy) // release the ptr second_node.release(); }
void move_from_back(Container & container, Iterator it) { BOOST_GEOMETRY_INDEX_ASSERT(!container.empty(), "cannot copy from empty container"); Iterator back_it = container.end(); --back_it; if ( it != back_it ) { *it = pdalboost::move(*back_it); // MAY THROW (copy) } }
static inline void apply(Elements const& elements, Parameters const& parameters, Translator const& translator, separation_type & separation, size_t & seed1, size_t & seed2) { const size_t elements_count = parameters.get_max_elements() + 1; BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "unexpected number of elements"); BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements_count, "unexpected number of elements"); // find the lowest low, highest high coordinate_type lowest = geometry::get<DimensionIndex>(rtree::element_indexable(elements[0], translator)); coordinate_type highest = geometry::get<DimensionIndex>(rtree::element_indexable(elements[0], translator)); size_t lowest_index = 0; size_t highest_index = 0; for ( size_t i = 1 ; i < elements_count ; ++i ) { coordinate_type coord = geometry::get<DimensionIndex>(rtree::element_indexable(elements[i], translator)); if ( coord < lowest ) { lowest = coord; lowest_index = i; } if ( highest < coord ) { highest = coord; highest_index = i; } } separation = highest - lowest; seed1 = lowest_index; seed2 = highest_index; if ( lowest_index == highest_index ) seed2 = (lowest_index + 1) % elements_count; // % is just in case since if this is true lowest_index is 0 ::boost::ignore_unused_variable_warning(parameters); }
static inline void apply(Elements const& elements, size_t & choosen_index, margin_type & sum_of_margins, content_type & smallest_overlap, content_type & smallest_content, Parameters const& parameters, Translator const& translator) { typedef typename Elements::value_type element_type; typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; typedef typename tag<indexable_type>::type indexable_tag; BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == parameters.get_max_elements() + 1, "wrong number of elements"); // copy elements Elements elements_copy(elements); // MAY THROW, STRONG (alloc, copy) // sort elements element_axis_corner_less<element_type, Translator, indexable_tag, Corner, AxisIndex> elements_less(translator); std::sort(elements_copy.begin(), elements_copy.end(), elements_less); // MAY THROW, BASIC (copy) // init outputs choosen_index = parameters.get_min_elements(); sum_of_margins = 0; smallest_overlap = (std::numeric_limits<content_type>::max)(); smallest_content = (std::numeric_limits<content_type>::max)(); // calculate sum of margins for all distributions size_t index_last = parameters.get_max_elements() - parameters.get_min_elements() + 2; for ( size_t i = parameters.get_min_elements() ; i < index_last ; ++i ) { // TODO - awulkiew: may be optimized - box of group 1 may be initialized with // box of min_elems number of elements and expanded for each iteration by another element Box box1 = rtree::elements_box<Box>(elements_copy.begin(), elements_copy.begin() + i, translator); Box box2 = rtree::elements_box<Box>(elements_copy.begin() + i, elements_copy.end(), translator); sum_of_margins += index::detail::comparable_margin(box1) + index::detail::comparable_margin(box2); content_type ovl = index::detail::intersection_content(box1, box2); content_type con = index::detail::content(box1) + index::detail::content(box2); // TODO - shouldn't here be < instead of <= ? if ( ovl < smallest_overlap || (ovl == smallest_overlap && con <= smallest_content) ) { choosen_index = i; smallest_overlap = ovl; smallest_content = con; } } ::boost::ignore_unused_variable_warning(parameters); }
inline void post_traverse(Node &n) { BOOST_GEOMETRY_INDEX_ASSERT(m_traverse_data.current_is_root() || &n == &rtree::get<Node>(*m_traverse_data.current_element().second), "if node isn't the root current_child_index should be valid"); // handle overflow if ( m_parameters.get_max_elements() < rtree::elements(n).size() ) { // NOTE: If the exception is thrown current node may contain more than MAX elements or be empty. // Furthermore it may be empty root - internal node. split(n); // MAY THROW (V, E: alloc, copy, N:alloc) } }
inline void apply_visitor(Visitor & v, weak_node<Value, Parameters, Box, Allocators, Tag> & n, bool is_internal_node) { BOOST_GEOMETRY_INDEX_ASSERT(&n, "null ptr"); if ( is_internal_node ) { typedef weak_internal_node<Value, Parameters, Box, Allocators, Tag> internal_node; v(get<internal_node>(n)); } else { typedef weak_leaf<Value, Parameters, Box, Allocators, Tag> leaf; v(get<leaf>(n)); } }
static inline size_t apply(internal_node & n, Indexable const& indexable, parameters_type const& /*parameters*/, size_t /*node_relative_level*/) { children_type & children = rtree::elements(n); BOOST_GEOMETRY_INDEX_ASSERT(!children.empty(), "can't choose the next node if children are empty"); size_t children_count = children.size(); // choose index with smallest content change or smallest content size_t choosen_index = 0; content_type smallest_content_diff = (std::numeric_limits<content_type>::max)(); content_type smallest_content = (std::numeric_limits<content_type>::max)(); // caculate areas and areas of all nodes' boxes for ( size_t i = 0 ; i < children_count ; ++i ) { typedef typename children_type::value_type child_type; child_type const& ch_i = children[i]; // expanded child node's box Box box_exp(ch_i.first); geometry::expand(box_exp, indexable); // areas difference content_type content = index::detail::content(box_exp); content_type content_diff = content - index::detail::content(ch_i.first); // update the result if ( content_diff < smallest_content_diff || ( content_diff == smallest_content_diff && content < smallest_content ) ) { smallest_content_diff = content_diff; smallest_content = content; choosen_index = i; } } return choosen_index; }
const value_type * operator->() const { BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not dereferencable"); const value_type * p = 0; return p; }
reference operator*() const { BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not dereferencable"); pointer p(0); return *p; }
static inline void apply(Elements const& elements, Parameters const& parameters, Translator const& translator, separation_type & separation, size_t & seed1, size_t & seed2) { const size_t elements_count = parameters.get_max_elements() + 1; BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "unexpected number of elements"); BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements_count, "unexpected number of elements"); // find the lowest low, highest high coordinate_type lowest_low = geometry::get<min_corner, DimensionIndex>(rtree::element_indexable(elements[0], translator)); coordinate_type highest_high = geometry::get<max_corner, DimensionIndex>(rtree::element_indexable(elements[0], translator)); // and the lowest high coordinate_type lowest_high = highest_high; size_t lowest_high_index = 0; for ( size_t i = 1 ; i < elements_count ; ++i ) { coordinate_type min_coord = geometry::get<min_corner, DimensionIndex>(rtree::element_indexable(elements[i], translator)); coordinate_type max_coord = geometry::get<max_corner, DimensionIndex>(rtree::element_indexable(elements[i], translator)); if ( max_coord < lowest_high ) { lowest_high = max_coord; lowest_high_index = i; } if ( min_coord < lowest_low ) lowest_low = min_coord; if ( highest_high < max_coord ) highest_high = max_coord; } // find the highest low size_t highest_low_index = lowest_high_index == 0 ? 1 : 0; coordinate_type highest_low = geometry::get<min_corner, DimensionIndex>(rtree::element_indexable(elements[highest_low_index], translator)); for ( size_t i = highest_low_index ; i < elements_count ; ++i ) { coordinate_type min_coord = geometry::get<min_corner, DimensionIndex>(rtree::element_indexable(elements[i], translator)); if ( highest_low < min_coord && i != lowest_high_index ) { highest_low = min_coord; highest_low_index = i; } } coordinate_type const width = highest_high - lowest_low; // highest_low - lowest_high separation = difference<separation_type>(lowest_high, highest_low); // BOOST_ASSERT(0 <= width); if ( std::numeric_limits<coordinate_type>::epsilon() < width ) separation /= width; seed1 = highest_low_index; seed2 = lowest_high_index; ::boost::ignore_unused_variable_warning(parameters); }
inline Derived & get(dynamic_node<Value, Parameters, Box, Allocators, Tag> & n) { BOOST_GEOMETRY_INDEX_ASSERT(dynamic_cast<Derived*>(&n), "can't cast to a Derived type"); return static_cast<Derived&>(n); }
inline void apply_visitor(Visitor & v, Visitable & n) { BOOST_GEOMETRY_INDEX_ASSERT(&n, "null ptr"); n.apply_visitor(v); }
element_type & current_element() const { BOOST_GEOMETRY_INDEX_ASSERT(parent, "null pointer"); return rtree::elements(*parent)[current_child_index]; }
const_reference dereference() const { BOOST_GEOMETRY_INDEX_ASSERT(m_values, "not dereferencable"); return *m_current; }
end_query_iterator operator++(int) { BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not incrementable"); return *this; }
inline void throw_out_of_range(const char * str) { BOOST_GEOMETRY_INDEX_ASSERT(!"out_of_range thrown", str); std::abort(); }
inline void throw_length_error(const char * str) { BOOST_GEOMETRY_INDEX_ASSERT(!"length_error thrown", str); std::abort(); }
inline void throw_invalid_argument(const char * str) { BOOST_GEOMETRY_INDEX_ASSERT(!"invalid_argument thrown", str); std::abort(); }
elements_type & parent_elements() const { BOOST_GEOMETRY_INDEX_ASSERT(parent, "null pointer"); return rtree::elements(*parent); }
static inline void apply(Node & n, Node & second_node, Box & box1, Box & box2, parameters_type const& parameters, Translator const& translator, Allocators & allocators) { typedef typename rtree::elements_type<Node>::type elements_type; typedef typename elements_type::value_type element_type; typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type; elements_type & elements1 = rtree::elements(n); elements_type & elements2 = rtree::elements(second_node); BOOST_GEOMETRY_INDEX_ASSERT(elements1.size() == parameters.get_max_elements() + 1, "unexpected elements number"); // copy original elements - use in-memory storage (std::allocator) // TODO: move if noexcept typedef typename rtree::container_from_elements_type<elements_type, element_type>::type container_type; container_type elements_copy(elements1.begin(), elements1.end()); // MAY THROW, STRONG (alloc, copy) container_type elements_backup(elements1.begin(), elements1.end()); // MAY THROW, STRONG (alloc, copy) // calculate initial seeds size_t seed1 = 0; size_t seed2 = 0; quadratic::pick_seeds<Box>(elements_copy, parameters, translator, seed1, seed2); // prepare nodes' elements containers elements1.clear(); BOOST_GEOMETRY_INDEX_ASSERT(elements2.empty(), "second node's elements container should be empty"); BOOST_TRY { // add seeds elements1.push_back(elements_copy[seed1]); // MAY THROW, STRONG (copy) elements2.push_back(elements_copy[seed2]); // MAY THROW, STRONG (alloc, copy) // calculate boxes detail::bounds(rtree::element_indexable(elements_copy[seed1], translator), box1); detail::bounds(rtree::element_indexable(elements_copy[seed2], translator), box2); // remove seeds if (seed1 < seed2) { rtree::move_from_back(elements_copy, elements_copy.begin() + seed2); // MAY THROW, STRONG (copy) elements_copy.pop_back(); rtree::move_from_back(elements_copy, elements_copy.begin() + seed1); // MAY THROW, STRONG (copy) elements_copy.pop_back(); } else { rtree::move_from_back(elements_copy, elements_copy.begin() + seed1); // MAY THROW, STRONG (copy) elements_copy.pop_back(); rtree::move_from_back(elements_copy, elements_copy.begin() + seed2); // MAY THROW, STRONG (copy) elements_copy.pop_back(); } // initialize areas content_type content1 = index::detail::content(box1); content_type content2 = index::detail::content(box2); size_t remaining = elements_copy.size(); // redistribute the rest of the elements while ( !elements_copy.empty() ) { typename container_type::reverse_iterator el_it = elements_copy.rbegin(); bool insert_into_group1 = false; size_t elements1_count = elements1.size(); size_t elements2_count = elements2.size(); // if there is small number of elements left and the number of elements in node is lesser than min_elems // just insert them to this node if ( elements1_count + remaining <= parameters.get_min_elements() ) { insert_into_group1 = true; } else if ( elements2_count + remaining <= parameters.get_min_elements() ) { insert_into_group1 = false; } // insert the best element else { // find element with minimum groups areas increses differences content_type content_increase1 = 0; content_type content_increase2 = 0; el_it = pick_next(elements_copy.rbegin(), elements_copy.rend(), box1, box2, content1, content2, translator, content_increase1, content_increase2); if ( content_increase1 < content_increase2 || ( content_increase1 == content_increase2 && ( content1 < content2 || ( content1 == content2 && elements1_count <= elements2_count ) ) ) ) { insert_into_group1 = true; } else { insert_into_group1 = false; } } // move element to the choosen group element_type const& elem = *el_it; indexable_type const& indexable = rtree::element_indexable(elem, translator); if ( insert_into_group1 ) { elements1.push_back(elem); // MAY THROW, STRONG (copy) geometry::expand(box1, indexable); content1 = index::detail::content(box1); } else { elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy) geometry::expand(box2, indexable); content2 = index::detail::content(box2); } BOOST_GEOMETRY_INDEX_ASSERT(!elements_copy.empty(), "expected more elements"); typename container_type::iterator el_it_base = el_it.base(); rtree::move_from_back(elements_copy, --el_it_base); // MAY THROW, STRONG (copy) elements_copy.pop_back(); BOOST_GEOMETRY_INDEX_ASSERT(0 < remaining, "expected more remaining elements"); --remaining; } } BOOST_CATCH(...) { //elements_copy.clear(); elements1.clear(); elements2.clear(); rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_backup, allocators); //elements_backup.clear(); BOOST_RETHROW // RETHROW, BASIC }