/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 |