inline allocators() : node_allocator_type() {} template <typename Alloc> inline explicit allocators(Alloc const& alloc) : node_allocator_type(alloc) {} inline allocators(BOOST_FWD_REF(allocators) a) : node_allocator_type(boost::move(a.node_allocator())) {} inline allocators & operator=(BOOST_FWD_REF(allocators) a) { node_allocator() = boost::move(a.node_allocator()); return *this; } #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES inline allocators & operator=(allocators const& a) { node_allocator() = a.node_allocator(); return *this; } #endif void swap(allocators & a) { boost::swap(node_allocator(), a.node_allocator()); }
inline allocators() : node_allocator_type() {} template <typename Alloc> inline explicit allocators(Alloc const& alloc) : node_allocator_type(alloc) {} inline allocators(BOOST_FWD_REF(allocators) a) : node_allocator_type(pdalboost::move(a.node_allocator())) {} inline allocators & operator=(BOOST_FWD_REF(allocators) a) { node_allocator() = pdalboost::move(a.node_allocator()); return *this; } #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES inline allocators & operator=(allocators const& a) { node_allocator() = a.node_allocator(); return *this; } #endif void swap(allocators & a) { pdalboost::swap(node_allocator(), a.node_allocator()); }
pow2_radix_patricia_trie_node<Dims, Coord, T, Traits>& pow2_radix_patricia_trie_node<Dims, Coord, T, Traits>::insert(loc_type leaf_loc) { // invariant: this 'node' variable changes but is never nullptr. node_type* node_to_initialize; node_type*const node = &this->find_node(leaf_loc); if(node->size_exponent_in_each_dimension() == 0 && node->min() == leaf_loc) { return *node; } if (node->is_empty()) { node_to_initialize = node; //LOG << "Type 1 " << std::hex << size_t(node_to_initialize) << std::dec << "\n"; } else { // That child's location was too specific (wrong) for us. sub_nodes_type* intermediate_nodes = node_allocator().allocate(1); if (!intermediate_nodes) { throw std::bad_alloc(); } try { // nothrow except monoids new (intermediate_nodes) sub_nodes_type(); for (node_type& intermediate_node : *intermediate_nodes) { intermediate_node.set_parent(node); assert(intermediate_node.size_exponent_in_each_dimension() == 0); } } catch(...) { node_allocator().deallocate(intermediate_nodes, 1); throw; } num_bits_type shared_size_exponent; node_type* new_location_for_node_original_contents; node_type* new_leaf_ptr_node; try { // loop is nothrow shared_size_exponent = 0; for (num_coordinates_type dim = 0; dim != dimensions; ++dim) { const num_bits_type dim_shared_size_exponent = num_bits_in_integer_that_are_not_leading_zeroes( to_unsigned_type(node->min()[dim] ^ leaf_loc[dim])); if(shared_size_exponent < dim_shared_size_exponent) { shared_size_exponent = dim_shared_size_exponent; } } // assert is typically nothrow, and it's also okay // if it throws here. assert(shared_size_exponent > 0); //LOG << "~~" << shared_size_exponent << std::endl; // move node's contents to its new location new_location_for_node_original_contents = // nothrow &child_matching(*intermediate_nodes, shared_size_exponent, node->min()); new_leaf_ptr_node = // nothrow &child_matching(*intermediate_nodes, shared_size_exponent, leaf_loc); assert(new_location_for_node_original_contents != new_leaf_ptr_node); // Monoid ops may throw. Do the copy before anything else so that if // it throws, we won't be in a partial state and have destructors // mess things up. new_location_for_node_original_contents->set_monoid(node->monoid()); new_location_for_node_original_contents->set_min(node->min()); new_location_for_node_original_contents->set_size_exponent_in_each_dimension(node->size_exponent_in_each_dimension()); new_location_for_node_original_contents->set_stable_node_reference_keeper(node->stable_node_reference_keeper()); // Compute shared coords here in case some Coord ops can throw. loc_type shared_loc_min; const Coord mask = safer_n_low_zero_bits<Coord>(shared_size_exponent); for (num_coordinates_type dim = 0; dim != dimensions; ++dim) { shared_loc_min[dim] = node->min()[dim] & mask; } // If Coord move throws, we're in trouble, because we're moving // an array of them so some of node's coords could be overwritten // already and we have no reliable way to restore them without // nothrow move. This is why we require nothrow Coord move. // // Nevertheless do this inside the try/catch so we at least // don't leak memory if it throws. node->set_min(::move(shared_loc_min)); } catch(...) { intermediate_nodes->~sub_nodes_type(); node_allocator().deallocate(intermediate_nodes, 1); throw; } // continue moving node's contents to its new location // nothrow new_location_for_node_original_contents->set_sub_nodes(node->sub_nodes()); new_location_for_node_original_contents->set_leaf(node->move_leaf()); if(sub_nodes_type* original_sub_nodes = new_location_for_node_original_contents->sub_nodes()) { for (node_type& sub_node : *original_sub_nodes) { sub_node.set_parent(new_location_for_node_original_contents); } } node->set_size_exponent_in_each_dimension(shared_size_exponent); node->set_leaf(); node->set_sub_nodes(intermediate_nodes); node->set_stable_node_reference_keeper(); //node->parent remains the same //node->monoid remains the same (it will be updated later as one of the parents) // nothrow node_to_initialize = new_leaf_ptr_node; //LOG << "Type 2 " << std::hex << size_t(node_to_initialize) << std::dec << "\n"; } assert(!node_to_initialize->sub_nodes()); node_to_initialize->set_min(::move(leaf_loc)); return *node_to_initialize; }