Skip to content

Commit 493cdfe

Browse files
author
Dave Abrahams
committed
Add basic support for segmentation and contiguous storage access
Lots still to do here, including: 1. make segments of bidirectional/random access collections conform to the right protocols. 2. adapt algorithms to take advantage of both segmentation and contiguous memory
1 parent c2f93ff commit 493cdfe

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

stdlib/public/core/Arrays.swift.gyb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,6 +1605,19 @@ extension ${Self} {
16051605
return try _buffer.withUnsafeBufferPointer(body)
16061606
}
16071607

1608+
public func withUnsafeElementStorage<R>(
1609+
_ body: (UnsafeBufferPointer<Element>?) throws -> R
1610+
) rethrows -> R {
1611+
return try _buffer.withUnsafeBufferPointer(body)
1612+
}
1613+
1614+
public var contiguousStorage: ContiguousStorage<Iterator.Element>? {
1615+
return ContiguousStorage(accessor: {
1616+
(f: (UnsafeBufferPointer<Element>)->Void) in
1617+
self.withUnsafeBufferPointer(f)
1618+
})
1619+
}
1620+
16081621
/// Calls the given closure with a pointer to the array's mutable contiguous
16091622
/// storage.
16101623
///

stdlib/public/core/Collection.swift

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,40 @@ public struct IndexingIterator<
419419
internal var _position: Elements.Index
420420
}
421421

422+
//===--- Contiguous Storage Access ----------------------------------------===//
423+
//
424+
// We're unsure which idiom will be best for users and implementors of
425+
// Collections, and which, if any, will be more optimizable, so we have two
426+
// schemes:
427+
//
428+
// 1. a contiguousStorage property that is an optional instance of
429+
// ContiguousStorage (below)
430+
//
431+
// 2. a withUnsafeElementStorage(_ body: ... ) method whose body takes an
432+
// optional UnsafeBufferPointer
433+
//
434+
// I can't figure out how to get the first one to support throwing closures.
435+
// We may not know which one is best until we handle the mutable storage case.
436+
//
437+
// Note: this should be for access to *already existing* contiguous storage.
438+
// Lazily-bridged Arrays will create that storage on demand, so the conformance
439+
// is imperfect.
440+
// ===----------------------------------------------------------------------===//
441+
/// A type that grants access to a collection's contiguous storage.
442+
public struct ContiguousStorage<Element> {
443+
/// Invokes `body` on the contiguous storage and returns the result.
444+
public func withUnsafeBufferPointer<R>(
445+
_ body: (UnsafeBufferPointer<Element>)->R
446+
) -> R {
447+
var r: R!
448+
accessor { p in
449+
r = body(p)
450+
}
451+
return r
452+
}
453+
let accessor: ((UnsafeBufferPointer<Element>)->Void) -> Void
454+
}
455+
422456
/// A sequence whose elements can be traversed multiple times,
423457
/// nondestructively, and accessed by indexed subscript.
424458
///
@@ -561,6 +595,32 @@ public protocol Collection : _Indexable, Sequence {
561595
/// type.
562596
associatedtype Iterator : IteratorProtocol = IndexingIterator<Self>
563597

598+
/// A type that provides access to sub-structure of the collection
599+
associatedtype Segments : _Indexable = EmptyCollection<Self>
600+
// where Segments : Collection, Segments.Iterator.Element : Collection,
601+
// Segments.Iterator.Element.Iterator.Element == Iterator.Element
602+
603+
/// The collection's sub-structure, if any
604+
///
605+
/// Anything for which a complete traversal can be most easily written using a
606+
/// nested loop should provide segments.
607+
var segments : Segments? { get }
608+
609+
/// The collection's contiguous storage, if any
610+
///
611+
/// Only non-nil if *all* of the collection's elements are stored contiguously
612+
/// in memory. A collection can vend multiple segments, each vending its own
613+
/// non-nil contiguousStorage, if there are multiple contiguous memory
614+
/// regions.
615+
///
616+
/// Note: a collection may choose to provide only `withUnsafeElementStorage`,
617+
/// in which case a default for contiguousStorage will be provided.
618+
var contiguousStorage: ContiguousStorage<Iterator.Element>? { get }
619+
620+
func withUnsafeElementStorage<R>(
621+
_ body: (UnsafeBufferPointer<Iterator.Element>?) throws -> R
622+
) rethrows -> R
623+
564624
// FIXME(ABI)#179 (Type checker): Needed here so that the `Iterator` is properly deduced from
565625
// a custom `makeIterator()` function. Otherwise we get an
566626
// `IndexingIterator`. <rdar://problem/21539115>
@@ -1182,6 +1242,35 @@ extension Collection where SubSequence == Self {
11821242
}
11831243
}
11841244

1245+
/// Default implementation of Segments for collections that don't expose any
1246+
/// sub-structure.
1247+
extension Collection where Segments == EmptyCollection<Self> {
1248+
public var segments : Segments? { return Segments() }
1249+
}
1250+
1251+
extension Collection {
1252+
// Default implementation of contiguousStorage in terms of
1253+
// withUnsafeElementStorage. This seems very unlikely to optimize well.
1254+
public var contiguousStorage: ContiguousStorage<Iterator.Element>? {
1255+
// FIXME: The straightforward formulation using a closure doesn't work.
1256+
// <rdar://30448445> Crash compiling CoreAudio
1257+
func factory(p: UnsafeBufferPointer<Iterator.Element>?)
1258+
-> ContiguousStorage<Iterator.Element>? {
1259+
return p == nil ? nil : ContiguousStorage {
1260+
(body: (UnsafeBufferPointer<Iterator.Element>)->Void) in
1261+
self.withUnsafeElementStorage { body($0!) }
1262+
}
1263+
}
1264+
return withUnsafeElementStorage(factory)
1265+
}
1266+
1267+
public func withUnsafeElementStorage<R>(
1268+
_ body: (UnsafeBufferPointer<Iterator.Element>?) throws -> R
1269+
) rethrows -> R {
1270+
return try body(nil)
1271+
}
1272+
}
1273+
11851274
/// Default implementations of core requirements
11861275
extension Collection {
11871276
/// A Boolean value indicating whether the collection is empty.

0 commit comments

Comments
 (0)