Skip to content

Commit e153ebf

Browse files
committed
[PersistentCollections] Reduce popcount usages where possible
# Conflicts: # Sources/PersistentCollections/Node/_Node+Primitive Removals.swift
1 parent 785caa4 commit e153ebf

File tree

5 files changed

+31
-13
lines changed

5 files changed

+31
-13
lines changed

Sources/PersistentCollections/Node/_Bitmap.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ extension _Bitmap {
8686
@inlinable @inline(__always)
8787
internal var isEmpty: Bool { _value == 0 }
8888

89+
@inlinable @inline(__always)
90+
internal var hasExactlyOneMember: Bool {
91+
_value != 0 && _value & (_value &- 1) == 0
92+
}
93+
8994
@inlinable @inline(__always)
9095
internal var first: _Bucket? {
9196
guard !isEmpty else { return nil }

Sources/PersistentCollections/Node/_Node+Primitive Removals.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ extension _Node {
127127
assert(count == 1)
128128
count = 0
129129
return update {
130-
assert($0.itemCount == 1 && $0.childCount == 0)
130+
assert($0.hasSingletonItem)
131131
let old = $0._removeItem(at: .zero) { $0.move() }
132132
$0.clear()
133133
return old
@@ -138,7 +138,7 @@ extension _Node {
138138
internal mutating func removeSingletonChild() -> _Node {
139139
defer { _invariantCheck() }
140140
let child: _Node = update {
141-
assert($0.itemCount == 0 && $0.childCount == 1)
141+
assert($0.hasSingletonChild)
142142
let child = $0._removeChild(at: .zero)
143143
$0.childMap = .empty
144144
return child

Sources/PersistentCollections/Node/_Node+Subtree Removals.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,9 @@ extension _Node {
165165
assert(slot == $0.itemMap.slot(of: bucket))
166166

167167
let willAtrophy = (
168-
$0.itemCount == 1
169-
&& $0.childCount == 1
168+
!$0.isCollisionNode
169+
&& $0.itemMap.hasExactlyOneMember
170+
&& $0.childMap.hasExactlyOneMember
170171
&& $0[child: .zero].isCollisionNode)
171172
if willAtrophy {
172173
// Compression
@@ -175,8 +176,8 @@ extension _Node {
175176
return (old, .collisionNode(level, child))
176177
}
177178

178-
let willEvaporate = ($0.itemCount == 2 && $0.childCount == 0)
179-
if willEvaporate {
179+
if $0.itemMap.count == 2 && $0.childMap.isEmpty {
180+
// Evaporating node
180181
let remainder = _Slot(1 &- slot.value)
181182

182183
var map = $0.itemMap
@@ -203,7 +204,7 @@ extension _Node {
203204
read {
204205
assert(!$0.isCollisionNode && $0.childMap.contains(bucket))
205206
let willAtrophy = (
206-
$0.itemCount == 0
207+
$0.itemMap.isEmpty
207208
&& $0.childCount == 2
208209
&& $0[child: _Slot(1 &- slot.value)].isCollisionNode
209210
)
@@ -212,12 +213,11 @@ extension _Node {
212213
let child = $0[child: _Slot(1 &- slot.value)]
213214
return .collisionNode(level, child)
214215
}
215-
let willTurnIntoItem = ($0.itemCount == 1 && $0.childCount == 1)
216-
if willTurnIntoItem {
216+
if $0.itemMap.hasExactlyOneMember && $0.childMap.hasExactlyOneMember {
217217
return .item(level, $0[item: .zero], at: $0.itemMap.first!)
218218
}
219-
let willEvaporate = ($0.itemCount == 0 && $0.childCount == 1)
220-
if willEvaporate {
219+
if $0.hasSingletonChild {
220+
// Evaporate node
221221
return .empty(level)
222222
}
223223

Sources/PersistentCollections/Node/_Node+UnsafeHandle.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,12 +280,12 @@ extension _Node.UnsafeHandle {
280280
extension _Node.UnsafeHandle {
281281
@inlinable
282282
internal var hasSingletonItem: Bool {
283-
itemCount == 1 && childCount == 0
283+
_header.pointee.hasSingletonItem
284284
}
285285

286286
@inlinable
287287
internal var hasSingletonChild: Bool {
288-
itemMap.isEmpty && childCount == 1
288+
_header.pointee.hasSingletonChild
289289
}
290290

291291
@inlinable

Sources/PersistentCollections/Node/_StorageHeader.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,19 @@ extension _StorageHeader {
8787
: itemMap.count)
8888
}
8989

90+
@inlinable
91+
internal var hasSingletonChild: Bool {
92+
itemMap.isEmpty && childMap.hasExactlyOneMember
93+
}
94+
95+
@inlinable
96+
internal var hasSingletonItem: Bool {
97+
if itemMap == childMap {
98+
return itemMap._value == 1
99+
}
100+
return childMap.isEmpty && itemMap.hasExactlyOneMember
101+
}
102+
90103
@inlinable @inline(__always)
91104
internal var childrenEndSlot: _Slot {
92105
_Slot(childCount)

0 commit comments

Comments
 (0)