Coverage Report

Created: 2025-12-11 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/immer/immer/detail/hamts/bits.hpp
Line
Count
Source
1
//
2
// immer: immutable data structures for C++
3
// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
4
//
5
// This software is distributed under the Boost Software License, Version 1.0.
6
// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
7
//
8
9
#pragma once
10
11
#include <cstddef>
12
#include <cstdint>
13
14
#if defined(_MSC_VER)
15
#include <intrin.h> // __popcnt
16
#endif
17
18
namespace immer {
19
namespace detail {
20
namespace hamts {
21
22
using size_t  = std::size_t;
23
using bits_t  = std::uint32_t;
24
using count_t = std::uint32_t;
25
using shift_t = std::uint32_t;
26
27
template <bits_t B>
28
struct get_bitmap_type
29
{
30
    static_assert(B < 6u, "B > 6 is not supported.");
31
    using type = std::uint8_t;
32
};
33
34
template <>
35
struct get_bitmap_type<6u>
36
{
37
    using type = std::uint64_t;
38
};
39
40
template <>
41
struct get_bitmap_type<5u>
42
{
43
    using type = std::uint32_t;
44
};
45
46
template <>
47
struct get_bitmap_type<4u>
48
{
49
    using type = std::uint16_t;
50
};
51
52
template <bits_t B, typename T = count_t>
53
constexpr T branches = T{1u} << B;
54
55
template <typename T, bits_t B>
56
constexpr T mask = branches<B, T> - 1u;
57
58
template <typename hash_t, bits_t B, typename T = count_t>
59
constexpr T max_depth = (sizeof(hash_t) * 8u + B - 1u) / B;
60
61
template <typename hash_t, bits_t B, typename T = count_t>
62
constexpr T max_shift = max_depth<hash_t, B, count_t> * B;
63
64
#define IMMER_HAS_BUILTIN_POPCOUNT 1
65
66
inline auto popcount_fallback(std::uint32_t x)
67
0
{
68
0
    // More alternatives:
69
0
    // https://en.wikipedia.org/wiki/Hamming_weight
70
0
    // http://wm.ite.pl/articles/sse-popcount.html
71
0
    // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
72
0
    x = x - ((x >> 1) & 0x55555555u);
73
0
    x = (x & 0x33333333u) + ((x >> 2) & 0x33333333u);
74
0
    return (((x + (x >> 4u)) & 0xF0F0F0Fu) * 0x1010101u) >> 24u;
75
0
}
76
77
inline auto popcount_fallback(std::uint64_t x)
78
0
{
79
0
    x = x - ((x >> 1) & 0x5555555555555555u);
80
0
    x = (x & 0x3333333333333333u) + ((x >> 2u) & 0x3333333333333333u);
81
0
    return (((x + (x >> 4)) & 0x0F0F0F0F0F0F0F0Fu) * 0x0101010101010101u) >>
82
0
           56u;
83
0
}
84
85
inline count_t popcount(std::uint32_t x)
86
5.71M
{
87
5.71M
#if IMMER_HAS_BUILTIN_POPCOUNT
88
#if defined(_MSC_VER)
89
    return __popcnt(x);
90
#else
91
5.71M
    return __builtin_popcount(x);
92
5.71M
#endif
93
#else
94
    return popcount_fallback(x);
95
#endif
96
5.71M
}
97
98
inline count_t popcount(std::uint64_t x)
99
0
{
100
0
#if IMMER_HAS_BUILTIN_POPCOUNT
101
0
#if defined(_MSC_VER)
102
0
#if defined(_WIN64)
103
0
    return static_cast<count_t>(__popcnt64(x));
104
0
#else
105
0
    // TODO: benchmark against popcount_fallback(std::uint64_t x)
106
0
    return popcount(static_cast<std::uint32_t>(x >> 32)) +
107
0
           popcount(static_cast<std::uint32_t>(x));
108
0
#endif
109
0
#else
110
0
    return __builtin_popcountll(x);
111
0
#endif
112
0
#else
113
0
    return popcount_fallback(x);
114
0
#endif
115
0
}
116
117
inline count_t popcount(std::uint16_t x)
118
0
{
119
0
    return popcount(static_cast<std::uint32_t>(x));
120
0
}
121
122
inline count_t popcount(std::uint8_t x)
123
0
{
124
0
    return popcount(static_cast<std::uint32_t>(x));
125
0
}
126
127
template <typename bitmap_t>
128
class set_bits_range
129
{
130
    bitmap_t bitmap;
131
132
    class set_bits_iterator
133
    {
134
        bitmap_t bitmap;
135
136
        inline static bitmap_t clearlsbit(bitmap_t bitmap)
137
919k
        {
138
919k
            return bitmap & (bitmap - 1);
139
919k
        }
140
141
        inline static bitmap_t lsbit(bitmap_t bitmap)
142
459k
        {
143
459k
            return bitmap ^ clearlsbit(bitmap);
144
459k
        }
145
146
    public:
147
        set_bits_iterator(bitmap_t bitmap)
148
484k
            : bitmap(bitmap){};
149
150
        set_bits_iterator operator++()
151
459k
        {
152
459k
            bitmap = clearlsbit(bitmap);
153
459k
            return *this;
154
459k
        }
155
156
        bool operator!=(set_bits_iterator const& other) const
157
702k
        {
158
702k
            return bitmap != other.bitmap;
159
702k
        }
160
161
459k
        bitmap_t operator*() const { return lsbit(bitmap); }
162
    };
163
164
public:
165
    set_bits_range(bitmap_t bitmap)
166
242k
        : bitmap(bitmap)
167
242k
    {
168
242k
    }
169
242k
    set_bits_iterator begin() const { return set_bits_iterator(bitmap); }
170
242k
    set_bits_iterator end() const { return set_bits_iterator(0); }
171
};
172
173
} // namespace hamts
174
} // namespace detail
175
} // namespace immer