Skip to content

Instantly share code, notes, and snippets.

@tardieu
Last active February 21, 2017 16:12
Show Gist options
  • Save tardieu/2ef5393a3037cfa639be7032193475c3 to your computer and use it in GitHub Desktop.
Save tardieu/2ef5393a3037cfa639be7032193475c3 to your computer and use it in GitHub Desktop.
Performance tests for unsafe String API
extension String {
/// The base address of the contiguous buffer containing the String elements
/// if the String is backed by a contiguous buffer.
///
/// There is no guarantee that the String is backed by a contiguous buffer.
/// Even if it is, there is no guarantee that the buffer is writable.
public var baseAddress: UnsafeRawPointer? {
return UnsafeRawPointer(self._core._baseAddress)
}
/// The number of elements stored in the buffer.
///
/// The count must not be increased beyond the buffer size for an immutable buffer
/// or capacity for a mutable buffer.
public var elementCount: Int {
get {
return self._core.count
}
set {
self._core.count = newValue
}
}
/// The read-only width of the elements stored in the buffer (1 or 2).
public var elementWidth: Int {
return self._core.elementWidth
}
/// The read-only capacity of the String buffer if the String is backed by a mutable contiguous buffer.
public var capacity: Int? {
if let capacity = self._core.nativeBuffer?.capacity {
return capacity + 2 - self.elementWidth
} else {
return nil
}
}
/// Ensures that the String is backed by a uniquely owned mutable contiguous buffer with at least
/// the requested capacity and returns the base address of the this buffer.
///
/// This call may require copying the String elements into a new buffer and modifying the element size.
/// The reserved capacity may be greater than the requested capacity.
/// Repeated calls with the same or lower capacity requirements are no ops.
///
/// - Parameter capacity: the requested String capacity (number of elements).
/// - Parameter minElementWidth: the requested minimum element width.
/// - Returns: the base address of the mutable contiguous buffer backing the String.
@discardableResult public mutating func claimOwnership(withCapacity capacity: Int? = nil, withMinElementWidth minElementWidth: Int = 1) -> UnsafeMutableRawPointer {
if self.elementWidth < minElementWidth {
self.append("\u{a3}") // force element width = 2
if let capacity = capacity {
self._core.reserveCapacity(capacity)
}
self.elementCount -= 1
} else {
self._core.reserveCapacity(capacity ?? 0)
}
return self._core.nativeBuffer!.start
}
/// Executes action on String buffer.
///
/// Assumes String is backed by uniquely owned mutable contiguous buffer already.
///
/// - Parameter action: the action to execute.
@inline(__always) public mutating func withUnsafeMutablePointer(execute action: (UnsafeMutablePointer<UInt8>) -> Void) {
action(self._core.nativeBuffer!.start.assumingMemoryBound(to: UInt8.self))
}
}
import Foundation
var now = mach_absolute_time()
var string = "AAA"
string.claimOwnership()
for _ in 1...3 {
// mutate string element using withUnsafe...
now = mach_absolute_time()
for i in 0..<100000000 {
string.withUnsafeMutablePointer { $0.pointee = 65 + UInt8(i % 26) }
}
print("closure: \(Double(mach_absolute_time() - now) / 1e6)ms")
// mutate string element using pointer obtained before entering loop
now = mach_absolute_time()
let ptr = string.claimOwnership().assumingMemoryBound(to: UInt8.self)
for i in 0..<100000000 {
ptr.pointee = 65 + UInt8(i % 26)
}
print("pointer: \(Double(mach_absolute_time() - now) / 1e6)ms")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment