Last active
February 21, 2017 16:12
-
-
Save tardieu/2ef5393a3037cfa639be7032193475c3 to your computer and use it in GitHub Desktop.
Performance tests for unsafe String API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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