Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
BitUtils.hxx
Go to the documentation of this file.
1// @(#)root/foundation:
2// Author: Philippe Canal, April 2026
3
4/*************************************************************************
5 * Copyright (C) 1995-2026, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#ifndef ROOT_BitUtils
13#define ROOT_BitUtils
14
15#include <algorithm>
16#include <cassert>
17#include <cstddef>
18#include <cstdint>
19#include <type_traits>
20
21#ifdef _MSC_VER
22#include <intrin.h> // for _BitScan*
23#endif
24
25namespace ROOT {
26namespace Internal {
27
28inline bool IsPowerOfTwo(std::uint64_t v)
29{
30 return (v & (v - 1)) == 0;
31}
32
33/// Return true if \p align is a valid C++ alignment value: strictly positive
34/// and a power of two. This is the set of values accepted by
35/// `::operator new[](n, std::align_val_t(align))`.
36inline constexpr bool IsValidAlignment(std::size_t align) noexcept
37{
38 return align > 0 && IsPowerOfTwo(align);
39}
40
41/// Round \p value up to the next multiple of \p align.
42/// \p align must be a power of two (asserted at runtime in debug builds).
43template <typename T>
44inline constexpr T AlignUp(T value, T align) noexcept
45{
46 assert(IsValidAlignment(static_cast<std::size_t>(align))); // must be a power of two
47 return (value + align - 1) & ~(align - 1);
48}
49
50/// Storage type whose alignment matches \a AlignT bytes.
51/// Used to instantiate std::vector specializations with guaranteed buffer alignment.
52template <std::size_t AlignT>
56
57/// Given an integer `x`, returns the number of leading 0-bits starting at the most significant bit position.
58/// If `x` is 0, it returns the size of `x` in bits.
59///
60/// Example:
61///
62/// if x is a std::uint32_t with value 42 (0b0...0101010), then LeadingZeroes(x) == 26
63template <typename T>
64inline std::size_t LeadingZeroes(T x)
65{
66 constexpr std::size_t maxBits = sizeof(T) * 8;
67 static_assert(std::is_integral_v<T> && (maxBits == 32 || maxBits == 64));
68
69 if (x == 0)
70 return maxBits;
71
72#ifdef _MSC_VER
73 unsigned long idx = 0;
74 [[maybe_unused]] unsigned char nonZero;
75 if constexpr (maxBits == 32) {
76 nonZero = _BitScanReverse(&idx, x);
77 } else {
78#ifdef _WIN64
79 // 64-bit machine
81#else
82 // 32-bit machine
83 std::uint32_t low = (x & 0xFFFF'FFFF);
84 std::uint32_t high = (x >> 32) & 0xFFFF'FFFF;
85 unsigned long lowIdx, highIdx;
86 unsigned char lowNonZero = _BitScanReverse(&lowIdx, low);
87 unsigned char highNonZero = _BitScanReverse(&highIdx, high);
89 if (high == 0)
90 idx = 63 - lowIdx;
91 else
92 idx = 31 - highIdx;
93 return static_cast<std::size_t>(idx);
94
95#endif // _WIN64
96 }
97
99 // NOTE: _BitScanReverse return the 0-based index of the leftmost non-zero bit.
100 // To convert it to the number of zeroes we need to "flip" it from [0, maxBits) to [maxBits, 0)
101 // (e.g. _BitScanReverse == 0 <=> LeadingZeroes == maxBits)
102 return static_cast<std::size_t>(maxBits - 1 - idx);
103#else
104 if constexpr (maxBits == 32) {
105 return static_cast<std::size_t>(__builtin_clz(x));
106 } else {
107 return static_cast<std::size_t>(__builtin_clzl(x));
108 }
109#endif // _MSC_VER
110}
111
112/// Given an integer `x`, returns the number of trailing 0-bits starting at the least significant bit position.
113/// If `x` is 0, it returns the size of `x` in bits.
114///
115/// Example:
116///
117/// if x is a std::uint32_t with value 42 (0b0...0101010), then TrailingZeroes(x) == 1
118template <typename T>
119inline std::size_t TrailingZeroes(T x)
120{
121 constexpr std::size_t maxBits = sizeof(T) * 8;
122 static_assert(std::is_integral_v<T> && (maxBits == 32 || maxBits == 64));
123
124 if (x == 0)
125 return maxBits;
126
127#ifdef _MSC_VER
128 unsigned long idx = 0;
129 [[maybe_unused]] unsigned char nonZero;
130 if constexpr (maxBits == 32) {
131 nonZero = _BitScanForward(&idx, x);
132 } else {
133#ifdef _WIN64
134 // 64-bit machine
135 nonZero = _BitScanForward64(&idx, x);
136#else
137 // 32-bit machine
138 std::uint32_t low = (x & 0xFFFF'FFFF);
139 std::uint32_t high = (x >> 32) & 0xFFFF'FFFF;
140 unsigned long lowIdx, highIdx;
141 unsigned char lowNonZero = _BitScanForward(&lowIdx, low);
142 unsigned char highNonZero = _BitScanForward(&highIdx, high);
144 if (low == 0)
145 idx = highIdx + 32;
146 else
147 idx = lowIdx;
148
149#endif // _WIN64
150 }
152 // Differently from LeadingZeroes, in this case the bit index returned by _BitScanForward is
153 // already equivalent to the number of trailing zeroes, so we don't need any transformation.
154 return static_cast<std::size_t>(idx);
155#else
156 if constexpr (maxBits == 32) {
157 return static_cast<std::size_t>(__builtin_ctz(x));
158 } else {
159 return static_cast<std::size_t>(__builtin_ctzl(x));
160 }
161#endif // _MSC_VER
162 }
163
164} // namespace Internal
165} // namespace ROOT
166
167#endif // ROOT_BitUtils
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Double_t x[n]
Definition legend1.C:17
std::size_t LeadingZeroes(T x)
Given an integer x, returns the number of leading 0-bits starting at the most significant bit positio...
Definition BitUtils.hxx:64
bool IsPowerOfTwo(std::uint64_t v)
Definition BitUtils.hxx:28
constexpr T AlignUp(T value, T align) noexcept
Round value up to the next multiple of align.
Definition BitUtils.hxx:44
std::size_t TrailingZeroes(T x)
Given an integer x, returns the number of trailing 0-bits starting at the least significant bit posit...
Definition BitUtils.hxx:119
constexpr bool IsValidAlignment(std::size_t align) noexcept
Return true if align is a valid C++ alignment value: strictly positive and a power of two.
Definition BitUtils.hxx:36
Storage type whose alignment matches AlignT bytes.
Definition BitUtils.hxx:53