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

[SVN r81301]
This commit is contained in:
Adam Wulkiewicz
2012-11-12 00:47:07 +00:00
parent d008473125
commit 25e10f2539
14 changed files with 600 additions and 173 deletions

View File

@@ -224,12 +224,16 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear
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 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear
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 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear
// 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 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear
( 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 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear
elements2.clear();
rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_copy, allocators);
//elements_copy.clear();
throw; // RETHROW
throw; // RETHROW
}
}
};

View File

@@ -53,6 +53,26 @@ inline Box elements_box(FwdIter first, FwdIter last, Translator const& tr)
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

View File

@@ -203,6 +203,8 @@ struct create_dynamic_node
try
{
// NOTE/TODO
// Here the whole node may be copied
alloc_node.construct(p, Node(alloc_elems));
}
catch(...)

View File

@@ -166,6 +166,8 @@ struct create_static_node
try
{
// NOTE/TODO
// Here the whole node may be copied
alloc_node.construct(p, Node(alloc_elems)); // implicit cast to Variant
}
catch(...)

View File

@@ -109,107 +109,127 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, quadra
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)
try
{
elements_copy.erase(elements_copy.begin() + seed2);
elements_copy.erase(elements_copy.begin() + seed1);
}
else
{
elements_copy.erase(elements_copy.begin() + seed1);
elements_copy.erase(elements_copy.begin() + seed2);
}
// add seeds
elements1.push_back(elements_copy[seed1]); // MAY THROW
elements2.push_back(elements_copy[seed2]); // MAY THROW
// initialize areas
content_type content1 = index::content(box1);
content_type content2 = index::content(box2);
// calculate boxes
geometry::convert(rtree::element_indexable(elements_copy[seed1], translator), box1);
geometry::convert(rtree::element_indexable(elements_copy[seed2], translator), 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();
// 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() )
{
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);
elements_copy.erase(elements_copy.begin() + seed1); // MAY THROW
elements_copy.erase(elements_copy.begin() + seed2); // MAY THROW
}
if ( content_increase1 < content_increase2 ||
( content_increase1 == content_increase2 && content1 < content2 ) ||
( content1 == content2 && elements1_count <= elements2_count ) )
// 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();
// 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);
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();
// move element to the choosen group
element_type const& elem = *el_it;
indexable_type const& indexable = rtree::element_indexable(elem, translator);
rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_backup, allocators);
//elements_backup.clear();
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);
}
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);
BOOST_GEOMETRY_INDEX_ASSERT(0 < remaining, "expected more remaining elements");
--remaining;
throw; // RETHROW
}
}

View File

@@ -37,7 +37,8 @@ public:
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 @@ public:
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 @@ public:
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
// 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;
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);
throw; // RETHROW
}
}
private:
@@ -161,16 +174,18 @@ struct level_insert_base
// 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 @@ struct level_insert_base
// overflow
if ( base::m_parameters.get_max_elements() < rtree::elements(n).size() )
{
base::split(n);
base::split(n); // MAY THROW
}
}
@@ -228,7 +243,7 @@ struct level_insert
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 @@ struct level_insert
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 @@ struct level_insert
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 @@ struct level_insert<InsertIndex, Value, Value, Options, Translator, Box, Allocat
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 @@ struct level_insert<InsertIndex, Value, Value, Options, Translator, Box, Allocat
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 @@ struct level_insert<0, Value, Value, Options, Translator, Box, Allocators>
"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 @@ struct level_insert<0, Value, Value, Options, Translator, Box, Allocators>
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 @@ public:
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 @@ public:
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 @@ private:
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
}
}
}

View File

@@ -68,11 +68,11 @@ struct choose_split_axis_and_index_for_corner
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 @@ struct choose_split_axis_and_index_for_axis<Parameters, Box, AxisIndex, box_tag>
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 @@ struct choose_split_axis_and_index_for_axis<Parameters, Box, AxisIndex, box_tag>
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 @@ struct choose_split_axis_and_index_for_axis<Parameters, Box, AxisIndex, point_ta
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 @@ struct choose_split_axis_and_index
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 @@ struct choose_split_axis_and_index
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 @@ struct choose_split_axis_and_index<Parameters, Box, 1>
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 @@ struct partial_sort
{
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 @@ struct partial_sort
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 @@ struct partial_sort<Corner, 1>
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 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, rstar_
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 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, rstar_
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);
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);
// 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
}
}
};

View File

@@ -277,27 +277,20 @@ public:
{
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;
}
/*!

View File

@@ -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.
//

View File

@@ -42,10 +42,11 @@ public:
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);

View File

@@ -139,11 +139,14 @@ public:
// 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 @@ protected:
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 @@ protected:
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 @@ public:
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 @@ public:
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
}

View File

@@ -37,5 +37,7 @@ test-suite boost-geometry-index-rtree
[ run rtree3d_rstar_f.cpp ]
[ run rtree3d_rstar_d.cpp ]
[ run rtree3d_rstar_tt.cpp ]
[ run rtree_exceptions.cpp ]
;

View File

@@ -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;
}

View File

@@ -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