A collection of open-source components for the iPhone SDK

iOS-app template with lots of common tasks solved

Objective-C wrapper for the iOS Keychain

iPhone app to view the RedUser forum

A delightful iOS and OS X networking framework

Model and repository framework

API Documentation for GitHub

Re-creation of the Gauges iPhone app

A ruby clone of Apple's autoingestion tool for iTunes Connect reports

pull request commentapple/swift-collections

Add a min-max heap implementation that can be used to back a priority queue

@lorentey Any update on when you might be able to look at this? 🙏

comment created time in 19 hours

startedBLAKE3-team/BLAKE3

started time in 4 days

startedgoogle/filament

started time in 9 days

startedmvt-project/mvt

started time in 10 days

startedrust-crdt/rust-crdt

started time in 10 days

pull request commentapple/swift-collections

Add a min-max heap implementation that can be used to back a priority queue

@kylemacomber How do you want to handle this? The code was already mostly reviewed in the other PR; should @timvermeulen take another look?

Also, do we want to merge this into `main`

or into a `priority-queue`

branch?

comment created time in 11 days

Pull request review commentapple/swift-collections

Add a min-max heap implementation that can be used to back a priority queue

+# Heap++A partially-ordered tree of elements with performant insertion and removal operations.++## Declaration++```swift+public struct Heap<Element: Comparable>+```++## Overview++Array-backed [binary heaps](https://en.wikipedia.org/wiki/Heap_(data_structure)) provide performant lookups (`O(1)`) of the smallest or largest element (depending on whether it's a min-heap or a max-heap, respectively) as well as insertion and removal (`O(log n)`). Heaps are commonly used as the backing storage for a priority queue.++A variant on this, the [min-max heap](https://en.wikipedia.org/wiki/Min-max_heap), allows for performant lookups and removal of both the smallest **and** largest elements by interleaving min and max levels in the backing array. `Heap` is an implementation of a min-max heap.++### Initialization++There are a couple of options for initializing a `Heap`. To create an empty `Heap`, call `init()`:++```swift+var heap = Heap<Int>()+```++You can also create a `Heap` from an existing sequence in linear time:++```swift+var heap = Heap((1...).prefix(20))+```++Finally, a `Heap` can be created from an array literal:++```swift+var heap: Heap<Double> = [0.1, 0.6, 1.0, 0.15, 0.42]+```++### Insertion++#### Of a single element++To insert an element into a `Heap`, call `insert(_:)`:++```swift+var heap = Heap<Int>()+heap.insert(6)+heap.insert(2)+```++This works by adding the new element into the end of the backing array and then bubbling it up to where it belongs in the heap.++#### Of a sequence of elements++You can also insert a sequence of elements into a `Heap`:++```swift+var heap = Heap((0..<10))+heap.insert(contentsOf: (20...100).shuffled())+heap.insert(contentsOf: [-5, -6, -8, -12, -3])+```++### Lookup++As mentioned earlier, the smallest and largest elements can be queried in constant time:++```swift+var heap = Heap((1...20))+let min = heap.min() // min = 1+let max = heap.max() // max = 20+```++In a min-max heap, the smallest element is stored at index 0 in the backing array; the largest element is stored at either index 1 or index 2, the first max level in the heap (so to look up the largest, we compare the two and return the larger one).++We also expose a read-only view into the backing array, should somebody need that.++```swift+let heap = Heap((1...100).shuffled())+for val in heap.unordered {+ ...+}+```++> Note: The elements aren't _arbitrarily_ ordered (it is, after all, a heap). However, no guarantees are given as to the ordering of the elements or that this won't change in future versions of the library.++### Removal++Removal has logarithmic complexity, and removing both the smallest and largest elements is supported:++```swift+var heap = Heap((1...20).shuffled())+var heap2 = heap++while let min = heap.popMin() {+ print("Next smallest element:", min)+}++while let max = heap2.popMax() {+ print("Next largest element:", max)+}+```++To remove the smallest element, we remove and return the element at index 0. The element at the end of the backing array is put in its place at index 0, and then we trickle it down to where it belongs in the heap. To remove the largest element, we do the same except the index is whatever the index of the largest element is (see above) instead of 0.++We also have non-optional flavors that assume the queue isn't empty, `removeMin()` and `removeMax()`.++### Iteration++`Heap` itself doesn't conform to `Sequence` because of the potential confusion around which direction it should iterate (largest-to-smallest? smallest-to-largest?). Instead, we expose two iterators that conform to `Sequence`:++```swift+for val in heap.ascending {+ ...+}++for val in heap.descending {+ ...+}+```++### Performance

Added

comment created time in 11 days

push eventAquaGeek/swift-collections

commit sha a6a698f7e89599852cf23a25ff4cbb510f8d6351

Add heap performance graph

push time in 11 days

startedValveSoftware/steamlink-sdk

started time in 13 days

startedbors-ng/bors-ng

started time in 13 days

Pull request review commentapple/swift-collections

Add a min-max heap implementation that can be used to back a priority queue

+# Heap++A partially-ordered tree of elements with performant insertion and removal operations.++## Declaration++```swift+public struct Heap<Element: Comparable>+```++## Overview++Array-backed [binary heaps](https://en.wikipedia.org/wiki/Heap_(data_structure)) provide performant lookups (`O(1)`) of the smallest or largest element (depending on whether it's a min-heap or a max-heap, respectively) as well as insertion and removal (`O(log n)`). Heaps are commonly used as the backing storage for a priority queue.++A variant on this, the [min-max heap](https://en.wikipedia.org/wiki/Min-max_heap), allows for performant lookups and removal of both the smallest **and** largest elements by interleaving min and max levels in the backing array. `Heap` is an implementation of a min-max heap.++### Initialization++There are a couple of options for initializing a `Heap`. To create an empty `Heap`, call `init()`:++```swift+var heap = Heap<Int>()+```++You can also create a `Heap` from an existing sequence in linear time:++```swift+var heap = Heap((1...).prefix(20))+```++Finally, a `Heap` can be created from an array literal:++```swift+var heap: Heap<Double> = [0.1, 0.6, 1.0, 0.15, 0.42]+```++### Insertion++#### Of a single element++To insert an element into a `Heap`, call `insert(_:)`:++```swift+var heap = Heap<Int>()+heap.insert(6)+heap.insert(2)+```++This works by adding the new element into the end of the backing array and then bubbling it up to where it belongs in the heap.++#### Of a sequence of elements++You can also insert a sequence of elements into a `Heap`:++```swift+var heap = Heap((0..<10))+heap.insert(contentsOf: (20...100).shuffled())+heap.insert(contentsOf: [-5, -6, -8, -12, -3])+```++### Lookup++As mentioned earlier, the smallest and largest elements can be queried in constant time:++```swift+var heap = Heap((1...20))+let min = heap.min() // min = 1+let max = heap.max() // max = 20+```++In a min-max heap, the smallest element is stored at index 0 in the backing array; the largest element is stored at either index 1 or index 2, the first max level in the heap (so to look up the largest, we compare the two and return the larger one).++We also expose a read-only view into the backing array, should somebody need that.++```swift+let heap = Heap((1...100).shuffled())+for val in heap.unordered {+ ...+}+```++> Note: The elements aren't _arbitrarily_ ordered (it is, after all, a heap). However, no guarantees are given as to the ordering of the elements or that this won't change in future versions of the library.++### Removal++Removal has logarithmic complexity, and removing both the smallest and largest elements is supported:++```swift+var heap = Heap((1...20).shuffled())+var heap2 = heap++while let min = heap.popMin() {+ print("Next smallest element:", min)+}++while let max = heap2.popMax() {+ print("Next largest element:", max)+}+```++To remove the smallest element, we remove and return the element at index 0. The element at the end of the backing array is put in its place at index 0, and then we trickle it down to where it belongs in the heap. To remove the largest element, we do the same except the index is whatever the index of the largest element is (see above) instead of 0.++We also have non-optional flavors that assume the queue isn't empty, `removeMin()` and `removeMax()`.++### Iteration++`Heap` itself doesn't conform to `Sequence` because of the potential confusion around which direction it should iterate (largest-to-smallest? smallest-to-largest?). Instead, we expose two iterators that conform to `Sequence`:++```swift+for val in heap.ascending {+ ...+}++for val in heap.descending {+ ...+}+```++### Performance

I added a table with the performance of the various operations. I'll defer to @kylemacomber and @lorentey on the point about performance graphs. I agree that they can be helpful, but I also wonder what the baseline of comparison one would want to see in them — Comparing to `Foundation`

/`Core Foundation`

types? Comparing to C++'s stdlib types? Just average per-element operation time (i.e. only show the graphs for `Heap`

itself)?

comment created time in 14 days

push eventAquaGeek/swift-collections

commit sha 6b5e637163b651926badcf5177f906f78c60e43e

Add table with performance of operations

push time in 14 days

push eventAquaGeek/swift-collections

commit sha 3f041224db788457d3ae068250829f7fb448108d

Add table with performance of operations

push time in 14 days

pull request commentapple/swift-collections

Add a min-max heap implementation that can be used to back a priority queue

I've updated the `CFBinaryHeap`

benchmark. Using raw integers instead of `NSNumber`

s significantly altered the performance comparison. Beyond 256 elements, `CFBinaryHeap`

is faster than `Heap`

for `popMin`

.

comment created time in 14 days

push eventAquaGeek/swift-collections

commit sha a97bca28ee853f1abc572ae291677bc275d0e890

Don't wrap integers in CFBinaryHeap benchmark in NSNumber

commit sha 26d786ae9de6d8a3dea465da57c081408223b2d2

Avoid heap allocation altogether

push time in 14 days

Pull request review commentapple/swift-collections

Add a min-max heap implementation that can be used to back a priority queue

+//===----------------------------------------------------------------------===//+//+// This source file is part of the Swift Collections open source project+//+// Copyright (c) 2021 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 <Foundation/Foundation.h>++#import "BinaryHeap.h"++@implementation BinaryHeap+{+ CFBinaryHeapRef _storage;+}++static const void *HeapRetain(CFAllocatorRef allocator, const void *object)+{+ return CFRetain(object);+}++static void HeapRelease(CFAllocatorRef allocator, const void *object)+{+ CFRelease(object);+}++static CFComparisonResult HeapCompare(const void *lhs, const void *rhs, void *context)+{+ return (CFComparisonResult)[(__bridge id)lhs compare:(__bridge id)rhs];+}++- (instancetype)init+{+ if ((self = [super init]))+ {+ CFBinaryHeapCallBacks callbacks = (CFBinaryHeapCallBacks){+ .version = 0,+ .retain = &HeapRetain,+ .release = &HeapRelease,+ .copyDescription = &CFCopyDescription,+ .compare = &HeapCompare+ };+ _storage = CFBinaryHeapCreate(kCFAllocatorDefault, 0, &callbacks, NULL);+ }++ return self;+}++- (void)dealloc+{+ CFRelease(_storage);+}++- (NSUInteger)count+{+ return CFBinaryHeapGetCount(_storage);+}++- (void)insert:(NSInteger)value+{+ NSNumber *val = @(value);

Ah! Got it — cast the integer to a pointer when inserting and back again when getting the minimum value/doing comparisons. I had assumed we would need to insert a pointer to the integer into the heap (hence my question above), so I started `malloc`

/`free`

ing.

comment created time in 14 days

Pull request review commentapple/swift-collections

Add a min-max heap implementation that can be used to back a priority queue

+//===----------------------------------------------------------------------===//+//+// This source file is part of the Swift Collections open source project+//+// Copyright (c) 2021 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 <Foundation/Foundation.h>++#import "BinaryHeap.h"++@implementation BinaryHeap+{+ CFBinaryHeapRef _storage;+}++static const void *HeapRetain(CFAllocatorRef allocator, const void *object)+{+ return CFRetain(object);+}++static void HeapRelease(CFAllocatorRef allocator, const void *object)+{+ CFRelease(object);+}++static CFComparisonResult HeapCompare(const void *lhs, const void *rhs, void *context)+{+ return (CFComparisonResult)[(__bridge id)lhs compare:(__bridge id)rhs];+}++- (instancetype)init+{+ if ((self = [super init]))+ {+ CFBinaryHeapCallBacks callbacks = (CFBinaryHeapCallBacks){+ .version = 0,+ .retain = &HeapRetain,+ .release = &HeapRelease,+ .copyDescription = &CFCopyDescription,+ .compare = &HeapCompare+ };+ _storage = CFBinaryHeapCreate(kCFAllocatorDefault, 0, &callbacks, NULL);+ }++ return self;+}++- (void)dealloc+{+ CFRelease(_storage);+}++- (NSUInteger)count+{+ return CFBinaryHeapGetCount(_storage);+}++- (void)insert:(NSInteger)value+{+ NSNumber *val = @(value);

(ping, @kylemacomber)

comment created time in 15 days

push eventAquaGeek/swift-collections

commit sha 8d2bf0a372f71ba02e178dcedba4fa215c0849b8

Fix reference to queue in documentation Co-authored-by: Dante Broggi <34220985+Dante-Broggi@users.noreply.github.com>

push time in 18 days

push eventAquaGeek/swift-collections

commit sha b9d53d7c893a35a4dc153a68918fd72e7ab7bd18

Make Heap.Iterator init and direction internal

push time in 21 days

Pull request review commentapple/swift-collections

Add a min-max heap implementation that can be used to back a priority queue

+//===----------------------------------------------------------------------===//+//+// This source file is part of the Swift Collections open source project+//+// Copyright (c) 2021 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 <Foundation/Foundation.h>++#import "BinaryHeap.h"++@implementation BinaryHeap+{+ CFBinaryHeapRef _storage;+}++static const void *HeapRetain(CFAllocatorRef allocator, const void *object)+{+ return CFRetain(object);+}++static void HeapRelease(CFAllocatorRef allocator, const void *object)+{+ CFRelease(object);+}++static CFComparisonResult HeapCompare(const void *lhs, const void *rhs, void *context)+{+ return (CFComparisonResult)[(__bridge id)lhs compare:(__bridge id)rhs];+}++- (instancetype)init+{+ if ((self = [super init]))+ {+ CFBinaryHeapCallBacks callbacks = (CFBinaryHeapCallBacks){+ .version = 0,+ .retain = &HeapRetain,+ .release = &HeapRelease,+ .copyDescription = &CFCopyDescription,+ .compare = &HeapCompare+ };+ _storage = CFBinaryHeapCreate(kCFAllocatorDefault, 0, &callbacks, NULL);+ }++ return self;+}++- (void)dealloc+{+ CFRelease(_storage);+}++- (NSUInteger)count+{+ return CFBinaryHeapGetCount(_storage);+}++- (void)insert:(NSInteger)value+{+ NSNumber *val = @(value);

Wouldn't we need to manually manage the memory for the integers, as the address of `value`

is only valid for the scope of the method?

comment created time in 21 days

Pull request review commentapple/swift-collections

Add a min-max heap implementation that can be used to back a priority queue

+# Heap++A partially-ordered tree of elements with performant insertion and removal operations.++## Declaration++```swift+public struct Heap<Element: Comparable>+```++## Overview++Array-backed [binary heaps](https://en.wikipedia.org/wiki/Heap_(data_structure)) provide performant lookups (`O(1)`) of the smallest or largest element (depending on whether it's a min-heap or a max-heap, respectively) as well as insertion and removal (`O(log n)`). Heaps are commonly used as the backing storage for a priority queue.++A variant on this, the [min-max heap](https://en.wikipedia.org/wiki/Min-max_heap), allows for performant lookups and removal of both the smallest **and** largest elements by interleaving min and max levels in the backing array. `Heap` is an implementation of a min-max heap.++### Initialization++There are a couple of options for initializing a `Heap`. To create an empty `Heap`, call `init()`:++```swift+var heap = Heap<Int>()+```++You can also create a `Heap` from an existing sequence in linear time:++```swift+var heap = Heap((1...).prefix(20))+```++Finally, a `Heap` can be created from an array literal:++```swift+var heap: Heap<Double> = [0.1, 0.6, 1.0, 0.15, 0.42]+```++### Insertion++#### Of a single element++To insert an element into a `Heap`, call `insert(_:)`:++```swift+var heap = Heap<Int>()+heap.insert(6)+heap.insert(2)+```++This works by adding the new element into the end of the backing array and then bubbling it up to where it belongs in the heap.++#### Of a sequence of elements++You can also insert a sequence of elements into a `Heap`:++```swift+var heap = Heap((0..<10))+heap.insert(contentsOf: (20...100).shuffled())+heap.insert(contentsOf: [-5, -6, -8, -12, -3])+```++### Lookup++As mentioned earlier, the smallest and largest elements can be queried in constant time:++```swift+var heap = Heap((1...20))+let min = heap.min() // min = 1+let max = heap.max() // max = 20+```++In a min-max heap, the smallest element is stored at index 0 in the backing array; the largest element is stored at either index 1 or index 2, the first max level in the heap (so to look up the largest, we compare the two and return the larger one).++We also expose a read-only view into the backing array, should somebody need that.++```swift+let heap = Heap((1...100).shuffled())+for val in heap.unordered {+ ...+}+```++> Note: The elements aren't _arbitrarily_ ordered (it is, after all, a heap). However, no guarantees are given as to the ordering of the elements or that this won't change in future versions of the library.++### Removal++Removal has logarithmic complexity, and removing both the smallest and largest elements is supported:++```swift+var heap = Heap((1...20).shuffled())+var heap2 = heap++while let min = heap.popMin() {+ print("Next smallest element:", min)+}++while let max = heap2.popMax() {+ print("Next largest element:", max)+}+```++To remove the smallest element, we remove and return the element at index 0. The element at the end of the backing array is put in its place at index 0, and then we trickle it down to where it belongs in the heap. To remove the largest element, we do the same except the index is whatever the index of the largest element is (see above) instead of 0.++We also have non-optional flavors that assume the queue isn't empty, `removeMin()` and `removeMax()`.++### Iteration++`Heap` itself doesn't conform to `Sequence` because of the potential confusion around which direction it should iterate (largest-to-smallest? smallest-to-largest?). Instead, we expose two iterators that conform to `Sequence`:++```swift+for val in heap.ascending {+ ...+}++for val in heap.descending {+ ...+}+```++### Performance

Ooops. I added that because it was in most of the other docs. I didn't end up filling it in, as it's covered elsewhere in here. Thoughts?

comment created time in 22 days

pull request commentapple/swift-collections

Add a min-max heap implementation that can be used to back a priority queue

OK, `Heap.md`

has been added to the `Documentation`

directory. This should be ready for a full review.

comment created time in 22 days

push eventAquaGeek/swift-collections

commit sha 5eaf6716c531d154ff64ac41abe7dc4781f36bc1

Add documentation for Heap

push time in 22 days

pull request commentapple/swift-collections

Add a priority queue implementation built on top of a min-max heap

@kylemacomber I opened a new PR (#61) with just the `Heap`

(and all the commits leading to that). I figure we can retarget that to a new `priority-queue`

branch if needed. Do we want to do another separate API review for that in the forums, or is the feedback we received from the `PriorityQueue`

API review (and the changes to split the two types apart and loosen the `Comparable`

requirement on the `PriorityQueue`

element type) sufficient?

comment created time in 23 days