Skip to content

Commit 5c33278

Browse files
author
Dave Abrahams
committed
[stdlib] Add ManagedBufferPointer
A revamped version of HeapBuffer that doesn't allow null buffer references. Something like this is needed for killing the null array state. Swift SVN r22683
1 parent 8ab25ab commit 5c33278

File tree

5 files changed

+348
-78
lines changed

5 files changed

+348
-78
lines changed

stdlib/core/Builtin.swift

+16
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
import SwiftShims
14+
1315
// Definitions that make elements of Builtin usable in real code
1416
// without gobs of boilerplate.
1517

@@ -223,3 +225,17 @@ func _slowPath<C: BooleanType>(x: C) -> Bool {
223225
return _branchHint(x.boolValue, false)
224226
}
225227

228+
//===--- Runtime shim wrappers --------------------------------------------===//
229+
230+
/// Returns `true`iff the class indicated by `theClass` is non-\ `@objc`.
231+
internal func _usesNativeSwiftReferenceCounting(theClass: AnyClass) -> Bool {
232+
return _swift_usesNativeSwiftReferenceCounting_class(
233+
unsafeAddressOf(theClass)
234+
) != 0
235+
}
236+
237+
/// Returns: `class_getInstanceSize(theClass)`
238+
internal func _class_getInstanceSize(theClass: AnyClass) -> Int {
239+
return Int(_swift_class_getInstanceSize_class(
240+
unsafeAddressOf(theClass)))
241+
}

stdlib/core/ManagedBuffer.swift

+232-76
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,8 @@ public class ManagedProtoBuffer<Value, Element> : NonObjectiveCBase {
3535
/// idea to store this information in the "value" area when
3636
/// an instance is created.
3737
public final var allocatedElementCount : Int {
38-
return (
39-
_allocatedByteCount &- ManagedProtoBuffer._elementOffset &+ sizeof(Element) &- 1
40-
) &/ sizeof(Element)
38+
let p = ManagedBufferPointer<Value,Element>(self)
39+
return p.allocatedElementCount
4140
}
4241

4342
/// Call `body` with an `UnsafeMutablePointer` to the stored `Value`
@@ -59,12 +58,7 @@ public class ManagedProtoBuffer<Value, Element> : NonObjectiveCBase {
5958
public final func withUnsafeMutablePointers<R>(
6059
body: (_: UnsafeMutablePointer<Value>, _: UnsafeMutablePointer<Element>)->R
6160
) -> R {
62-
let result = body(
63-
UnsafeMutablePointer(_address + ManagedProtoBuffer._valueOffset),
64-
UnsafeMutablePointer(_address + ManagedProtoBuffer._elementOffset)
65-
)
66-
_fixLifetime(self)
67-
return result
61+
return ManagedBufferPointer(self).withUnsafeMutablePointers(body)
6862
}
6963

7064
//===--- internal/private API -------------------------------------------===//
@@ -73,41 +67,6 @@ public class ManagedProtoBuffer<Value, Element> : NonObjectiveCBase {
7367
internal init(_doNotCallMe: ()) {
7468
_sanityCheckFailure("Only initialize these by calling create")
7569
}
76-
77-
/// The required alignment for allocations of this type, minus 1
78-
internal final class var _alignmentMask : Int {
79-
return max(
80-
alignof(_HeapObject.self),
81-
max(alignof(Value.self), alignof(Element.self))) &- 1
82-
}
83-
84-
/// The actual number of bytes allocated for this object.
85-
internal final var _allocatedByteCount : Int {
86-
return Int(bitPattern: malloc_size(unsafeAddressOf(self)))
87-
}
88-
89-
/// The address of this instance in a convenient pointer-to-bytes form
90-
internal final var _address : UnsafePointer<UInt8> {
91-
return UnsafePointer(unsafeAddressOf(self))
92-
}
93-
94-
/// Offset from the allocated storage for `self` to the stored `Value`
95-
internal final class var _valueOffset : Int {
96-
return _roundUpToAlignment(sizeof(_HeapObject.self), alignof(Value.self))
97-
}
98-
99-
/// Offset from the allocated storage for `self` to the `Element` storage
100-
internal final class var _elementOffset : Int {
101-
return _roundUpToAlignment(
102-
_valueOffset + sizeof(Value.self), alignof(Element.self))
103-
}
104-
105-
/// A hack that gives the deallocator information about our
106-
/// allocated size. Probably completely unused per
107-
/// <rdar://problem/18156440>
108-
internal final func __getInstanceSizeAndAlignMask() -> (Int,Int) {
109-
return (_allocatedByteCount, ManagedProtoBuffer._alignmentMask)
110-
}
11170
}
11271

11372
/// A class whose instances contain a property of type `Value` and raw
@@ -125,58 +84,255 @@ public class ManagedBuffer<Value, Element>
12584
: ManagedProtoBuffer<Value, Element> {
12685

12786
/// Create a new instance of the most-derived class, calling
128-
/// `initialize` on the partially-constructed object to generate an
129-
/// initial `Value`.
130-
///
131-
/// Note, in particular, accessing `value` inside the `initialize`
132-
/// function is undefined.
87+
/// `initializeValue` on the partially-constructed object to
88+
/// generate an initial `Value`.
13389
public final class func create(
134-
minimumCapacity: Int, initialize: (ManagedProtoBuffer<Value,Element>)->Value
135-
) -> ManagedBuffer {
90+
minimumCapacity: Int,
91+
initialValue: (ManagedProtoBuffer<Value,Element>)->Value
92+
) -> ManagedBuffer<Value,Element> {
93+
94+
let p = ManagedBufferPointer<Value,Element>(
95+
bufferClass: self,
96+
minimumCapacity: minimumCapacity,
97+
{ buffer, _ in initialValue(
98+
// FIXME: should be an unsafeDowncast <rdar://problem/18618169>
99+
Builtin.bridgeFromRawPointer(Builtin.bridgeToRawPointer(buffer)))
100+
})
101+
102+
// FIXME: should be an unsafeDowncast <rdar://problem/18618169>
103+
return Builtin.bridgeFromRawPointer(Builtin.bridgeToRawPointer(p.buffer))
104+
}
105+
106+
/// Destroy the stored Value
107+
deinit {
108+
ManagedBufferPointer(self).withUnsafeMutablePointerToValue { $0.destroy() }
109+
}
110+
111+
/// The stored `Value` instance.
112+
public final var value: Value {
113+
address {
114+
return ManagedBufferPointer(self).withUnsafeMutablePointerToValue {
115+
UnsafePointer($0)
116+
}
117+
}
118+
mutableAddress {
119+
return ManagedBufferPointer(self).withUnsafeMutablePointerToValue { $0 }
120+
}
121+
}
122+
}
123+
124+
/// Contains a buffer object, and provides access to an instance of
125+
/// `Value` and contiguous storage for an arbitrary number of
126+
/// `Element` instances stored in that buffer.
127+
///
128+
/// For most purposes, the `ManagedBuffer` class works fine for this
129+
/// purpose, and can simply be used on its own. However, in cases
130+
/// where objects of various different classes must serve as storage,
131+
/// `ManagedBufferPointer` is needed.
132+
///
133+
/// A valid buffer class is non-`@objc`, with no declared stored
134+
/// properties. Its `deinit` must destroy its
135+
/// stored `Value` and any constructed `Elements`.
136+
///
137+
/// Example Buffer Class
138+
/// --------------------
139+
///
140+
/// ::
141+
///
142+
/// class MyBuffer<Element> { // non-@objc
143+
/// typealias Manager = ManagedBufferPointer<(Int,String), Element>
144+
/// deinit {
145+
/// Manager(unsafeBufferObject: self).withUnsafeMutablePointers {
146+
/// (pointerToValue, pointerToElements)->Void in
147+
/// pointerToElements.destroy(self.count)
148+
/// pointerToValue.destroy()
149+
/// }
150+
/// }
151+
///
152+
/// // All properties are *computed* based on members of the Value
153+
/// var count : Int {
154+
/// return Manager(unsafeBufferObject: self).value.0
155+
/// }
156+
/// var name : String {
157+
/// return Manager(unsafeBufferObject: self).value.1
158+
/// }
159+
/// }
160+
///
161+
public struct ManagedBufferPointer<Value, Element> : Equatable {
162+
163+
/// Create with new storage containing an initial `Value` and space
164+
/// for at least `minimumCapacity` `element`\ s.
165+
///
166+
/// :param: `bufferClass` - the class of the object used for storage.
167+
/// :param: `minimumCapacity` - the minimum number of `Elements` that
168+
/// must be able to be stored in the new buffer.
169+
/// :param: `initialValue` - a function that produces the initial
170+
/// `Value` instance stored in the buffer, given the `buffer`
171+
/// object and a function that can be called on it to get the actual
172+
/// number of allocated elements.
173+
///
174+
/// Requires: minimumCapacity >= 0, and the type indicated by
175+
/// `bufferClass` is a non-`@objc` class with no declared stored
176+
/// properties. The `deinit` of `bufferClass` must destroy its
177+
/// stored `Value` and any constructed `Elements`.
178+
public init(
179+
bufferClass: AnyClass,
180+
minimumCapacity: Int,
181+
initialValue: (buffer: AnyObject, allocatedCount: (AnyObject)->Int)->Value
182+
) {
183+
ManagedBufferPointer._checkValidBufferClass(bufferClass)
136184
_precondition(
137185
minimumCapacity >= 0,
138-
"ManagedBuffer must have non-negative capacity")
186+
"ManagedBufferPointer must have non-negative capacity")
139187

140-
let totalSize = ManagedBuffer._elementOffset
188+
let totalSize = _My._elementOffset
141189
+ minimumCapacity * strideof(Element.self)
142190

143-
let alignMask = ManagedBuffer._alignmentMask
191+
let newBuffer: AnyObject = _swift_bufferAllocate(
192+
bufferClass, totalSize, _My._alignmentMask)
144193

145-
let result: ManagedBuffer = unsafeDowncast(
146-
_swift_bufferAllocate(self, totalSize, alignMask)
147-
)
148-
149-
result.withUnsafeMutablePointerToValue {
150-
$0.initialize(initialize(result))
151-
}
152-
return result
153-
}
194+
self._nativeBuffer = Builtin.castToNativeObject(newBuffer)
154195

155-
/// Destroy the stored Value
156-
deinit {
157-
// FIXME: doing the work in a helper is a workaround for
158-
// <rdar://problem/18158010>
159-
_deinit()
196+
// initialize the value field
197+
withUnsafeMutablePointerToValue {
198+
$0.initialize(
199+
initialValue(
200+
buffer: newBuffer,
201+
allocatedCount: {
202+
ManagedBufferPointer(unsafeBufferObject: $0).allocatedElementCount
203+
}))
204+
}
160205
}
161206

162-
// FIXME: separating this from the real deinit is a workaround for
163-
// <rdar://problem/18158010>
164-
/// The guts of deinit(); do not call
165-
internal final func _deinit() {
166-
withUnsafeMutablePointerToValue { $0.destroy() }
207+
/// Manage the given `buffer`.
208+
///
209+
/// Requires: `buffer` is an instance of a non-`@objc` class with no
210+
/// declared stored properties, whose `deinit` destroys its
211+
/// stored `Value` and any constructed `Elements`.
212+
public init(unsafeBufferObject buffer: AnyObject) {
213+
ManagedBufferPointer._checkValidBufferClass(buffer.dynamicType)
214+
self._nativeBuffer = Builtin.castToNativeObject(buffer)
167215
}
168216

169217
/// The stored `Value` instance.
170-
///
171-
/// Note: this value must not be accessed during instance creation.
172-
public final var value: Value {
218+
public var value: Value {
219+
/*
173220
address {
174221
return withUnsafeMutablePointerToValue { UnsafePointer($0) }
175222
}
176223
mutableAddress {
177224
return withUnsafeMutablePointerToValue { $0 }
178225
}
226+
*/
227+
// FIXME: <rdar://problem/18619176> replace get/set with
228+
// addressors => link error
229+
get { return withUnsafeMutablePointerToValue { $0.memory } }
230+
set { withUnsafeMutablePointerToValue { $0.memory = newValue } }
179231
}
232+
233+
/// Return the object instance being used for storage.
234+
public var buffer: AnyObject {
235+
return Builtin.castFromNativeObject(_nativeBuffer)
236+
}
237+
238+
/// The actual number of elements that can be stored in this object.
239+
///
240+
/// This value may be nontrivial to compute; it is usually a good
241+
/// idea to store this information in the "value" area when
242+
/// an instance is created.
243+
public var allocatedElementCount : Int {
244+
return (
245+
_allocatedByteCount &- _My._elementOffset &+ sizeof(Element) &- 1
246+
) &/ sizeof(Element)
247+
}
248+
249+
/// Call `body` with an `UnsafeMutablePointer` to the stored `Value`
250+
public func withUnsafeMutablePointerToValue<R>(
251+
body: (UnsafeMutablePointer<Value>)->R
252+
) -> R {
253+
return withUnsafeMutablePointers { (v, e) in return body(v) }
254+
}
255+
256+
/// Call body with an `UnsafeMutablePointer` to the `Element` storage
257+
public func withUnsafeMutablePointerToElements<R>(
258+
body: (UnsafeMutablePointer<Element>)->R
259+
) -> R {
260+
return withUnsafeMutablePointers { return body($0.1) }
261+
}
262+
263+
/// Call body with `UnsafeMutablePointer`\ s to the stored `Value`
264+
/// and raw `Element` storage
265+
public func withUnsafeMutablePointers<R>(
266+
body: (_: UnsafeMutablePointer<Value>, _: UnsafeMutablePointer<Element>)->R
267+
) -> R {
268+
let result = body(
269+
UnsafeMutablePointer(_address + _My._valueOffset),
270+
UnsafeMutablePointer(_address + _My._elementOffset)
271+
)
272+
_fixLifetime(_nativeBuffer)
273+
return result
274+
}
275+
276+
//===--- internal/private API -------------------------------------------===//
277+
278+
/// Manage the given `buffer`.
279+
///
280+
/// **Note:** it is an error to use the `value` property of the resulting
281+
/// instance unless it has been initialized.
282+
internal init(_ buffer: ManagedProtoBuffer<Value, Element>) {
283+
_nativeBuffer = Builtin.castToNativeObject(buffer)
284+
}
285+
286+
internal typealias _My = ManagedBufferPointer
287+
288+
internal static func _checkValidBufferClass(bufferClass: AnyClass) {
289+
_debugPrecondition(
290+
_class_getInstanceSize(bufferClass)
291+
== _class_getInstanceSize(ManagedBuffer<Int,Int>.self),
292+
"ManagedBufferPointer buffer class has declared stored properties"
293+
)
294+
_debugPrecondition(
295+
_usesNativeSwiftReferenceCounting(bufferClass),
296+
"ManagedBufferPointer buffer class must be non-@objc"
297+
)
298+
}
299+
300+
/// The required alignment for allocations of this type, minus 1
301+
internal static var _alignmentMask : Int {
302+
return max(
303+
alignof(_HeapObject.self),
304+
max(alignof(Value.self), alignof(Element.self))) &- 1
305+
}
306+
307+
/// The actual number of bytes allocated for this object.
308+
internal var _allocatedByteCount : Int {
309+
return Int(bitPattern: malloc_size(_address))
310+
}
311+
312+
/// The address of this instance in a convenient pointer-to-bytes form
313+
internal var _address : UnsafePointer<UInt8> {
314+
return UnsafePointer(Builtin.bridgeToRawPointer(_nativeBuffer))
315+
}
316+
317+
/// Offset from the allocated storage for `self` to the stored `Value`
318+
internal static var _valueOffset : Int {
319+
return _roundUpToAlignment(sizeof(_HeapObject.self), alignof(Value.self))
320+
}
321+
322+
/// Offset from the allocated storage for `self` to the `Element` storage
323+
internal static var _elementOffset : Int {
324+
return _roundUpToAlignment(
325+
_valueOffset + sizeof(Value.self), alignof(Element.self))
326+
}
327+
328+
internal var _nativeBuffer: Builtin.NativeObject
329+
}
330+
331+
public func == <Value, Element>(
332+
lhs: ManagedBufferPointer<Value, Element>,
333+
rhs: ManagedBufferPointer<Value, Element>
334+
) -> Bool {
335+
return lhs._address == rhs._address
180336
}
181337

182338
// FIXME: when our calling convention changes to pass self at +0,

0 commit comments

Comments
 (0)