Files
swift-mirror/stdlib/core/StringLegacy.swift
Dmitri Hrybenko 2cc8fe40d4 stdlib/printing: replace four printing systems with one new one
The old ones were:

- print/println
- printAny
- printf
- Console

The new printing story is just print/println.  Every object can be printed.
You can customize the way it is printed by adopting Printable protocol.  Full
details in comments inside stdlib/core/OutputStream.swift.

Printing is not completely finished yet.  We still have ReplPrintable, which
should be removed, string interpolation still uses String constructors, and
printing objects that don't conform to Printable will result in printing
mangled names.


Swift SVN r18001
2014-05-13 13:07:59 +00:00

406 lines
12 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
//
//===----------------------------------------------------------------------===//
// Interfaces with a questionable future that are needed in order to
// be a drop-in replacement for String
//
extension String {
init<
Encoding: UnicodeCodec, Input: Collection
where Input.GeneratorType.Element == Encoding.CodeUnit
>(
_ _encoding: Encoding.Type, input: Input
)
{
self = String(_StringBuffer(encoding: _encoding, input: input))
}
init(count sz: Int, character c: Character) {
let s = String(c)
self = String(_StringBuffer(capacity: s.core.count * sz,
initialSize: 0,
elementWidth: s.core.elementWidth))
for i in 0...sz {
self += s
}
}
init(count: Int, scalar _c: UnicodeScalar) {
self = String(UTF32.self,
input: Repeat(count: count, repeatedValue: _c.value))
}
func asUTF8() -> UTF8.CodeUnit[] {
var result = new UTF8.CodeUnit[_encodedLength(UTF8.self)]
var len = 0
_encode(UTF8.self, output: SinkOf<UTF8.CodeUnit>({ result[len++] = $0 }))
return result
}
func byteLength() -> Int {
return _encodedLength(UTF8.self)
}
var lines : String[] {
return split("\n")
}
func split(separator: UnicodeScalar) -> String[] {
var scalarSlices = Swift.split(unicodeScalars, { $0 == separator })
return scalarSlices.map { $0 as String }
}
func size() -> Int {
var count = 0
for c in unicodeScalars {
++count
}
return count
}
func isEmpty() -> Bool {
return core.count == 0
}
}
extension String : ReplPrintable {
func replPrint() {
print("\"")
for c in unicodeScalars {
print(c.escape())
}
print("\"")
}
}
extension String {
// FIXME: Locales make this interesting
var uppercase : String {
let end = utf8.endIndex
var resultArray = NativeArray<UTF8.CodeUnit>(count: countElements(utf8),
value: 0)
var i = utf8.startIndex
var j = 0
while i != end {
let u8 = utf8[i++]
if u8 < 0x80 {
if 97...123 ~= u8 {
resultArray[j++] = u8 - 32
} else {
resultArray[j++] = u8
}
} else if u8 < 0xE0 {
resultArray[j++] = u8
let u8_1 = utf8[i++]
if u8 == 0xC3 && 0xA0...0xBF ~= Int(u8_1) && u8_1 != 0xB7 {
resultArray[j++] = u8_1 - 0x20
} else {
resultArray[j++] = u8_1
}
} else {
resultArray[j++] = u8
if u8 >= 0xF0 {
resultArray[j++] = utf8[i++]
}
resultArray[j++] = utf8[i++]
resultArray[j++] = utf8[i++]
}
}
return String(UTF8.self, input: resultArray)
}
var lowercase : String {
let end = utf8.endIndex
var resultArray = NativeArray<UTF8.CodeUnit>(count: countElements(utf8),
value: 0)
var i = utf8.startIndex
var j = 0
while i != end {
let u8 = utf8[i++]
if u8 < 0x80 {
if 65...91 ~= u8 {
resultArray[j++] = u8 + 32
} else {
resultArray[j++] = u8
}
} else if u8 < 0xE0 {
resultArray[j++] = u8
let u8_1 = utf8[i++]
if u8 == 0xC3 && 0x80...0x9F ~= u8_1 && u8_1 != 0x97 {
resultArray[j++] = u8_1 + 0x20
} else {
resultArray[j++] = u8_1
}
} else {
resultArray[j++] = u8
if u8 >= 0xF0 {
resultArray[j++] = utf8[i++]
}
resultArray[j++] = utf8[i++]
resultArray[j++] = utf8[i++]
}
}
return String(UTF8.self, input: resultArray)
}
init(_ _c: UnicodeScalar) {
self = String(count: 1, scalar: _c)
}
func _isAll(predicate: (UnicodeScalar) -> Bool) -> Bool {
for c in unicodeScalars { if !predicate(c) { return false } }
return true
}
func startsWith(prefix: String) -> Bool {
return Swift.startsWith(self, prefix)
}
func endsWith(suffix: String) -> Bool {
return Swift.startsWith(Reverse(self), Reverse(suffix))
}
func isAlpha() -> Bool { return _isAll({ $0.isAlpha() }) }
func isDigit() -> Bool { return _isAll({ $0.isDigit() }) }
func isSpace() -> Bool { return _isAll({ $0.isSpace() }) }
}
/// \brief Represent a positive integer value in the given radix,
/// writing each ASCII character into stream. The value of `ten'
/// should be either "A" or "a", depending on whether you want upper-
/// or lower-case letters when radix > 10
func _formatPositiveInteger(
value: UInt64,
radix: UInt64,
ten: UnicodeScalar = "a") ( stream: (UTF8.CodeUnit)->Void )
{
if value == 0 {
return
}
_formatPositiveInteger(value / radix, radix, ten: ten)(stream: stream)
var digit = UInt32(value % radix)
var baseCharOrd: UInt32 = digit <= 9 ? _asUnicodeCodePoint("0")
: _asUnicodeCodePoint(ten) - 10
stream(UTF8.CodeUnit(baseCharOrd + digit))
}
func _formatSignedInteger(
value: Int64,
radix: UInt64,
ten: UnicodeScalar = "a") ( stream: (UTF8.CodeUnit)->Void ) {
if value == 0 {
stream(UTF8.CodeUnit(_asUnicodeCodePoint("0")))
}
else {
if (value < 0) {
let minusCharacter: UnicodeScalar = "-"
stream(UTF8.CodeUnit(_asUnicodeCodePoint("-")))
}
// Compute the absolute value without causing overflow when value
// == Int64.min
let absValue = value < 0 ? UInt64(~value) + 1 : UInt64(value)
_formatPositiveInteger(absValue, radix, ten: ten)(stream: stream)
}
}
// Conversions to string from other types.
extension String {
init(_ v: Int64, radix: Int = 10, uppercase: Bool = false) {
var format = _formatSignedInteger(v, UInt64(radix),
ten: uppercase ? "A" : "a")
var asciiCount = 0
format(stream: { _ in ++asciiCount;() })
var buffer = _StringBuffer(
capacity: asciiCount, initialSize: asciiCount, elementWidth: 1)
var p = UnsafePointer<UTF8.CodeUnit>(buffer.start)
format(stream: { p++.set($0) })
self = String(buffer)
}
// FIXME: This function assumes UTF16
init(_ v: UInt64, radix: Int = 10, uppercase: Bool = false) {
var format = _formatPositiveInteger(v, UInt64(radix),
ten: uppercase ? "A" : "a")
var asciiCount = v == 0 ? 1 : 0
format(stream: { _ in ++asciiCount;() })
var buffer = _StringBuffer(
capacity: asciiCount, initialSize: asciiCount, elementWidth: 1)
var p = UnsafePointer<UTF8.CodeUnit>(buffer.start)
format(stream: { p++.set($0) })
if v == 0 {
p++.set(UTF8.CodeUnit("0"))
}
self = String(buffer)
}
init(_ v : Int8, radix : Int = 10, uppercase : Bool = false) {
self = String(Int64(v), radix: radix, uppercase: uppercase)
}
init(_ v : Int16, radix : Int = 10, uppercase : Bool = false) {
self = String(Int64(v), radix: radix, uppercase: uppercase)
}
init(_ v : Int32, radix : Int = 10, uppercase : Bool = false) {
self = String(Int64(v), radix: radix, uppercase: uppercase)
}
init(_ v : Int, radix : Int = 10, uppercase : Bool = false) {
self = String(Int64(v), radix: radix, uppercase: uppercase)
}
init(_ v : UInt8, radix : Int = 10, uppercase : Bool = false) {
self = String(UInt64(v), radix: radix, uppercase: uppercase)
}
init(_ v : UInt16, radix : Int = 10, uppercase : Bool = false) {
self = String(UInt64(v), radix: radix, uppercase: uppercase)
}
init(_ v : UInt32, radix : Int = 10, uppercase : Bool = false) {
self = String(UInt64(v), radix: radix, uppercase: uppercase)
}
init(_ v : UInt, radix : Int = 10, uppercase : Bool = false) {
self = String(UInt64(v), radix: radix, uppercase: uppercase)
}
init(_ v : Double) {
self = _doubleToString(v)
}
init(_ v : Float) {
self = String(Double(v))
}
init(_ b : Bool) {
if b {
self = "true"
} else {
self = "false"
}
}
}
// Conversions from string to other types.
extension String {
/// \brief If the string represents an integer that fits into an Int, returns
/// the corresponding integer.
func toInt() -> Int? {
var scalars = self.unicodeScalars
var start = scalars.startIndex
if start == scalars.endIndex {
return .None
}
// Interpet '+' or '-' before the number.
var negativeFactor = -1
var firstC = scalars[start]
if (firstC == "+") {
++start
} else if (firstC == "-") {
++start
negativeFactor = 1
}
// Interpret the string as an integer.
// Since Int.min has a larger absolute value, perform addition with
// negative numbers; detect underflows before they happen.
var res : Int = 0
for c in scalars[start...scalars.endIndex] {
if !c.isDigit() {
// Conversion failed if a non-digit is encountered.
return .None
}
// Underflow occurs if res * 10 < Int.min.
if res < Int.min / 10 {
return .None
}
res = res * 10
var d : Int = (c - "0")
// Underflow occurs if res - d < Int.min.
if res < Int.min + d {
return .None
}
res = res - d
}
// If res is Int.min and the result should be positive, the next
// operation will overflow.
if negativeFactor == -1 && res == Int.min {
return .None
}
return .Some(res * negativeFactor)
}
}
extension String {
/// \brief Produce a substring of the given string from the given character
/// index to the end of the string.
func substr(start: Int) -> String {
var rng = unicodeScalars
var startIndex = rng.startIndex
for i in 0...start {
++startIndex
}
return rng[startIndex...rng.endIndex]
}
/// \brief Split the given string at the given delimiter character, returning
/// the strings before and after that character (neither includes the character
/// found) and a boolean value indicating whether the delimiter was found.
func splitFirst(delim: UnicodeScalar)
-> (before: String, after: String, wasFound : Bool)
{
var rng = unicodeScalars
for i in indices(rng) {
if rng[i] == delim {
return (rng[rng.startIndex...i], rng[i.succ()...rng.endIndex], true)
}
}
return (self, "", false)
}
/// \brief Split the given string at the first character for which the given
/// predicate returns true. Returns the string before that character, the
/// character that matches, the string after that character, and a boolean value
/// indicating whether any character was found.
func splitFirstIf(pred: (UnicodeScalar) -> Bool)
-> (before: String, found: UnicodeScalar, after: String, wasFound: Bool)
{
var rng = unicodeScalars
for i in indices(rng) {
if pred(rng[i]) {
return (rng[rng.startIndex...i], rng[i], rng[i.succ()...rng.endIndex], true)
}
}
return (self, "🎃", String(), false)
}
/// \brief Split the given string at each occurrence of a character for which
/// the given predicate evaluates true, returning an array of strings that
/// before/between/after those delimiters.
func splitIf(pred: (UnicodeScalar) -> Bool) -> String[] {
var scalarSlices = Swift.split(unicodeScalars, pred)
return scalarSlices.map { $0 as String }
}
}