Files
swift-mirror/stdlib/core/StringBuffer.swift
Dave Abrahams 6d1095f44e Protocol names end in "Type," "ible," or "able"
Mechanically add "Type" to the end of any protocol names that don't end
in "Type," "ible," or "able."  Also, drop "Type" from the end of any
associated type names, except for those of the *LiteralConvertible
protocols.

There are obvious improvements to make in some of these names, which can
be handled with separate commits.

Fixes <rdar://problem/17165920> Protocols `Integer` etc should get
uglier names.

Swift SVN r19883
2014-07-12 17:29:57 +00:00

187 lines
5.6 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
struct _StringBufferIVars {
init(_ elementWidth: Int) {
_sanityCheck(elementWidth == 1 || elementWidth == 2)
usedEnd = .null()
capacityAndElementShift = elementWidth - 1
}
init(
usedEnd: UnsafePointer<RawByte>,
byteCapacity: Int,
elementWidth: Int
) {
_sanityCheck(elementWidth == 1 || elementWidth == 2)
_sanityCheck((byteCapacity & 0x1) == 0)
self.usedEnd = usedEnd
self.capacityAndElementShift = byteCapacity + (elementWidth - 1)
}
var usedEnd: UnsafePointer<RawByte>
var capacityAndElementShift: Int
var byteCapacity: Int {
return capacityAndElementShift & ~0x1
}
var elementShift: Int {
return capacityAndElementShift & 0x1
}
}
// FIXME: Wanted this to be a subclass of
// HeapBuffer<_StringBufferIVars,UTF16.CodeUnit>, but
// <rdar://problem/15520519> (Can't call static method of derived
// class of generic class with dependent argument type) prevents it.
public struct _StringBuffer {
// Make this a buffer of UTF-16 code units so that it's properly
// aligned for them if that's what we store.
typealias _Storage = HeapBuffer<_StringBufferIVars, UTF16.CodeUnit>
init(_ storage: _Storage) {
_storage = storage
}
public init(capacity: Int, initialSize: Int, elementWidth: Int) {
_sanityCheck(elementWidth == 1 || elementWidth == 2)
let elementShift = elementWidth - 1
// We need at least 1 extra byte if we're storing 8-bit elements,
// because indexing will always grab 2 consecutive bytes at a
// time.
let capacityBump = 1 - elementShift
// Used to round capacity up to nearest multiple of 16 bits, the
// element size of our storage.
let divRound = 1 - elementShift
_storage = _Storage(_Storage.Storage.self,
_StringBufferIVars(elementWidth),
(capacity + capacityBump + divRound) >> divRound
)
self.usedEnd = start + (initialSize << elementShift)
_storage.value.capacityAndElementShift
= ((_storage._capacity() - capacityBump) << 1) + elementShift
}
static func fromCodeUnits<
Encoding : UnicodeCodecType, Input : CollectionType // SequenceType?
where Input.Generator.Element == Encoding.CodeUnit
>(
encoding: Encoding.Type, input: Input, repairIllFormedSequences: Bool,
minimumCapacity: Int = 0
) -> (_StringBuffer?, hadError: Bool) {
// Determine how many UTF-16 code units we'll need
var inputStream = input.generate()
if let (utf16Count, isAscii) = UTF16.measure(encoding, input: inputStream,
repairIllFormedSequences: repairIllFormedSequences) {
// Allocate storage
var result = _StringBuffer(
capacity: max(utf16Count, minimumCapacity),
initialSize: utf16Count,
elementWidth: isAscii ? 1 : 2)
if isAscii {
var p = UnsafePointer<UTF8.CodeUnit>(result.start)
let hadError = transcode(encoding, UTF32.self, input.generate(),
SinkOf {
(p++).memory = UTF8.CodeUnit($0)
},
stopOnError: !repairIllFormedSequences)
_sanityCheck(!hadError, "string can not be ASCII if there were decoding errors")
return (result, hadError)
}
else {
var p = result._storage.elementStorage
let hadError = transcode(encoding, UTF16.self, input.generate(),
SinkOf {
(p++).memory = $0
},
stopOnError: !repairIllFormedSequences)
return (result, hadError)
}
} else {
return (.None, true)
}
}
/// a pointer to the start of this buffer's data area
public var start: UnsafePointer<RawByte> {
return UnsafePointer(_storage.elementStorage)
}
/// a past-the-end pointer for this buffer's stored data
var usedEnd: UnsafePointer<RawByte> {
get {
return _storage.value.usedEnd
}
set(newValue) {
_storage.value.usedEnd = newValue
}
}
var usedCount: Int {
return (usedEnd - start) >> elementShift
}
/// a past-the-end pointer for this buffer's available storage
var capacityEnd: UnsafePointer<RawByte> {
return start + _storage.value.byteCapacity
}
/// The number of elements that can be stored in this buffer
public var capacity: Int {
return _storage.value.byteCapacity >> elementShift
}
/// 1 if the buffer stores UTF-16; 0 otherwise
var elementShift: Int {
return _storage.value.elementShift
}
/// the number of bytes per element
var elementWidth: Int {
return elementShift + 1
}
mutating func grow(oldUsedEnd: UnsafePointer<RawByte>,
newUsedCount: Int) -> Bool {
if _slowPath(newUsedCount > capacity) {
return false
}
let newUsedEnd = start + (newUsedCount << elementShift)
if _fastPath(
self._storage.isUniquelyReferenced()
) {
usedEnd = newUsedEnd
return true
}
// FIXME: this function is currently NOT THREADSAFE. The test +
// assignment below should be replaced by a CAS
if usedEnd == oldUsedEnd {
usedEnd = newUsedEnd
return true
}
return false
}
var _anyObject: AnyObject? {
return _storage.storage ? .Some(_storage.storage!) : .None
}
var _storage: _Storage
}