profile
viewpoint
If you are wondering where the data of this site comes from, please visit https://api.github.com/users/AquaGeek/events. GitMemory does not store any data, but only uses NGINX to cache data for a period of time. The idea behind GitMemory is simply to give users a better reading experience.

AquaGeek/OpenKit 21

A collection of open-source components for the iPhone SDK

AquaGeek/iOS-boilerplate 4

iOS-app template with lots of common tasks solved

AquaGeek/ObjectiveKeychain 4

Objective-C wrapper for the iOS Keychain

AquaGeek/CodeRED 2

iPhone app to view the RedUser forum

AquaGeek/AFNetworking 1

A delightful iOS and OS X networking framework

AquaGeek/curator 1

Model and repository framework

AquaGeek/develop.github.com 1

API Documentation for GitHub

AquaGeek/Gauges 1

Re-creation of the Gauges iPhone app

AquaGeek/itunesconnect 1

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? 🙏

AquaGeek

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?

AquaGeek

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

AquaGeek

comment created time in 11 days

PullRequestReviewEvent

push eventAquaGeek/swift-collections

Tyler Stromberg

commit sha a6a698f7e89599852cf23a25ff4cbb510f8d6351

Add heap performance graph

view details

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)?

AquaGeek

comment created time in 14 days

PullRequestReviewEvent

push eventAquaGeek/swift-collections

Tyler Stromberg

commit sha 6b5e637163b651926badcf5177f906f78c60e43e

Add table with performance of operations

view details

push time in 14 days

push eventAquaGeek/swift-collections

Tyler Stromberg

commit sha 3f041224db788457d3ae068250829f7fb448108d

Add table with performance of operations

view details

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 NSNumbers significantly altered the performance comparison. Beyond 256 elements, CFBinaryHeap is faster than Heap for popMin.

CFBinaryHeap Updated Comparison

AquaGeek

comment created time in 14 days

push eventAquaGeek/swift-collections

Tyler Stromberg

commit sha a97bca28ee853f1abc572ae291677bc275d0e890

Don't wrap integers in CFBinaryHeap benchmark in NSNumber

view details

Tyler Stromberg

commit sha 26d786ae9de6d8a3dea465da57c081408223b2d2

Avoid heap allocation altogether

view details

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/freeing.

AquaGeek

comment created time in 14 days

PullRequestReviewEvent

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)

AquaGeek

comment created time in 15 days

PullRequestReviewEvent

push eventAquaGeek/swift-collections

Tyler Stromberg

commit sha 8d2bf0a372f71ba02e178dcedba4fa215c0849b8

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

view details

push time in 18 days

push eventAquaGeek/swift-collections

Tyler Stromberg

commit sha b9d53d7c893a35a4dc153a68918fd72e7ab7bd18

Make Heap.Iterator init and direction internal

view details

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?

AquaGeek

comment created time in 21 days

PullRequestReviewEvent
PullRequestReviewEvent

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?

AquaGeek

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.

AquaGeek

comment created time in 22 days

push eventAquaGeek/swift-collections

Tyler Stromberg

commit sha 5eaf6716c531d154ff64ac41abe7dc4781f36bc1

Add documentation for Heap

view details

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?

AquaGeek

comment created time in 23 days