[Performance] LOUDSのlookupを高速化 (#28)

* simplify calculation

* cleanup

* add code fro debug

* fix bug

* cleanup

* cleanup

* cleanup
This commit is contained in:
Miwa / Ensan
2024-01-07 02:19:39 +09:00
committed by GitHub
parent 595d38f123
commit a36b0e0049

View File

@@ -8,30 +8,26 @@
import Foundation
private extension UInt64 {
static let prefixOne: UInt64 = 1 << 63
}
/// LOUDS
struct LOUDS {
struct LOUDS: Sendable {
private typealias Unit = UInt64
private static let unit = 64
private static let uExp = 6
private let bits: [Unit]
private let indices: Range<Int>
private let char2nodeIndices: [[Int]]
/// 01
private let rankLarge: [Int]
///
/// LOUDS4GB`UInt32`
private let rankLarge: [UInt32]
@inlinable init(bytes: [UInt64], nodeIndex2ID: [UInt8]) {
self.bits = bytes
self.char2nodeIndices = nodeIndex2ID.enumerated().reduce(into: .init(repeating: [], count: 1 << 8)) { list, data in
list[Int(data.element)].append(data.offset)
}
self.indices = self.bits.indices
self.rankLarge = bytes.reduce(into: [0]) {
$0.append(($0.last ?? 0) &+ (Self.unit &- $1.nonzeroBitCount))
$0.append($0.last! &+ UInt32(Self.unit &- $1.nonzeroBitCount))
}
}
@@ -49,50 +45,49 @@ struct LOUDS {
// startIndexbitsindex `i`
var left = (parentNodeIndex >> Self.uExp) &- 1
while true {
let dif = parentNodeIndex &- self.rankLarge[left &+ 1]
let dif = parentNodeIndex &- Int(self.rankLarge[Int(left) &+ 1])
if dif >= Self.unit {
left &+= dif >> Self.uExp
} else {
break
}
}
guard let i = (left &+ 1 ..< self.bits.count).first(where: {(index: Int) in self.rankLarge[index &+ 1] >= parentNodeIndex}) else {
var i: Int?
for index in left &+ 1 ..< self.bits.endIndex where self.rankLarge[index &+ 1] >= parentNodeIndex {
i = index
break
}
guard let i else {
return 0 ..< 0
}
return self.bits.withUnsafeBufferPointer {(buffer: UnsafeBufferPointer<Unit>) -> Range<Int> in
//
// `k`
// byte(dif)0k
let byte = buffer[i]
let dif = self.rankLarge[i &+ 1] &- parentNodeIndex // 0
var count = Unit(Self.unit &- byte.nonzeroBitCount) // 0
var k = Self.unit
for c in 0 ..< Self.unit {
if count == dif {
k = c
break
}
// bytec0 == (byte << 0)10000 == 1
count &-= (byte << c) < Unit.prefixOne ? 1:0
}
let start = (i << Self.uExp) &+ k &- parentNodeIndex &+ 1
if dif == .zero {
//
// parentNodeIndex0`k`
let byte = self.bits[i]
var k = 0
for _ in 0 ..< parentNodeIndex - Int(self.rankLarge[i]) {
k = (~(byte << k)).leadingZeroBitCount &+ k &+ 1
}
let start = (i << Self.uExp) &+ k &- parentNodeIndex &+ 1
// parentNodeIndex0i
if self.rankLarge[i &+ 1] == parentNodeIndex {
return self.bits.withUnsafeBufferPointer {(buffer: UnsafeBufferPointer<Unit>) -> Range<Int> in
var j = i &+ 1
while buffer[j] == Unit.max {
j &+= 1
}
let byte2 = buffer[j]
// 0
let a = (0 ..< Self.unit).first(where: {(byte2 << $0) < Unit.prefixOne})
return start ..< (j << Self.uExp) &+ (a ?? 0) &- parentNodeIndex &+ 1
} else {
// 0
let a = (k ..< Self.unit).first(where: {(byte << $0) < Unit.prefixOne})
return start ..< (i << Self.uExp) &+ (a ?? 0) &- parentNodeIndex &+ 1
// 00
// Ex. 1110_0000 => [000]1_1111 => 3
let byte2 = buffer[j]
let a = (~byte2).leadingZeroBitCount % Self.unit
return start ..< (j << Self.uExp) &+ a &- parentNodeIndex &+ 1
}
} else {
// dif0k0
// k=1
// Ex. 1011_1101 => 0111_1010 => 1000_0101 => 1 => 2
let a = ((~(byte << k)).leadingZeroBitCount &+ k) % Self.unit
return start ..< (i << Self.uExp) &+ a &- parentNodeIndex &+ 1
}
}