Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cleanup handle_collision() and key comparison functions #97

Merged
merged 3 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Added B+tree multimap for internal (future) use. [#93](https://github.com/tzaeschke/phtree-cpp/issues/93)

### Changed
- Cleaned up HandleCollision() and key comparison functions. [#97](https://github.com/tzaeschke/phtree-cpp/pull/97)
- Improved performance by eliminating memory indirection for DIM > 3.
This was enabled by referencing "Node" directly in "Entry" which was enabled by
implanting an indirection in array_map. [#96](https://github.com/tzaeschke/phtree-cpp/pull/96)
Expand Down
16 changes: 8 additions & 8 deletions include/phtree/common/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,23 +94,23 @@ template <dimension_t DIM, typename SCALAR>
static bit_width_t NumberOfDivergingBits(
const PhPoint<DIM, SCALAR>& v1, const PhPoint<DIM, SCALAR>& v2) {
// write all differences to diff, we just check diff afterwards
bit_mask_t<SCALAR> diff = 0;
SCALAR diff = 0;
for (dimension_t i = 0; i < DIM; ++i) {
diff |= (v1[i] ^ v2[i]);
}
assert(CountLeadingZeros(diff) <= MAX_BIT_WIDTH<SCALAR>);
return MAX_BIT_WIDTH<SCALAR> - CountLeadingZeros(diff);
auto diff2 = reinterpret_cast<bit_mask_t<SCALAR>&>(diff);
assert(CountLeadingZeros(diff2) <= MAX_BIT_WIDTH<SCALAR>);
return MAX_BIT_WIDTH<SCALAR> - CountLeadingZeros(diff2);
}

template <dimension_t DIM, typename SCALAR>
static bool KeyEquals(
const PhPoint<DIM, SCALAR>& key_a, const PhPoint<DIM, SCALAR>& key_b, bit_mask_t<SCALAR> mask) {
const PhPoint<DIM, SCALAR>& key_a, const PhPoint<DIM, SCALAR>& key_b, bit_width_t ignore_bits) {
SCALAR diff{0};
for (dimension_t i = 0; i < DIM; ++i) {
if (((key_a[i] ^ key_b[i]) & mask) != 0) {
return false;
}
diff |= key_a[i] ^ key_b[i];
}
return true;
return diff >> ignore_bits == 0;
}

// ************************************************************************
Expand Down
43 changes: 17 additions & 26 deletions include/phtree/v16/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,37 +301,29 @@ class Node {
*/
template <typename... Args>
auto& HandleCollision(
EntryT& existing_entry,
EntryT& entry,
bool& is_inserted,
const KeyT& new_key,
bit_width_t current_postfix_len,
Args&&... args) {
assert(!is_inserted);
// We have two entries in the same location (local pos).
// Now we need to compare the keys.
// If they are identical, we simply return the entry for further traversal.
if (existing_entry.IsNode()) {
if (existing_entry.HasNodeInfix(current_postfix_len)) {
bit_width_t max_conflicting_bits =
NumberOfDivergingBits(new_key, existing_entry.GetKey());
if (max_conflicting_bits > existing_entry.GetNodePostfixLen() + 1) {
is_inserted = true;
return InsertSplit(
existing_entry, new_key, max_conflicting_bits, std::forward<Args>(args)...);
}
}
// No infix conflict, just traverse subnode
} else {
bit_width_t max_conflicting_bits =
NumberOfDivergingBits(new_key, existing_entry.GetKey());
if (max_conflicting_bits > 0) {
is_inserted = true;
return InsertSplit(
existing_entry, new_key, max_conflicting_bits, std::forward<Args>(args)...);
}
// Now we need to compare the keys, respectively the prefix of the subnode.
// If they match, we return the entry for further traversal.
bool is_node = entry.IsNode();
if (is_node && !entry.HasNodeInfix(current_postfix_len)) {
// No infix conflict (because infix has length=0), just traverse subnode
return entry;
}

bit_width_t max_conflicting_bits = NumberOfDivergingBits(new_key, entry.GetKey());
auto split_len = is_node ? entry.GetNodePostfixLen() + 1 : 0;
if (max_conflicting_bits <= split_len) {
// perfect match -> return existing
return entry;
}
return existing_entry;

is_inserted = true;
return InsertSplit(entry, new_key, max_conflicting_bits, std::forward<Args>(args)...);
}

template <typename... Args>
Expand Down Expand Up @@ -366,8 +358,7 @@ class Node {
const EntryT& entry, const KeyT& key, const bit_width_t parent_postfix_len) const {
if (entry.IsNode()) {
if (entry.HasNodeInfix(parent_postfix_len)) {
const bit_mask_t<SCALAR> mask = MAX_MASK<SCALAR> << (entry.GetNodePostfixLen() + 1);
return KeyEquals(entry.GetKey(), key, mask);
return KeyEquals(entry.GetKey(), key, entry.GetNodePostfixLen() + 1);
}
return true;
}
Expand Down