Skip to content

Commit 1913568

Browse files
committed
BTree supports Codable
1 parent 407fda7 commit 1913568

15 files changed

+230
-23
lines changed

Sources/BTree.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,3 +1071,7 @@ extension BTree {
10711071
return suffix(from: start).prefix(through: stop)
10721072
}
10731073
}
1074+
1075+
#if swift(>=4.2)
1076+
extension BTree:Codable where Key: Codable, Value:Codable {}
1077+
#endif

Sources/BTreeIndex.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,9 @@ internal struct BTreeWeakPath<Key: Comparable, Value>: BTreePath {
192192
}
193193
}
194194
}
195+
196+
#if swift(>=4.2)
197+
extension BTreeWeakPath: Codable where Key: Codable, Value: Codable {}
198+
199+
extension BTreeIndex: Codable where Key: Codable, Value: Codable {}
200+
#endif

Sources/BTreeIterator.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public struct BTreeValueIterator<Value>: IteratorProtocol {
5454

5555
/// An iterator for the keys stored in a B-tree without a value.
5656
public struct BTreeKeyIterator<Key: Comparable>: IteratorProtocol {
57-
internal typealias Base = BTreeIterator<Key, Void>
57+
internal typealias Base = BTreeIterator<Key, EmptyValue>
5858
fileprivate var base: Base
5959

6060
internal init(_ base: Base) {
@@ -147,3 +147,15 @@ internal struct BTreeStrongPath<Key: Comparable, Value>: BTreePath {
147147
}
148148
}
149149
}
150+
151+
#if swift(>=4.2)
152+
extension EmptyKey: Codable {}
153+
154+
extension BTreeKeyIterator: Codable where Key: Codable {}
155+
156+
extension BTreeValueIterator: Codable where Value: Codable {}
157+
158+
extension BTreeIterator: Codable where Key: Codable, Value: Codable {}
159+
160+
extension BTreeStrongPath: Codable where Key: Codable, Value: Codable {}
161+
#endif

Sources/BTreeNode.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,3 +611,48 @@ extension BTreeNode {
611611
}
612612
}
613613

614+
#if swift(>=4.2)
615+
extension BTreeNode: Codable where Key: Codable, Value: Codable {
616+
// Swift's tuples do not support Codable yet, so we have to generate this manually
617+
618+
enum CodingKeys: String, CodingKey {
619+
case elements
620+
case children
621+
case count
622+
case _order
623+
case _depth
624+
}
625+
626+
struct Pair<Key: Codable, Value: Codable>: Codable {
627+
var key: Key
628+
var value: Value
629+
init(_ key: Key, _ value: Value) {
630+
self.key = key
631+
self.value = value
632+
}
633+
}
634+
635+
func encode(to encoder: Encoder) throws {
636+
var container = encoder.container(keyedBy: CodingKeys.self)
637+
try container.encode(self.elements.map({Pair($0.0, $0.1)}), forKey: .elements)
638+
try container.encode(children, forKey: .children)
639+
try container.encode(count, forKey: .count)
640+
try container.encode(_order, forKey: ._order)
641+
try container.encode(_depth, forKey: ._depth)
642+
}
643+
644+
convenience init(from decoder: Decoder) throws {
645+
let container = try decoder.container(keyedBy: CodingKeys.self)
646+
let elements = try container.decode(Array<Pair<Key, Value>>.self, forKey: .elements)
647+
let children = try container.decode(Array<BTreeNode<Key, Value>>.self, forKey: .children)
648+
let count = try container.decode(Int.self, forKey: .count)
649+
let _order = try container.decode(Int32.self, forKey: ._order)
650+
let _depth = try container.decode(Int32.self, forKey: ._depth)
651+
assert(_depth == (children.count == 0 ? 0 : children[0]._depth + 1))
652+
self.init(order: numericCast(_order),
653+
elements: elements.map({ ($0.key, $0.value) }),
654+
children: children,
655+
count: count)
656+
}
657+
}
658+
#endif

Sources/List.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,3 +565,7 @@ extension List {
565565
return result
566566
}
567567
}
568+
569+
#if swift(>=4.2)
570+
extension List: Codable where Element: Codable {}
571+
#endif

Sources/Map.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,3 +564,7 @@ extension Map {
564564
return excluding(SortedSet(keys))
565565
}
566566
}
567+
568+
#if swift(>=4.2)
569+
extension Map: Codable where Key: Codable, Value: Codable {}
570+
#endif

Sources/SortedBag.swift

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
///
2525
/// - SeeAlso: `SortedSet`
2626
public struct SortedBag<Element: Comparable>: SetAlgebra {
27-
internal typealias Tree = BTree<Element, Void>
27+
internal typealias Tree = BTree<Element, EmptyValue>
2828

2929
/// The b-tree that serves as storage.
3030
internal fileprivate(set) var tree: Tree
@@ -54,15 +54,15 @@ extension SortedBag {
5454
///
5555
/// - Complexity: O(*n* * log(*n*)), where *n* is the number of items in the sequence.
5656
public init<S: Sequence>(_ elements: S) where S.Element == Element {
57-
self.init(Tree(sortedElements: elements.sorted().lazy.map { ($0, ()) }, dropDuplicates: false))
57+
self.init(Tree(sortedElements: elements.sorted().lazy.map { ($0, EmptyValue.def) }, dropDuplicates: false))
5858
}
5959

6060
/// Create a bag from a sorted finite sequence of items.
6161
/// If the sequence contains duplicate items, all of them are kept.
6262
///
6363
/// - Complexity: O(*n*), where *n* is the number of items in the sequence.
6464
public init<S: Sequence>(sortedElements elements: S) where S.Element == Element {
65-
self.init(Tree(sortedElements: elements.lazy.map { ($0, ()) }, dropDuplicates: false))
65+
self.init(Tree(sortedElements: elements.lazy.map { ($0, EmptyValue.def) }, dropDuplicates: false))
6666
}
6767

6868
/// Create a bag with the specified list of items.
@@ -75,7 +75,7 @@ extension SortedBag {
7575
extension SortedBag: BidirectionalCollection {
7676
//MARK: CollectionType
7777

78-
public typealias Index = BTreeIndex<Element, Void>
78+
public typealias Index = BTreeIndex<Element, EmptyValue>
7979
public typealias Iterator = BTreeKeyIterator<Element>
8080
public typealias SubSequence = SortedBag<Element>
8181

@@ -442,7 +442,7 @@ extension SortedBag {
442442
/// Returns the index of the first instance of a given member, or `nil` if the member is not present in the bag.
443443
///
444444
/// - Complexity: O(log(`count`))
445-
public func index(of member: Element) -> BTreeIndex<Element, Void>? {
445+
public func index(of member: Element) -> BTreeIndex<Element, EmptyValue>? {
446446
return tree.index(forKey: member, choosing: .first)
447447
}
448448

@@ -451,7 +451,7 @@ extension SortedBag {
451451
/// This function never returns `endIndex`. (If it returns non-nil, the returned index can be used to subscript the bag.)
452452
///
453453
/// - Complexity: O(log(`count`))
454-
public func indexOfFirstElement(after element: Element) -> BTreeIndex<Element, Void>? {
454+
public func indexOfFirstElement(after element: Element) -> BTreeIndex<Element, EmptyValue>? {
455455
let index = tree.index(forInserting: element, at: .last)
456456
if tree.offset(of: index) == tree.count { return nil }
457457
return index
@@ -462,7 +462,7 @@ extension SortedBag {
462462
/// This function never returns `endIndex`. (If it returns non-nil, the returned index can be used to subscript the bag.)
463463
///
464464
/// - Complexity: O(log(`count`))
465-
public func indexOfFirstElement(notBefore element: Element) -> BTreeIndex<Element, Void>? {
465+
public func indexOfFirstElement(notBefore element: Element) -> BTreeIndex<Element, EmptyValue>? {
466466
let index = tree.index(forInserting: element, at: .first)
467467
if tree.offset(of: index) == tree.count { return nil }
468468
return index
@@ -473,7 +473,7 @@ extension SortedBag {
473473
/// This function never returns `endIndex`. (If it returns non-nil, the returned index can be used to subscript the bag.)
474474
///
475475
/// - Complexity: O(log(`count`))
476-
public func indexOfLastElement(before element: Element) -> BTreeIndex<Element, Void>? {
476+
public func indexOfLastElement(before element: Element) -> BTreeIndex<Element, EmptyValue>? {
477477
var index = tree.index(forInserting: element, at: .first)
478478
if tree.offset(of: index) == 0 { return nil }
479479
tree.formIndex(before: &index)
@@ -485,7 +485,7 @@ extension SortedBag {
485485
/// This function never returns `endIndex`. (If it returns non-nil, the returned index can be used to subscript the bag.)
486486
///
487487
/// - Complexity: O(log(`count`))
488-
public func indexOfLastElement(notAfter element: Element) -> BTreeIndex<Element, Void>? {
488+
public func indexOfLastElement(notAfter element: Element) -> BTreeIndex<Element, EmptyValue>? {
489489
var index = tree.index(forInserting: element, at: .last)
490490
if tree.offset(of: index) == 0 { return nil }
491491
tree.formIndex(before: &index)
@@ -600,7 +600,7 @@ extension SortedBag {
600600
/// - Complexity: O(log(`count`))
601601
@discardableResult
602602
public mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element) {
603-
tree.insert((newMember, ()), at: .after)
603+
tree.insert((newMember, EmptyValue.def), at: .after)
604604
return (true, newMember)
605605
}
606606

@@ -617,7 +617,7 @@ extension SortedBag {
617617
/// - Returns: Always returns `nil`, to satisfy the syntactic requirements of the `SetAlgebra` protocol.
618618
@discardableResult
619619
public mutating func update(with newMember: Element) -> Element? {
620-
tree.insert((newMember, ()), at: .first)
620+
tree.insert((newMember, EmptyValue.def), at: .first)
621621
return nil
622622
}
623623
}
@@ -984,3 +984,7 @@ extension SortedBag where Element: Strideable {
984984
}
985985

986986
}
987+
988+
#if swift(>=4.2)
989+
extension SortedBag: Codable where Element: Codable {}
990+
#endif

Sources/SortedSet.swift

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
///
2121
/// - SeeAlso: `SortedBag`
2222
public struct SortedSet<Element: Comparable>: SetAlgebra {
23-
internal typealias Tree = BTree<Element, Void>
23+
internal typealias Tree = BTree<Element, EmptyValue>
2424

2525
/// The b-tree that serves as storage.
2626
internal fileprivate(set) var tree: Tree
@@ -43,15 +43,15 @@ extension SortedSet {
4343
///
4444
/// - Complexity: O(*n* * log(*n*)), where *n* is the number of items in the sequence.
4545
public init<S: Sequence>(_ elements: S) where S.Element == Element {
46-
self.init(Tree(sortedElements: elements.sorted().lazy.map { ($0, ()) }, dropDuplicates: true))
46+
self.init(Tree(sortedElements: elements.sorted().lazy.map { ($0, EmptyValue.def) }, dropDuplicates: true))
4747
}
4848

4949
/// Create a set from a sorted finite sequence of items.
5050
/// If the sequence contains duplicate items, only the last instance will be kept in the set.
5151
///
5252
/// - Complexity: O(*n*), where *n* is the number of items in the sequence.
5353
public init<S: Sequence>(sortedElements elements: S) where S.Element == Element {
54-
self.init(Tree(sortedElements: elements.lazy.map { ($0, ()) }, dropDuplicates: true))
54+
self.init(Tree(sortedElements: elements.lazy.map { ($0, EmptyValue.def) }, dropDuplicates: true))
5555
}
5656

5757
/// Create a set with the specified list of items.
@@ -64,7 +64,7 @@ extension SortedSet {
6464
extension SortedSet: BidirectionalCollection {
6565
//MARK: CollectionType
6666

67-
public typealias Index = BTreeIndex<Element, Void>
67+
public typealias Index = BTreeIndex<Element, EmptyValue>
6868
public typealias Iterator = BTreeKeyIterator<Element>
6969
public typealias SubSequence = SortedSet<Element>
7070

@@ -420,7 +420,7 @@ extension SortedSet {
420420
/// Returns the index of a given member, or `nil` if the member is not present in the set.
421421
///
422422
/// - Complexity: O(log(`count`))
423-
public func index(of member: Element) -> BTreeIndex<Element, Void>? {
423+
public func index(of member: Element) -> BTreeIndex<Element, EmptyValue>? {
424424
return tree.index(forKey: member)
425425
}
426426

@@ -429,7 +429,7 @@ extension SortedSet {
429429
/// This function never returns `endIndex`. (If it returns non-nil, the returned index can be used to subscript the set.)
430430
///
431431
/// - Complexity: O(log(`count`))
432-
public func indexOfFirstElement(after element: Element) -> BTreeIndex<Element, Void>? {
432+
public func indexOfFirstElement(after element: Element) -> BTreeIndex<Element, EmptyValue>? {
433433
let index = tree.index(forInserting: element, at: .last)
434434
if tree.offset(of: index) == tree.count { return nil }
435435
return index
@@ -440,7 +440,7 @@ extension SortedSet {
440440
/// This function never returns `endIndex`. (If it returns non-nil, the returned index can be used to subscript the set.)
441441
///
442442
/// - Complexity: O(log(`count`))
443-
public func indexOfFirstElement(notBefore element: Element) -> BTreeIndex<Element, Void>? {
443+
public func indexOfFirstElement(notBefore element: Element) -> BTreeIndex<Element, EmptyValue>? {
444444
let index = tree.index(forInserting: element, at: .first)
445445
if tree.offset(of: index) == tree.count { return nil }
446446
return index
@@ -451,7 +451,7 @@ extension SortedSet {
451451
/// This function never returns `endIndex`. (If it returns non-nil, the returned index can be used to subscript the set.)
452452
///
453453
/// - Complexity: O(log(`count`))
454-
public func indexOfLastElement(before element: Element) -> BTreeIndex<Element, Void>? {
454+
public func indexOfLastElement(before element: Element) -> BTreeIndex<Element, EmptyValue>? {
455455
var index = tree.index(forInserting: element, at: .first)
456456
if tree.offset(of: index) == 0 { return nil }
457457
tree.formIndex(before: &index)
@@ -463,7 +463,7 @@ extension SortedSet {
463463
/// This function never returns `endIndex`. (If it returns non-nil, the returned index can be used to subscript the set.)
464464
///
465465
/// - Complexity: O(log(`count`))
466-
public func indexOfLastElement(notAfter element: Element) -> BTreeIndex<Element, Void>? {
466+
public func indexOfLastElement(notAfter element: Element) -> BTreeIndex<Element, EmptyValue>? {
467467
var index = tree.index(forInserting: element, at: .last)
468468
if tree.offset(of: index) == 0 { return nil }
469469
tree.formIndex(before: &index)
@@ -572,7 +572,7 @@ extension SortedSet {
572572
/// - Complexity: O(log(`count`))
573573
@discardableResult
574574
public mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element) {
575-
guard let old = tree.insertOrFind((newMember, ())) else {
575+
guard let old = tree.insertOrFind((newMember, EmptyValue.def)) else {
576576
return (true, newMember)
577577
}
578578
return (false, old.0)
@@ -589,7 +589,7 @@ extension SortedSet {
589589
/// comparison or some other means.
590590
@discardableResult
591591
public mutating func update(with newMember: Element) -> Element? {
592-
return tree.insertOrReplace((newMember, ()))?.0
592+
return tree.insertOrReplace((newMember, EmptyValue.def))?.0
593593
}
594594
}
595595

@@ -910,3 +910,17 @@ extension SortedSet where Element: Strideable {
910910
}
911911
}
912912
}
913+
914+
// Swift Void is not codable, and having 2 Codable extensions is not allowed
915+
// for BTree<Codable, Codable> and for BTree<Codable, Void>
916+
//
917+
// thus the need for EmptyValue
918+
public struct EmptyValue {
919+
static let def = EmptyValue()
920+
}
921+
922+
#if swift(>=4.2)
923+
extension EmptyValue: Codable {}
924+
925+
extension SortedSet: Codable where Element: Codable {}
926+
#endif

Sources/Weak.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ internal struct Weak<T: AnyObject> {
1313
self.value = value
1414
}
1515
}
16+
17+
#if swift(>=4.2)
18+
extension Weak: Codable where T: Codable {}
19+
#endif

Tests/BTreeTests/BTreeNodeTests.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,4 +492,22 @@ class BTreeNodeTests: XCTestCase {
492492
node.assertValid()
493493
assertEqualElements(node, (0..<100).map { (0, $0) })
494494
}
495+
496+
#if swift(>=4.2)
497+
func testCanBeCodedDecoded() {
498+
let node = maximalNode(depth: 1, order: 5)
499+
let encoder = PropertyListEncoder()
500+
guard let data = try? encoder.encode(node) else {
501+
XCTFail("failed encode")
502+
return
503+
}
504+
let decoder = PropertyListDecoder()
505+
guard let decodedNode = try? decoder.decode(Node.self, from: data) else {
506+
XCTFail("failed decode")
507+
return
508+
}
509+
assertEqualElements(IteratorSequence(decodedNode.makeIterator()),
510+
IteratorSequence(node.makeIterator()))
511+
}
512+
#endif
495513
}

Tests/BTreeTests/BTreeTests.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,4 +1236,22 @@ class BTreeTests: XCTestCase {
12361236
tree.assertValid()
12371237
assertEqualElements(tree, [(0, "0*"), (1, "1*"), (2, "2*"), (3, "3*"), (4, "4*")])
12381238
}
1239+
1240+
#if swift(>=4.2)
1241+
func testCanBeCodedDecoded() {
1242+
let tree = Tree(minimalTree(depth: 2, order: 5))
1243+
let encoder = PropertyListEncoder()
1244+
guard let data = try? encoder.encode(tree) else {
1245+
XCTFail("failed encode")
1246+
return
1247+
}
1248+
let decoder = PropertyListDecoder()
1249+
guard let decodedTree = try? decoder.decode(Tree.self, from: data) else {
1250+
XCTFail("failed decode")
1251+
return
1252+
}
1253+
assertEqualElements(IteratorSequence(decodedTree.makeIterator()),
1254+
IteratorSequence(tree.makeIterator()))
1255+
}
1256+
#endif
12391257
}

0 commit comments

Comments
 (0)