mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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
406 lines
12 KiB
Swift
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 }
|
|
}
|
|
}
|
|
|