-
Notifications
You must be signed in to change notification settings - Fork 309
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ART: Adaptive Radix Tree implementation #307
Draft
vishesh
wants to merge
67
commits into
apple:main
Choose a base branch
from
vishesh:develop-artree
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
67 commits
Select commit
Hold shift + click to select a range
8a54021
ART: Adaptive Radix Tree implementation
vishesh b6c1de1
Add license headers
vishesh 66a6727
Use ManagedBuffer for underlying storage
vishesh 5346d29
Fix test formatting
vishesh dd98a04
Add FixedArray type using tuples
vishesh 3fd67ac
Fixed some test case formatting
vishesh 21ebcb6
Make NodeLeaf follow ManagedBuffer semantics
vishesh 579aabe
Remove Header pointer
vishesh 8d3a75d
Initialize and bindMemory properly
vishesh f52d685
Update size test
vishesh 0ed8b2b
Some refactor, cleanup and regression fixes
vishesh 69ca513
Iterate empty tree
vishesh 439c6a1
Remove some TODO's
vishesh 91e2c7c
Move around and some cleanup
vishesh f9a5452
Fix deletion when node4/16 is full
vishesh 4174087
Cleanup some NodeLeaf generic and some warnings
vishesh accbd63
Replace unsafe parent updating in delete functions
vishesh 8ade1e4
Replace unsafe update of parent in insertion
vishesh 8634916
Fix warnings
vishesh 79e1966
Make insert work, but still using unsafe ChildSlotPtr
vishesh 9d313d1
Removed unused `child(at: .., ref: ...)` methods
vishesh 5d76b25
Don't use ChildSlotPtr out as InternalNode method params directly
vishesh 1ce7b8f
Break ARTree.insert into two parts
vishesh 4d5a9c9
Use Node.rawNode instead of constructor
vishesh dd52ccb
Add NodeReference type to avoid exposing pointer directly
vishesh 784b788
Generalize Tree a bit more
vishesh e29d1da
Refactor ARTree into ARTreeImpl
vishesh 2de02bd
Rename ChildSlotRef to RawNode.SlotRef
vishesh cdecdd1
Retain refcounts when expanding/shrinking to a new node
vishesh 485f91a
Add clone() method to ManagedNodes
vishesh e95ea5f
Copy-on-write for inserts and delete
vishesh 06255c0
Remove some warnings
vishesh 32db022
Remove some redundant constructors
vishesh 6cc2899
Use UnmanagedStorage for Node* functions
vishesh 0953a32
Start adding tests for checking if we optimizing for unique reference…
vishesh da71164
Enforce no-copy for copy in unique tree/subtree inserts
vishesh 0ff4d4c
Add optional printaddress to string description
vishesh 30bbb36
Add some test cases for delete
vishesh 6ab1b17
Start writing some documentation
vishesh 5cdc9a5
Move things around
vishesh 602b4c5
Check unique references for delete
vishesh 3831595
Format ARTree
vishesh 9e7c5f9
Rename some private variables
vishesh 7046527
Add CMakeLists.txt
vishesh 6e065aa
Add some more tests
vishesh 17604fb
Add few test and fixed a bug when setting partial length
vishesh 5fa86d5
Refactor to use getters
vishesh 7641a5a
Implement replace when inserting
vishesh e6fc5b7
Add some refcounting tests
vishesh d0c680e
More testing
vishesh 9f74116
Move ARTree into separate submodule
vishesh 1490717
Add support for unsigned integers and RadixTree type
vishesh f7d27b1
Support signed integer
vishesh bd143f9
Reorganize some tests
vishesh a67393a
Reorganize some files
vishesh c9578a2
Remove old FixedArray implementation
vishesh 27bfed1
Add README
vishesh 6ecc661
Rename FixedStorage to FixedArrayStorage
vishesh 1b74fbc
Supress some warnings
vishesh 6ef8f08
Use collection test library
vishesh 5b18390
change testRefCountBasic
vishesh 79abfd9
Fix IntMapTest unique number generation
vishesh 46f2054
Add String as BinaryComparableBytes
vishesh cf652bc
Add subscript and dictionary literal
vishesh 562a42c
Some documentation
vishesh 2613cb2
More documentation
vishesh 1cf3b88
WIP on Collection protocol
vishesh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Swift Collections open source project | ||
// | ||
// Copyright (c) 2023 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
@available(macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4, *) | ||
extension ARTreeImpl { | ||
var startIndex: Index { | ||
var idx = Index(forTree: self) | ||
idx.descentToLeftMostChild() | ||
return idx | ||
} | ||
|
||
var endIndex: Index { | ||
return Index(forTree: self) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) 2023 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
@available(macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4, *) | ||
extension ARTreeImpl: Sequence { | ||
public typealias Iterator = _Iterator | ||
|
||
public struct _Iterator { | ||
typealias _ChildIndex = InternalNode<Spec>.Index | ||
|
||
private let tree: ARTreeImpl<Spec> | ||
private var path: [(any InternalNode<Spec>, _ChildIndex)] | ||
|
||
init(tree: ARTreeImpl<Spec>) { | ||
self.tree = tree | ||
self.path = [] | ||
guard let node = tree._root else { return } | ||
|
||
assert(node.type != .leaf, "root can't be leaf") | ||
let n: any InternalNode<Spec> = node.toInternalNode() | ||
if n.count > 0 { | ||
self.path = [(n, n.startIndex)] | ||
} | ||
} | ||
} | ||
|
||
public func makeIterator() -> Iterator { | ||
return Iterator(tree: self) | ||
} | ||
} | ||
|
||
// TODO: Instead of index, use node iterators, to advance to next child. | ||
@available(macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4, *) | ||
extension ARTreeImpl._Iterator: IteratorProtocol { | ||
public typealias Element = (Key, Spec.Value) // TODO: Why just Value fails? | ||
|
||
// Exhausted childs on the tip of path. Forward to sibling. | ||
mutating private func advanceToSibling() { | ||
let _ = path.popLast() | ||
advanceToNextChild() | ||
} | ||
|
||
mutating private func advanceToNextChild() { | ||
guard let (node, index) = path.popLast() else { | ||
return | ||
} | ||
|
||
path.append((node, node.index(after: index))) | ||
} | ||
|
||
mutating func next() -> Element? { | ||
while !path.isEmpty { | ||
while let (node, index) = path.last { | ||
if index == node.endIndex { | ||
advanceToSibling() | ||
break | ||
} | ||
|
||
let next = node.child(at: index)! | ||
if next.type == .leaf { | ||
let leaf: NodeLeaf<Spec> = next.toLeafNode() | ||
let result = (leaf.key, leaf.value) | ||
advanceToNextChild() | ||
return result | ||
} | ||
|
||
let nextNode: any InternalNode<Spec> = next.toInternalNode() | ||
path.append((nextNode, nextNode.startIndex)) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Swift Collections open source project | ||
// | ||
// Copyright (c) 2023 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
@available(macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4, *) | ||
extension ARTreeImpl { | ||
public mutating func delete(key: Key) { | ||
if _root == nil { | ||
return | ||
} | ||
|
||
let isUnique = _root!.isUnique | ||
var child = _root | ||
switch _delete(child: &child, key: key, depth: 0, isUniquePath: isUnique) { | ||
case .noop: | ||
return | ||
case .replaceWith(let newValue): | ||
_root = newValue | ||
} | ||
} | ||
|
||
public mutating func deleteRange(start: Key, end: Key) { | ||
// TODO | ||
fatalError("not implemented") | ||
} | ||
|
||
private mutating func _delete( | ||
child: inout RawNode?, | ||
key: Key, | ||
depth: Int, | ||
isUniquePath: Bool | ||
) -> UpdateResult<RawNode?> { | ||
if child?.type == .leaf { | ||
let leaf: NodeLeaf<Spec> = child!.toLeafNode() | ||
if !leaf.keyEquals(with: key, depth: depth) { | ||
return .noop | ||
} | ||
|
||
return .replaceWith(nil) | ||
} | ||
|
||
assert(!Const.testCheckUnique || isUniquePath, "unique path is expected in this test") | ||
var node: any InternalNode<Spec> = child!.toInternalNode() | ||
var newDepth = depth | ||
|
||
if node.partialLength > 0 { | ||
let matchedBytes = node.prefixMismatch(withKey: key, fromIndex: depth) | ||
assert(matchedBytes <= node.partialLength) | ||
newDepth += matchedBytes | ||
} | ||
|
||
return node.updateChild(forKey: key[newDepth], isUniquePath: isUniquePath) { | ||
var child = $0 | ||
return _delete(child: &child, key: key, depth: newDepth + 1, isUniquePath: $1) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Swift Collections open source project | ||
// | ||
// Copyright (c) 2023 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
@available(macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4, *) | ||
extension ARTreeImpl { | ||
public func getValue(key: Key) -> Value? { | ||
var current = _root | ||
var depth = 0 | ||
while depth <= key.count { | ||
guard let _rawNode = current else { | ||
return nil | ||
} | ||
|
||
if _rawNode.type == .leaf { | ||
let leaf: NodeLeaf<Spec> = _rawNode.toLeafNode() | ||
return leaf.keyEquals(with: key) | ||
? leaf.value | ||
: nil | ||
} | ||
|
||
let node: any InternalNode<Spec> = _rawNode.toInternalNode() | ||
if node.partialLength > 0 { | ||
let prefixLen = node.prefixMismatch(withKey: key, fromIndex: depth) | ||
assert(prefixLen <= Const.maxPartialLength, "partial length is always bounded") | ||
if prefixLen != node.partialLength { | ||
return nil | ||
} | ||
depth = depth + node.partialLength | ||
} | ||
|
||
current = node.child(forKey: key[depth]) | ||
depth += 1 | ||
} | ||
|
||
return nil | ||
} | ||
|
||
public mutating func getRange(start: Key, end: Key) { | ||
// TODO | ||
fatalError("not implemented") | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this right?