This is an automated email from the ASF dual-hosted git repository.

apitrou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new 2691103628 GH-48591: [C++] Remove some bit utils from bit_utils.h and 
replace them with C++ 20 built in functions (#49298)
2691103628 is described below

commit 269110362820185db3bf7aa78ba176d71cb00e75
Author: PaweÅ‚ Biegun <[email protected]>
AuthorDate: Wed Feb 18 00:54:17 2026 -0800

    GH-48591: [C++] Remove some bit utils from bit_utils.h and replace them 
with C++ 20 built in functions (#49298)
    
    ### Rationale for this change
    Before C++ 20 there was no built in implementation for many common bit 
operations utilities included in the stdlib so they were implemented in 
bit_utils.h. Now that they are included in the stdlib they should be removed 
from bit_utils to decrease the amount of code that needs to be maintained as 
described in #48591
    
    ### What changes are included in this PR?
    IsPowerOf2, PopCount, CountLeadingZeros, CountTrailingZeros, 
NumRequiredBits are removed from bit_utils and replaced with their equivalents 
from bit.h i.e. has_single_bit, popcount, countl_zero, countr_zero and 
bit_width.
    
    ### Are these changes tested?
    No new code is introduced and the stdlib implementation maintains parity 
with the replaced functions so no new unit tests are necessary.
    
    ### Are there any user-facing changes?
    No
    * GitHub Issue: #48591
    
    Lead-authored-by: PaweÅ‚ Biegun <[email protected]>
    Co-authored-by: Antoine Pitrou <[email protected]>
    Signed-off-by: Antoine Pitrou <[email protected]>
---
 cpp/src/arrow/acero/aggregate_benchmark.cc         |   3 +-
 cpp/src/arrow/acero/bloom_filter_test.cc           |   5 +-
 cpp/src/arrow/acero/swiss_join.cc                  |   5 +-
 .../compute/kernels/base_arithmetic_internal.h     |   4 +-
 cpp/src/arrow/compute/key_hash_internal.cc         |   5 +-
 cpp/src/arrow/compute/key_map_internal.cc          |  18 +--
 cpp/src/arrow/compute/row/row_internal.cc          |  10 +-
 cpp/src/arrow/compute/row/row_internal.h           |   8 +-
 cpp/src/arrow/compute/util.cc                      |   7 +-
 cpp/src/arrow/compute/util_avx2.cc                 |   5 +-
 cpp/src/arrow/testing/uniform_real.h               |   5 +-
 cpp/src/arrow/util/align_util.h                    |   3 +-
 cpp/src/arrow/util/basic_decimal.cc                |   9 +-
 cpp/src/arrow/util/bit_block_counter.h             |  28 ++--
 cpp/src/arrow/util/bit_run_reader.h                |  19 +--
 cpp/src/arrow/util/bit_util.h                      | 144 +--------------------
 cpp/src/arrow/util/bit_util_test.cc                |  69 ----------
 cpp/src/arrow/util/bitmap_ops.cc                   |  10 +-
 cpp/src/arrow/util/bitmap_reader_benchmark.cc      |   7 +-
 cpp/src/arrow/util/bitmap_writer.h                 |   3 +-
 cpp/src/arrow/util/rle_encoding_test.cc            |   3 +-
 cpp/src/gandiva/selection_vector.cc                |   3 +-
 cpp/src/parquet/chunker_internal.cc                |   4 +-
 cpp/src/parquet/encoder.cc                         |   5 +-
 cpp/src/parquet/level_conversion_inc.h             |   9 +-
 25 files changed, 101 insertions(+), 290 deletions(-)

diff --git a/cpp/src/arrow/acero/aggregate_benchmark.cc 
b/cpp/src/arrow/acero/aggregate_benchmark.cc
index 2e9cccd80d..171d19830a 100644
--- a/cpp/src/arrow/acero/aggregate_benchmark.cc
+++ b/cpp/src/arrow/acero/aggregate_benchmark.cc
@@ -17,6 +17,7 @@
 
 #include "benchmark/benchmark.h"
 
+#include <bit>
 #include <cassert>
 #include <cmath>
 #include <iostream>
@@ -269,7 +270,7 @@ struct SumBitmapVectorizeUnroll : public Summer<T> {
         local.total += SUM_SHIFT(5);
         local.total += SUM_SHIFT(6);
         local.total += SUM_SHIFT(7);
-        local.valid_count += bit_util::kBytePopcount[valid_byte];
+        local.valid_count += std::popcount(valid_byte);
       } else {
         // No nulls
         local.total += values[i + 0] + values[i + 1] + values[i + 2] + 
values[i + 3] +
diff --git a/cpp/src/arrow/acero/bloom_filter_test.cc 
b/cpp/src/arrow/acero/bloom_filter_test.cc
index 30cafd120c..62071cfcf1 100644
--- a/cpp/src/arrow/acero/bloom_filter_test.cc
+++ b/cpp/src/arrow/acero/bloom_filter_test.cc
@@ -18,6 +18,7 @@
 #include <gmock/gmock-matchers.h>
 
 #include <algorithm>
+#include <bit>
 #include <chrono>
 #include <condition_variable>
 #include <thread>
@@ -407,14 +408,14 @@ void TestBloomLarge(BloomFilterBuildStrategy strategy, 
int64_t num_build,
     uint64_t num_negatives = 0ULL;
     for (int iword = 0; iword < next_batch_size / 64; ++iword) {
       uint64_t word = reinterpret_cast<const 
uint64_t*>(result_bit_vector.data())[iword];
-      num_negatives += ARROW_POPCOUNT64(~word);
+      num_negatives += std::popcount(~word);
     }
     if (next_batch_size % 64 > 0) {
       uint64_t word = reinterpret_cast<const uint64_t*>(
           result_bit_vector.data())[next_batch_size / 64];
       uint64_t mask = (1ULL << (next_batch_size % 64)) - 1;
       word |= ~mask;
-      num_negatives += ARROW_POPCOUNT64(~word);
+      num_negatives += std::popcount(~word);
     }
     if (i < num_build) {
       num_negatives_build += num_negatives;
diff --git a/cpp/src/arrow/acero/swiss_join.cc 
b/cpp/src/arrow/acero/swiss_join.cc
index 97632e0ca0..9b2ebc33e1 100644
--- a/cpp/src/arrow/acero/swiss_join.cc
+++ b/cpp/src/arrow/acero/swiss_join.cc
@@ -17,6 +17,7 @@
 
 #include <sys/stat.h>
 #include <algorithm>  // std::upper_bound
+#include <bit>
 #include <cstdio>
 #include <cstdlib>
 #include <mutex>
@@ -666,7 +667,7 @@ void SwissTableMerge::MergePartition(SwissTable* target, 
const SwissTable* sourc
     // For each non-empty source slot...
     constexpr uint64_t kHighBitOfEachByte = 0x8080808080808080ULL;
     int num_full_slots = SwissTable::kSlotsPerBlock -
-                         static_cast<int>(ARROW_POPCOUNT64(block & 
kHighBitOfEachByte));
+                         static_cast<int>(std::popcount(block & 
kHighBitOfEachByte));
     for (int local_slot_id = 0; local_slot_id < num_full_slots; 
++local_slot_id) {
       // Read group id and hash for this slot.
       //
@@ -722,7 +723,7 @@ inline bool SwissTableMerge::InsertNewGroup(SwissTable* 
target, uint32_t group_i
     return false;
   }
   int local_slot_id = SwissTable::kSlotsPerBlock -
-                      static_cast<int>(ARROW_POPCOUNT64(block & 
kHighBitOfEachByte));
+                      static_cast<int>(std::popcount(block & 
kHighBitOfEachByte));
   uint32_t global_slot_id = SwissTable::global_slot_id(block_id, 
local_slot_id);
   target->insert_into_empty_slot(global_slot_id, hash, group_id);
   return true;
diff --git a/cpp/src/arrow/compute/kernels/base_arithmetic_internal.h 
b/cpp/src/arrow/compute/kernels/base_arithmetic_internal.h
index 960ba59892..b4840061ae 100644
--- a/cpp/src/arrow/compute/kernels/base_arithmetic_internal.h
+++ b/cpp/src/arrow/compute/kernels/base_arithmetic_internal.h
@@ -17,6 +17,7 @@
 
 #pragma once
 
+#include <bit>
 #include <limits>
 #include "arrow/compute/api_scalar.h"
 #include "arrow/compute/kernels/common_internal.h"
@@ -594,8 +595,7 @@ struct PowerChecked {
     }
     // left to right O(logn) power with overflow checks
     bool overflow = false;
-    uint64_t bitmask =
-        1ULL << (63 - bit_util::CountLeadingZeros(static_cast<uint64_t>(exp)));
+    uint64_t bitmask = 1ULL << (63 - 
std::countl_zero(static_cast<uint64_t>(exp)));
     T pow = 1;
     while (bitmask) {
       overflow |= MultiplyWithOverflow(pow, pow, &pow);
diff --git a/cpp/src/arrow/compute/key_hash_internal.cc 
b/cpp/src/arrow/compute/key_hash_internal.cc
index a0002efb3f..4608a742e1 100644
--- a/cpp/src/arrow/compute/key_hash_internal.cc
+++ b/cpp/src/arrow/compute/key_hash_internal.cc
@@ -20,6 +20,7 @@
 #include <memory.h>
 
 #include <algorithm>
+#include <bit>
 #include <cstdint>
 
 #include "arrow/compute/light_array_internal.h"
@@ -357,7 +358,7 @@ void Hashing32::HashInt(bool combine_hashes, uint32_t 
num_keys, uint64_t key_len
 void Hashing32::HashFixed(int64_t hardware_flags, bool combine_hashes, 
uint32_t num_keys,
                           uint64_t key_length, const uint8_t* keys, uint32_t* 
hashes,
                           uint32_t* temp_hashes_for_combine) {
-  if (ARROW_POPCOUNT64(key_length) == 1 && key_length <= sizeof(uint64_t)) {
+  if (std::popcount(key_length) == 1 && key_length <= sizeof(uint64_t)) {
     HashInt(combine_hashes, num_keys, key_length, keys, hashes);
     return;
   }
@@ -809,7 +810,7 @@ void Hashing64::HashInt(bool combine_hashes, uint32_t 
num_keys, uint64_t key_len
 
 void Hashing64::HashFixed(bool combine_hashes, uint32_t num_keys, uint64_t 
key_length,
                           const uint8_t* keys, uint64_t* hashes) {
-  if (ARROW_POPCOUNT64(key_length) == 1 && key_length <= sizeof(uint64_t)) {
+  if (std::popcount(key_length) == 1 && key_length <= sizeof(uint64_t)) {
     HashInt(combine_hashes, num_keys, key_length, keys, hashes);
     return;
   }
diff --git a/cpp/src/arrow/compute/key_map_internal.cc 
b/cpp/src/arrow/compute/key_map_internal.cc
index 4a2405e754..353449cf16 100644
--- a/cpp/src/arrow/compute/key_map_internal.cc
+++ b/cpp/src/arrow/compute/key_map_internal.cc
@@ -18,6 +18,7 @@
 #include "arrow/compute/key_map_internal.h"
 
 #include <algorithm>
+#include <bit>
 #include <cstdint>
 
 #include "arrow/util/bit_util.h"
@@ -27,7 +28,6 @@
 
 namespace arrow {
 
-using bit_util::CountLeadingZeros;
 using internal::CpuInfo;
 
 namespace compute {
@@ -91,7 +91,7 @@ inline void SwissTable::search_block(uint64_t block, int 
stamp, int start_slot,
   // Now if we or with the highest bits of the block and scan zero bits in 
reverse, we get
   // 8x slot index that we were looking for. This formula works in all three 
cases a), b)
   // and c).
-  *out_slot = static_cast<int>(CountLeadingZeros(matches | block_high_bits) >> 
3);
+  *out_slot = static_cast<int>(std::countl_zero(matches | block_high_bits) >> 
3);
 }
 
 template <typename T, bool use_selection>
@@ -204,8 +204,8 @@ void SwissTable::init_slot_ids_for_new_keys(uint32_t 
num_ids, const uint16_t* id
   int num_block_bytes = 
num_block_bytes_from_num_groupid_bits(num_groupid_bits);
   if (log_blocks_ == 0) {
     uint64_t block = *reinterpret_cast<const 
uint64_t*>(blocks_->mutable_data());
-    uint32_t empty_slot = static_cast<uint32_t>(
-        kSlotsPerBlock - ARROW_POPCOUNT64(block & kHighBitOfEachByte));
+    uint32_t empty_slot =
+        static_cast<uint32_t>(kSlotsPerBlock - std::popcount(block & 
kHighBitOfEachByte));
     for (uint32_t i = 0; i < num_ids; ++i) {
       int id = ids[i];
       slot_ids[id] = empty_slot;
@@ -224,7 +224,7 @@ void SwissTable::init_slot_ids_for_new_keys(uint32_t 
num_ids, const uint16_t* id
         }
         iblock = (iblock + 1) & ((1 << log_blocks_) - 1);
       }
-      uint32_t empty_slot = static_cast<int>(kSlotsPerBlock - 
ARROW_POPCOUNT64(block));
+      uint32_t empty_slot = static_cast<int>(kSlotsPerBlock - 
std::popcount(block));
       slot_ids[id] = global_slot_id(iblock, empty_slot);
     }
   }
@@ -684,7 +684,7 @@ Status SwissTable::grow_double() {
         mutable_block_data(blocks_new->mutable_data(), 2 * i, 
block_size_after);
     uint64_t block = *reinterpret_cast<const uint64_t*>(block_base);
 
-    uint32_t full_slots = CountLeadingZeros(block & kHighBitOfEachByte) >> 3;
+    uint32_t full_slots = std::countl_zero(block & kHighBitOfEachByte) >> 3;
     uint32_t full_slots_new[2];
     full_slots_new[0] = full_slots_new[1] = 0;
     util::SafeStore(double_block_base_new, kHighBitOfEachByte);
@@ -722,7 +722,7 @@ Status SwissTable::grow_double() {
     // How many full slots in this block
     const uint8_t* block_base = block_data(i, block_size_before);
     uint64_t block = util::SafeLoadAs<uint64_t>(block_base);
-    uint32_t full_slots = CountLeadingZeros(block & kHighBitOfEachByte) >> 3;
+    uint32_t full_slots = std::countl_zero(block & kHighBitOfEachByte) >> 3;
 
     for (uint32_t j = 0; j < full_slots; ++j) {
       uint32_t slot_id = global_slot_id(i, j);
@@ -741,13 +741,13 @@ Status SwissTable::grow_double() {
           mutable_block_data(blocks_new->mutable_data(), block_id_new, 
block_size_after);
       uint64_t block_new = util::SafeLoadAs<uint64_t>(block_base_new);
       int full_slots_new =
-          static_cast<int>(CountLeadingZeros(block_new & kHighBitOfEachByte) 
>> 3);
+          static_cast<int>(std::countl_zero(block_new & kHighBitOfEachByte) >> 
3);
       while (full_slots_new == kSlotsPerBlock) {
         block_id_new = (block_id_new + 1) & ((1 << log_blocks_after) - 1);
         block_base_new = blocks_new->mutable_data() + block_id_new * 
block_size_after;
         block_new = util::SafeLoadAs<uint64_t>(block_base_new);
         full_slots_new =
-            static_cast<int>(CountLeadingZeros(block_new & kHighBitOfEachByte) 
>> 3);
+            static_cast<int>(std::countl_zero(block_new & kHighBitOfEachByte) 
>> 3);
       }
 
       hashes_new[block_id_new * kSlotsPerBlock + full_slots_new] = hash;
diff --git a/cpp/src/arrow/compute/row/row_internal.cc 
b/cpp/src/arrow/compute/row/row_internal.cc
index 6af5458ea9..39d0bb0c63 100644
--- a/cpp/src/arrow/compute/row/row_internal.cc
+++ b/cpp/src/arrow/compute/row/row_internal.cc
@@ -17,6 +17,8 @@
 
 #include "arrow/compute/row/row_internal.h"
 
+#include <bit>
+
 #include "arrow/compute/util.h"
 #include "arrow/util/logging_internal.h"
 
@@ -89,9 +91,9 @@ void RowTableMetadata::FromColumnMetadataVector(
   std::sort(
       column_order.begin(), column_order.end(), [&cols](uint32_t left, 
uint32_t right) {
         bool is_left_pow2 =
-            !cols[left].is_fixed_length || 
ARROW_POPCOUNT64(cols[left].fixed_length) <= 1;
-        bool is_right_pow2 = !cols[right].is_fixed_length ||
-                             ARROW_POPCOUNT64(cols[right].fixed_length) <= 1;
+            !cols[left].is_fixed_length || 
std::popcount(cols[left].fixed_length) <= 1;
+        bool is_right_pow2 =
+            !cols[right].is_fixed_length || 
std::popcount(cols[right].fixed_length) <= 1;
         bool is_left_fixedlen = cols[left].is_fixed_length;
         bool is_right_fixedlen = cols[right].is_fixed_length;
         uint32_t width_left =
@@ -127,7 +129,7 @@ void RowTableMetadata::FromColumnMetadataVector(
   for (uint32_t i = 0; i < num_cols; ++i) {
     const KeyColumnMetadata& col = cols[column_order[i]];
     if (col.is_fixed_length && col.fixed_length != 0 &&
-        ARROW_POPCOUNT64(col.fixed_length) != 1) {
+        std::popcount(col.fixed_length) != 1) {
       offset_within_row += RowTableMetadata::padding_for_alignment_within_row(
           offset_within_row, string_alignment, col);
     }
diff --git a/cpp/src/arrow/compute/row/row_internal.h 
b/cpp/src/arrow/compute/row/row_internal.h
index 219fcbc51f..1c1ed5ca7c 100644
--- a/cpp/src/arrow/compute/row/row_internal.h
+++ b/cpp/src/arrow/compute/row/row_internal.h
@@ -16,6 +16,7 @@
 // under the License.
 #pragma once
 
+#include <bit>
 #include <cstdint>
 #include <vector>
 
@@ -85,7 +86,7 @@ struct ARROW_COMPUTE_EXPORT RowTableMetadata {
   /// Alignment must be a power of 2.
   static inline uint32_t padding_for_alignment_within_row(uint32_t offset,
                                                           int 
required_alignment) {
-    ARROW_DCHECK(ARROW_POPCOUNT64(required_alignment) == 1);
+    ARROW_DCHECK(std::popcount(static_cast<uint64_t>(required_alignment)) == 
1);
     return static_cast<uint32_t>((-static_cast<int32_t>(offset)) &
                                  (required_alignment - 1));
   }
@@ -94,8 +95,7 @@ struct ARROW_COMPUTE_EXPORT RowTableMetadata {
   /// choosing required alignment based on the data type of that column.
   static inline uint32_t padding_for_alignment_within_row(
       uint32_t offset, int string_alignment, const KeyColumnMetadata& 
col_metadata) {
-    if (!col_metadata.is_fixed_length ||
-        ARROW_POPCOUNT64(col_metadata.fixed_length) <= 1) {
+    if (!col_metadata.is_fixed_length || 
std::popcount(col_metadata.fixed_length) <= 1) {
       return 0;
     } else {
       return padding_for_alignment_within_row(offset, string_alignment);
@@ -106,7 +106,7 @@ struct ARROW_COMPUTE_EXPORT RowTableMetadata {
   /// Alignment must be a power of 2.
   static inline offset_type padding_for_alignment_row(offset_type row_offset,
                                                       int required_alignment) {
-    ARROW_DCHECK(ARROW_POPCOUNT64(required_alignment) == 1);
+    ARROW_DCHECK(std::popcount(static_cast<uint64_t>(required_alignment)) == 
1);
     return (-row_offset) & (required_alignment - 1);
   }
 
diff --git a/cpp/src/arrow/compute/util.cc b/cpp/src/arrow/compute/util.cc
index b90b3a6405..28bbfb7072 100644
--- a/cpp/src/arrow/compute/util.cc
+++ b/cpp/src/arrow/compute/util.cc
@@ -17,12 +17,13 @@
 
 #include "arrow/compute/util.h"
 
+#include <bit>
+
 #include "arrow/util/logging.h"
 #include "arrow/util/ubsan.h"
 
 namespace arrow {
 
-using bit_util::CountTrailingZeros;
 using internal::CpuInfo;
 
 namespace util {
@@ -65,7 +66,7 @@ inline void bits_to_indexes_helper(uint64_t word, uint16_t 
base_index, int* num_
                                    uint16_t* indexes) {
   int n = *num_indexes;
   while (word) {
-    indexes[n++] = base_index + 
static_cast<uint16_t>(CountTrailingZeros(word));
+    indexes[n++] = base_index + static_cast<uint16_t>(std::countr_zero(word));
     word &= word - 1;
   }
   *num_indexes = n;
@@ -75,7 +76,7 @@ inline void bits_filter_indexes_helper(uint64_t word, const 
uint16_t* input_inde
                                        int* num_indexes, uint16_t* indexes) {
   int n = *num_indexes;
   while (word) {
-    indexes[n++] = input_indexes[CountTrailingZeros(word)];
+    indexes[n++] = input_indexes[std::countr_zero(word)];
     word &= word - 1;
   }
   *num_indexes = n;
diff --git a/cpp/src/arrow/compute/util_avx2.cc 
b/cpp/src/arrow/compute/util_avx2.cc
index a554e0463f..9e1b7e4c0f 100644
--- a/cpp/src/arrow/compute/util_avx2.cc
+++ b/cpp/src/arrow/compute/util_avx2.cc
@@ -15,6 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
+#include <bit>
 #include <cstring>
 
 #include "arrow/compute/util.h"
@@ -54,7 +55,7 @@ void bits_to_indexes_imp_avx2(const int num_bits, const 
uint8_t* bits, int* num_
           _pext_u64(mask, _pdep_u64(word, kEachByteIs1) * 0xff) + base;
       *reinterpret_cast<uint64_t*>(byte_indexes + num_indexes_loop) = 
byte_indexes_next;
       base += incr;
-      num_indexes_loop += static_cast<int>(arrow::bit_util::PopCount(word & 
0xff));
+      num_indexes_loop += static_cast<int>(std::popcount(word & 0xff));
       word >>= 8;
     }
     // Unpack indexes to 16-bits and either add the base of i * 64 or shuffle 
input
@@ -144,7 +145,7 @@ void bits_filter_indexes_imp_avx2(const int num_bits, const 
uint8_t* bits,
                                                       
kByteSequence_0_8_1_9_2_10_3_11,
                                                       
kByteSequence_4_12_5_13_6_14_7_15));
       _mm256_storeu_si256((__m256i*)(indexes + num_indexes), output);
-      num_indexes += static_cast<int>(arrow::bit_util::PopCount(word & 
0xffff));
+      num_indexes += static_cast<int>(std::popcount(word & 0xffff));
       word >>= 16;
       ++loop_id;
     }
diff --git a/cpp/src/arrow/testing/uniform_real.h 
b/cpp/src/arrow/testing/uniform_real.h
index 8aa04a8328..4ad106188f 100644
--- a/cpp/src/arrow/testing/uniform_real.h
+++ b/cpp/src/arrow/testing/uniform_real.h
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include <bit>
 #include <limits>
 
 #include <arrow/util/bit_util.h>
@@ -39,8 +40,8 @@ namespace detail {
 template <typename RealType, typename Rng>
 RealType generate_canonical(Rng& rng) {
   const size_t b = std::numeric_limits<RealType>::digits;
-  const size_t log2R = 63 - ::arrow::bit_util::CountLeadingZeros(
-                                static_cast<uint64_t>(Rng::max() - Rng::min()) 
+ 1);
+  const size_t log2R =
+      63 - std::countl_zero(static_cast<uint64_t>(Rng::max() - Rng::min()) + 
1);
   const size_t k = b / log2R + (b % log2R != 0) + (b == 0);
   const RealType r = static_cast<RealType>(Rng::max() - Rng::min()) + 1;
   RealType base = r;
diff --git a/cpp/src/arrow/util/align_util.h b/cpp/src/arrow/util/align_util.h
index 71920e49f4..64eb1f7ba6 100644
--- a/cpp/src/arrow/util/align_util.h
+++ b/cpp/src/arrow/util/align_util.h
@@ -18,6 +18,7 @@
 #pragma once
 
 #include <algorithm>
+#include <bit>
 
 #include "arrow/memory_pool.h"
 #include "arrow/type_fwd.h"
@@ -43,7 +44,7 @@ struct BitmapWordAlignParams {
 template <uint64_t ALIGN_IN_BYTES>
 inline BitmapWordAlignParams BitmapWordAlign(const uint8_t* data, int64_t 
bit_offset,
                                              int64_t length) {
-  static_assert(bit_util::IsPowerOf2(ALIGN_IN_BYTES),
+  static_assert(std::has_single_bit(ALIGN_IN_BYTES),
                 "ALIGN_IN_BYTES should be a positive power of two");
   constexpr uint64_t ALIGN_IN_BITS = ALIGN_IN_BYTES * 8;
 
diff --git a/cpp/src/arrow/util/basic_decimal.cc 
b/cpp/src/arrow/util/basic_decimal.cc
index fc69bcf6f8..eddb1aae7b 100644
--- a/cpp/src/arrow/util/basic_decimal.cc
+++ b/cpp/src/arrow/util/basic_decimal.cc
@@ -19,6 +19,7 @@
 
 #include <algorithm>
 #include <array>
+#include <bit>
 #include <climits>
 #include <cstdint>
 #include <cstdlib>
@@ -388,7 +389,7 @@ BasicDecimal64 operator%(const BasicDecimal64& left, const 
BasicDecimal64& right
 
 template <typename BaseType>
 int32_t SmallBasicDecimal<BaseType>::CountLeadingBinaryZeros() const {
-  return 
bit_util::CountLeadingZeros(static_cast<std::make_unsigned_t<BaseType>>(value_));
+  return std::countl_zero(static_cast<std::make_unsigned_t<BaseType>>(value_));
 }
 
 // same as kDecimal128PowersOfTen[38] - 1
@@ -892,7 +893,7 @@ static inline DecimalStatus DecimalDivide(const 
DecimalClass& dividend,
   // Normalize by shifting both by a multiple of 2 so that
   // the digit guessing is better. The requirement is that
   // divisor_array[0] is greater than 2**31.
-  int64_t normalize_bits = bit_util::CountLeadingZeros(divisor_array[0]);
+  int64_t normalize_bits = std::countl_zero(divisor_array[0]);
   ShiftArrayLeft(divisor_array, divisor_length, normalize_bits);
   ShiftArrayLeft(dividend_array, dividend_length, normalize_bits);
 
@@ -1155,9 +1156,9 @@ int32_t BasicDecimal128::CountLeadingBinaryZeros() const {
   DCHECK_GE(*this, BasicDecimal128(0));
 
   if (high_bits() == 0) {
-    return bit_util::CountLeadingZeros(low_bits()) + 64;
+    return std::countl_zero(low_bits()) + 64;
   } else {
-    return bit_util::CountLeadingZeros(static_cast<uint64_t>(high_bits()));
+    return std::countl_zero(static_cast<uint64_t>(high_bits()));
   }
 }
 
diff --git a/cpp/src/arrow/util/bit_block_counter.h 
b/cpp/src/arrow/util/bit_block_counter.h
index 73a1ee8600..82651a9d38 100644
--- a/cpp/src/arrow/util/bit_block_counter.h
+++ b/cpp/src/arrow/util/bit_block_counter.h
@@ -18,6 +18,7 @@
 #pragma once
 
 #include <algorithm>
+#include <bit>
 #include <cstdint>
 #include <limits>
 #include <memory>
@@ -130,10 +131,10 @@ class ARROW_EXPORT BitBlockCounter {
       if (bits_remaining_ < kFourWordsBits) {
         return GetBlockSlow(kFourWordsBits);
       }
-      total_popcount += bit_util::PopCount(LoadWord(bitmap_));
-      total_popcount += bit_util::PopCount(LoadWord(bitmap_ + 8));
-      total_popcount += bit_util::PopCount(LoadWord(bitmap_ + 16));
-      total_popcount += bit_util::PopCount(LoadWord(bitmap_ + 24));
+      total_popcount += std::popcount(LoadWord(bitmap_));
+      total_popcount += std::popcount(LoadWord(bitmap_ + 8));
+      total_popcount += std::popcount(LoadWord(bitmap_ + 16));
+      total_popcount += std::popcount(LoadWord(bitmap_ + 24));
     } else {
       // When the offset is > 0, we need there to be a word beyond the last
       // aligned word in the bitmap for the bit shifting logic.
@@ -142,16 +143,16 @@ class ARROW_EXPORT BitBlockCounter {
       }
       auto current = LoadWord(bitmap_);
       auto next = LoadWord(bitmap_ + 8);
-      total_popcount += bit_util::PopCount(ShiftWord(current, next, offset_));
+      total_popcount += std::popcount(ShiftWord(current, next, offset_));
       current = next;
       next = LoadWord(bitmap_ + 16);
-      total_popcount += bit_util::PopCount(ShiftWord(current, next, offset_));
+      total_popcount += std::popcount(ShiftWord(current, next, offset_));
       current = next;
       next = LoadWord(bitmap_ + 24);
-      total_popcount += bit_util::PopCount(ShiftWord(current, next, offset_));
+      total_popcount += std::popcount(ShiftWord(current, next, offset_));
       current = next;
       next = LoadWord(bitmap_ + 32);
-      total_popcount += bit_util::PopCount(ShiftWord(current, next, offset_));
+      total_popcount += std::popcount(ShiftWord(current, next, offset_));
     }
     bitmap_ += bit_util::BytesForBits(kFourWordsBits);
     bits_remaining_ -= kFourWordsBits;
@@ -175,15 +176,15 @@ class ARROW_EXPORT BitBlockCounter {
       if (bits_remaining_ < kWordBits) {
         return GetBlockSlow(kWordBits);
       }
-      popcount = bit_util::PopCount(LoadWord(bitmap_));
+      popcount = std::popcount(LoadWord(bitmap_));
     } else {
       // When the offset is > 0, we need there to be a word beyond the last
       // aligned word in the bitmap for the bit shifting logic.
       if (bits_remaining_ < 2 * kWordBits - offset_) {
         return GetBlockSlow(kWordBits);
       }
-      popcount = bit_util::PopCount(
-          ShiftWord(LoadWord(bitmap_), LoadWord(bitmap_ + 8), offset_));
+      popcount =
+          std::popcount(ShiftWord(LoadWord(bitmap_), LoadWord(bitmap_ + 8), 
offset_));
     }
     bitmap_ += kWordBits / 8;
     bits_remaining_ -= kWordBits;
@@ -318,14 +319,13 @@ class ARROW_EXPORT BinaryBitBlockCounter {
 
     int64_t popcount = 0;
     if (left_offset_ == 0 && right_offset_ == 0) {
-      popcount =
-          bit_util::PopCount(Op::Call(LoadWord(left_bitmap_), 
LoadWord(right_bitmap_)));
+      popcount = std::popcount(Op::Call(LoadWord(left_bitmap_), 
LoadWord(right_bitmap_)));
     } else {
       auto left_word =
           ShiftWord(LoadWord(left_bitmap_), LoadWord(left_bitmap_ + 8), 
left_offset_);
       auto right_word =
           ShiftWord(LoadWord(right_bitmap_), LoadWord(right_bitmap_ + 8), 
right_offset_);
-      popcount = bit_util::PopCount(Op::Call(left_word, right_word));
+      popcount = std::popcount(Op::Call(left_word, right_word));
     }
     left_bitmap_ += kWordBits / 8;
     right_bitmap_ += kWordBits / 8;
diff --git a/cpp/src/arrow/util/bit_run_reader.h 
b/cpp/src/arrow/util/bit_run_reader.h
index 7bb0014027..1a9638880c 100644
--- a/cpp/src/arrow/util/bit_run_reader.h
+++ b/cpp/src/arrow/util/bit_run_reader.h
@@ -17,6 +17,7 @@
 
 #pragma once
 
+#include <bit>
 #include <cassert>
 #include <cstdint>
 #include <cstring>
@@ -93,7 +94,7 @@ class ARROW_EXPORT BitRunReader {
       return {/*length=*/0, false};
     }
     // This implementation relies on a efficient implementations of
-    // CountTrailingZeros and assumes that runs are more often then
+    // std::countr_zero and assumes that runs are more often then
     // not.  The logic is to incrementally find the next bit change
     // from the current position.  This is done by zeroing all
     // bits in word_ up to position_ and using the TrailingZeroCount
@@ -104,12 +105,12 @@ class ARROW_EXPORT BitRunReader {
 
     int64_t start_position = position_;
     int64_t start_bit_offset = start_position & 63;
-    // Invert the word for proper use of CountTrailingZeros and
-    // clear bits so CountTrailingZeros can do it magic.
+    // Invert the word for proper use of std::countr_zero and
+    // clear bits so std::countr_zero can do it magic.
     word_ = ~word_ & 
~bit_util::LeastSignificantBitMask<uint64_t>(start_bit_offset);
 
     // Go  forward until the next change from unset to set.
-    int64_t new_bits = bit_util::CountTrailingZeros(word_) - start_bit_offset;
+    int64_t new_bits = std::countr_zero(word_) - start_bit_offset;
     position_ += new_bits;
 
     if (ARROW_PREDICT_FALSE(bit_util::IsMultipleOf64(position_)) &&
@@ -129,7 +130,7 @@ class ARROW_EXPORT BitRunReader {
       // Advance the position of the bitmap for loading.
       bitmap_ += sizeof(uint64_t);
       LoadNextWord();
-      new_bits = bit_util::CountTrailingZeros(word_);
+      new_bits = std::countr_zero(word_);
       // Continue calculating run length.
       position_ += new_bits;
     } while (ARROW_PREDICT_FALSE(bit_util::IsMultipleOf64(position_)) &&
@@ -155,9 +156,9 @@ class ARROW_EXPORT BitRunReader {
     }
 
     // Two cases:
-    //   1. For unset, CountTrailingZeros works naturally so we don't
+    //   1. For unset, std::countr_zero works naturally so we don't
     //   invert the word.
-    //   2. Otherwise invert so we can use CountTrailingZeros.
+    //   2. Otherwise invert so we can use std::countr_zero.
     if (current_run_bit_set_) {
       word_ = ~word_;
     }
@@ -438,12 +439,12 @@ class BaseSetBitRunReader {
 
 template <>
 inline int BaseSetBitRunReader<false>::CountFirstZeros(uint64_t word) {
-  return bit_util::CountTrailingZeros(word);
+  return std::countr_zero(word);
 }
 
 template <>
 inline int BaseSetBitRunReader<true>::CountFirstZeros(uint64_t word) {
-  return bit_util::CountLeadingZeros(word);
+  return std::countl_zero(word);
 }
 
 template <>
diff --git a/cpp/src/arrow/util/bit_util.h b/cpp/src/arrow/util/bit_util.h
index c7849db871..0d2b2655ea 100644
--- a/cpp/src/arrow/util/bit_util.h
+++ b/cpp/src/arrow/util/bit_util.h
@@ -17,20 +17,7 @@
 
 #pragma once
 
-#if defined(_MSC_VER)
-#  if defined(_M_AMD64) || defined(_M_X64)
-#    include <intrin.h>  // IWYU pragma: keep
-#  endif
-
-#  pragma intrinsic(_BitScanReverse)
-#  pragma intrinsic(_BitScanForward)
-#  define ARROW_POPCOUNT64 __popcnt64
-#  define ARROW_POPCOUNT32 __popcnt
-#else
-#  define ARROW_POPCOUNT64 __builtin_popcountll
-#  define ARROW_POPCOUNT32 __builtin_popcount
-#endif
-
+#include <bit>
 #include <cstdint>
 #include <type_traits>
 
@@ -49,26 +36,6 @@ typename std::make_unsigned<Integer>::type 
as_unsigned(Integer x) {
 
 namespace bit_util {
 
-// The number of set bits in a given unsigned byte value, pre-computed
-//
-// Generated with the following Python code
-// output = 'static constexpr uint8_t kBytePopcount[] = {{{0}}};'
-// popcounts = [str(bin(i).count('1')) for i in range(0, 256)]
-// print(output.format(', '.join(popcounts)))
-static constexpr uint8_t kBytePopcount[] = {
-    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 
3, 3, 4, 3,
-    4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 
4, 5, 3, 4,
-    4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 
4, 3, 4, 4,
-    5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
3, 4, 4, 5,
-    4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 
4, 4, 5, 2,
-    3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 
4, 5, 4, 5,
-    5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 
5, 3, 4, 4,
-    5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 
4, 5, 5, 6,
-    4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
-
-static inline uint64_t PopCount(uint64_t bitmap) { return 
ARROW_POPCOUNT64(bitmap); }
-static inline uint32_t PopCount(uint32_t bitmap) { return 
ARROW_POPCOUNT32(bitmap); }
-
 //
 // Bit-related computations on integer values
 //
@@ -84,14 +51,6 @@ constexpr int64_t BytesForBits(int64_t bits) {
   return (bits >> 3) + ((bits & 7) != 0);
 }
 
-constexpr bool IsPowerOf2(int64_t value) {
-  return value > 0 && (value & (value - 1)) == 0;
-}
-
-constexpr bool IsPowerOf2(uint64_t value) {
-  return value > 0 && (value & (value - 1)) == 0;
-}
-
 // Returns the smallest power of two that contains v.  If v is already a
 // power of two, it is returned as is.
 static inline int64_t NextPower2(int64_t n) {
@@ -140,13 +99,10 @@ constexpr int64_t RoundDown(int64_t value, int64_t factor) 
{
 // The result is undefined on overflow, i.e. if `value > 2**64 - factor`,
 // since we cannot return the correct result which would be 2**64.
 constexpr int64_t RoundUpToPowerOf2(int64_t value, int64_t factor) {
-  // DCHECK(value >= 0);
-  // DCHECK(IsPowerOf2(factor));
   return (value + (factor - 1)) & ~(factor - 1);
 }
 
 constexpr uint64_t RoundUpToPowerOf2(uint64_t value, uint64_t factor) {
-  // DCHECK(IsPowerOf2(factor));
   return (value + (factor - 1)) & ~(factor - 1);
 }
 
@@ -179,106 +135,10 @@ static inline uint64_t TrailingBits(uint64_t v, int 
num_bits) {
   return (v << n) >> n;
 }
 
-/// \brief Count the number of leading zeros in an unsigned integer.
-static inline int CountLeadingZeros(uint32_t value) {
-#if defined(__clang__) || defined(__GNUC__)
-  if (value == 0) return 32;
-  return static_cast<int>(__builtin_clz(value));
-#elif defined(_MSC_VER)
-  unsigned long index;                                               // NOLINT
-  if (_BitScanReverse(&index, static_cast<unsigned long>(value))) {  // NOLINT
-    return 31 - static_cast<int>(index);
-  } else {
-    return 32;
-  }
-#else
-  int bitpos = 0;
-  while (value != 0) {
-    value >>= 1;
-    ++bitpos;
-  }
-  return 32 - bitpos;
-#endif
-}
-
-static inline int CountLeadingZeros(uint64_t value) {
-#if defined(__clang__) || defined(__GNUC__)
-  if (value == 0) return 64;
-  return static_cast<int>(__builtin_clzll(value));
-#elif defined(_MSC_VER)
-  unsigned long index;                     // NOLINT
-  if (_BitScanReverse64(&index, value)) {  // NOLINT
-    return 63 - static_cast<int>(index);
-  } else {
-    return 64;
-  }
-#else
-  int bitpos = 0;
-  while (value != 0) {
-    value >>= 1;
-    ++bitpos;
-  }
-  return 64 - bitpos;
-#endif
-}
-
-static inline int CountTrailingZeros(uint32_t value) {
-#if defined(__clang__) || defined(__GNUC__)
-  if (value == 0) return 32;
-  return static_cast<int>(__builtin_ctzl(value));
-#elif defined(_MSC_VER)
-  unsigned long index;  // NOLINT
-  if (_BitScanForward(&index, value)) {
-    return static_cast<int>(index);
-  } else {
-    return 32;
-  }
-#else
-  int bitpos = 0;
-  if (value) {
-    while (value & 1 == 0) {
-      value >>= 1;
-      ++bitpos;
-    }
-  } else {
-    bitpos = 32;
-  }
-  return bitpos;
-#endif
-}
-
-static inline int CountTrailingZeros(uint64_t value) {
-#if defined(__clang__) || defined(__GNUC__)
-  if (value == 0) return 64;
-  return static_cast<int>(__builtin_ctzll(value));
-#elif defined(_MSC_VER)
-  unsigned long index;  // NOLINT
-  if (_BitScanForward64(&index, value)) {
-    return static_cast<int>(index);
-  } else {
-    return 64;
-  }
-#else
-  int bitpos = 0;
-  if (value) {
-    while (value & 1 == 0) {
-      value >>= 1;
-      ++bitpos;
-    }
-  } else {
-    bitpos = 64;
-  }
-  return bitpos;
-#endif
-}
-
-// Returns the minimum number of bits needed to represent an unsigned value
-static inline int NumRequiredBits(uint64_t x) { return 64 - 
CountLeadingZeros(x); }
-
 // Returns ceil(log2(x)).
 static inline int Log2(uint64_t x) {
   // DCHECK_GT(x, 0);
-  return NumRequiredBits(x - 1);
+  return std::bit_width(x - 1);
 }
 
 //
diff --git a/cpp/src/arrow/util/bit_util_test.cc 
b/cpp/src/arrow/util/bit_util_test.cc
index 13aa319d70..1e7714540e 100644
--- a/cpp/src/arrow/util/bit_util_test.cc
+++ b/cpp/src/arrow/util/bit_util_test.cc
@@ -739,79 +739,10 @@ TEST(BitUtil, Log2) {
   EXPECT_EQ(bit_util::Log2(ULLONG_MAX), 64);
 }
 
-TEST(BitUtil, NumRequiredBits) {
-  EXPECT_EQ(bit_util::NumRequiredBits(0), 0);
-  EXPECT_EQ(bit_util::NumRequiredBits(1), 1);
-  EXPECT_EQ(bit_util::NumRequiredBits(2), 2);
-  EXPECT_EQ(bit_util::NumRequiredBits(3), 2);
-  EXPECT_EQ(bit_util::NumRequiredBits(4), 3);
-  EXPECT_EQ(bit_util::NumRequiredBits(5), 3);
-  EXPECT_EQ(bit_util::NumRequiredBits(7), 3);
-  EXPECT_EQ(bit_util::NumRequiredBits(8), 4);
-  EXPECT_EQ(bit_util::NumRequiredBits(9), 4);
-  EXPECT_EQ(bit_util::NumRequiredBits(UINT_MAX - 1), 32);
-  EXPECT_EQ(bit_util::NumRequiredBits(UINT_MAX), 32);
-  EXPECT_EQ(bit_util::NumRequiredBits(static_cast<uint64_t>(UINT_MAX) + 1), 
33);
-  EXPECT_EQ(bit_util::NumRequiredBits(ULLONG_MAX / 2), 63);
-  EXPECT_EQ(bit_util::NumRequiredBits(ULLONG_MAX / 2 + 1), 64);
-  EXPECT_EQ(bit_util::NumRequiredBits(ULLONG_MAX - 1), 64);
-  EXPECT_EQ(bit_util::NumRequiredBits(ULLONG_MAX), 64);
-}
-
 #define U32(x) static_cast<uint32_t>(x)
 #define U64(x) static_cast<uint64_t>(x)
 #define S64(x) static_cast<int64_t>(x)
 
-TEST(BitUtil, CountLeadingZeros) {
-  EXPECT_EQ(bit_util::CountLeadingZeros(U32(0)), 32);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U32(1)), 31);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U32(2)), 30);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U32(3)), 30);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U32(4)), 29);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U32(7)), 29);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U32(8)), 28);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U32(UINT_MAX / 2)), 1);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U32(UINT_MAX / 2 + 1)), 0);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U32(UINT_MAX)), 0);
-
-  EXPECT_EQ(bit_util::CountLeadingZeros(U64(0)), 64);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U64(1)), 63);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U64(2)), 62);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U64(3)), 62);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U64(4)), 61);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U64(7)), 61);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U64(8)), 60);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U64(UINT_MAX)), 32);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U64(UINT_MAX) + 1), 31);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U64(ULLONG_MAX / 2)), 1);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U64(ULLONG_MAX / 2 + 1)), 0);
-  EXPECT_EQ(bit_util::CountLeadingZeros(U64(ULLONG_MAX)), 0);
-}
-
-TEST(BitUtil, CountTrailingZeros) {
-  EXPECT_EQ(bit_util::CountTrailingZeros(U32(0)), 32);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U32(1) << 31), 31);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U32(1) << 30), 30);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U32(1) << 29), 29);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U32(1) << 28), 28);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U32(8)), 3);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U32(4)), 2);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U32(2)), 1);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U32(1)), 0);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U32(ULONG_MAX)), 0);
-
-  EXPECT_EQ(bit_util::CountTrailingZeros(U64(0)), 64);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U64(1) << 63), 63);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U64(1) << 62), 62);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U64(1) << 61), 61);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U64(1) << 60), 60);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U64(8)), 3);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U64(4)), 2);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U64(2)), 1);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U64(1)), 0);
-  EXPECT_EQ(bit_util::CountTrailingZeros(U64(ULLONG_MAX)), 0);
-}
-
 TEST(BitUtil, RoundUpToPowerOf2) {
   EXPECT_EQ(bit_util::RoundUpToPowerOf2(S64(7), 8), 8);
   EXPECT_EQ(bit_util::RoundUpToPowerOf2(S64(8), 8), 8);
diff --git a/cpp/src/arrow/util/bitmap_ops.cc b/cpp/src/arrow/util/bitmap_ops.cc
index ce2224f2f6..cc24146ae9 100644
--- a/cpp/src/arrow/util/bitmap_ops.cc
+++ b/cpp/src/arrow/util/bitmap_ops.cc
@@ -61,10 +61,10 @@ int64_t CountSetBits(const uint8_t* data, int64_t 
bit_offset, int64_t length) {
     // Unroll the loop for better performance
     for (int64_t i = 0; i < words_rounded; i += kCountUnrollFactor) {
       // (hand-unrolled as some gcc versions would unnest a nested `for` loop)
-      count_unroll[0] += bit_util::PopCount(u64_data[0]);
-      count_unroll[1] += bit_util::PopCount(u64_data[1]);
-      count_unroll[2] += bit_util::PopCount(u64_data[2]);
-      count_unroll[3] += bit_util::PopCount(u64_data[3]);
+      count_unroll[0] += std::popcount(u64_data[0]);
+      count_unroll[1] += std::popcount(u64_data[1]);
+      count_unroll[2] += std::popcount(u64_data[2]);
+      count_unroll[3] += std::popcount(u64_data[3]);
       u64_data += kCountUnrollFactor;
     }
     for (int64_t k = 0; k < kCountUnrollFactor; k++) {
@@ -73,7 +73,7 @@ int64_t CountSetBits(const uint8_t* data, int64_t bit_offset, 
int64_t length) {
 
     // The trailing part
     for (; u64_data < end; ++u64_data) {
-      count += bit_util::PopCount(*u64_data);
+      count += std::popcount(*u64_data);
     }
   }
 
diff --git a/cpp/src/arrow/util/bitmap_reader_benchmark.cc 
b/cpp/src/arrow/util/bitmap_reader_benchmark.cc
index b3c199ec3b..3563ba75ad 100644
--- a/cpp/src/arrow/util/bitmap_reader_benchmark.cc
+++ b/cpp/src/arrow/util/bitmap_reader_benchmark.cc
@@ -15,6 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
+#include <bit>
 #include <bitset>
 #include <cstdint>
 #include <cstdlib>
@@ -88,9 +89,9 @@ static void BitmapWordReaderBench(benchmark::State& state) {
       //      if (word == UINT64_MAX) {
       //        set_bits += sizeof(uint64_t) * 8;
       //      } else if (word) {
-      //        set_bits += PopCount(word);
+      //        set_bits += std::popcount(word);
       //      }
-      set_bits += PopCount(word);
+      set_bits += std::popcount(word);
       benchmark::DoNotOptimize(set_bits);
     }
 
@@ -98,7 +99,7 @@ static void BitmapWordReaderBench(benchmark::State& state) {
     while (cnt--) {
       int valid_bits;
       const auto& byte = 
static_cast<uint32_t>(counter.NextTrailingByte(valid_bits));
-      set_bits += PopCount(kPrecedingBitmask[valid_bits] & byte);
+      set_bits += std::popcount(kPrecedingBitmask[valid_bits] & byte);
       benchmark::DoNotOptimize(set_bits);
     }
     benchmark::ClobberMemory();
diff --git a/cpp/src/arrow/util/bitmap_writer.h 
b/cpp/src/arrow/util/bitmap_writer.h
index c9ce8012f3..8c47793fde 100644
--- a/cpp/src/arrow/util/bitmap_writer.h
+++ b/cpp/src/arrow/util/bitmap_writer.h
@@ -17,6 +17,7 @@
 
 #pragma once
 
+#include <bit>
 #include <cstdint>
 #include <cstring>
 
@@ -112,7 +113,7 @@ class FirstTimeBitmapWriter {
 
     // Update state variables except for current_byte_ here.
     position_ += number_of_bits;
-    int64_t bit_offset = 
bit_util::CountTrailingZeros(static_cast<uint32_t>(bit_mask_));
+    int64_t bit_offset = std::countr_zero(static_cast<uint32_t>(bit_mask_));
     bit_mask_ = bit_util::kBitmask[(bit_offset + number_of_bits) % 8];
     byte_offset_ += (bit_offset + number_of_bits) / 8;
 
diff --git a/cpp/src/arrow/util/rle_encoding_test.cc 
b/cpp/src/arrow/util/rle_encoding_test.cc
index b2d4f7df6f..f77f91f6cd 100644
--- a/cpp/src/arrow/util/rle_encoding_test.cc
+++ b/cpp/src/arrow/util/rle_encoding_test.cc
@@ -17,6 +17,7 @@
 
 // From Apache Impala (incubating) as of 2016-01-29
 
+#include <bit>
 #include <cstdint>
 #include <cstring>
 #include <random>
@@ -912,7 +913,7 @@ TEST(BitRle, Random) {
       }
       parity = !parity;
     }
-    if (!CheckRoundTrip(values, bit_util::NumRequiredBits(values.size()))) {
+    if (!CheckRoundTrip(values, std::bit_width(values.size()))) {
       FAIL() << "failing seed: " << seed;
     }
   }
diff --git a/cpp/src/gandiva/selection_vector.cc 
b/cpp/src/gandiva/selection_vector.cc
index 8d5f9f4210..0d8ecb66b7 100644
--- a/cpp/src/gandiva/selection_vector.cc
+++ b/cpp/src/gandiva/selection_vector.cc
@@ -17,6 +17,7 @@
 
 #include "gandiva/selection_vector.h"
 
+#include <bit>
 #include <memory>
 #include <sstream>
 #include <utility>
@@ -64,7 +65,7 @@ Status SelectionVector::PopulateFromBitMap(const uint8_t* 
bitmap, int64_t bitmap
 #  pragma warning(pop)
 #endif
 
-      int pos_in_word = arrow::bit_util::CountTrailingZeros(highest_only);
+      int pos_in_word = std::countr_zero(highest_only);
 
       int64_t pos_in_bitmap = bitmap_idx * 64 + pos_in_word;
       if (pos_in_bitmap > max_bitmap_index) {
diff --git a/cpp/src/parquet/chunker_internal.cc 
b/cpp/src/parquet/chunker_internal.cc
index cc0a386f4c..5cd31f8334 100644
--- a/cpp/src/parquet/chunker_internal.cc
+++ b/cpp/src/parquet/chunker_internal.cc
@@ -17,6 +17,7 @@
 
 #include "parquet/chunker_internal.h"
 
+#include <bit>
 #include <cstdint>
 #include <iterator>
 #include <string>
@@ -85,7 +86,8 @@ uint64_t CalculateMask(int64_t min_chunk_size, int64_t 
max_chunk_size, int norm_
 
   // assuming that the gear hash has a uniform distribution, we can calculate 
the mask
   // by taking the floor(log2(target_size))
-  int mask_bits = std::max(0, ::arrow::bit_util::NumRequiredBits(target_size) 
- 1);
+  auto target_bits = std::bit_width(static_cast<uint64_t>(target_size));
+  int mask_bits = target_bits == 0 ? 0 : static_cast<int>(target_bits - 1);
 
   // a user defined `norm_level` can be used to adjust the mask size, hence 
the matching
   // probability, by increasing the norm_level we increase the probability of 
matching
diff --git a/cpp/src/parquet/encoder.cc b/cpp/src/parquet/encoder.cc
index 0e8c0ba32b..97a5d77d41 100644
--- a/cpp/src/parquet/encoder.cc
+++ b/cpp/src/parquet/encoder.cc
@@ -18,6 +18,7 @@
 #include "parquet/encoding.h"
 
 #include <algorithm>
+#include <bit>
 #include <cstdint>
 #include <cstdlib>
 #include <limits>
@@ -1164,8 +1165,8 @@ void DeltaBitPackEncoder<DType>::FlushBlock() {
 
     // The minimum number of bits required to write any of values in deltas_ 
vector.
     // See overflow comment above.
-    const auto bit_width = bit_width_data[i] = bit_util::NumRequiredBits(
-        static_cast<UT>(max_delta) - static_cast<UT>(min_delta));
+    const auto bit_width = bit_width_data[i] =
+        std::bit_width(static_cast<UT>(max_delta) - 
static_cast<UT>(min_delta));
 
     for (uint32_t j = start; j < start + values_current_mini_block; j++) {
       // Convert delta to frame of reference. See overflow comment above.
diff --git a/cpp/src/parquet/level_conversion_inc.h 
b/cpp/src/parquet/level_conversion_inc.h
index 335f5b9215..33b4fae084 100644
--- a/cpp/src/parquet/level_conversion_inc.h
+++ b/cpp/src/parquet/level_conversion_inc.h
@@ -19,6 +19,7 @@
 #include "parquet/level_conversion.h"
 
 #include <algorithm>
+#include <bit>
 #include <cstdint>
 #include <limits>
 
@@ -248,7 +249,7 @@ inline uint64_t ExtractBitsSoftware(uint64_t bitmap, 
uint64_t select_bitmap) {
   int bit_len = 0;
   constexpr uint8_t kLookupMask = (1U << kLookupBits) - 1;
   while (select_bitmap != 0) {
-    const auto mask_len = ARROW_POPCOUNT32(select_bitmap & kLookupMask);
+    const auto mask_len = std::popcount(select_bitmap & kLookupMask);
     const uint64_t value = kPextTable[select_bitmap & kLookupMask][bitmap & 
kLookupMask];
     bit_value |= (value << bit_len);
     bit_len += mask_len;
@@ -309,12 +310,12 @@ int64_t DefLevelsBatchToBitmap(const int16_t* def_levels, 
const int64_t batch_si
         ::arrow::bit_util::FromLittleEndian(internal::GreaterThanBitmap(
             def_levels, batch_size, level_info.repeated_ancestor_def_level - 
1)));
     auto selected_bits = ExtractBits(defined_bitmap, present_bitmap);
-    int64_t selected_count = ::arrow::bit_util::PopCount(present_bitmap);
+    int64_t selected_count = std::popcount(present_bitmap);
     if (ARROW_PREDICT_FALSE(selected_count > upper_bound_remaining)) {
       throw ParquetException("Values read exceeded upper bound");
     }
     writer->AppendWord(selected_bits, selected_count);
-    return ::arrow::bit_util::PopCount(selected_bits);
+    return std::popcount(selected_bits);
   } else {
     if (ARROW_PREDICT_FALSE(batch_size > upper_bound_remaining)) {
       std::stringstream ss;
@@ -323,7 +324,7 @@ int64_t DefLevelsBatchToBitmap(const int16_t* def_levels, 
const int64_t batch_si
     }
 
     writer->AppendWord(defined_bitmap, batch_size);
-    return ::arrow::bit_util::PopCount(defined_bitmap);
+    return std::popcount(defined_bitmap);
   }
 }
 


Reply via email to