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 <type_traits>
19
20#ifdef _MSC_VER
21#include <intrin.h> // for _BitScan*
22#endif
23
24namespace ROOT {
25namespace Internal {
26
27/// Return true if \p align is a valid C++ alignment value: strictly positive
28/// and a power of two. This is the set of values accepted by
29/// `::operator new[](n, std::align_val_t(align))`.
30inline constexpr bool IsValidAlignment(std::size_t align) noexcept
31{
32 return align > 0 && (align & (align - 1)) == 0;
33}
34
35/// Round \p value up to the next multiple of \p align.
36/// \p align must be a power of two (asserted at runtime in debug builds).
37template <typename T>
38inline constexpr T AlignUp(T value, T align) noexcept
39{
40 assert(IsValidAlignment(static_cast<std::size_t>(align))); // must be a power of two
41 return (value + align - 1) & ~(align - 1);
42}
43
44/// Given an integer `x`, returns the number of leading 0-bits starting at the most significant bit position.
45/// If `x` is 0, it returns the size of `x` in bits.
46///
47/// Example:
48///
49/// if x is a std::uint32_t with value 42 (0b0...0101010), then LeadingZeroes(x) == 26
50template <typename T>
51inline std::size_t LeadingZeroes(T x)
52{
53 constexpr std::size_t maxBits = sizeof(T) * 8;
54 static_assert(std::is_integral_v<T> && (maxBits == 32 || maxBits == 64));
55
56 if (x == 0)
57 return maxBits;
58
59#ifdef _MSC_VER
60 unsigned long idx = 0;
61 [[maybe_unused]] unsigned char nonZero;
62 if constexpr (maxBits == 32) {
63 nonZero = _BitScanReverse(&idx, x);
64 } else {
65#ifdef _WIN64
66 // 64-bit machine
68#else
69 // 32-bit machine
70 std::uint32_t low = (x & 0xFFFF'FFFF);
71 std::uint32_t high = (x >> 32) & 0xFFFF'FFFF;
72 unsigned long lowIdx, highIdx;
73 unsigned char lowNonZero = _BitScanReverse(&lowIdx, low);
74 unsigned char highNonZero = _BitScanReverse(&highIdx, high);
76 if (high == 0)
77 idx = 63 - lowIdx;
78 else
79 idx = 31 - highIdx;
80 return static_cast<std::size_t>(idx);
81
82#endif // _WIN64
83 }
84
86 // NOTE: _BitScanReverse return the 0-based index of the leftmost non-zero bit.
87 // To convert it to the number of zeroes we need to "flip" it from [0, maxBits) to [maxBits, 0)
88 // (e.g. _BitScanReverse == 0 <=> LeadingZeroes == maxBits)
89 return static_cast<std::size_t>(maxBits - 1 - idx);
90#else
91 if constexpr (maxBits == 32) {
92 return static_cast<std::size_t>(__builtin_clz(x));
93 } else {
94 return static_cast<std::size_t>(__builtin_clzl(x));
95 }
96#endif // _MSC_VER
97}
98
99/// Given an integer `x`, returns the number of trailing 0-bits starting at the least significant bit position.
100/// If `x` is 0, it returns the size of `x` in bits.
101///
102/// Example:
103///
104/// if x is a std::uint32_t with value 42 (0b0...0101010), then TrailingZeroes(x) == 1
105template <typename T>
106inline std::size_t TrailingZeroes(T x)
107{
108 constexpr std::size_t maxBits = sizeof(T) * 8;
109 static_assert(std::is_integral_v<T> && (maxBits == 32 || maxBits == 64));
110
111 if (x == 0)
112 return maxBits;
113
114#ifdef _MSC_VER
115 unsigned long idx = 0;
116 [[maybe_unused]] unsigned char nonZero;
117 if constexpr (maxBits == 32) {
118 nonZero = _BitScanForward(&idx, x);
119 } else {
120#ifdef _WIN64
121 // 64-bit machine
122 nonZero = _BitScanForward64(&idx, x);
123#else
124 // 32-bit machine
125 std::uint32_t low = (x & 0xFFFF'FFFF);
126 std::uint32_t high = (x >> 32) & 0xFFFF'FFFF;
127 unsigned long lowIdx, highIdx;
128 unsigned char lowNonZero = _BitScanForward(&lowIdx, low);
129 unsigned char highNonZero = _BitScanForward(&highIdx, high);
131 if (low == 0)
132 idx = highIdx + 32;
133 else
134 idx = lowIdx;
135
136#endif // _WIN64
137 }
139 // Differently from LeadingZeroes, in this case the bit index returned by _BitScanForward is
140 // already equivalent to the number of trailing zeroes, so we don't need any transformation.
141 return static_cast<std::size_t>(idx);
142#else
143 if constexpr (maxBits == 32) {
144 return static_cast<std::size_t>(__builtin_ctz(x));
145 } else {
146 return static_cast<std::size_t>(__builtin_ctzl(x));
147 }
148#endif // _MSC_VER
149 }
150
151} // namespace Internal
152} // namespace ROOT
153
154#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 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:51
constexpr T AlignUp(T value, T align) noexcept
Round value up to the next multiple of align.
Definition BitUtils.hxx:38
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:106
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:30