Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r81301 - in sandbox-branches/geometry/index_dev: boost/geometry/extensions/index/rtree boost/geometry/extensions/index/rtree/linear boost/geometry/extensions/index/rtree/node boost/geometry/extensions/index/rtree/quadratic boost/geometry/extensions/index/rtree/rstar boost/geometry/extensions/index/rtree/visitors test/rtree
From: adam.wulkiewicz_at_[hidden]
Date: 2012-11-11 19:47:09


Author: awulkiew
Date: 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
New Revision: 81301
URL: http://svn.boost.org/trac/boost/changeset/81301

Log:
potential mem leaks fixed in inserting algorithms, exceptions tests added.

Added:
   sandbox-branches/geometry/index_dev/test/rtree/rtree_exceptions.cpp (contents, props changed)
   sandbox-branches/geometry/index_dev/test/rtree/test_rtree_exceptions.hpp (contents, props changed)
Text files modified:
   sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/linear/redistribute_elements.hpp | 23 +++--
   sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/node/node.hpp | 20 ++++
   sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/node/node_d_mem_dynamic.hpp | 2
   sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/node/node_s_mem_dynamic.hpp | 2
   sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/quadratic/redistribute_elements.hpp | 168 ++++++++++++++++++++++-----------------
   sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/rstar/insert.hpp | 85 +++++++++++--------
   sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/rstar/redistribute_elements.hpp | 74 +++++++++++------
   sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/rtree.hpp | 31 ++----
   sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/tags.hpp | 2
   sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/visitors/destroy.hpp | 3
   sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/visitors/insert.hpp | 19 ++-
   sandbox-branches/geometry/index_dev/test/rtree/Jamfile.v2 | 2
   12 files changed, 258 insertions(+), 173 deletions(-)

Modified: sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/linear/redistribute_elements.hpp
==============================================================================
--- sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/linear/redistribute_elements.hpp (original)
+++ sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/linear/redistribute_elements.hpp 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
@@ -224,12 +224,16 @@
                 BOOST_GEOMETRY_INDEX_ASSERT(elements1.size() == elements1_count, "unexpected number of elements");
 
                 // copy original elements
- elements_type elements_copy(elements1); // MAY THROW
+ elements_type elements_copy(elements1); // MAY THROW
 
         // calculate initial seeds
         size_t seed1 = 0;
         size_t seed2 = 0;
- linear::pick_seeds<elements_type, parameters_type, Translator>::apply(elements_copy, parameters, translator, seed1, seed2);
+ linear::pick_seeds<
+ elements_type,
+ parameters_type,
+ Translator
+ >::apply(elements_copy, parameters, translator, seed1, seed2);
 
         // prepare nodes' elements containers
         elements1.clear();
@@ -238,8 +242,8 @@
         try
         {
             // add seeds
- elements1.push_back(elements_copy[seed1]); // MAY THROW
- elements2.push_back(elements_copy[seed2]); // MAY THROW
+ elements1.push_back(elements_copy[seed1]); // MAY THROW
+ elements2.push_back(elements_copy[seed2]); // MAY THROW
 
             // calculate boxes
             geometry::convert(rtree::element_indexable(elements_copy[seed1], translator), box1);
@@ -264,13 +268,13 @@
                     // just insert them to this node
                     if ( elements1.size() + remaining <= parameters.get_min_elements() )
                     {
- elements1.push_back(elem); // MAY THROW
+ elements1.push_back(elem); // MAY THROW
                         geometry::expand(box1, indexable);
                         content1 = index::content(box1);
                     }
                     else if ( elements2.size() + remaining <= parameters.get_min_elements() )
                     {
- elements2.push_back(elem); // MAY THROW
+ elements2.push_back(elem); // MAY THROW
                         geometry::expand(box2, indexable);
                         content2 = index::content(box2);
                     }
@@ -293,13 +297,13 @@
                              ( content_increase1 == content_increase2 && content1 < content2 ) ||
                              ( content1 == content2 && elements1.size() <= elements2.size() ) )
                         {
- elements1.push_back(elem); // MAY THROW
+ elements1.push_back(elem); // MAY THROW
                             box1 = enlarged_box1;
                             content1 = enlarged_content1;
                         }
                         else
                         {
- elements2.push_back(elem); // MAY THROW
+ elements2.push_back(elem); // MAY THROW
                             box2 = enlarged_box2;
                             content2 = enlarged_content2;
                         }
@@ -316,8 +320,9 @@
             elements2.clear();
 
             rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_copy, allocators);
+ //elements_copy.clear();
 
- throw; // RETHROW
+ throw; // RETHROW
         }
     }
 };

Modified: sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/node/node.hpp
==============================================================================
--- sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/node/node.hpp (original)
+++ sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/node/node.hpp 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
@@ -53,6 +53,26 @@
     return result;
 }
 
+// destroys subtree if the element is internal node's element
+template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
+struct destroy_element
+{
+ typedef typename Options::parameters_type parameters_type;
+
+ typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
+ typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
+
+ typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr;
+
+ inline static void apply(typename internal_node::elements_type::value_type & element, Allocators & allocators)
+ {
+ node_auto_ptr dummy(element.second, allocators);
+ element.second = 0;
+ }
+
+ inline static void apply(typename leaf::elements_type::value_type &, Allocators &) {}
+};
+
 // destroys stored subtrees if internal node's elements are passed
 template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
 struct destroy_elements

Modified: sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/node/node_d_mem_dynamic.hpp
==============================================================================
--- sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/node/node_d_mem_dynamic.hpp (original)
+++ sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/node/node_d_mem_dynamic.hpp 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
@@ -203,6 +203,8 @@
 
         try
         {
+ // NOTE/TODO
+ // Here the whole node may be copied
             alloc_node.construct(p, Node(alloc_elems));
         }
         catch(...)

Modified: sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/node/node_s_mem_dynamic.hpp
==============================================================================
--- sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/node/node_s_mem_dynamic.hpp (original)
+++ sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/node/node_s_mem_dynamic.hpp 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
@@ -166,6 +166,8 @@
 
         try
         {
+ // NOTE/TODO
+ // Here the whole node may be copied
             alloc_node.construct(p, Node(alloc_elems)); // implicit cast to Variant
         }
         catch(...)

Modified: sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/quadratic/redistribute_elements.hpp
==============================================================================
--- sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/quadratic/redistribute_elements.hpp (original)
+++ sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/quadratic/redistribute_elements.hpp 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
@@ -109,107 +109,127 @@
                 BOOST_GEOMETRY_INDEX_ASSERT(elements1.size() == elements1_count, "unexpected elements number");
 
         // copy original elements
- elements_type elements_copy(elements1);
+ elements_type elements_copy(elements1); // MAY THROW
+ elements_type elements_backup(elements1); // MAY THROW
         
         // calculate initial seeds
         size_t seed1 = 0;
         size_t seed2 = 0;
- quadratic::pick_seeds<elements_type, parameters_type, Translator, Box>::apply(elements_copy, parameters, translator, seed1, seed2);
+ quadratic::pick_seeds<
+ elements_type,
+ parameters_type,
+ Translator,
+ Box
+ >::apply(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");
 
- // add seeds
- elements1.push_back(elements_copy[seed1]);
- elements2.push_back(elements_copy[seed2]);
-
- // calculate boxes
- geometry::convert(rtree::element_indexable(elements_copy[seed1], translator), box1);
- geometry::convert(rtree::element_indexable(elements_copy[seed2], translator), box2);
-
- // remove seeds
- if (seed1 < seed2)
- {
- elements_copy.erase(elements_copy.begin() + seed2);
- elements_copy.erase(elements_copy.begin() + seed1);
- }
- else
+ try
         {
- elements_copy.erase(elements_copy.begin() + seed1);
- elements_copy.erase(elements_copy.begin() + seed2);
- }
-
- // initialize areas
- content_type content1 = index::content(box1);
- content_type content2 = index::content(box2);
-
- size_t remaining = elements_copy.size();
-
- // redistribute the rest of the elements
- while ( !elements_copy.empty() )
- {
- typename elements_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();
+ // add seeds
+ elements1.push_back(elements_copy[seed1]); // MAY THROW
+ elements2.push_back(elements_copy[seed2]); // MAY THROW
+
+ // calculate boxes
+ geometry::convert(rtree::element_indexable(elements_copy[seed1], translator), box1);
+ geometry::convert(rtree::element_indexable(elements_copy[seed2], translator), box2);
 
- // 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() )
+ // remove seeds
+ if (seed1 < seed2)
             {
- insert_into_group1 = true;
+ elements_copy.erase(elements_copy.begin() + seed2); // MAY THROW
+ elements_copy.erase(elements_copy.begin() + seed1); // MAY THROW
             }
- else if ( elements2_count + remaining <= parameters.get_min_elements() )
+ else
             {
- insert_into_group1 = false;
+ elements_copy.erase(elements_copy.begin() + seed1); // MAY THROW
+ elements_copy.erase(elements_copy.begin() + seed2); // MAY THROW
             }
- // insert the best element
- else
+
+ // initialize areas
+ content_type content1 = index::content(box1);
+ content_type content2 = index::content(box2);
+
+ size_t remaining = elements_copy.size();
+
+ // redistribute the rest of the elements
+ while ( !elements_copy.empty() )
             {
- // 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 ) )
+ typename elements_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
+ 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);
+ // 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);
- geometry::expand(box1, indexable);
- content1 = index::content(box1);
- }
- else
- {
- elements2.push_back(elem);
- geometry::expand(box2, indexable);
- content2 = index::content(box2);
+ if ( insert_into_group1 )
+ {
+ elements1.push_back(elem); // MAY THROW
+ geometry::expand(box1, indexable);
+ content1 = index::content(box1);
+ }
+ else
+ {
+ elements2.push_back(elem); // MAY THROW
+ geometry::expand(box2, indexable);
+ content2 = index::content(box2);
+ }
+
+ BOOST_GEOMETRY_INDEX_ASSERT(!elements_copy.empty(), "expected more elements");
+ typename elements_type::iterator el_it_base = el_it.base();
+ elements_copy.erase(--el_it_base); // MAY THROW
+
+ BOOST_GEOMETRY_INDEX_ASSERT(0 < remaining, "expected more remaining elements");
+ --remaining;
             }
+ }
+ catch(...)
+ {
+ //elements_copy.clear();
+ elements1.clear();
+ elements2.clear();
 
- BOOST_GEOMETRY_INDEX_ASSERT(!elements_copy.empty(), "expected more elements");
- typename elements_type::iterator el_it_base = el_it.base();
- elements_copy.erase(--el_it_base);
+ rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_backup, allocators);
+ //elements_backup.clear();
 
- BOOST_GEOMETRY_INDEX_ASSERT(0 < remaining, "expected more remaining elements");
- --remaining;
+ throw; // RETHROW
         }
     }
 

Modified: sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/rstar/insert.hpp
==============================================================================
--- sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/rstar/insert.hpp (original)
+++ sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/rstar/insert.hpp 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
@@ -37,7 +37,8 @@
                                                           internal_node *parent,
                                                          size_t current_child_index,
                              parameters_type const& parameters,
- Translator const& translator)
+ Translator const& translator,
+ Allocators & allocators)
     {
         typedef typename rtree::elements_type<Node>::type elements_type;
         typedef typename elements_type::value_type element_type;
@@ -62,15 +63,14 @@
         typename index::detail::rtree::container_from_elements_type<
             elements_type,
             std::pair<distance_type, element_type>
- >::type sorted_elements(elements_count);
-
+ >::type sorted_elements(elements_count); // MAY THROW
+
                 for ( size_t i = 0 ; i < elements_count ; ++i )
         {
             point_type element_center;
- geometry::centroid( rtree::element_indexable(elements[i], translator),
- element_center);
+ geometry::centroid( rtree::element_indexable(elements[i], translator), element_center);
             sorted_elements[i].first = geometry::comparable_distance(node_center, element_center);
- sorted_elements[i].second = elements[i];
+ sorted_elements[i].second = elements[i]; // MAY THROW
         }
 
         // sort elements by distances from center
@@ -78,17 +78,30 @@
             sorted_elements.begin(),
             sorted_elements.begin() + reinserted_elements_count,
             sorted_elements.end(),
- distances_dsc<distance_type, element_type>);
+ distances_dsc<distance_type, element_type>); // MAY THROW
 
         // copy elements which will be reinserted
- result_elements.resize(reinserted_elements_count);
+ result_elements.resize(reinserted_elements_count); // MAY THROW
         for ( size_t i = 0 ; i < reinserted_elements_count ; ++i )
- result_elements[i] = sorted_elements[i].second;
+ result_elements[i] = sorted_elements[i].second; // MAY THROW
+
+ try
+ {
+ // copy remaining elements to the current node
+ size_t elements_new_count = elements_count - reinserted_elements_count;
+ elements.resize(elements_new_count); // MIGHT THROW
+ for ( size_t i = 0 ; i < elements_new_count ; ++i )
+ elements[i] = sorted_elements[i + reinserted_elements_count].second; // MAY THROW
+ }
+ catch(...)
+ {
+ elements.clear();
+
+ for ( size_t i = 0 ; i < elements_count ; ++i )
+ destroy_element<Value, Options, Translator, Box, Allocators>::apply(sorted_elements[i].second, allocators);
 
- // copy remaining elements to the current node
- elements.resize(elements_count - reinserted_elements_count);
- for ( size_t i = reinserted_elements_count ; i < elements_count ; ++i )
- elements[i - reinserted_elements_count] = sorted_elements[i].second;
+ throw; // RETHROW
+ }
     }
 
 private:
@@ -161,16 +174,18 @@
                         // node isn't root node
                         if ( !base::m_traverse_data.current_is_root() )
                         {
+ // NOTE: exception-safety
+ // After an exception result_elements may contain garbage
                                 rstar::remove_elements_to_reinsert<Value, Options, Translator, Box, Allocators>::apply(
                                         result_elements, n,
                                         base::m_traverse_data.parent, base::m_traverse_data.current_child_index,
- base::m_parameters, base::m_translator);
+ base::m_parameters, base::m_translator, base::m_allocators); // MAY THROW
                         }
                         // node is root node
                         else
                         {
                                 BOOST_GEOMETRY_INDEX_ASSERT(&n == rtree::get<Node>(base::m_root_node), "node should be the root node");
- base::split(n);
+ base::split(n); // MAY THROW
                         }
                 }
         }
@@ -181,7 +196,7 @@
                 // overflow
                 if ( base::m_parameters.get_max_elements() < rtree::elements(n).size() )
                 {
- base::split(n);
+ base::split(n); // MAY THROW
                 }
         }
 
@@ -228,7 +243,7 @@
         if ( base::m_traverse_data.current_level < base::m_level )
         {
             // next traversing step
- base::traverse(*this, n);
+ base::traverse(*this, n); // MAY THROW
 
             // further insert
             if ( 0 < InsertIndex )
@@ -237,7 +252,7 @@
 
                 if ( base::m_traverse_data.current_level == base::m_level - 1 )
                 {
- base::handle_possible_reinsert_or_split_of_root(n);
+ base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW
                 }
             }
         }
@@ -246,17 +261,17 @@
                         BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level, "unexpected level");
 
             // push new child node
- rtree::elements(n).push_back(base::m_element);
+ rtree::elements(n).push_back(base::m_element); // MAY THROW
 
             // first insert
             if ( 0 == InsertIndex )
             {
- base::handle_possible_reinsert_or_split_of_root(n);
+ base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW
             }
             // not the first insert
             else
             {
- base::handle_possible_split(n);
+ base::handle_possible_split(n); // MAY THROW
             }
         }
 
@@ -296,13 +311,13 @@
                 BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level, "unexpected level");
 
         // next traversing step
- base::traverse(*this, n);
+ base::traverse(*this, n); // MAY THROW
 
                 BOOST_GEOMETRY_INDEX_ASSERT(0 < base::m_level, "illegal level value, level shouldn't be the root level for 0 < InsertIndex");
         
         if ( base::m_traverse_data.current_level == base::m_level - 1 )
         {
- base::handle_possible_reinsert_or_split_of_root(n);
+ base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW
         }
 
         base::recalculate_aabb_if_necessary(n);
@@ -316,9 +331,9 @@
                                             base::m_level == (std::numeric_limits<size_t>::max)(),
                                             "unexpected level");
         
- rtree::elements(n).push_back(base::m_element);
+ rtree::elements(n).push_back(base::m_element); // MAY THROW
 
- base::handle_possible_split(n);
+ base::handle_possible_split(n); // MAY THROW
     }
 };
 
@@ -351,7 +366,7 @@
                                             "unexpected level");
                 
         // next traversing step
- base::traverse(*this, n);
+ base::traverse(*this, n); // MAY THROW
 
         base::recalculate_aabb_if_necessary(n);
     }
@@ -364,11 +379,11 @@
                                             base::m_level == (std::numeric_limits<size_t>::max)(),
                                             "unexpected level");
 
- rtree::elements(n).push_back(base::m_element);
+ rtree::elements(n).push_back(base::m_element); // MAY THROW
 
- base::handle_possible_reinsert_or_split_of_root(n);
-
- base::recalculate_aabb_if_necessary(n);
+ base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW
+
+ base::recalculate_aabb_if_necessary(n);
     }
 };
 
@@ -408,11 +423,11 @@
                 detail::rstar::level_insert<0, Element, Value, Options, Translator, Box, Allocators> lins_v(
                         m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
 
- rtree::apply_visitor(lins_v, *m_root);
+ rtree::apply_visitor(lins_v, *m_root); // MAY THROW
 
                 if ( !lins_v.result_elements.empty() )
                 {
- recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level);
+ recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level); // MAY THROW
                 }
         }
 
@@ -423,7 +438,7 @@
                 detail::rstar::level_insert<0, Element, Value, Options, Translator, Box, Allocators> lins_v(
                         m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
 
- rtree::apply_visitor(lins_v, *m_root);
+ rtree::apply_visitor(lins_v, *m_root); // MAY THROW
 
                 // we're in the root, so root should be split and there should be no elements to reinsert
                 assert(lins_v.result_elements.empty());
@@ -442,14 +457,14 @@
                         detail::rstar::level_insert<1, element_type, Value, Options, Translator, Box, Allocators> lins_v(
                                 m_root, m_leafs_level, *it, m_parameters, m_translator, m_allocators, relative_level);
 
- rtree::apply_visitor(lins_v, *m_root);
+ rtree::apply_visitor(lins_v, *m_root); // MAY THROW
 
                         assert(relative_level + 1 == lins_v.result_relative_level);
 
                         // non-root relative level
                         if ( lins_v.result_relative_level < m_leafs_level && !lins_v.result_elements.empty())
                         {
- recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level);
+ recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level); // MAY THROW
                         }
                 }
         }

Modified: sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/rstar/redistribute_elements.hpp
==============================================================================
--- sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/rstar/redistribute_elements.hpp (original)
+++ sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/rstar/redistribute_elements.hpp 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
@@ -68,11 +68,11 @@
         BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == parameters.get_max_elements() + 1, "wrong number of elements");
 
         // copy elements
- Elements elements_copy = elements;
+ Elements elements_copy(elements); // MAY THROW
         
         // sort elements
         element_axis_corner_less<element_type, Translator, Corner, AxisIndex> elements_less(translator);
- std::sort(elements_copy.begin(), elements_copy.end(), elements_less);
+ std::sort(elements_copy.begin(), elements_copy.end(), elements_less); // MAY THROW
 
         // init outputs
         choosen_index = parameters.get_min_elements();
@@ -135,7 +135,7 @@
         choose_split_axis_and_index_for_corner<Parameters, Box, min_corner, AxisIndex>::
             apply(elements, index1,
                   som1, ovl1, con1,
- parameters, translator);
+ parameters, translator); // MAY THROW
 
         size_t index2 = 0;
         margin_type som2 = 0;
@@ -145,7 +145,7 @@
         choose_split_axis_and_index_for_corner<Parameters, Box, max_corner, AxisIndex>::
             apply(elements, index2,
                   som2, ovl2, con2,
- parameters, translator);
+ parameters, translator); // MAY THROW
 
         sum_of_margins = som1 + som2;
 
@@ -185,7 +185,7 @@
         choose_split_axis_and_index_for_corner<Parameters, Box, min_corner, AxisIndex>::
             apply(elements, choosen_index,
                   sum_of_margins, smallest_overlap, smallest_content,
- parameters, translator);
+ parameters, translator); // MAY THROW
 
         choosen_corner = min_corner;
     }
@@ -215,7 +215,7 @@
         choose_split_axis_and_index<Parameters, Box, Dimension - 1>::
             apply(elements, choosen_axis, choosen_corner, choosen_index,
                   smallest_sum_of_margins, smallest_overlap, smallest_content,
- parameters, translator);
+ parameters, translator); // MAY THROW
 
         margin_type sum_of_margins = 0;
 
@@ -230,7 +230,7 @@
             Box,
             Dimension - 1,
             typename index::traits::tag<element_indexable_type>::type
- >::apply(elements, corner, index, sum_of_margins, overlap_val, content_val, parameters, translator);
+ >::apply(elements, corner, index, sum_of_margins, overlap_val, content_val, parameters, translator); // MAY THROW
 
         if ( sum_of_margins < smallest_sum_of_margins )
         {
@@ -270,7 +270,7 @@
             Box,
             0,
             typename index::traits::tag<element_indexable_type>::type
- >::apply(elements, choosen_corner, choosen_index, smallest_sum_of_margins, smallest_overlap, smallest_content, parameters, translator);
+ >::apply(elements, choosen_corner, choosen_index, smallest_sum_of_margins, smallest_overlap, smallest_content, parameters, translator); // MAY THROW
     }
 };
 
@@ -284,7 +284,7 @@
     {
         if ( axis < Dimension - 1 )
         {
- partial_sort<Corner, Dimension - 1>::apply(elements, axis, index, tr);
+ partial_sort<Corner, Dimension - 1>::apply(elements, axis, index, tr); // MAY THROW
         }
         else
         {
@@ -292,7 +292,7 @@
 
             typedef typename Elements::value_type element_type;
             element_axis_corner_less<element_type, Translator, Corner, Dimension - 1> less(tr);
- std::partial_sort(elements.begin(), elements.begin() + index, elements.end(), less);
+ std::partial_sort(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW
         }
     }
 };
@@ -307,7 +307,7 @@
 
         typedef typename Elements::value_type element_type;
         element_axis_corner_less<element_type, Translator, Corner, 0> less(tr);
- std::partial_sort(elements.begin(), elements.begin() + index, elements.end(), less);
+ std::partial_sort(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW
     }
 };
 
@@ -349,11 +349,14 @@
         content_type smallest_overlap = (std::numeric_limits<content_type>::max)();
         content_type smallest_content = (std::numeric_limits<content_type>::max)();
 
- rstar::choose_split_axis_and_index<typename Options::parameters_type, Box, index::traits::dimension<Box>::value>::
- apply(elements1,
- split_axis, split_corner, split_index,
- smallest_sum_of_margins, smallest_overlap, smallest_content,
- parameters, translator);
+ rstar::choose_split_axis_and_index<
+ typename Options::parameters_type,
+ Box,
+ index::traits::dimension<Box>::value
+ >::apply(elements1,
+ split_axis, split_corner, split_index,
+ smallest_sum_of_margins, smallest_overlap, smallest_content,
+ parameters, translator); // MAY THROW
 
         // TODO: awulkiew - get rid of following static_casts?
 
@@ -361,20 +364,39 @@
         BOOST_GEOMETRY_INDEX_ASSERT(split_corner == static_cast<size_t>(min_corner) || split_corner == static_cast<size_t>(max_corner), "unexpected value");
         BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= split_index && split_index <= parameters.get_max_elements() - parameters.get_min_elements() + 1, "unexpected value");
         
+ // copy original elements
+ elements_type elements_copy(elements1); // MAY THROW
+
         // TODO: awulkiew - check if std::partial_sort produces the same result as std::sort
         if ( split_corner == static_cast<size_t>(min_corner) )
- rstar::partial_sort<min_corner, dimension>::apply(elements1, split_axis, split_index, translator);
+ rstar::partial_sort<min_corner, dimension>
+ ::apply(elements_copy, split_axis, split_index, translator); // MAY THROW
         else
- rstar::partial_sort<max_corner, dimension>::apply(elements1, split_axis, split_index, translator);
+ rstar::partial_sort<max_corner, dimension>
+ ::apply(elements_copy, split_axis, split_index, translator); // MAY THROW
 
- // copy elements to node 2 and remove from node 1
- elements2.resize(parameters.get_max_elements() + 1 - split_index);
- std::copy(elements1.begin() + split_index, elements1.end(), elements2.begin());
- elements1.resize(split_index);
-
- // calculate boxes
- box1 = rtree::elements_box<Box>(elements1.begin(), elements1.end(), translator);
- box2 = rtree::elements_box<Box>(elements2.begin(), elements2.end(), translator);
+ try
+ {
+ // copy elements to nodes
+ elements1.resize(split_index); // MIGHT THROW
+ std::copy(elements_copy.begin(), elements_copy.begin() + split_index, elements1.begin()); // MAY THROW
+ elements2.resize(parameters.get_max_elements() + 1 - split_index); // MAY THROW
+ std::copy(elements_copy.begin() + split_index, elements_copy.end(), elements2.begin()); // MAY THROW
+
+ // calculate boxes
+ box1 = rtree::elements_box<Box>(elements1.begin(), elements1.end(), translator);
+ box2 = rtree::elements_box<Box>(elements2.begin(), elements2.end(), translator);
+ }
+ catch(...)
+ {
+ elements1.clear();
+ elements2.clear();
+
+ rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_copy, allocators);
+ //elements_copy.clear();
+
+ throw; // RETHROW
+ }
     }
 };
 

Modified: sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/rtree.hpp
==============================================================================
--- sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/rtree.hpp (original)
+++ sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/rtree.hpp 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
@@ -277,27 +277,20 @@
     {
         BOOST_GEOMETRY_INDEX_ASSERT(index::is_valid(m_translator(value)), "Indexable is invalid");
 
- try
- {
- detail::rtree::visitors::insert<
- value_type,
- value_type,
- options_type,
- translator_type,
- box_type,
- allocators_type,
- typename options_type::insert_tag
- > insert_v(m_root, m_leafs_level, value, m_parameters, m_translator, m_allocators);
+ detail::rtree::visitors::insert<
+ value_type,
+ value_type,
+ options_type,
+ translator_type,
+ box_type,
+ allocators_type,
+ typename options_type::insert_tag
+ > insert_v(m_root, m_leafs_level, value, m_parameters, m_translator, m_allocators);
 
- detail::rtree::apply_visitor(insert_v, *m_root);
+ detail::rtree::apply_visitor(insert_v, *m_root);
 
- ++m_values_count;
- }
- catch(...)
- {
- this->destroy(*this);
- throw;
- }
+ // If exception is thrown, m_values_count is invalid
+ ++m_values_count;
     }
 
     /*!

Modified: sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/tags.hpp
==============================================================================
--- sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/tags.hpp (original)
+++ sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/tags.hpp 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
@@ -1,6 +1,6 @@
 // Boost.Geometry Index
 //
-// Tags used by the R-tree implementation.
+// Tags used by the R-tree predicates implementation.
 //
 // Copyright (c) 2011-2012 Adam Wulkiewicz, Lodz, Poland.
 //

Modified: sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/visitors/destroy.hpp
==============================================================================
--- sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/visitors/destroy.hpp (original)
+++ sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/visitors/destroy.hpp 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
@@ -42,10 +42,11 @@
         elements_type & elements = rtree::elements(n);
 
         for (typename elements_type::iterator it = elements.begin();
- it != elements.end(); ++it)
+ it != elements.end(); ++it)
         {
             m_current_node = it->second;
             rtree::apply_visitor(*this, *m_current_node);
+ it->second = 0;
         }
 
         rtree::destroy_node<Allocators, internal_node>::apply(m_allocators, node_to_destroy);

Modified: sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/visitors/insert.hpp
==============================================================================
--- sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/visitors/insert.hpp (original)
+++ sandbox-branches/geometry/index_dev/boost/geometry/extensions/index/rtree/visitors/insert.hpp 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
@@ -139,11 +139,14 @@
         // create reference to the newly created node
         Node & n2 = rtree::get<Node>(*second_node);
 
- // After throwing an exception by redistribute_elements both nodes may be empty.
- // The tree won't be valid r-tree.
+ // 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, but then, if exception was thrown, the node would have more than max
- // elements which also is not allowed in the r-tree.
+ // 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;
@@ -266,7 +269,7 @@
             rtree::element_indexable(m_element, m_translator));
 
         // next traversing step
- traverse_apply_visitor(visitor, n, choosen_node_index);
+ traverse_apply_visitor(visitor, n, choosen_node_index); // MAY THROW
     }
 
     // TODO: awulkiew - change post_traverse name to handle_overflow or overflow_treatment?
@@ -295,7 +298,7 @@
         m_traverse_data.move_to_next_level(&n, choosen_node_index);
 
         // next traversing step
- rtree::apply_visitor(visitor, *rtree::elements(n)[choosen_node_index].second);
+ rtree::apply_visitor(visitor, *rtree::elements(n)[choosen_node_index].second); // MAY THROW
 
         // restore previous traverse inputs
         m_traverse_data = backup_traverse_data;
@@ -415,7 +418,7 @@
         if ( base::m_traverse_data.current_level < base::m_level )
         {
             // next traversing step
- base::traverse(*this, n);
+ base::traverse(*this, n); // MAY THROW
         }
         else
         {
@@ -464,7 +467,7 @@
         BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level, "unexpected level");
 
         // next traversing step
- base::traverse(*this, n);
+ base::traverse(*this, n); // MAY THROW
 
         base::post_traverse(n); // MAY THROW
     }

Modified: sandbox-branches/geometry/index_dev/test/rtree/Jamfile.v2
==============================================================================
--- sandbox-branches/geometry/index_dev/test/rtree/Jamfile.v2 (original)
+++ sandbox-branches/geometry/index_dev/test/rtree/Jamfile.v2 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
@@ -37,5 +37,7 @@
     [ run rtree3d_rstar_f.cpp ]
     [ run rtree3d_rstar_d.cpp ]
     [ run rtree3d_rstar_tt.cpp ]
+
+ [ run rtree_exceptions.cpp ]
     ;
     

Added: sandbox-branches/geometry/index_dev/test/rtree/rtree_exceptions.cpp
==============================================================================
--- (empty file)
+++ sandbox-branches/geometry/index_dev/test/rtree/rtree_exceptions.cpp 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
@@ -0,0 +1,51 @@
+// Boost.Geometry Index
+// Unit Test
+
+// Copyright (c) 2011-2012 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)
+
+#include <rtree/test_rtree_exceptions.hpp>
+
+#include <boost/geometry/geometries/point_xy.hpp>
+#include <boost/geometry/geometries/point.hpp>
+#include <boost/geometry/geometries/box.hpp>
+
+// test value exceptions
+template <typename Parameters>
+void test_rtree_value_exceptions(Parameters const& parameters = Parameters())
+{
+ typedef std::pair<bg::model::point<float, 2, bg::cs::cartesian>, throwing_value> Value;
+ typedef bgi::rtree<Value, Parameters> Tree;
+ typedef typename Tree::box_type B;
+
+ for ( size_t i = 10 ; i < 100 ; i += 10 )
+ {
+ throwing_value::reset_calls_counter();
+ throwing_value::set_max_calls((std::numeric_limits<size_t>::max)());
+
+ Tree tree(parameters);
+ std::vector<Value> input;
+ B qbox;
+ generate_input<2>::apply(input, qbox);
+
+ throwing_value::reset_calls_counter();
+ throwing_value::set_max_calls(0);
+
+ BOOST_CHECK_THROW( tree.insert(input.begin(), input.end()), throwing_value_copy_exception );
+ }
+}
+
+int test_main(int, char* [])
+{
+ test_rtree_value_exceptions< bgi::linear<4, 2> >();
+ test_rtree_value_exceptions(bgi::runtime::linear(4, 2));
+ test_rtree_value_exceptions< bgi::quadratic<4, 2> >();
+ test_rtree_value_exceptions(bgi::runtime::quadratic(4, 2));
+ test_rtree_value_exceptions< bgi::rstar<4, 2> >();
+ test_rtree_value_exceptions(bgi::runtime::rstar(4, 2));
+
+ return 0;
+}

Added: sandbox-branches/geometry/index_dev/test/rtree/test_rtree_exceptions.hpp
==============================================================================
--- (empty file)
+++ sandbox-branches/geometry/index_dev/test/rtree/test_rtree_exceptions.hpp 2012-11-11 19:47:07 EST (Sun, 11 Nov 2012)
@@ -0,0 +1,291 @@
+// Boost.Geometry Index
+//
+// R-tree nodes based on runtime-polymorphism, storing static-size containers
+// test version throwing exceptions on creation
+//
+// Copyright (c) 2011-2012 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_EXTENSIONS_INDEX_TEST_RTREE_EXCEPTIONS_HPP
+#define BOOST_GEOMETRY_EXTENSIONS_INDEX_TEST_RTREE_EXCEPTIONS_HPP
+
+#include <rtree/test_rtree.hpp>
+
+#include <boost/geometry/extensions/index/rtree/node/dynamic_visitor.hpp>
+#include <boost/geometry/extensions/index/pushable_array.hpp>
+
+namespace boost { namespace geometry { namespace index {
+
+// options implementation (from options.hpp)
+
+struct node_throwing_d_mem_static_tag {};
+
+template <size_t MaxElements, size_t MinElements>
+struct linear_throwing : public linear<MaxElements, MinElements> {};
+
+template <size_t MaxElements, size_t MinElements>
+struct quadratic_throwing : public quadratic<MaxElements, MinElements> {};
+
+template <size_t MaxElements, size_t MinElements, size_t OverlapCostThreshold = 0, size_t ReinsertedElements = options::detail::default_rstar_reinserted_elements<MaxElements>::value>
+struct rstar_throwing : public rstar<MaxElements, MinElements, OverlapCostThreshold, ReinsertedElements> {};
+
+namespace detail { namespace rtree {
+
+template <size_t MaxElements, size_t MinElements>
+struct options_type< linear_throwing<MaxElements, MinElements> >
+{
+ typedef options::rtree<
+ linear_throwing<MaxElements, MinElements>,
+ insert_default_tag, choose_by_content_diff_tag, split_default_tag, linear_tag,
+ node_throwing_d_mem_static_tag
+ > type;
+};
+
+template <size_t MaxElements, size_t MinElements>
+struct options_type< quadratic_throwing<MaxElements, MinElements> >
+{
+ typedef options::rtree<
+ quadratic_throwing<MaxElements, MinElements>,
+ insert_default_tag, choose_by_content_diff_tag, split_default_tag, quadratic_tag,
+ node_throwing_d_mem_static_tag
+ > type;
+};
+
+template <size_t MaxElements, size_t MinElements, size_t OverlapCostThreshold, size_t ReinsertedElements>
+struct options_type< rstar_throwing<MaxElements, MinElements, OverlapCostThreshold, ReinsertedElements> >
+{
+ typedef options::rtree<
+ rstar_throwing<MaxElements, MinElements, OverlapCostThreshold, ReinsertedElements>,
+ insert_reinsert_tag, choose_by_overlap_diff_tag, split_default_tag, rstar_tag,
+ node_throwing_d_mem_static_tag
+ > type;
+};
+
+}} // namespace detail::rtree
+
+// node implementation
+
+namespace detail { namespace rtree {
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct dynamic_internal_node<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag>
+ : public dynamic_node<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag>
+{
+ typedef index::pushable_array<
+ std::pair<
+ Box,
+ dynamic_node<Value, Parameters, Box, Allocators, node_d_mem_static_tag> *
+ >,
+ Parameters::max_elements + 1
+ > elements_type;
+
+ template <typename Dummy>
+ inline dynamic_internal_node(Dummy) {}
+
+ void apply_visitor(dynamic_visitor<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag, false> & v) { v(*this); }
+ void apply_visitor(dynamic_visitor<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag, true> & v) const { v(*this); }
+
+ elements_type elements;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct dynamic_leaf<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag>
+ : public dynamic_node<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag>
+{
+ typedef index::pushable_array<Value, Parameters::max_elements + 1> elements_type;
+
+ template <typename Dummy>
+ inline dynamic_leaf(Dummy) {}
+
+ void apply_visitor(dynamic_visitor<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag, false> & v) { v(*this); }
+ void apply_visitor(dynamic_visitor<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag, true> & v) const { v(*this); }
+
+ elements_type elements;
+};
+
+// nodes traits
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct node<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag>
+{
+ typedef dynamic_node<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag> type;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct internal_node<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag>
+{
+ typedef dynamic_internal_node<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag> type;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators>
+struct leaf<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag>
+{
+ typedef dynamic_leaf<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag> type;
+};
+
+template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst>
+struct visitor<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag, IsVisitableConst>
+{
+ typedef dynamic_visitor<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag, IsVisitableConst> type;
+};
+
+// allocators
+
+template <typename Allocator, typename Value, typename Parameters, typename Box>
+struct allocators<Allocator, Value, Parameters, Box, node_throwing_d_mem_static_tag>
+{
+ typedef Allocator allocator_type;
+ typedef typename allocator_type::size_type size_type;
+
+ typedef typename allocator_type::template rebind<
+ typename internal_node<Value, Parameters, Box, allocators, node_throwing_d_mem_static_tag>::type
+ >::other internal_node_allocator_type;
+
+ typedef typename allocator_type::template rebind<
+ typename leaf<Value, Parameters, Box, allocators, node_throwing_d_mem_static_tag>::type
+ >::other leaf_allocator_type;
+
+ inline explicit allocators(Allocator alloc)
+ : allocator(alloc)
+ , internal_node_allocator(allocator)
+ , leaf_allocator(allocator)
+ {}
+
+ allocator_type allocator;
+ internal_node_allocator_type internal_node_allocator;
+ leaf_allocator_type leaf_allocator;
+};
+
+struct internal_node_bad_alloc : public std::exception
+{
+ const char * what() { return "internal node creation failed."; }
+};
+
+// create_node
+
+template <typename Allocators, typename Value, typename Parameters, typename Box>
+struct create_node<
+ Allocators,
+ dynamic_internal_node<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag>
+>
+{
+ static inline dynamic_node<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag> *
+ apply(Allocators & allocators)
+ {
+ // throw if counter meets max count
+ if ( get_max_calls_ref() <= get_calls_counter_ref() )
+ throw internal_node_bad_alloc();
+ else
+ ++get_calls_counter_ref();
+
+ return create_dynamic_node<
+ dynamic_node<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag>,
+ dynamic_internal_node<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag>
+ >::template apply(allocators.internal_node_allocator, allocators.internal_node_allocator);
+ }
+
+ static void reset_calls_counter() { get_calls_counter_ref() = 0; }
+ static void set_max_calls(size_t mc) { get_max_calls_ref() = mc; }
+
+ static size_t & get_calls_counter_ref() { static size_t cc = 0; return cc; }
+ static size_t & get_max_calls_ref() { static size_t mc = 0; return mc; }
+};
+
+struct leaf_bad_alloc : public std::exception
+{
+ const char * what() { return "leaf node creation failed."; }
+};
+
+template <typename Allocators, typename Value, typename Parameters, typename Box>
+struct create_node<
+ Allocators,
+ dynamic_leaf<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag>
+>
+{
+ static inline typename node<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag>::type *
+ apply(Allocators & allocators)
+ {
+ // throw if counter meets max count
+ if ( get_max_calls_ref() <= get_calls_counter_ref() )
+ throw leaf_bad_alloc();
+ else
+ ++get_calls_counter_ref();
+
+ return create_dynamic_node<
+ dynamic_node<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag>,
+ dynamic_leaf<Value, Parameters, Box, Allocators, node_throwing_d_mem_static_tag>
+ >::template apply(allocators.leaf_allocator, allocators.leaf_allocator);
+ }
+
+ static void reset_calls_counter() { get_calls_counter_ref() = 0; }
+ static void set_max_calls(size_t mc) { get_max_calls_ref() = mc; }
+
+ static size_t & get_calls_counter_ref() { static size_t cc = 0; return cc; }
+ static size_t & get_max_calls_ref() { static size_t mc = 0; return mc; }
+};
+
+}} // namespace detail::rtree
+
+}}} // namespace boost::geometry::index
+
+// value implementation
+
+struct throwing_value_copy_exception : public std::exception
+{
+ const char * what() { return "value copy failed."; }
+};
+
+struct throwing_value
+{
+ explicit throwing_value(int v = 0)
+ : value(v)
+ {}
+
+ throwing_value(throwing_value const& v)
+ {
+ throw_if_required();
+
+ value = v.value;
+ }
+
+ throwing_value & operator=(throwing_value const& v)
+ {
+ throw_if_required();
+
+ value = v.value;
+ return *this;
+ }
+
+ void throw_if_required()
+ {
+ // throw if counter meets max count
+ if ( get_max_calls_ref() <= get_calls_counter_ref() )
+ throw throwing_value_copy_exception();
+ else
+ ++get_calls_counter_ref();
+ }
+
+ static void reset_calls_counter() { get_calls_counter_ref() = 0; }
+ static void set_max_calls(size_t mc) { get_max_calls_ref() = mc; }
+
+ static size_t & get_calls_counter_ref() { static size_t cc = 0; return cc; }
+ static size_t & get_max_calls_ref() { static size_t mc = 0; return mc; }
+
+ int value;
+};
+
+template <typename T, typename C>
+struct generate_value< std::pair<bg::model::point<T, 2, C>, throwing_value> >
+{
+ typedef bg::model::point<T, 2, C> P;
+ typedef std::pair<P, throwing_value> R;
+ static R apply(int x, int y)
+ {
+ return std::make_pair(P(x, y), throwing_value(x + y * 100));
+ }
+};
+
+#endif // BOOST_GEOMETRY_EXTENSIONS_INDEX_TEST_RTREE_EXCEPTIONS_HPP


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk