1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Collections open source project
//
// Copyright (c) 2022 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//
%{
from gyb_utils import *
}%
${autogenerated_warning()}
% for modifier in visibility_levels:
${visibility_boilerplate(modifier)}
extension FixedWidthInteger {
@inlinable @inline(__always)
internal var _nonzeroBitCount: Self {
Self(truncatingIfNeeded: nonzeroBitCount)
}
@inlinable @inline(__always)
${modifier} func _rank(ofBit bit: UInt) -> Int {
assert(bit < Self.bitWidth)
let mask: Self = (1 &<< bit) &- 1
return (self & mask).nonzeroBitCount
}
}
extension UInt {
@_effects(releasenone)
${"@usableFromInline" if modifier != "public" else "//@usableFromInline" }
${modifier} func _bit(ranked n: Int) -> UInt? {
// FIXME: Use bit deposit instruction when available (PDEP on Intel).
assert(UInt.bitWidth == 64 || UInt.bitWidth == 32,
"Unsupported UInt bitWidth")
var shift: Self = 0
var n = Self(truncatingIfNeeded: n)
if MemoryLayout<UInt>.size == 8 {
let c32 = (self & 0xFFFFFFFF)._nonzeroBitCount
if n >= c32 {
shift &+= 32
n &-= c32
}
} else {
assert(MemoryLayout<Self>.size == 4, "Unknown platform")
}
let c16 = ((self &>> shift) & 0xFFFF)._nonzeroBitCount
if n >= c16 {
shift &+= 16
n &-= c16
}
let c8 = ((self &>> shift) & 0xFF)._nonzeroBitCount
if n >= c8 {
shift &+= 8
n &-= c8
}
let c4 = ((self &>> shift) & 0xF)._nonzeroBitCount
if n >= c4 {
shift &+= 4
n &-= c4
}
let c2 = ((self &>> shift) & 0x3)._nonzeroBitCount
if n >= c2 {
shift &+= 2
n &-= c2
}
let c1 = (self &>> shift) & 0x1
if n >= c1 {
shift &+= 1
n &-= c1
}
guard n == 0 && (self &>> shift) & 0x1 == 1 else { return nil }
return shift
}
}
extension UInt32 {
// Returns the position of the `n`th set bit in `self`, i.e., the bit with
// rank `n`.
@_effects(releasenone)
${"@usableFromInline" if modifier != "public" else "//@usableFromInline" }
${modifier} func _bit(ranked n: Int) -> UInt? {
// FIXME: Use bit deposit instruction when available (PDEP on Intel).
assert(n >= 0 && n < Self.bitWidth)
var shift: Self = 0
var n = Self(truncatingIfNeeded: n)
let c16 = (self & 0xFFFF)._nonzeroBitCount
if n >= c16 {
shift = 16
n -= c16
}
let c8 = ((self &>> shift) & 0xFF)._nonzeroBitCount
if n >= c8 {
shift &+= 8
n -= c8
}
let c4 = ((self &>> shift) & 0xF)._nonzeroBitCount
if n >= c4 {
shift &+= 4
n -= c4
}
let c2 = ((self &>> shift) & 0x3)._nonzeroBitCount
if n >= c2 {
shift &+= 2
n -= c2
}
let c1 = (self &>> shift) & 0x1
if n >= c1 {
shift &+= 1
n -= c1
}
guard n == 0, (self &>> shift) & 0x1 == 1 else { return nil }
return UInt(truncatingIfNeeded: shift)
}
}
extension UInt16 {
// Returns the position of the `n`th set bit in `self`, i.e., the bit with
// rank `n`.
@_effects(releasenone)
${"@usableFromInline" if modifier != "public" else "//@usableFromInline" }
${modifier} func _bit(ranked n: Int) -> UInt? {
// FIXME: Use bit deposit instruction when available (PDEP on Intel).
assert(n >= 0 && n < Self.bitWidth)
var shift: Self = 0
var n = Self(truncatingIfNeeded: n)
let c8 = ((self &>> shift) & 0xFF)._nonzeroBitCount
if n >= c8 {
shift &+= 8
n -= c8
}
let c4 = ((self &>> shift) & 0xF)._nonzeroBitCount
if n >= c4 {
shift &+= 4
n -= c4
}
let c2 = ((self &>> shift) & 0x3)._nonzeroBitCount
if n >= c2 {
shift &+= 2
n -= c2
}
let c1 = (self &>> shift) & 0x1
if n >= c1 {
shift &+= 1
n -= c1
}
guard n == 0, (self &>> shift) & 0x1 == 1 else { return nil }
return UInt(truncatingIfNeeded: shift)
}
}
% end
${visibility_boilerplate("end")}
|