Skip to content

Commit

Permalink
Merge pull request #177 from lorentey/PersistentCollections-updates
Browse files Browse the repository at this point in the history
Persistent collections updates (part 4)
  • Loading branch information
lorentey authored Sep 16, 2022
2 parents 9b9d877 + 9d9659a commit a205397
Show file tree
Hide file tree
Showing 42 changed files with 1,849 additions and 1,573 deletions.
1 change: 0 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ let package = Package(

.target(
name: "_CollectionsUtilities",
exclude: ["CMakeLists.txt"],
swiftSettings: settings),

// Deque<Element>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,25 @@ extension _Bitmap: Equatable {
}
}

extension _Bitmap: CustomStringConvertible {
@usableFromInline
internal var description: String {
let b = String(_value, radix: 2)
let bits = String(repeating: "0", count: _Bitmap.capacity - b.count) + b
return "\(String(bits.reversed())) (\(_value))"
}
}

extension _Bitmap {
@inlinable @inline(__always)
internal static var empty: Self { .init(_value: 0) }

@inlinable @inline(__always)
internal static var capacity: Int { Value.bitWidth }

@inlinable @inline(__always)
internal static var bitWidth: Int { capacity.trailingZeroBitCount }

@inlinable @inline(__always)
internal var count: Int { _value.nonzeroBitCount }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ internal struct _Bucket {
internal var value: UInt

@inlinable @inline(__always)
internal init(_ value: UInt) { self.value = value }
internal init(_ value: UInt) {
assert(value < _Bitmap.capacity || value == .max)
self.value = value
}
}

extension _Bucket {
@inlinable @inline(__always)
static var bitWidth: Int { _Bitmap.capacity.trailingZeroBitCount }

Expand All @@ -28,6 +33,9 @@ internal struct _Bucket {

@inlinable @inline(__always)
static var invalid: _Bucket { _Bucket(.max) }

@inlinable @inline(__always)
var isInvalid: Bool { value == .max }
}

extension _Bucket: Equatable {
Expand All @@ -43,3 +51,10 @@ extension _Bucket: Comparable {
left.value < right.value
}
}

extension _Bucket: CustomStringConvertible {
@usableFromInline
internal var description: String {
String(value, radix: _Bitmap.capacity)
}
}
89 changes: 89 additions & 0 deletions Sources/PersistentCollections/Node/_Hash.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Collections open source project
//
// Copyright (c) 2022 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
//
//===----------------------------------------------------------------------===//

/// An abstract representation of a hash value.
@usableFromInline
@frozen
internal struct _Hash {
@usableFromInline
internal var value: UInt

@inlinable
internal init<Key: Hashable>(_ key: Key) {
let hashValue = key._rawHashValue(seed: 0)
self.value = UInt(bitPattern: hashValue)
}

@inlinable
internal init(_value: UInt) {
self.value = _value
}
}

extension _Hash: Equatable {
@inlinable @inline(__always)
internal static func ==(left: Self, right: Self) -> Bool {
left.value == right.value
}
}

extension _Hash: CustomStringConvertible {
@usableFromInline
internal var description: String {
// Print hash values in radix 32 & reversed, so that the path in the hash
// tree is readily visible.
let p = String(value, radix: _Bitmap.capacity, uppercase: true)
let c = _Level.limit
let path = String(repeating: "0", count: Swift.max(0, c - p.count)) + p
return String(path.reversed())
}
}


extension _Hash {
@inlinable @inline(__always)
internal static var bitWidth: Int { UInt.bitWidth }
}

extension _Hash {
@inlinable
internal subscript(_ level: _Level) -> _Bucket {
get {
assert(!level.isAtBottom)
return _Bucket((value &>> level.shift) & _Bucket.bitMask)
}
set {
let mask = _Bucket.bitMask &<< level.shift
self.value &= ~mask
self.value |= newValue.value &<< level.shift
}
}
}

extension _Hash {
@inlinable
internal func appending(_ bucket: _Bucket, at level: _Level) -> Self {
assert(value >> level.shift == 0)
var copy = self
copy[level] = bucket
return copy
}

@inlinable
internal func isEqual(to other: _Hash, upTo level: _Level) -> Bool {
if level.isAtRoot { return true }
if level.isAtBottom { return self == other }
let s = UInt(UInt.bitWidth) - level.shift
let v1 = self.value &<< s
let v2 = self.value &<< s
return v1 == v2
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,74 +9,55 @@
//
//===----------------------------------------------------------------------===//

/// An abstract representation of a hash value.
@usableFromInline
@frozen
internal struct _HashValue {
@usableFromInline
internal var value: UInt

@inlinable
internal init<Key: Hashable>(_ key: Key) {
let hashValue = key._rawHashValue(seed: 0)
self.value = UInt(bitPattern: hashValue)
}
}

extension _HashValue: Equatable {
@inlinable @inline(__always)
internal static func ==(left: Self, right: Self) -> Bool {
left.value == right.value
}
}

extension _HashValue {
@inlinable
internal subscript(_ level: _Level) -> _Bucket {
assert(!level.isAtBottom)
return _Bucket((value &>> level.shift) & _Bucket.bitMask)
}
}

@usableFromInline
@frozen
internal struct _Level {
@usableFromInline
internal var shift: UInt

@inlinable
@inlinable @inline(__always)
init(shift: UInt) {
self.shift = shift
}
}

extension _Level {
@inlinable
@inlinable @inline(__always)
internal static var limit: Int {
(_Hash.bitWidth + _Bitmap.bitWidth - 1) / _Bitmap.bitWidth
}

@inlinable @inline(__always)
internal static var _step: UInt {
UInt(bitPattern: _Bitmap.bitWidth)
}

@inlinable @inline(__always)
internal static var top: _Level {
_Level(shift: 0)
}

@inlinable
@inlinable @inline(__always)
internal var isAtRoot: Bool { shift == 0 }

@inlinable
@inlinable @inline(__always)
internal var isAtBottom: Bool { shift >= UInt.bitWidth }

@inlinable
@inlinable @inline(__always)
internal func descend() -> _Level {
// FIXME: Consider returning nil when we run out of bits
_Level(shift: shift &+ UInt(bitPattern: _Bucket.bitWidth))
_Level(shift: shift &+ Self._step)
}

@inlinable
@inlinable @inline(__always)
internal func ascend() -> _Level {
assert(!isAtRoot)
return _Level(shift: shift &+ UInt(bitPattern: _Bucket.bitWidth))
return _Level(shift: shift &+ Self._step)
}
}

extension _Level: Equatable {
@inlinable
@inlinable @inline(__always)
internal static func ==(left: Self, right: Self) -> Bool {
left.shift == right.shift
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//
//===----------------------------------------------------------------------===//

extension PersistentDictionary._Node: CustomStringConvertible {
extension _Node: CustomStringConvertible {
@usableFromInline
internal var description: String {
guard count > 0 else {
Expand All @@ -18,21 +18,23 @@ extension PersistentDictionary._Node: CustomStringConvertible {

var result = "["
var first = true
for (key, value) in _items {
if first {
first = false
} else {
result += ", "
read {
for (key, value) in $0._items {
if first {
first = false
} else {
result += ", "
}
result += "\(key): \(value)"
}
result += "\(key): \(value)"
}
for node in _children {
if first {
first = false
} else {
result += ", "
for child in $0._children {
if first {
first = false
} else {
result += ", "
}
result += "\(child.description)"
}
result += "\(node.description)"
}
result += "]"
return result
Expand Down
82 changes: 82 additions & 0 deletions Sources/PersistentCollections/Node/_Node+Debugging.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Collections open source project
//
// Copyright (c) 2022 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
//
//===----------------------------------------------------------------------===//

import _CollectionsUtilities

extension _Node {
@usableFromInline
internal func dump(
firstPrefix: String = "", restPrefix: String = "", limit: Int = Int.max
) {
read {
$0.dump(
firstPrefix: firstPrefix,
restPrefix: restPrefix,
extra: "count: \(count), ",
limit: limit)
}
}
}

extension _Node.Storage {
@usableFromInline
final internal func dump() {
UnsafeHandle.read(self) { $0.dump() }
}
}

extension _Node.UnsafeHandle {
@usableFromInline
internal func dump(
firstPrefix: String = "",
restPrefix: String = "",
extra: String = "",
limit: Int = Int.max
) {
print("""
\(firstPrefix)\(isCollisionNode ? "CollisionNode" : "Node")(\
at: \(_addressString(for: _header)), \
\(extra)\
byteCapacity: \(byteCapacity), \
freeBytes: \(bytesFree))
""")
guard limit > 0 else { return }
if isCollisionNode {
let items = self._items
for offset in items.indices {
let item = items[offset]
let hash = _Hash(item.key).description
let itemStr = "hash: \(hash), key: \(item.key), value: \(item.value)"
print("\(restPrefix) \(offset): \(itemStr)")
}
} else {
var itemOffset = 0
var childOffset = 0
for b in 0 ..< UInt(_Bitmap.capacity) {
let bucket = _Bucket(b)
let bucketStr = "#\(String(b, radix: _Bitmap.capacity, uppercase: true))"
if itemMap.contains(bucket) {
let item = self[item: itemOffset]
let hash = _Hash(item.key).description
let itemStr = "hash: \(hash), key: \(item.key), value: \(item.value)"
print("\(restPrefix) \(bucketStr) \(itemStr)")
itemOffset += 1
} else if childMap.contains(bucket) {
self[child: childOffset].dump(
firstPrefix: "\(restPrefix) \(bucketStr) ",
restPrefix: "\(restPrefix) ",
limit: limit - 1)
childOffset += 1
}
}
}
}
}
Loading

0 comments on commit a205397

Please sign in to comment.