mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-11 11:52:11 +00:00
potential mem leaks fixed in inserting algorithms, exceptions tests added.
[SVN r81301]
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(...)
|
||||
|
||||
@@ -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(...)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -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.
|
||||
//
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 ]
|
||||
;
|
||||
|
||||
|
||||
51
test/rtree/rtree_exceptions.cpp
Normal file
51
test/rtree/rtree_exceptions.cpp
Normal 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;
|
||||
}
|
||||
291
test/rtree/test_rtree_exceptions.hpp
Normal file
291
test/rtree/test_rtree_exceptions.hpp
Normal 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
|
||||
Reference in New Issue
Block a user