Skip to content

Commit

Permalink
Add support for c++20 likely/unlikely attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
duckdoom5 authored Dec 8, 2024
1 parent 73f3cbb commit 1ead665
Showing 1 changed file with 31 additions and 18 deletions.
49 changes: 31 additions & 18 deletions include/ankerl/unordered_dense.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,23 @@
# pragma intrinsic(_umul128)
# endif

# if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)
# define ANKERL_UNORDERED_DENSE_LIKELY(x) __builtin_expect(x, 1) // NOLINT(cppcoreguidelines-macro-usage)
# define ANKERL_UNORDERED_DENSE_UNLIKELY(x) __builtin_expect(x, 0) // NOLINT(cppcoreguidelines-macro-usage)
# if __has_cpp_attribute(likely) && __has_cpp_attribute(unlikely)
# define ANKERL_UNORDERED_DENSE_LIKELY_ATTR [[likely]] // NOLINT(cppcoreguidelines-macro-usage)
# define ANKERL_UNORDERED_DENSE_UNLIKELY_ATTR [[unlikely]] // NOLINT(cppcoreguidelines-macro-usage)
# define ANKERL_UNORDERED_DENSE_LIKELY(x) (x) // NOLINT(cppcoreguidelines-macro-usage)
# define ANKERL_UNORDERED_DENSE_UNLIKELY(x) (x) // NOLINT(cppcoreguidelines-macro-usage)
# else
# define ANKERL_UNORDERED_DENSE_LIKELY(x) (x) // NOLINT(cppcoreguidelines-macro-usage)
# define ANKERL_UNORDERED_DENSE_UNLIKELY(x) (x) // NOLINT(cppcoreguidelines-macro-usage)
# define ANKERL_UNORDERED_DENSE_LIKELY_ATTR // NOLINT(cppcoreguidelines-macro-usage)
# define ANKERL_UNORDERED_DENSE_UNLIKELY_ATTR // NOLINT(cppcoreguidelines-macro-usage)

# if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)
# define ANKERL_UNORDERED_DENSE_LIKELY(x) __builtin_expect(x, 1) // NOLINT(cppcoreguidelines-macro-usage)
# define ANKERL_UNORDERED_DENSE_UNLIKELY(x) __builtin_expect(x, 0) // NOLINT(cppcoreguidelines-macro-usage)
# else
# define ANKERL_UNORDERED_DENSE_LIKELY(x) (x) // NOLINT(cppcoreguidelines-macro-usage)
# define ANKERL_UNORDERED_DENSE_UNLIKELY(x) (x) // NOLINT(cppcoreguidelines-macro-usage)
# endif

# endif

namespace ankerl::unordered_dense {
Expand Down Expand Up @@ -226,11 +237,11 @@ inline void mum(uint64_t* a, uint64_t* b) {
uint64_t seed = secret[0];
uint64_t a{};
uint64_t b{};
if (ANKERL_UNORDERED_DENSE_LIKELY(len <= 16)) {
if (ANKERL_UNORDERED_DENSE_LIKELY(len >= 4)) {
if (ANKERL_UNORDERED_DENSE_LIKELY(len <= 16)) ANKERL_UNORDERED_DENSE_LIKELY_ATTR {
if (ANKERL_UNORDERED_DENSE_LIKELY(len >= 4)) ANKERL_UNORDERED_DENSE_LIKELY_ATTR {
a = (r4(p) << 32U) | r4(p + ((len >> 3U) << 2U));
b = (r4(p + len - 4) << 32U) | r4(p + len - 4 - ((len >> 3U) << 2U));
} else if (ANKERL_UNORDERED_DENSE_LIKELY(len > 0)) {
} else if (ANKERL_UNORDERED_DENSE_LIKELY(len > 0)) ANKERL_UNORDERED_DENSE_LIKELY_ATTR {
a = r3(p, len);
b = 0;
} else {
Expand All @@ -239,7 +250,7 @@ inline void mum(uint64_t* a, uint64_t* b) {
}
} else {
size_t i = len;
if (ANKERL_UNORDERED_DENSE_UNLIKELY(i > 48)) {
if (ANKERL_UNORDERED_DENSE_UNLIKELY(i > 48)) ANKERL_UNORDERED_DENSE_UNLIKELY_ATTR {
uint64_t see1 = seed;
uint64_t see2 = seed;
do {
Expand All @@ -251,7 +262,7 @@ inline void mum(uint64_t* a, uint64_t* b) {
} while (ANKERL_UNORDERED_DENSE_LIKELY(i > 48));
seed ^= see1 ^ see2;
}
while (ANKERL_UNORDERED_DENSE_UNLIKELY(i > 16)) {
while (ANKERL_UNORDERED_DENSE_UNLIKELY(i > 16)) ANKERL_UNORDERED_DENSE_UNLIKELY_ATTR {
seed = mix(r8(p) ^ secret[1], r8(p + 8) ^ seed);
i -= 16;
p += 16;
Expand Down Expand Up @@ -869,9 +880,11 @@ class table : public std::conditional_t<is_map_v<T>, base_table_type_map<T>, bas
uint8_t m_shifts = initial_shifts;

[[nodiscard]] auto next(value_idx_type bucket_idx) const -> value_idx_type {
return ANKERL_UNORDERED_DENSE_UNLIKELY(bucket_idx + 1U == bucket_count())
? 0
: static_cast<value_idx_type>(bucket_idx + 1U);
if (ANKERL_UNORDERED_DENSE_UNLIKELY(bucket_idx + 1U == bucket_count())) ANKERL_UNORDERED_DENSE_UNLIKELY_ATTR {
return 0;
}

return static_cast<value_idx_type>(bucket_idx + 1U);
}

// Helper to access bucket through pointer types
Expand Down Expand Up @@ -1120,7 +1133,7 @@ class table : public std::conditional_t<is_map_v<T>, base_table_type_map<T>, bas
m_values.emplace_back(std::forward<Args>(args)...);

auto value_idx = static_cast<value_idx_type>(m_values.size() - 1);
if (ANKERL_UNORDERED_DENSE_UNLIKELY(is_full())) {
if (ANKERL_UNORDERED_DENSE_UNLIKELY(is_full())) ANKERL_UNORDERED_DENSE_UNLIKELY_ATTR {
increase_size();
} else {
place_and_shift_up({dist_and_fingerprint, value_idx}, bucket_idx);
Expand Down Expand Up @@ -1156,7 +1169,7 @@ class table : public std::conditional_t<is_map_v<T>, base_table_type_map<T>, bas

template <typename K>
auto do_find(K const& key) -> iterator {
if (ANKERL_UNORDERED_DENSE_UNLIKELY(empty())) {
if (ANKERL_UNORDERED_DENSE_UNLIKELY(empty())) ANKERL_UNORDERED_DENSE_UNLIKELY_ATTR {
return end();
}

Expand Down Expand Up @@ -1201,7 +1214,7 @@ class table : public std::conditional_t<is_map_v<T>, base_table_type_map<T>, bas

template <typename K, typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
auto do_at(K const& key) -> Q& {
if (auto it = find(key); ANKERL_UNORDERED_DENSE_LIKELY(end() != it)) {
if (auto it = find(key); ANKERL_UNORDERED_DENSE_LIKELY(end() != it)) ANKERL_UNORDERED_DENSE_LIKELY_ATTR {
return it->second;
}
on_error_key_not_found();
Expand Down Expand Up @@ -1453,7 +1466,7 @@ class table : public std::conditional_t<is_map_v<T>, base_table_type_map<T>, bas
// nonstandard API:
// Discards the internally held container and replaces it with the one passed. Erases non-unique elements.
auto replace(value_container_type&& container) {
if (ANKERL_UNORDERED_DENSE_UNLIKELY(container.size() > max_size())) {
if (ANKERL_UNORDERED_DENSE_UNLIKELY(container.size() > max_size())) ANKERL_UNORDERED_DENSE_UNLIKELY_ATTR {
on_error_too_many_elements();
}
auto shifts = calc_shifts_for_size(container.size());
Expand Down Expand Up @@ -1590,7 +1603,7 @@ class table : public std::conditional_t<is_map_v<T>, base_table_type_map<T>, bas

// value is new, place the bucket and shift up until we find an empty spot
auto value_idx = static_cast<value_idx_type>(m_values.size() - 1);
if (ANKERL_UNORDERED_DENSE_UNLIKELY(is_full())) {
if (ANKERL_UNORDERED_DENSE_UNLIKELY(is_full())) ANKERL_UNORDERED_DENSE_UNLIKELY_ATTR {
// increase_size just rehashes all the data we have in m_values
increase_size();
} else {
Expand Down

0 comments on commit 1ead665

Please sign in to comment.