Skip to content

Instantly share code, notes, and snippets.

@treboc
Created January 24, 2026 11:19
Show Gist options
  • Select an option

  • Save treboc/dcd76b0f2adaf7e2740b0273889361d4 to your computer and use it in GitHub Desktop.

Select an option

Save treboc/dcd76b0f2adaf7e2740b0273889361d4 to your computer and use it in GitHub Desktop.
import Foundation
import SwiftUI
main()
func main() {
let items = (0..<10_000).map {
InternalWidgetModelWrapper(id: $0, size: Size.allCases.randomElement()!)
}
measure(functionName: "buildRows_removeSubrange") {
_ = buildRows_removeSubrange(from: items)
}
measure(functionName: "buildRows_indexSet") {
_ = buildRows_indexSet(from: items)
}
}
enum Size: CaseIterable {
case small
case medium
}
protocol Sizable {
var size: Size { get }
}
struct InternalWidgetModelWrapper: Identifiable, Sizable {
let id: Int
let size: Size
}
struct LayoutRowItem<T: Sizable & Identifiable>: Identifiable {
let id = UUID()
let first: T
var second: T? = nil
}
/// A method that reorders a given array of items, where the items conform to `Sizable`,
/// to make them usable in a grid like structure.
/// - Parameter items: The array of items to be restructured.
/// - Returns: An array of rows.
func buildRows<T: Sizable>(
from items: [T]
) -> [LayoutRowItem<T>] {
var rows: [LayoutRowItem<T>] = []
var pendingItems = items
while pendingItems.isEmpty == false {
// Get the first item of the list and remove it from the list directly.
let item = pendingItems.removeFirst()
switch item.size {
// Only one medium item can fit in a row, so add it.
case .medium:
rows.append(LayoutRowItem(first: item))
case .small:
// If there's another small item that can be placed to the right, do that.
if let secondItemIndex = pendingItems.firstIndex(where: { $0.size == .small }) {
let second = pendingItems.remove(at: secondItemIndex)
rows.append(LayoutRowItem(first: item, second: second))
// If then there's no other medium item coming, it's the last small item, place it alone.
} else if !pendingItems.contains(where: { $0.size == .medium }) {
rows.append(LayoutRowItem(first: item))
// If the previous cases did not match at all, insert it back in the list,
// but after the item that's now the first in the list.
} else {
pendingItems.insert(item, at: 1)
}
}
}
return rows
}
func buildRows_indexSet<T: Sizable>(
from items: [T]
) -> [LayoutRowItem<T>] {
var rows: [LayoutRowItem<T>] = []
var pendingItems = items
while pendingItems.isEmpty == false {
let index = 0
let item = pendingItems[index]
// Check if there is a next item, if not it's the last. Append and break.
guard index + 1 < pendingItems.endIndex else {
rows.append(LayoutRowItem(first: item))
pendingItems.remove(at: index)
break
}
if item.size == .medium {
// Medium items always go alone
rows.append(LayoutRowItem(first: item))
pendingItems.remove(at: index)
} else {
if let secondItemIndex = pendingItems[1...].firstIndex(where: { $0.size == .small }) {
rows.append(LayoutRowItem(first: item, second: pendingItems[secondItemIndex]))
pendingItems.remove(atOffsets: IndexSet([0, 1]))
} else if !pendingItems.contains(where: { $0.size == .medium }) {
rows.append(LayoutRowItem(first: item))
pendingItems.remove(at: index)
} else if let nextMediumItemIndex = pendingItems.firstIndex(where: { $0.size == .medium }) {
rows.append(LayoutRowItem(first: pendingItems[nextMediumItemIndex]))
pendingItems.remove(at: nextMediumItemIndex)
}
}
}
return rows
}
func buildRows_removeSubrange<T: Sizable>(
from items: [T]
) -> [LayoutRowItem<T>] {
var rows: [LayoutRowItem<T>] = []
var pendingItems = items
while pendingItems.isEmpty == false {
let index = 0
let item = pendingItems[index]
// Check if there is a next item, if not it's the last. Append and break.
guard index + 1 < pendingItems.endIndex else {
rows.append(LayoutRowItem(first: item))
pendingItems.remove(at: index)
break
}
if item.size == .medium {
// Medium items always go alone
rows.append(LayoutRowItem(first: item))
pendingItems.remove(at: index)
} else {
if let secondItemIndex = pendingItems[1...].firstIndex(where: { $0.size == .small }) {
rows.append(LayoutRowItem(first: item, second: pendingItems[secondItemIndex]))
pendingItems.removeSubrange(0...1)
} else if !pendingItems.contains(where: { $0.size == .medium }) {
rows.append(LayoutRowItem(first: item))
pendingItems.remove(at: index)
} else if let nextMediumItemIndex = pendingItems.firstIndex(where: { $0.size == .medium }) {
rows.append(LayoutRowItem(first: pendingItems[nextMediumItemIndex]))
pendingItems.remove(at: nextMediumItemIndex)
}
}
}
return rows
}
@discardableResult
func measure<R>(functionName: String = #function, body: () throws -> R) rethrows -> R {
#if DEBUG // Don't waste time logging unless we're in debug
// I'm using CoreFoundation's clock as an example,
// but you can use `clock_gettime(CLOCK_MONOTONIC, ...)` or whatever
let startTime = CFAbsoluteTimeGetCurrent()
defer {
let endTime = CFAbsoluteTimeGetCurrent()
let duration = endTime - startTime
NSLog("\(functionName): \(duration) seconds")
}
#endif
return try body()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment