mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Adjust test cases.
Swift SVN r17964
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
:orphan:
|
||||
|
||||
Hacking on Swift
|
||||
================
|
||||
|
||||
|
||||
@@ -6,11 +6,13 @@ swift - the amazingly new programming language
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<swift> [B<-c>|B<-S>|B<-i>] B<-sdk=>I<SDK-path> B<-g>
|
||||
[B<-O0>|B<-O1>|B<-O2>|B<-O3>]
|
||||
B<swift> [B<-emit-object>|B<-emit-assembly>|B<-emit-library>|B<-i>]
|
||||
[-help]
|
||||
B<-o> I<output-file>
|
||||
I<input-filenames>
|
||||
|
||||
The full list of supported options is available via "swift -help".
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<Swift> is a new, high performance systems programming language. It has a clean
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===--- SwiftTargetInfo.cpp --------------------------------------------*-===//
|
||||
//===--- SwiftTargetInfo.cpp ----------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
@@ -19,63 +19,137 @@
|
||||
#include "IRGenModule.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "swift/IRGen/Options.h"
|
||||
#include "swift/ABI/System.h"
|
||||
#include "swift/AST/IRGenOptions.h"
|
||||
|
||||
using namespace swift;
|
||||
using namespace irgen;
|
||||
|
||||
/// Creates a generic SwiftTargetInfo with conservative values that should
|
||||
/// be valid for any platform absent more specific information.
|
||||
static SwiftTargetInfo getGenericSwiftTargetInfo(IRGenModule &IGM) {
|
||||
auto pointerSize = IGM.DataLayout.getPointerSizeInBits();
|
||||
|
||||
// Assume no spare bits in pointers.
|
||||
llvm::BitVector pointerSpareBits(pointerSize, false);
|
||||
// Assume all bit patterns are reserved by the ObjC runtime.
|
||||
llvm::BitVector objcReservedBits(pointerSize, true);
|
||||
// Assume no special alignment of heap objects.
|
||||
Alignment heapObjectAlignment(1);
|
||||
// Assume only zero is an invalid pointer.
|
||||
uint64_t leastValidPointerValue = 1;
|
||||
|
||||
return SwiftTargetInfo(std::move(pointerSpareBits),
|
||||
std::move(objcReservedBits),
|
||||
heapObjectAlignment,
|
||||
leastValidPointerValue);
|
||||
/// Initialize a bit vector to be equal to the given bit-mask.
|
||||
static void setToMask(llvm::BitVector &bits, uint64_t mask) {
|
||||
// This is a ridiculously inefficient way of doing this.
|
||||
for (unsigned i = 0, e = bits.size(); i != e; ++i) {
|
||||
if (mask & (1ULL << i)) {
|
||||
bits.set(i);
|
||||
} else {
|
||||
bits.reset(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates SwiftTargetInfo for X86-64 platforms.
|
||||
static SwiftTargetInfo getX86_64SwiftTargetInfo(IRGenModule &IGM) {
|
||||
// User space only uses the low 47 bits of a pointer.
|
||||
// FIXME: In kernel mode, the highest bit is occupied.
|
||||
llvm::BitVector pointerSpareBits(47, false);
|
||||
pointerSpareBits.resize(64, true);
|
||||
/// Configures target-specific information for arm64 platforms.
|
||||
static void configureARM64(IRGenModule &IGM, const llvm::Triple &triple,
|
||||
SwiftTargetInfo &target) {
|
||||
setToMask(target.PointerSpareBits,
|
||||
SWIFT_ABI_ARM64_SWIFT_SPARE_BITS_MASK);
|
||||
setToMask(target.ObjCPointerReservedBits,
|
||||
SWIFT_ABI_ARM64_OBJC_RESERVED_BITS_MASK);
|
||||
|
||||
// Objective-C reserves the lowest and highest bits for tagged pointers.
|
||||
llvm::BitVector objcReservedBits(64, false);
|
||||
objcReservedBits[0] = true;
|
||||
objcReservedBits[63] = true;
|
||||
if (triple.isOSDarwin()) {
|
||||
target.LeastValidPointerValue =
|
||||
SWIFT_ABI_DARWIN_ARM64_LEAST_VALID_POINTER;
|
||||
}
|
||||
|
||||
// Heap objects are 16-byte-aligned.
|
||||
Alignment heapObjectAlignment(16);
|
||||
// CGPoint and CGRect are both returned in registers.
|
||||
target.MaxScalarsForDirectResult = 4;
|
||||
|
||||
// The null 4K page is always unmapped.
|
||||
// FIXME: Are additional null pages always unmapped on some platforms?
|
||||
uint64_t leastValidPointerValue = 4096;
|
||||
// arm64 has no special objc_msgSend variants, not even stret.
|
||||
target.ObjCUseStret = false;
|
||||
|
||||
return SwiftTargetInfo(std::move(pointerSpareBits),
|
||||
std::move(objcReservedBits),
|
||||
heapObjectAlignment,
|
||||
leastValidPointerValue);
|
||||
// arm64 requires marker assembly for objc_retainAutoreleasedReturnValue.
|
||||
target.ObjCRetainAutoreleasedReturnValueMarker =
|
||||
"mov\tfp, fp\t\t; marker for objc_retainAutoreleaseReturnValue";
|
||||
}
|
||||
|
||||
/// Configures target-specific information for x86-64 platforms.
|
||||
static void configureX86_64(IRGenModule &IGM, const llvm::Triple &triple,
|
||||
SwiftTargetInfo &target) {
|
||||
setToMask(target.PointerSpareBits,
|
||||
SWIFT_ABI_X86_64_SWIFT_SPARE_BITS_MASK);
|
||||
setToMask(target.ObjCPointerReservedBits,
|
||||
SWIFT_ABI_X86_64_OBJC_RESERVED_BITS_MASK);
|
||||
|
||||
if (triple.isOSDarwin()) {
|
||||
target.LeastValidPointerValue =
|
||||
SWIFT_ABI_DARWIN_X86_64_LEAST_VALID_POINTER;
|
||||
}
|
||||
|
||||
// On simulator targets, use null instead of &_objc_empty_vtable.
|
||||
if (triple.isiOS())
|
||||
target.ObjCUseNullForEmptyVTable = true;
|
||||
|
||||
// x86-64 has every objc_msgSend variant known to humankind.
|
||||
target.ObjCUseFPRet = true;
|
||||
target.ObjCUseFP2Ret = true;
|
||||
}
|
||||
|
||||
/// Configures target-specific information for 32-bit x86 platforms.
|
||||
static void configureX86(IRGenModule &IGM, const llvm::Triple &triple,
|
||||
SwiftTargetInfo &target) {
|
||||
// On simulator targets, use null instead of &_objc_empty_vtable.
|
||||
if (triple.isiOS())
|
||||
target.ObjCUseNullForEmptyVTable = true;
|
||||
|
||||
// x86 uses objc_msgSend_fpret but not objc_msgSend_fp2ret.
|
||||
target.ObjCUseFPRet = true;
|
||||
}
|
||||
|
||||
/// Configures target-specific information for 32-bit arm platforms.
|
||||
static void configureARM(IRGenModule &IGM, const llvm::Triple &triple,
|
||||
SwiftTargetInfo &target) {
|
||||
// ARM requires marker assembly for objc_retainAutoreleasedReturnValue.
|
||||
target.ObjCRetainAutoreleasedReturnValueMarker =
|
||||
"mov\tr7, r7\t\t@ marker for objc_retainAutoreleaseReturnValue";
|
||||
}
|
||||
|
||||
/// Configure a default target.
|
||||
SwiftTargetInfo::SwiftTargetInfo(unsigned numPointerBits)
|
||||
: PointerSpareBits(numPointerBits, false),
|
||||
ObjCPointerReservedBits(numPointerBits, true),
|
||||
HeapObjectAlignment(numPointerBits / 8),
|
||||
LeastValidPointerValue(SWIFT_ABI_DEFAULT_LEAST_VALID_POINTER)
|
||||
{
|
||||
setToMask(PointerSpareBits,
|
||||
SWIFT_ABI_DEFAULT_SWIFT_SPARE_BITS_MASK);
|
||||
setToMask(ObjCPointerReservedBits,
|
||||
SWIFT_ABI_DEFAULT_OBJC_RESERVED_BITS_MASK);
|
||||
}
|
||||
|
||||
SwiftTargetInfo SwiftTargetInfo::get(IRGenModule &IGM) {
|
||||
llvm::Triple triple(IGM.Opts.Triple);
|
||||
auto pointerSize = IGM.DataLayout.getPointerSizeInBits();
|
||||
|
||||
/// Prepare generic target information.
|
||||
SwiftTargetInfo target(pointerSize);
|
||||
|
||||
switch (triple.getArch()) {
|
||||
case llvm::Triple::x86_64:
|
||||
return getX86_64SwiftTargetInfo(IGM);
|
||||
configureX86_64(IGM, triple, target);
|
||||
break;
|
||||
|
||||
case llvm::Triple::x86:
|
||||
configureX86(IGM, triple, target);
|
||||
break;
|
||||
|
||||
case llvm::Triple::arm:
|
||||
configureARM(IGM, triple, target);
|
||||
break;
|
||||
|
||||
case llvm::Triple::arm64:
|
||||
configureARM64(IGM, triple, target);
|
||||
break;
|
||||
|
||||
default:
|
||||
return getGenericSwiftTargetInfo(IGM);
|
||||
// FIXME: Complain here? Default target info is unlikely to be correct.
|
||||
break;
|
||||
}
|
||||
|
||||
// The JIT does not support absolute symbols, so we have to use null
|
||||
// for &objc_empty_vtable.
|
||||
if (IGM.Opts.UseJIT) {
|
||||
target.ObjCUseNullForEmptyVTable = true;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,40 +26,52 @@ namespace irgen {
|
||||
class IRGenModule;
|
||||
|
||||
class SwiftTargetInfo {
|
||||
explicit SwiftTargetInfo(unsigned numPointerBits);
|
||||
|
||||
public:
|
||||
SwiftTargetInfo(llvm::BitVector &&pointerSpareBits,
|
||||
llvm::BitVector &&objcPointerReservedBits,
|
||||
Alignment heapObjectAlignment,
|
||||
uint64_t leastValidPointerValue)
|
||||
: PointerSpareBits(std::move(pointerSpareBits)),
|
||||
ObjCPointerReservedBits(std::move(objcPointerReservedBits)),
|
||||
HeapObjectAlignment(heapObjectAlignment),
|
||||
LeastValidPointerValue(leastValidPointerValue)
|
||||
{}
|
||||
|
||||
/// Produces a SwiftTargetInfo object appropriate to the target.
|
||||
static SwiftTargetInfo get(IRGenModule &IGM);
|
||||
|
||||
/// The spare bit mask for pointers. Bits set in this mask are unused by
|
||||
/// pointers of any alignment.
|
||||
const llvm::BitVector PointerSpareBits;
|
||||
llvm::BitVector PointerSpareBits;
|
||||
|
||||
/// The reserved bit mask for Objective-C pointers. Pointer values with
|
||||
/// bits from this mask set are reserved by the ObjC runtime and cannot be
|
||||
/// used for Swift value layout when a reference type may reference ObjC
|
||||
/// objects.
|
||||
const llvm::BitVector ObjCPointerReservedBits;
|
||||
llvm::BitVector ObjCPointerReservedBits;
|
||||
|
||||
/// The alignment of heap objects.
|
||||
const Alignment HeapObjectAlignment;
|
||||
/// The alignment of heap objects. By default, assume pointer alignment.
|
||||
Alignment HeapObjectAlignment;
|
||||
|
||||
/// The least integer value that can theoretically form a valid pointer.
|
||||
/// This excludes addresses in the null page(s) guaranteed to be unmapped by
|
||||
/// the platform.
|
||||
const uint64_t LeastValidPointerValue;
|
||||
/// By default, assume that there's an entire page free.
|
||||
///
|
||||
/// This excludes addresses in the null page(s) guaranteed to be
|
||||
/// unmapped by the platform.
|
||||
///
|
||||
/// Changes to this must be kept in sync with swift/Runtime/Metadata.h.
|
||||
uint64_t LeastValidPointerValue;
|
||||
|
||||
/// The maximum number of scalars that we allow to be returned directly.
|
||||
/// FIXME Until rdar://14679857, this must be set such that
|
||||
/// NSRect and NSPoint structs are returned correctly.
|
||||
unsigned MaxScalarsForDirectResult = 3;
|
||||
|
||||
/// Inline assembly to mark a call to objc_retainAutoreleasedReturnValue.
|
||||
llvm::StringRef ObjCRetainAutoreleasedReturnValueMarker;
|
||||
|
||||
/// Some architectures have specialized objc_msgSend variants.
|
||||
bool ObjCUseStret = true;
|
||||
bool ObjCUseFPRet = false;
|
||||
bool ObjCUseFP2Ret = false;
|
||||
bool ObjCUseNullForEmptyVTable = false;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,114 +1,281 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Swift Algorithm Library.
|
||||
// ===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
func minElement<
|
||||
R : Enumerator
|
||||
requires R.Element : Comparable>(range : R)
|
||||
-> R.Element {
|
||||
var result = range.next()
|
||||
while !range.isEmpty() {
|
||||
var next = range.next()
|
||||
if next < result { result = next }
|
||||
R : Sequence
|
||||
where R.GeneratorType.Element : Comparable>(range: R)
|
||||
-> R.GeneratorType.Element {
|
||||
var g = range.generate()
|
||||
var result = g.next()!
|
||||
for e in GeneratorSequence(g) {
|
||||
if e < result { result = e }
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func maxElement<
|
||||
R : Enumerator
|
||||
requires R.Element : Comparable>(range : R)
|
||||
-> R.Element {
|
||||
var result = range.next()
|
||||
while !range.isEmpty() {
|
||||
var next = range.next()
|
||||
if next > result { result = next }
|
||||
R : Sequence
|
||||
where R.GeneratorType.Element : Comparable>(range: R)
|
||||
-> R.GeneratorType.Element {
|
||||
var g = range.generate()
|
||||
var result = g.next()!
|
||||
for e in GeneratorSequence(g) {
|
||||
if e > result { result = e }
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func find<T : Equatable>(array : T[], value : T) -> Int {
|
||||
var idx = 0
|
||||
for elt in array {
|
||||
if elt == value { return idx }
|
||||
++idx
|
||||
// Returns the first index where value appears in domain or nil if
|
||||
// domain doesn't contain the value. O(countElements(domain))
|
||||
func find<
|
||||
C: Collection where C.GeneratorType.Element : Equatable
|
||||
>(domain: C, value: C.GeneratorType.Element) -> C.IndexType? {
|
||||
for i in indices(domain) {
|
||||
if domain[i] == value {
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FIXME: use generic predicated sort()
|
||||
// BLOCKED: <rdar://problem/12780569> Crash in IRGen while making sort()/map() generic
|
||||
func sort<T : Comparable>(array : T[]) -> T[] {
|
||||
var result = array.copy()
|
||||
for i in 0..result.length {
|
||||
for j in i+1..result.length {
|
||||
if result[j] < result[i] {
|
||||
// FIXME: Use swap()
|
||||
// BLOCKED: <rdar://problem/12782554> write-back properties do not work
|
||||
var temp = result[i]
|
||||
result[i] = result[j]
|
||||
result[j] = temp
|
||||
func insertionSort<
|
||||
C: MutableCollection where C.IndexType: BidirectionalIndex
|
||||
>(
|
||||
inout elements: C,
|
||||
range: Range<C.IndexType>,
|
||||
inout less: (C.GeneratorType.Element, C.GeneratorType.Element)->Bool
|
||||
) {
|
||||
if range {
|
||||
let start = range.startIndex
|
||||
|
||||
// Keep track of the end of the initial sequence of sorted
|
||||
// elements.
|
||||
var sortedEnd = start
|
||||
|
||||
// One element is trivially already-sorted, thus pre-increment
|
||||
// Continue until the sorted elements cover the whole sequence
|
||||
while (++sortedEnd != range.endIndex) {
|
||||
// get the first unsorted element
|
||||
var x: C.GeneratorType.Element = elements[sortedEnd]
|
||||
|
||||
// Look backwards for x's position in the sorted sequence,
|
||||
// moving elements forward to make room.
|
||||
var i = sortedEnd
|
||||
do {
|
||||
let predecessor: C.GeneratorType.Element = elements[i.pred()]
|
||||
|
||||
// if x doesn't belong before y, we've found its position
|
||||
if !less(x, predecessor) {
|
||||
break
|
||||
}
|
||||
|
||||
// Move y forward
|
||||
elements[i] = predecessor
|
||||
}
|
||||
while --i != start
|
||||
|
||||
if i != sortedEnd {
|
||||
// Plop x into position
|
||||
elements[i] = x
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// FIXME: make generic
|
||||
// BLOCKED: <rdar://problem/12780569> Crash in IRGen while making sort()/map() generic
|
||||
func sort(array : String[], pred : (String, String) -> Bool) -> String[] {
|
||||
var result = array.copy()
|
||||
for i in 0..result.length {
|
||||
for j in i+1..result.length {
|
||||
if pred(result[j], result[i]) {
|
||||
// FIXME: Use swap()
|
||||
// BLOCKED: <rdar://problem/12782554> write-back properties do not work
|
||||
var temp = result[i]
|
||||
result[i] = result[j]
|
||||
result[j] = temp
|
||||
/// Partition a non empty range into two partially sorted regions:
|
||||
/// [start..idx), [idx..end)
|
||||
func partition<C: MutableCollection where C.IndexType: SignedInteger>(
|
||||
inout elements: C,
|
||||
range: Range<C.IndexType>,
|
||||
inout less: (C.GeneratorType.Element, C.GeneratorType.Element)->Bool
|
||||
) -> C.IndexType {
|
||||
|
||||
var i = range.startIndex
|
||||
var j = range.endIndex - 1
|
||||
|
||||
let pivot = (i + j) / 2
|
||||
while i <= j {
|
||||
while less(elements[i], elements[pivot]) {
|
||||
i++
|
||||
}
|
||||
while less(elements[pivot], elements[j]) {
|
||||
j--
|
||||
}
|
||||
if i <= j {
|
||||
swap(&elements[i], &elements[j])
|
||||
i++
|
||||
j--
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
// FIXME: make generic
|
||||
// BLOCKED: <rdar://problem/12780569> Crash in IRGen while making sort()/map() generic
|
||||
func sort(array : (key: String, value: Int)[],
|
||||
pred : ((key: String, value: Int), (key: String, value: Int)) -> Bool)
|
||||
-> (key: String, value: Int)[] {
|
||||
var result = array.copy()
|
||||
for i in 0..result.length {
|
||||
for j in i+1..result.length {
|
||||
if pred(result[j], result[i]) {
|
||||
// FIXME: Use swap()
|
||||
// BLOCKED: <rdar://problem/12782554> write-back properties do not work
|
||||
var temp = result[i]
|
||||
result[i] = result[j]
|
||||
result[j] = temp
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
func quickSort<C: MutableCollection where C.IndexType: SignedInteger>(
|
||||
inout elements: C,
|
||||
range: Range<C.IndexType>,
|
||||
less: (C.GeneratorType.Element, C.GeneratorType.Element)->Bool
|
||||
) {
|
||||
var comp = less
|
||||
_quickSort(&elements, range, &comp)
|
||||
}
|
||||
|
||||
// FIXME: map() should support returning an array of a different type:
|
||||
// func map<U>(f : (T) -> U) -> U[] {
|
||||
func map<T>(array : T[], fn : (T) -> T) -> T[] {
|
||||
var result = new T[array.length]
|
||||
for i in 0..array.length {
|
||||
result[i] = fn(array[i])
|
||||
func _quickSort<C: MutableCollection where C.IndexType: SignedInteger>(
|
||||
inout elements: C,
|
||||
range: Range<C.IndexType>,
|
||||
inout less: (C.GeneratorType.Element, C.GeneratorType.Element)->Bool
|
||||
) {
|
||||
|
||||
// Insertion sort is better at handling smaller regions.
|
||||
let cnt = count(range)
|
||||
if cnt < 16 {
|
||||
insertionSort(&elements, range, &less)
|
||||
return
|
||||
}
|
||||
return result
|
||||
|
||||
// Partition and sort.
|
||||
let part_idx : C.IndexType = partition(&elements, range, &less)
|
||||
_quickSort(&elements, range.startIndex...part_idx, &less);
|
||||
_quickSort(&elements, part_idx...range.endIndex, &less);
|
||||
}
|
||||
|
||||
func swap<T>(a : [byref] T, b : [byref] T) {
|
||||
var c = a
|
||||
a = b
|
||||
b = c
|
||||
struct Less<T: Comparable> {
|
||||
static func compare(x: T, _ y: T) -> Bool {
|
||||
return x < y
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME -- BLOCKED: <rdar://problem/12695123> Crash while trying to make min/max generic
|
||||
//func min<T : Comparable>(x : T, y : T, rest : T...) -> T {
|
||||
func min(x : Int, y : Int, rest : Int...) -> Int {
|
||||
func sort<T>(var array: T[], pred: (T, T) -> Bool) -> T[] {
|
||||
quickSort(&array, 0...array.count, pred)
|
||||
return array
|
||||
}
|
||||
|
||||
/// The functions below are a copy of the functions above except that
|
||||
/// they don't accept a predicate and they are hardcoded to use the less-than
|
||||
/// comparator.
|
||||
func sort<T : Comparable>(var array: T[]) -> T[] {
|
||||
quickSort(&array, 0...array.count)
|
||||
return array
|
||||
}
|
||||
|
||||
func insertionSort<
|
||||
C: MutableCollection where C.IndexType: BidirectionalIndex,
|
||||
C.GeneratorType.Element: Comparable>(
|
||||
inout elements: C,
|
||||
range: Range<C.IndexType>) {
|
||||
|
||||
if range {
|
||||
let start = range.startIndex
|
||||
|
||||
// Keep track of the end of the initial sequence of sorted
|
||||
// elements.
|
||||
var sortedEnd = start
|
||||
|
||||
// One element is trivially already-sorted, thus pre-increment
|
||||
// Continue until the sorted elements cover the whole sequence
|
||||
while (++sortedEnd != range.endIndex) {
|
||||
// get the first unsorted element
|
||||
var x: C.GeneratorType.Element = elements[sortedEnd]
|
||||
|
||||
// Look backwards for x's position in the sorted sequence,
|
||||
// moving elements forward to make room.
|
||||
var i = sortedEnd
|
||||
do {
|
||||
let predecessor: C.GeneratorType.Element = elements[i.pred()]
|
||||
|
||||
// if x doesn't belong before y, we've found its position
|
||||
if !Less.compare(x, predecessor) {
|
||||
break
|
||||
}
|
||||
|
||||
// Move y forward
|
||||
elements[i] = predecessor
|
||||
}
|
||||
while --i != start
|
||||
|
||||
if i != sortedEnd {
|
||||
// Plop x into position
|
||||
elements[i] = x
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Partition a non empty range into two partially sorted regions:
|
||||
/// [start..idx), [idx..end)
|
||||
func partition<C: MutableCollection where C.GeneratorType.Element: Comparable, C.IndexType: SignedInteger>(
|
||||
inout elements: C,
|
||||
range: Range<C.IndexType>) -> C.IndexType {
|
||||
|
||||
var i = range.startIndex
|
||||
var j = range.endIndex - 1
|
||||
|
||||
let pivot = (i + j) / 2
|
||||
while i <= j {
|
||||
while Less.compare(elements[i], elements[pivot]) {
|
||||
i++
|
||||
}
|
||||
while Less.compare(elements[pivot], elements[j]) {
|
||||
j--
|
||||
}
|
||||
if i <= j {
|
||||
swap(&elements[i], &elements[j])
|
||||
i++
|
||||
j--
|
||||
}
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
func quickSort<C: MutableCollection where C.GeneratorType.Element: Comparable, C.IndexType: SignedInteger>(
|
||||
inout elements: C,
|
||||
range: Range<C.IndexType>) {
|
||||
_quickSort(&elements, range)
|
||||
}
|
||||
|
||||
func _quickSort<C: MutableCollection where C.GeneratorType.Element: Comparable, C.IndexType: SignedInteger>(
|
||||
inout elements: C, range: Range<C.IndexType>) {
|
||||
// Insertion sort is better at handling smaller regions.
|
||||
let cnt = count(range)
|
||||
if cnt < 16 {
|
||||
insertionSort(&elements, range)
|
||||
return
|
||||
}
|
||||
// Partition and sort.
|
||||
let part_idx : C.IndexType = partition(&elements, range)
|
||||
_quickSort(&elements, range.startIndex...part_idx);
|
||||
_quickSort(&elements, part_idx...range.endIndex);
|
||||
}
|
||||
//// End of non-predicate sort functions.
|
||||
|
||||
|
||||
func swap<T>(inout a : T, inout b : T) {
|
||||
// Semantically equivalent to (a, b) = (b, a).
|
||||
// Microoptimized to avoid retain/release traffic.
|
||||
let p1 = Builtin.addressof(&a)
|
||||
let p2 = Builtin.addressof(&b)
|
||||
|
||||
// Take from P1.
|
||||
let tmp : T = Builtin.take(p1)
|
||||
// Transfer P2 into P1.
|
||||
Builtin.initialize(Builtin.take(p2) as T, p1)
|
||||
// Initialize P2.
|
||||
Builtin.initialize(tmp, p2)
|
||||
}
|
||||
|
||||
|
||||
func min<T : Comparable>(x: T, y: T, rest: T...) -> T {
|
||||
var r = x
|
||||
if y < x {
|
||||
r = y
|
||||
@@ -121,22 +288,7 @@ func min(x : Int, y : Int, rest : Int...) -> Int {
|
||||
return r
|
||||
}
|
||||
|
||||
func min(x : Double, y : Double, rest : Double...) -> Double {
|
||||
var r = x
|
||||
if y < x {
|
||||
r = y
|
||||
}
|
||||
for z in rest {
|
||||
if z < r {
|
||||
r = z
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// FIXME -- BLOCKED: <rdar://problem/12695123> Crash while trying to make min/max generic
|
||||
//func max<T : Comparable>(x : T, y : T, rest : T...) -> T {
|
||||
func max(x : Int, y : Int, rest : Int...) -> Int {
|
||||
func max<T : Comparable>(x: T, y: T, rest: T...) -> T {
|
||||
var r = y
|
||||
if y < x {
|
||||
r = x
|
||||
@@ -149,80 +301,237 @@ func max(x : Int, y : Int, rest : Int...) -> Int {
|
||||
return r
|
||||
}
|
||||
|
||||
func max(x : Double, y : Double, rest : Double...) -> Double {
|
||||
var r = y
|
||||
if y < x {
|
||||
r = x
|
||||
}
|
||||
for z in rest {
|
||||
if z >= r {
|
||||
r = z
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func split<
|
||||
Seq: Sliceable,
|
||||
IsSeparator: Predicate
|
||||
requires IsSeparator.Arguments == Seq.Element
|
||||
>(seq: Seq,
|
||||
isSeparator: IsSeparator,
|
||||
maxSplit: Int = Int.max(),
|
||||
func split<Seq: Sliceable, R:LogicValue>(
|
||||
seq: Seq,
|
||||
isSeparator: (Seq.GeneratorType.Element)->R,
|
||||
maxSplit: Int = Int.max,
|
||||
allowEmptySlices: Bool = false
|
||||
) -> Seq[] {
|
||||
) -> Seq.SliceType[] {
|
||||
|
||||
var result = Vector<Seq>()
|
||||
var result = Array<Seq.SliceType>()
|
||||
|
||||
var startIndex = allowEmptySlices ? Some(seq.begin()) : None
|
||||
// FIXME: could be simplified pending <rdar://problem/15032945>
|
||||
// (ternary operator not resolving some/none)
|
||||
var startIndex: Optional<Seq.IndexType>
|
||||
= allowEmptySlices ? .Some(seq.startIndex) : .None
|
||||
var splits = 0
|
||||
|
||||
for j in indices(seq) {
|
||||
if apply(isSeparator, seq.__getitem__(j)) {
|
||||
if isSeparator(seq[j]) {
|
||||
if startIndex {
|
||||
var i = startIndex.get()
|
||||
result.append(seq.__slice__(i, j))
|
||||
startIndex = Some(j.succ())
|
||||
var i = startIndex!
|
||||
result.append(seq[i...j])
|
||||
startIndex = .Some(j.succ())
|
||||
if ++splits >= maxSplit {
|
||||
break
|
||||
}
|
||||
if !allowEmptySlices {
|
||||
startIndex = None
|
||||
startIndex = .None
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if !startIndex {
|
||||
startIndex = Some(j)
|
||||
startIndex = .Some(j)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i in startIndex { // destructuring bind
|
||||
result.append(seq.__slice__(i, seq.end()))
|
||||
switch startIndex {
|
||||
case .Some(var i):
|
||||
result.append(seq[i...seq.endIndex])
|
||||
default:
|
||||
()
|
||||
}
|
||||
return result.takeArray()
|
||||
return result
|
||||
}
|
||||
|
||||
// FIXME: Until <rdar://problem/13985164> is fixed, we can't build
|
||||
// generic algorithms that work on Enumerables, so we're operating on
|
||||
// Enumerators here.
|
||||
|
||||
/// \brief Return true iff the elements of e1 are equal to the initial
|
||||
/// elements of e2
|
||||
|
||||
func startsWith<
|
||||
E0: Enumerator, E1: Enumerator
|
||||
requires
|
||||
E0.Element == E1.Element,
|
||||
E0.Element : Equatable
|
||||
>(e0: E0, e1: E1) -> Bool
|
||||
S0: Sequence, S1: Sequence
|
||||
where
|
||||
S0.GeneratorType.Element == S1.GeneratorType.Element,
|
||||
S0.GeneratorType.Element : Equatable
|
||||
>(s0: S0, s1: S1) -> Bool
|
||||
{
|
||||
while !e0.isEmpty() {
|
||||
if e1.isEmpty() { return true }
|
||||
if e0.next() != e1.next() {
|
||||
var g1 = s1.generate()
|
||||
|
||||
for e0 in s0 {
|
||||
var e1 = g1.next()
|
||||
if !e1 { return true }
|
||||
if e0 != e1! {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return e1.isEmpty()
|
||||
return g1.next() ? false : true
|
||||
}
|
||||
|
||||
struct EnumerateGenerator<Base: Generator> : Generator, Sequence {
|
||||
typealias Element = (index: Int, element: Base.Element)
|
||||
var base: Base
|
||||
var count: Int
|
||||
|
||||
init(_ base: Base) {
|
||||
self.base = base
|
||||
count = 0
|
||||
}
|
||||
|
||||
mutating func next() -> Element? {
|
||||
var b = base.next()
|
||||
if !b { return .None }
|
||||
return .Some((index: count++, element: b!))
|
||||
}
|
||||
|
||||
// Every Generator is also a single-pass Sequence
|
||||
typealias GeneratorType = EnumerateGenerator<Base>
|
||||
func generate() -> GeneratorType {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
func enumerate<Seq : Sequence>(
|
||||
seq: Seq
|
||||
) -> EnumerateGenerator<Seq.GeneratorType> {
|
||||
return EnumerateGenerator(seq.generate())
|
||||
}
|
||||
|
||||
|
||||
/// Return true iff `a1` and `a2` contain the same elements.
|
||||
func equal<
|
||||
S1 : Sequence, S2 : Sequence
|
||||
where
|
||||
S1.GeneratorType.Element == S2.GeneratorType.Element,
|
||||
S1.GeneratorType.Element : Equatable
|
||||
>(a1: S1, a2: S2) -> Bool
|
||||
{
|
||||
var g1 = a1.generate()
|
||||
var g2 = a2.generate()
|
||||
while true {
|
||||
var e1 = g1.next()
|
||||
var e2 = g2.next()
|
||||
if e1 && e2 {
|
||||
if e1! != e2! {
|
||||
return false
|
||||
}
|
||||
}
|
||||
else {
|
||||
return !e1 == !e2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true iff `a1` and `a2` contain the same elements, using
|
||||
/// `pred` as equality `==` comparison.
|
||||
func equal<
|
||||
S1 : Sequence, S2 : Sequence
|
||||
where
|
||||
S1.GeneratorType.Element == S2.GeneratorType.Element
|
||||
>(a1: S1, a2: S2,
|
||||
pred: (S1.GeneratorType.Element, S1.GeneratorType.Element) -> Bool) -> Bool
|
||||
{
|
||||
var g1 = a1.generate()
|
||||
var g2 = a2.generate()
|
||||
while true {
|
||||
var e1 = g1.next()
|
||||
var e2 = g2.next()
|
||||
if e1 && e2 {
|
||||
if !pred(e1!, e2!) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
else {
|
||||
return !e1 == !e2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true iff a1 precedes a2 in a lexicographical ("dictionary")
|
||||
/// ordering, using "<" as the comparison between elements.
|
||||
func lexicographicalCompare<
|
||||
S1 : Sequence, S2 : Sequence
|
||||
where
|
||||
S1.GeneratorType.Element == S2.GeneratorType.Element,
|
||||
S1.GeneratorType.Element : Comparable>(
|
||||
a1: S1, a2: S2) -> Bool {
|
||||
var g1 = a1.generate()
|
||||
var g2 = a2.generate()
|
||||
while true {
|
||||
var e1_ = g1.next()
|
||||
var e2_ = g2.next()
|
||||
if let e1 = e1_ {
|
||||
if let e2 = e2_ {
|
||||
if e1 < e2 {
|
||||
return true
|
||||
}
|
||||
if e2 < e1 {
|
||||
return false
|
||||
}
|
||||
continue // equivalent
|
||||
}
|
||||
return false
|
||||
}
|
||||
return e2_.getLogicValue()
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true iff a1 precedes a2 in a lexicographical ("dictionary")
|
||||
/// ordering, using less as the comparison between elements.
|
||||
func lexicographicalCompare<
|
||||
S1 : Sequence, S2 : Sequence
|
||||
where
|
||||
S1.GeneratorType.Element == S2.GeneratorType.Element
|
||||
>(
|
||||
a1: S1, a2: S2,
|
||||
less: (S1.GeneratorType.Element,S1.GeneratorType.Element)->Bool
|
||||
) -> Bool {
|
||||
var g1 = a1.generate()
|
||||
var g2 = a2.generate()
|
||||
while true {
|
||||
var e1_ = g1.next()
|
||||
var e2_ = g2.next()
|
||||
if let e1 = e1_ {
|
||||
if let e2 = e2_ {
|
||||
if less(e1, e2) {
|
||||
return true
|
||||
}
|
||||
if less(e2, e1) {
|
||||
return false
|
||||
}
|
||||
continue // equivalent
|
||||
}
|
||||
return false
|
||||
}
|
||||
return e2_.getLogicValue()
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief return true iff an element in seq satisfies predicate
|
||||
func contains<
|
||||
S: Sequence, L: LogicValue
|
||||
>(seq: S, predicate: (S.GeneratorType.Element)->L) -> Bool {
|
||||
for a in seq {
|
||||
if predicate(a) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/// \brief return true iff x is in seq
|
||||
func contains<
|
||||
S: Sequence where S.GeneratorType.Element: Equatable
|
||||
>(seq: S, x: S.GeneratorType.Element) -> Bool {
|
||||
return contains(seq, { $0 == x })
|
||||
}
|
||||
|
||||
func reduce<S: Sequence, U>(
|
||||
sequence: S, initial: U, combine: (U, S.GeneratorType.Element)->U
|
||||
) -> U {
|
||||
var result = initial
|
||||
for element in sequence {
|
||||
result = combine(result, element)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct ArrayBody {
|
||||
|
||||
struct _ArrayBody {
|
||||
init(count: Int, capacity: Int, elementTypeIsBridgedVerbatim: Bool = false) {
|
||||
assert(count >= 0)
|
||||
assert(capacity >= 0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===--- ArrayBuffer.swift - Dynamically-allocated storage for Swift Array ---===//
|
||||
//===--- ArrayBuffer.swift - Dynamic storage for Swift Array --------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
@@ -15,22 +15,325 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// A HeapBuffer whose storage contains zero or more consecutive Elements
|
||||
class ArrayBufferStorage<T>
|
||||
: HeapBufferStorage<CountAndCapacity, T> {
|
||||
import SwiftShims
|
||||
|
||||
destructor() {
|
||||
let p = HeapBuffer(self).elementStorage
|
||||
for i in 0...HeapBuffer(self).value.count {
|
||||
(p + i).destroy()
|
||||
enum _ArrayCastDirection { case Up, Down }
|
||||
|
||||
@final
|
||||
class IndirectArrayBuffer {
|
||||
|
||||
init<T>(_ buffer: NativeArrayBuffer<T>, _ mutable: Bool) {
|
||||
self.buffer = buffer.storage
|
||||
self.isMutable = mutable
|
||||
self.isCocoa = false
|
||||
}
|
||||
|
||||
init(_ x: CocoaArray) {
|
||||
self.buffer = x
|
||||
self.isMutable = false
|
||||
self.isCocoa = true
|
||||
}
|
||||
|
||||
init(castFrom: IndirectArrayBuffer, direction: _ArrayCastDirection) {
|
||||
self.buffer = castFrom.buffer
|
||||
self.isMutable = direction == .Down
|
||||
self.isCocoa = castFrom.isCocoa
|
||||
}
|
||||
|
||||
// When this buffer has immutable storage and it is modified, the
|
||||
// storage is replaced with mutable storage.
|
||||
func replaceStorage<T>(buffer: NativeArrayBuffer<T>) {
|
||||
self.buffer = buffer.storage
|
||||
self.isMutable = true
|
||||
self.isCocoa = false
|
||||
}
|
||||
|
||||
var buffer: AnyObject?
|
||||
var isMutable: Bool
|
||||
var isCocoa: Bool
|
||||
|
||||
func getNative<T>() -> NativeArrayBuffer<T> {
|
||||
assert(!isCocoa)
|
||||
return NativeArrayBuffer(
|
||||
buffer ? reinterpretCast(buffer) as NativeArrayStorage<T> : nil)
|
||||
}
|
||||
|
||||
func getCocoa() -> CocoaArray {
|
||||
assert(isCocoa)
|
||||
return reinterpretCast(buffer!) as CocoaArray
|
||||
}
|
||||
}
|
||||
|
||||
func arrayBuffer<T>(_:T.metatype, count: Int, capacity: Int) -> HeapBuffer<CountAndCapacity, T> {
|
||||
return HeapBuffer(
|
||||
ArrayBufferStorage<T>,
|
||||
CountAndCapacity(count: count, capacity: capacity),
|
||||
capacity
|
||||
struct ArrayBuffer<T> : ArrayBufferType {
|
||||
var storage: Builtin.NativeObject?
|
||||
|
||||
var indirect: IndirectArrayBuffer {
|
||||
assert(_isClassOrObjCExistential(T.self))
|
||||
return Builtin.castFromNativeObject(storage!)
|
||||
}
|
||||
|
||||
typealias Element = T
|
||||
|
||||
/// create an empty buffer
|
||||
init() {
|
||||
storage = !_isClassOrObjCExistential(T.self)
|
||||
? nil : Builtin.castToNativeObject(
|
||||
IndirectArrayBuffer(NativeArrayBuffer<T>(), false))
|
||||
}
|
||||
|
||||
init(_ cocoa: CocoaArray) {
|
||||
assert(_isClassOrObjCExistential(T.self))
|
||||
storage = Builtin.castToNativeObject(IndirectArrayBuffer(cocoa))
|
||||
}
|
||||
|
||||
/// An ArrayBuffer<T> containing the same elements.
|
||||
/// Requires: the elements actually have dynamic type T.
|
||||
init<U>(castFrom: ArrayBuffer<U>, direction: _ArrayCastDirection) {
|
||||
assert(_canBeClass(T.self))
|
||||
assert(_canBeClass(U.self))
|
||||
storage = Builtin.castToNativeObject(
|
||||
IndirectArrayBuffer(castFrom: castFrom.indirect, direction: direction))
|
||||
}
|
||||
|
||||
var dynamicElementType: Any.Type {
|
||||
return _isNative ? _native.dynamicElementType : AnyObject.self
|
||||
}
|
||||
}
|
||||
|
||||
extension ArrayBuffer {
|
||||
/// Adopt the storage of x
|
||||
init(_ buffer: NativeBuffer) {
|
||||
if !_isClassOrObjCExistential(T.self) {
|
||||
self.storage
|
||||
= buffer.storage ? Builtin.castToNativeObject(buffer.storage!) : nil
|
||||
}
|
||||
else {
|
||||
self.storage = Builtin.castToNativeObject(
|
||||
IndirectArrayBuffer(buffer, true))
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true iff this buffer's storage is uniquely-referenced.
|
||||
mutating func isUniquelyReferenced() -> Bool {
|
||||
return Swift.isUniquelyReferenced(&storage)
|
||||
}
|
||||
|
||||
/// Convert to an NSArray.
|
||||
/// Precondition: isBridgedToObjectiveC(Element.self)
|
||||
/// O(1) if the element type is bridged verbatim, O(N) otherwise
|
||||
func asCocoaArray() -> CocoaArray {
|
||||
assert(
|
||||
isBridgedToObjectiveC(T.self),
|
||||
"Array element type is not bridged to ObjectiveC")
|
||||
|
||||
return _fastPath(_isNative) ? _native.asCocoaArray() : _nonNative!
|
||||
}
|
||||
|
||||
var _hasMutableBuffer: Bool {
|
||||
if !_isClassOrObjCExistential(T.self) {
|
||||
return true
|
||||
}
|
||||
return indirect.isMutable && Swift.isUniquelyReferenced(&indirect.buffer)
|
||||
}
|
||||
|
||||
/// If this buffer is backed by a uniquely-referenced mutable
|
||||
/// NativeArrayBuffer that can be grown in-place to allow the self
|
||||
/// buffer store minimumCapacity elements, returns that buffer.
|
||||
/// Otherwise, returns nil
|
||||
mutating func requestUniqueMutableBuffer(minimumCapacity: Int)
|
||||
-> NativeBuffer?
|
||||
{
|
||||
if _fastPath(Swift.isUniquelyReferenced(&storage) && _hasMutableBuffer) {
|
||||
let b = _native
|
||||
return b.capacity >= minimumCapacity ? b : nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/// If this buffer is backed by a NativeArrayBuffer, return it.
|
||||
/// Otherwise, return nil. Note: the result's elementStorage may
|
||||
/// not match ours, if we are a SliceBuffer.
|
||||
func requestNativeBuffer() -> NativeBuffer? {
|
||||
return self._native
|
||||
}
|
||||
|
||||
/// Copy the given subRange of this buffer into uninitialized memory
|
||||
/// starting at target. Return a pointer past-the-end of the
|
||||
/// just-initialized memory.
|
||||
func _uninitializedCopy(
|
||||
subRange: Range<Int>, target: UnsafePointer<T>
|
||||
) -> UnsafePointer<T> {
|
||||
if _fastPath(_isNative) {
|
||||
return _native._uninitializedCopy(subRange, target: target)
|
||||
}
|
||||
|
||||
let nonNative = _nonNative!
|
||||
|
||||
let nsSubRange = SwiftShims._SwiftNSRange(
|
||||
location:subRange.startIndex,
|
||||
length: subRange.endIndex - subRange.startIndex)
|
||||
|
||||
let buffer = reinterpretCast(target) as UnsafePointer<AnyObject>
|
||||
|
||||
// Copies the references out of the NSArray without retaining them
|
||||
nonNative.getObjects(buffer, range: nsSubRange)
|
||||
|
||||
// Make another pass to retain the copied objects
|
||||
var result = target
|
||||
for i in subRange {
|
||||
result.initialize(result.get())
|
||||
++result
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/// Return a SliceBuffer containing the given subRange of values
|
||||
/// from this buffer.
|
||||
subscript(subRange: Range<Int>) -> SliceBuffer<T> {
|
||||
|
||||
if _fastPath(_isNative) {
|
||||
return _native[subRange]
|
||||
}
|
||||
|
||||
let nonNative = self._nonNative
|
||||
|
||||
let subRangeCount = countElements(subRange)
|
||||
|
||||
// Look for contiguous storage in the NSArray
|
||||
let cocoa = CocoaArrayWrapper(nonNative!)
|
||||
let start = cocoa.contiguousStorage(subRange)
|
||||
if start != nil {
|
||||
return SliceBuffer(owner: nonNative, start: UnsafePointer(start),
|
||||
count: subRangeCount, hasNativeBuffer: false)
|
||||
}
|
||||
|
||||
// No contiguous storage found; we must allocate
|
||||
var result = NativeArrayBuffer<T>(count: subRangeCount, minimumCapacity: 0)
|
||||
|
||||
// Tell Cocoa to copy the objects into our storage
|
||||
cocoa.buffer.getObjects(
|
||||
UnsafePointer(result.elementStorage),
|
||||
range: _SwiftNSRange(location: subRange.startIndex, length: subRangeCount)
|
||||
)
|
||||
|
||||
return SliceBuffer(result)
|
||||
}
|
||||
|
||||
/// If the elements are stored contiguously, a pointer to the first
|
||||
/// element. Otherwise, nil.
|
||||
var elementStorage: UnsafePointer<T> {
|
||||
if (_fastPath(_isNative)) {
|
||||
return _native.elementStorage
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/// How many elements the buffer stores
|
||||
var count: Int {
|
||||
get {
|
||||
return _fastPath(_isNative) ? _native.count : _nonNative!.count
|
||||
}
|
||||
set {
|
||||
// Allow zero here for the case where elements have been moved
|
||||
// out of the buffer during reallocation
|
||||
assert(
|
||||
newValue == 0 || newValue >= count,
|
||||
"We don't yet know how to shrink an array")
|
||||
|
||||
assert(_isNative, "attempting to update count of Cocoa array")
|
||||
_native.count = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/// How many elements the buffer can store without reallocation
|
||||
var capacity: Int {
|
||||
return _fastPath(_isNative) ? _native.capacity : _nonNative!.count
|
||||
}
|
||||
|
||||
/// Get/set the value of the ith element
|
||||
subscript(i: Int) -> T {
|
||||
get {
|
||||
if _fastPath(_isNative) {
|
||||
return _native[i]
|
||||
}
|
||||
return reinterpretCast(_nonNative!.objectAtIndex(i))
|
||||
}
|
||||
|
||||
nonmutating set {
|
||||
if _fastPath(_hasMutableBuffer) {
|
||||
_native[i] = newValue
|
||||
}
|
||||
else {
|
||||
indirect.replaceStorage(_copyCollectionToNativeArrayBuffer(self))
|
||||
_native[i] = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An object that keeps the elements stored in this buffer alive
|
||||
var owner: AnyObject? {
|
||||
return _fastPath(_isNative) ? _native.storage : _nonNative!
|
||||
}
|
||||
|
||||
/// A value that identifies first mutable element, if any. Two
|
||||
/// arrays compare === iff they are both empty or if their buffers
|
||||
/// have the same identity and count.
|
||||
var identity: Word {
|
||||
let p = elementStorage
|
||||
return p != nil ? reinterpretCast(p) : reinterpretCast(owner)
|
||||
}
|
||||
|
||||
//===--- Collection conformance -----------------------------------------===//
|
||||
var startIndex: Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
var endIndex: Int {
|
||||
return count
|
||||
}
|
||||
|
||||
func generate() -> IndexingGenerator<ArrayBuffer> {
|
||||
return IndexingGenerator(self)
|
||||
}
|
||||
|
||||
//===--- private --------------------------------------------------------===//
|
||||
typealias Storage = NativeArrayStorage<T>
|
||||
typealias NativeBuffer = NativeArrayBuffer<T>
|
||||
|
||||
func _invariantCheck() -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var _isNative: Bool {
|
||||
if !_isClassOrObjCExistential(T.self) {
|
||||
return true
|
||||
}
|
||||
else {
|
||||
return !indirect.isCocoa
|
||||
}
|
||||
}
|
||||
|
||||
/// Our native representation, if any. If there's no native
|
||||
/// representation, the result is an empty buffer.
|
||||
var _native: NativeBuffer {
|
||||
if !_isClassOrObjCExistential(T.self) {
|
||||
return NativeBuffer(
|
||||
reinterpretCast(storage) as NativeArrayStorage<T>?)
|
||||
}
|
||||
else {
|
||||
let i = indirect
|
||||
return _fastPath(!i.isCocoa) ? i.getNative() : NativeBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
var _nonNative: CocoaArray? {
|
||||
if !_isClassOrObjCExistential(T.self) {
|
||||
return nil
|
||||
}
|
||||
else {
|
||||
let i = indirect
|
||||
return _fastPath(!i.isCocoa) ? nil : i.getCocoa()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Serves as the buffer for an ArrayType. An ArrayBufferType does
|
||||
/// not impose value semantics on its elements, and whether its
|
||||
/// elements are actually being managed by copy-on-write (COW) is, in
|
||||
/// principle, unknown to the buffer.
|
||||
/// The underlying buffer for an ArrayType conforms to ArrayBufferType
|
||||
protocol ArrayBufferType : MutableCollection {
|
||||
/// The type of elements stored in the buffer
|
||||
typealias Element
|
||||
@@ -22,7 +19,7 @@ protocol ArrayBufferType : MutableCollection {
|
||||
init()
|
||||
|
||||
/// Adopt the storage of x
|
||||
init(x: NativeArrayBuffer<Element>)
|
||||
init(_ buffer: NativeArrayBuffer<Element>)
|
||||
|
||||
/// Copy the given subRange of this buffer into uninitialized memory
|
||||
/// starting at target. Return a pointer past-the-end of the
|
||||
@@ -30,26 +27,30 @@ protocol ArrayBufferType : MutableCollection {
|
||||
func _uninitializedCopy(subRange: Range<Int>, target: UnsafePointer<Element>)
|
||||
-> UnsafePointer<Element>
|
||||
|
||||
/// Convert to an NSArray in O(1).
|
||||
/// Convert to an NSArray.
|
||||
/// Precondition: isBridgedToObjectiveC(Element.self)
|
||||
/// O(1) if the element type is bridged verbatim, O(N) otherwise
|
||||
func asCocoaArray() -> CocoaArray
|
||||
|
||||
/// Convert to a NativeArrayBuffer storing the same elements.
|
||||
/// managedByCopyOnWrite is destined to be removed soon, but it
|
||||
/// indicates whether the buffer is to be marked for copying in
|
||||
/// copyWithZone.
|
||||
func toNativeBuffer(managedByCopyOnWrite: Bool)
|
||||
-> NativeArrayBuffer<Element>
|
||||
/// Get/set the index'th element
|
||||
subscript(index: Int) -> Element { get nonmutating set}
|
||||
|
||||
/// Return true iff this buffer's storage is uniquely-referenced.
|
||||
/// NOTE: this does not mean the buffer is mutable. Other factors
|
||||
/// may need to be considered, such as whether the buffer could be
|
||||
/// some immutable Cocoa container.
|
||||
mutating func isUniquelyReferenced() -> Bool
|
||||
/// If this buffer is backed by a uniquely-referenced mutable
|
||||
/// NativeArrayBuffer that can be grown in-place to allow the self
|
||||
/// buffer store minimumCapacity elements, returns that buffer.
|
||||
/// Otherwise, returns nil. Note: the result's elementStorage may
|
||||
/// not match ours, if we are a SliceBuffer.
|
||||
///
|
||||
/// Note: this function must remain mutating; otherwise the buffer
|
||||
/// may acquire spurious extra references, which will cause
|
||||
/// unnecessary reallocation.
|
||||
mutating func requestUniqueMutableBuffer(minimumCapacity: Int)
|
||||
-> NativeArrayBuffer<Element>?
|
||||
|
||||
/// Returns true iff this buffer is mutable. NOTE: a true result
|
||||
/// does not mean the buffer is uniquely-referenced.
|
||||
func isMutable() -> Bool
|
||||
/// If this buffer is backed by a NativeArrayBuffer, return it.
|
||||
/// Otherwise, return nil. Note: the result's elementStorage may
|
||||
/// not match ours, if we are a SliceBuffer.
|
||||
func requestNativeBuffer() -> NativeArrayBuffer<Element>?
|
||||
|
||||
/// Return a SliceBuffer containing the given subRange of values
|
||||
/// from this buffer.
|
||||
@@ -60,4 +61,16 @@ protocol ArrayBufferType : MutableCollection {
|
||||
|
||||
/// How many elements the buffer can store without reallocation
|
||||
var capacity: Int {get}
|
||||
|
||||
/// An object that keeps the elements stored in this buffer alive
|
||||
var owner: AnyObject? {get}
|
||||
|
||||
/// If the elements are stored contiguously, a pointer to the first
|
||||
/// element. Otherwise, nil.
|
||||
var elementStorage: UnsafePointer<Element> {get}
|
||||
|
||||
/// A value that identifies first mutable element, if any. Two
|
||||
/// arrays compare === iff they are both empty, or if their buffers
|
||||
/// have the same identity and count.
|
||||
var identity: Word {get}
|
||||
}
|
||||
|
||||
@@ -11,46 +11,107 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
protocol ArrayType
|
||||
// FIXME: must start with Collection; see <rdar://problem/16465340>
|
||||
: Collection,
|
||||
_ArrayType,
|
||||
MutableCollection,
|
||||
Sliceable,
|
||||
ArrayLiteralConvertible,
|
||||
ConditionallyBridgedToObjectiveC
|
||||
: _ArrayType,
|
||||
Collection,
|
||||
MutableSliceable,
|
||||
ArrayLiteralConvertible
|
||||
{
|
||||
//===--- public interface -----------------------------------------------===//
|
||||
/// Construct an empty Array
|
||||
init()
|
||||
|
||||
/// Construct an array of count elements, each initialized to value
|
||||
init(count: Int, value: Self.GeneratorType.Element)
|
||||
|
||||
/// How many elements the Array stores
|
||||
var count: Int {get}
|
||||
|
||||
/// How many elements the Array can store without reallocation
|
||||
var capacity: Int {get}
|
||||
|
||||
mutating func reserve(n: Int)
|
||||
mutating func append(element: Self.GeneratorType.Element)
|
||||
/// true if and only if the Array is empty
|
||||
var isEmpty: Bool {get}
|
||||
|
||||
/// An object that guarantees the lifetime of this array's elements
|
||||
var owner: AnyObject? {get}
|
||||
|
||||
/// If the elements are stored contiguously, a pointer to the first
|
||||
/// element. Otherwise, nil.
|
||||
var elementStorage: UnsafePointer<Element> {get}
|
||||
|
||||
subscript(index: Int) -> Self.GeneratorType.Element {get nonmutating set}
|
||||
|
||||
//===--- basic mutations ------------------------------------------------===//
|
||||
|
||||
/// Reserve enough space to store newCapacity elements in O(N). If
|
||||
/// newCapacity is less than count, has no effect. PostCondition:
|
||||
/// the array has mutable contiguous storage
|
||||
mutating func reserve(newCapacity: Int)
|
||||
|
||||
/// Append newElement to the Array in O(1) (amortized)
|
||||
mutating func append(newElement: Self.GeneratorType.Element)
|
||||
|
||||
/// Remove an element from the end of the Array in O(1). Returns:
|
||||
/// the removed element. Requires: count > 0
|
||||
mutating func popLast() -> Self.GeneratorType.Element
|
||||
|
||||
/// Insert an element at the given index in O(N). Requires: atIndex
|
||||
/// <= count
|
||||
mutating func insert(atIndex: Int, newElement: Self.GeneratorType.Element)
|
||||
|
||||
/// Remove the element at the given index. Returns: the removed
|
||||
/// element. Worst case complexity: O(N). Requires: count > index
|
||||
mutating func removeAt(index: Int) -> Self.GeneratorType.Element
|
||||
|
||||
/// Erase all the elements and release the storage
|
||||
mutating func clear()
|
||||
|
||||
/// Erase all the elements. If keepStorage is true, capacity will not change
|
||||
mutating func clear(keepStorage: Bool)
|
||||
|
||||
//===--- algorithms -----------------------------------------------------===//
|
||||
func reduce<U>(initial: U, combine: (U, Self.GeneratorType.Element) -> U) -> U
|
||||
|
||||
mutating func sort(
|
||||
isOrderedBefore: (
|
||||
Self.GeneratorType.Element, Self.GeneratorType.Element
|
||||
) -> Bool
|
||||
)
|
||||
|
||||
//===--- implementation detail -----------------------------------------===//
|
||||
|
||||
typealias Buffer : ArrayBufferType
|
||||
init(_: Buffer)
|
||||
|
||||
mutating func _adopt(
|
||||
newBuffer: NativeArrayBuffer<Self.GeneratorType.Element>)
|
||||
|
||||
// Returns true iff Self can allow its buffer to be directly
|
||||
// mutated. *Must* remain a mutating function and not a get-only
|
||||
// property if we are to have a hope of accurate uniqueness checks
|
||||
mutating func _hasMutableBuffer() -> Bool
|
||||
|
||||
// Copy elements from the given subRange into the range starting at
|
||||
// target, returning a pointer past-the-end of the target range
|
||||
func _uninitializedCopy(
|
||||
subRange: Range<Self.IndexType>,
|
||||
target: UnsafePointer<Self.GeneratorType.Element>
|
||||
) -> UnsafePointer<Self.GeneratorType.Element>
|
||||
|
||||
// Update this Array's idea of its count. Does NOT construct or
|
||||
// destroy elements to ensure that count is accurate.
|
||||
mutating func _updateCount(newCount: Int)
|
||||
init(_ buffer: Buffer)
|
||||
|
||||
var buffer: Buffer {get set}
|
||||
}
|
||||
|
||||
struct _ArrayTypeMirror<T : ArrayType> : Mirror {
|
||||
let _value : T
|
||||
|
||||
init(_ v : T) { _value = v }
|
||||
|
||||
var value: Any { return (_value as Any) }
|
||||
|
||||
var valueType: Any.Type { return (_value as Any).dynamicType }
|
||||
|
||||
var objectIdentifier: ObjectIdentifier? { return nil }
|
||||
|
||||
var count: Int { return _value.count }
|
||||
|
||||
subscript(i: Int) -> (String, Mirror) {
|
||||
if (i >= 0) && (i < count) {
|
||||
return ("[\(i)]",reflect(_value[i]))
|
||||
}
|
||||
fatal("don't ask")
|
||||
}
|
||||
|
||||
var summary: String {
|
||||
if count == 1 { return "1 element" }
|
||||
return "\(count) elements"
|
||||
}
|
||||
|
||||
var quickLookObject: QuickLookObject? { return nil }
|
||||
|
||||
var disposition: MirrorDisposition { return .IndexContainer }
|
||||
}
|
||||
|
||||
@@ -24,15 +24,9 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
% for Self in ['NativeArray', 'Slice', 'NewArray']:
|
||||
struct ${Self}<T> {
|
||||
% for Self in ['NativeArray', 'Slice', 'Array']:
|
||||
struct ${Self}<T> : MutableCollection, Sliceable {
|
||||
typealias Element = T
|
||||
typealias Buffer = ${'Array' if Self.startswith('New') else Self}Buffer<T>
|
||||
|
||||
var buffer: Buffer
|
||||
}
|
||||
|
||||
extension ${Self} : Collection {
|
||||
var startIndex: Int {
|
||||
return 0
|
||||
}
|
||||
@@ -41,32 +35,636 @@ extension ${Self} : Collection {
|
||||
return buffer.count
|
||||
}
|
||||
|
||||
subscript(i: Int) -> Element {
|
||||
subscript(index: Int) -> Element {
|
||||
get {
|
||||
return buffer[i]
|
||||
assert(index < count, "Array index out of range")
|
||||
return buffer[index]
|
||||
}
|
||||
nonmutating set {
|
||||
assert(index < count, "Array index out of range")
|
||||
buffer[index] = newValue
|
||||
}
|
||||
}
|
||||
|
||||
func generate() -> IndexingGenerator<${Self}> {
|
||||
return IndexingGenerator(self)
|
||||
}
|
||||
|
||||
typealias SliceType = Slice<T>
|
||||
subscript(subRange: Range<Int>) -> SliceType {
|
||||
get {
|
||||
return Slice(buffer[subRange])
|
||||
}
|
||||
set {
|
||||
if self[subRange] !== newValue {
|
||||
replace(&self, subRange, newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===--- private --------------------------------------------------------===//
|
||||
typealias Buffer = ${'Array' if Self.startswith('New') else Self}Buffer<T>
|
||||
|
||||
init(_ buffer: Buffer) {
|
||||
self.buffer = buffer
|
||||
}
|
||||
|
||||
var buffer: Buffer
|
||||
}
|
||||
|
||||
extension ${Self} /*: _ArrayType*/ {
|
||||
func toNativeBuffer(managedByCopyOnWrite: Bool)
|
||||
-> NativeArrayBuffer<Element> {
|
||||
return buffer.toNativeBuffer(managedByCopyOnWrite)
|
||||
extension ${Self} : ArrayLiteralConvertible {
|
||||
static func convertFromArrayLiteral(elements: Element...) -> ${Self} {
|
||||
return ${Self}(_extractOrCopyToNativeArrayBuffer(elements.buffer))
|
||||
}
|
||||
}
|
||||
|
||||
extension ${Self} {
|
||||
func asCocoaArray() -> CocoaArray {
|
||||
return buffer.asCocoaArray()
|
||||
}
|
||||
}
|
||||
|
||||
extension ${Self} : ArrayType {
|
||||
/// Construct an empty ${Self}
|
||||
init() {
|
||||
buffer = Buffer()
|
||||
}
|
||||
|
||||
init<S: Sequence where S.GeneratorType.Element == Buffer.Element>(_ s: S) {
|
||||
self = ${Self}(Buffer(s~>_copyToNativeArrayBuffer()))
|
||||
}
|
||||
|
||||
/// Construct an array of count elements, each initialized to value
|
||||
init(count: Int, value: T) {
|
||||
assert(count >= 0)
|
||||
buffer = Buffer()
|
||||
reserve(count)
|
||||
var p = buffer.elementStorage
|
||||
for _ in 0...count {
|
||||
p++.initialize(value)
|
||||
}
|
||||
buffer.count = count
|
||||
}
|
||||
|
||||
/// How many elements the ${Self} stores
|
||||
var count: Int {
|
||||
get {
|
||||
return buffer.count
|
||||
}
|
||||
|
||||
/// How many elements the ${Self} can store without reallocation
|
||||
var capacity: Int {
|
||||
return buffer.capacity
|
||||
}
|
||||
|
||||
/// true if and only if the ${Self} is empty
|
||||
var isEmpty: Bool {
|
||||
return count == 0
|
||||
}
|
||||
|
||||
/// An object that guarantees the lifetime of this array's elements
|
||||
var owner: AnyObject? {
|
||||
return buffer.owner
|
||||
}
|
||||
|
||||
/// If the elements are stored contiguously, a pointer to the first
|
||||
/// element. Otherwise, nil.
|
||||
var elementStorage: UnsafePointer<Element> {
|
||||
return buffer.elementStorage
|
||||
}
|
||||
|
||||
//===--- basic mutations ------------------------------------------------===//
|
||||
|
||||
|
||||
/// Returns a new array that does not share the underlying storage with this
|
||||
/// array.
|
||||
/// Complexity: O(N)
|
||||
func copy() -> ${Self} {
|
||||
var result = self
|
||||
result.reserve(0)
|
||||
return result
|
||||
}
|
||||
|
||||
/// Ensure the uniqueness of the array.
|
||||
/// Complexity: O(N)
|
||||
mutating func unshare() {
|
||||
reserve(0)
|
||||
}
|
||||
|
||||
/// Ensure the array has enough mutable contiguous storage to store
|
||||
/// newCapacity elements in. Note: does not affect count.
|
||||
/// Complexity: O(N)
|
||||
mutating func reserve(newCapacity: Int) {
|
||||
if !buffer.requestUniqueMutableBuffer(newCapacity) {
|
||||
var newBuffer = NativeArrayBuffer<T>(count: count, minimumCapacity: newCapacity)
|
||||
buffer._uninitializedCopy(0...count, target: newBuffer.elementStorage)
|
||||
buffer = Buffer(newBuffer)
|
||||
}
|
||||
assert(capacity >= newCapacity)
|
||||
}
|
||||
|
||||
/// Append newElement to the ${Self} in O(1) (amortized)
|
||||
mutating func append(newElement: T) {
|
||||
_arrayAppend(&buffer, newElement)
|
||||
}
|
||||
|
||||
/// Remove an element from the end of the ${Self} in O(1).
|
||||
/// Requires: count > 0
|
||||
mutating func popLast() -> T {
|
||||
assert(count > 0, "can't pop from an empty ${Self}")
|
||||
let c = count
|
||||
let result = self[c - 1]
|
||||
replace(&self, (c - 1)...c, EmptyCollection())
|
||||
return result
|
||||
}
|
||||
|
||||
/// Insert an element at the given index in O(N). Requires: atIndex
|
||||
/// <= count
|
||||
mutating func insert(atIndex: Int, newElement: T) {
|
||||
replace(&self, atIndex...atIndex, CollectionOfOne(newElement))
|
||||
}
|
||||
|
||||
/// Remove the element at the given index. Worst case complexity:
|
||||
/// O(N). Requires: index < count
|
||||
mutating func removeAt(index: Int) -> T {
|
||||
let result = self[index]
|
||||
replace(&self, index...(index + 1), EmptyCollection())
|
||||
return result
|
||||
}
|
||||
|
||||
/// Erase all the elements and release the storage
|
||||
mutating func clear() {
|
||||
buffer = Buffer()
|
||||
}
|
||||
|
||||
/// Erase all the elements. If keepStorage is true, capacity will not change
|
||||
mutating func clear(keepStorage: Bool) {
|
||||
if !keepStorage {
|
||||
clear()
|
||||
}
|
||||
else {
|
||||
replace(&self, indices(self), EmptyCollection())
|
||||
}
|
||||
}
|
||||
|
||||
//===--- algorithms -----------------------------------------------------===//
|
||||
func reduce<U>(initial: U, combine: (U, T)->U) -> U {
|
||||
return Swift.reduce(self, initial, combine)
|
||||
}
|
||||
|
||||
mutating func sort(isOrderedBefore: (T, T)->Bool) {
|
||||
quickSort(&self, indices(self), isOrderedBefore)
|
||||
}
|
||||
|
||||
func map<U>(transform: (T)->U) -> ${Self}<U> {
|
||||
var result = ${Self}<U>()
|
||||
|
||||
let count = self.count
|
||||
result.reserve(count)
|
||||
var p = result.buffer.elementStorage
|
||||
for i in 0...count {
|
||||
p++.initialize( transform(self[i]) )
|
||||
}
|
||||
result.buffer.count = count
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
extension ${Self} : Reflectable {
|
||||
func getMirror() -> Mirror {
|
||||
return _ArrayTypeMirror(self)
|
||||
}
|
||||
}
|
||||
|
||||
extension ${Self} {
|
||||
@transparent
|
||||
func _cPointerArgs() -> (AnyObject?, Builtin.RawPointer) {
|
||||
let p = elementStorage
|
||||
if _fastPath(p != nil || count == 0) {
|
||||
return (owner, p.value)
|
||||
}
|
||||
let n = _extractOrCopyToNativeArrayBuffer(self.buffer)
|
||||
return (n.owner, n.elementStorage.value)
|
||||
}
|
||||
|
||||
// Conversion to C pointer arguments
|
||||
@transparent @conversion
|
||||
func __conversion() -> CConstPointer<T> {
|
||||
return CConstPointer(_cPointerArgs())
|
||||
}
|
||||
|
||||
@transparent @conversion
|
||||
func __conversion() -> CConstVoidPointer {
|
||||
return CConstVoidPointer(_cPointerArgs())
|
||||
}
|
||||
}
|
||||
|
||||
%if Self != 'Array': # // Array does not necessarily have contiguous storage
|
||||
extension ${Self} {
|
||||
func withUnsafePointerToElements<R>(body: (UnsafePointer<T>)->R) -> R {
|
||||
return buffer.withUnsafePointerToElements(body)
|
||||
}
|
||||
}
|
||||
%end
|
||||
|
||||
%end
|
||||
|
||||
extension Array {
|
||||
static func convertFromHeapArray(
|
||||
base: Builtin.RawPointer,
|
||||
owner: Builtin.NativeObject,
|
||||
count: Builtin.Word
|
||||
) -> Array {
|
||||
let elements = UnsafeArray(
|
||||
start: reinterpretCast(base) as UnsafePointer<T>,
|
||||
length: reinterpretCast(count) as Int
|
||||
)
|
||||
let r = Array(elements)
|
||||
_fixLifetime(owner)
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
struct _InitializeMemoryFromCollection<C: Collection> : PointerFunction {
|
||||
func call(rawMemory: UnsafePointer<C.GeneratorType.Element>) {
|
||||
var p = rawMemory
|
||||
for x in newValues {
|
||||
p++.initialize(x)
|
||||
}
|
||||
}
|
||||
|
||||
init(_ newValues: C) {
|
||||
self.newValues = newValues
|
||||
}
|
||||
|
||||
var newValues: C
|
||||
}
|
||||
|
||||
func replace<
|
||||
A: ArrayType, C: Collection
|
||||
where C.GeneratorType.Element == A.Buffer.Element, A.IndexType == Int
|
||||
>(
|
||||
inout target: A, subRange: Range<Int>, newValues: C
|
||||
) {
|
||||
assert(subRange.startIndex >= 0)
|
||||
assert(subRange.endIndex >= subRange.startIndex)
|
||||
assert(subRange.endIndex <= target.endIndex)
|
||||
|
||||
let oldCount = target.count
|
||||
let eraseCount = countElements(subRange)
|
||||
let insertCount = numericCast(countElements(newValues)) as Int
|
||||
var newBuffer = _demandUniqueMutableBuffer(
|
||||
&target.buffer, oldCount + insertCount - eraseCount)
|
||||
|
||||
if _fastPath(!newBuffer) {
|
||||
let growth = insertCount - eraseCount
|
||||
|
||||
let elements = target.buffer.elementStorage
|
||||
assert(elements != nil)
|
||||
|
||||
let oldTailIndex = subRange.endIndex
|
||||
let oldTailStart = elements + oldTailIndex
|
||||
let newTailIndex = oldTailIndex + growth
|
||||
let newTailStart = oldTailStart + growth
|
||||
let tailCount = oldCount - subRange.endIndex
|
||||
|
||||
if growth > 0 {
|
||||
// Slide the tail part of the buffer forwards, in reverse order
|
||||
// so as not to self-clobber.
|
||||
newTailStart.moveInitializeBackwardFrom(oldTailStart, count: tailCount)
|
||||
|
||||
// Assign over the original subRange
|
||||
var i = newValues.startIndex
|
||||
for j in subRange {
|
||||
elements[j] = newValues[i++]
|
||||
}
|
||||
// Initialize the hole left by sliding the tail forward
|
||||
for j in oldTailIndex...newTailIndex {
|
||||
(elements + j).initialize(newValues[i++])
|
||||
}
|
||||
}
|
||||
else { // We're not growing the buffer
|
||||
// Assign all the new elements into the start of the subRange
|
||||
var i = subRange.startIndex
|
||||
for j in indices(newValues) {
|
||||
elements[i++] = newValues[j]
|
||||
}
|
||||
|
||||
// If the size didn't change, we're done.
|
||||
if growth == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Move the tail backward to cover the shrinkage.
|
||||
let shrinkage = -growth
|
||||
if tailCount > shrinkage { // If the tail length exceeds the shrinkage
|
||||
|
||||
// Assign over the rest of the replaced range with the first
|
||||
// part of the tail.
|
||||
newTailStart.moveAssignFrom(oldTailStart, count: shrinkage)
|
||||
|
||||
// slide the rest of the tail back
|
||||
oldTailStart.moveInitializeFrom(
|
||||
oldTailStart + shrinkage, count: tailCount - shrinkage)
|
||||
}
|
||||
else { // tail fits within erased elements
|
||||
// Assign over the start of the replaced range with the tail
|
||||
newTailStart.moveAssignFrom(oldTailStart, count: tailCount)
|
||||
|
||||
// destroy elements remaining after the tail in subRange
|
||||
(newTailStart + tailCount).destroy(shrinkage - tailCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
_arrayOutOfPlaceUpdate(
|
||||
&target.buffer, &newBuffer,
|
||||
subRange.startIndex, insertCount,
|
||||
_InitializeMemoryFromCollection(newValues)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@assignment
|
||||
func += <
|
||||
A: ArrayType, S: Sequence
|
||||
where S.GeneratorType.Element == A.Buffer.Element
|
||||
>(inout lhs: A, rhs: S) {
|
||||
_arrayAppendSequence(&lhs.buffer, rhs)
|
||||
}
|
||||
|
||||
@assignment
|
||||
func += <
|
||||
A: ArrayType, C: Collection
|
||||
where C.GeneratorType.Element == A.Buffer.Element
|
||||
>(inout lhs: A, rhs: C) {
|
||||
let rhsCount = numericCast(countElements(rhs)) as Int
|
||||
|
||||
let oldCount = lhs.count
|
||||
let capacity = lhs.capacity
|
||||
let newCount = oldCount + rhsCount
|
||||
|
||||
// Ensure uniqueness, mutability, and sufficient storage. Note that
|
||||
// for consistency, we need unique lhs even if rhs is empty.
|
||||
lhs.reserve(newCount > capacity ? max(newCount, capacity * 2) : newCount)
|
||||
var p = lhs.buffer.elementStorage + oldCount
|
||||
for x in rhs {
|
||||
(p++).initialize(x)
|
||||
}
|
||||
lhs.buffer.count = newCount
|
||||
}
|
||||
|
||||
@assignment
|
||||
func += <
|
||||
A: ArrayType
|
||||
>(inout lhs: A, rhs: A.Buffer.Element) {
|
||||
lhs += CollectionOfOne(rhs)
|
||||
}
|
||||
|
||||
//===--- generic helpers --------------------------------------------------===//
|
||||
/// Ensure there's a NativeArrayBuffer capable of storing
|
||||
/// max(newCount, minimumCapacity) elements, with count set to
|
||||
/// newCount.
|
||||
///
|
||||
/// If source has sufficient capacity, returns nil. Otherwise,
|
||||
/// returns a new buffer.
|
||||
///
|
||||
/// NOTE: does not initialize or destroy any elements. In general,
|
||||
/// the buffer that satisfies the capacity request now has a count
|
||||
/// that does not match its number of initialized elements, and that
|
||||
/// needs to be corrected before the buffer can go back into circulation.
|
||||
func _demandUniqueMutableBuffer<Buffer: ArrayBufferType>(
|
||||
inout source: Buffer, newCount: Int, minimumCapacity: Int = 0)
|
||||
-> NativeArrayBuffer<Buffer.Element>? {
|
||||
|
||||
assert(newCount >= 0)
|
||||
|
||||
let requiredCapacity = max(newCount, minimumCapacity)
|
||||
|
||||
if let b = source.requestUniqueMutableBuffer(requiredCapacity) {
|
||||
source.count = newCount
|
||||
return nil
|
||||
}
|
||||
|
||||
let newCapacity = max(
|
||||
requiredCapacity,
|
||||
newCount > source.capacity ? source.capacity * 2 : source.capacity)
|
||||
|
||||
return NativeArrayBuffer(count: newCount, minimumCapacity: newCapacity)
|
||||
}
|
||||
|
||||
protocol PointerFunction {
|
||||
typealias Element
|
||||
func call(UnsafePointer<Element>)
|
||||
}
|
||||
|
||||
/// initialize the elements of dest by copying the first headCount
|
||||
/// items from source, calling initializeNewElements on the next
|
||||
/// uninitialized element, and finally by copying the last N items
|
||||
/// from source into the N remaining uninitialized elements of dest.
|
||||
///
|
||||
/// As an optimization, may move elements out of source rather than
|
||||
/// copying when it isUniquelyReferenced.
|
||||
func _arrayOutOfPlaceUpdate<
|
||||
Buffer: ArrayBufferType, Initializer: PointerFunction
|
||||
where Initializer.Element == Buffer.Element
|
||||
>(
|
||||
inout source: Buffer,
|
||||
inout dest: NativeArrayBuffer<Buffer.Element>?,
|
||||
headCount: Int, // Count of initial source elements to copy/move
|
||||
newCount: Int, // Count of new elements to insert
|
||||
initializeNewElements: Initializer
|
||||
) {
|
||||
assert(headCount >= 0)
|
||||
assert(newCount >= 0)
|
||||
|
||||
// Count of trailing source elements to copy/move
|
||||
let tailCount = dest!.count - headCount - newCount
|
||||
assert(headCount + tailCount <= source.count)
|
||||
|
||||
let sourceCount = source.count
|
||||
let oldCount = sourceCount - headCount - tailCount
|
||||
let destStart = dest!.elementStorage
|
||||
let newStart = destStart + headCount
|
||||
let newEnd = newStart + newCount
|
||||
|
||||
// Check to see if we have storage we can move from
|
||||
if let backing = source.requestUniqueMutableBuffer(sourceCount) {
|
||||
let sourceStart = source.elementStorage
|
||||
let oldStart = sourceStart + headCount
|
||||
|
||||
// Destroy any items that may be lurking in a SliceBuffer before
|
||||
// its real first element
|
||||
let backingStart = backing.elementStorage
|
||||
let sourceOffset = sourceStart - backingStart
|
||||
backingStart.destroy(sourceOffset)
|
||||
|
||||
// Move the head items
|
||||
destStart.moveInitializeFrom(sourceStart, count: headCount)
|
||||
|
||||
// Destroy unused source items
|
||||
oldStart.destroy(oldCount)
|
||||
|
||||
initializeNewElements.call(newStart)
|
||||
|
||||
// Move the tail items
|
||||
newEnd.moveInitializeFrom(oldStart + oldCount, count: tailCount)
|
||||
|
||||
// Destroy any items that may be lurking in a SliceBuffer after
|
||||
// its real last element
|
||||
let backingEnd = backingStart + backing.count
|
||||
let sourceEnd = sourceStart + sourceCount
|
||||
sourceEnd.destroy(sourceEnd - backingEnd)
|
||||
backing.count = 0
|
||||
}
|
||||
else {
|
||||
let newStart = source._uninitializedCopy(0...headCount, target: destStart)
|
||||
initializeNewElements.call(newStart)
|
||||
source._uninitializedCopy(headCount + oldCount...sourceCount,
|
||||
target: newEnd)
|
||||
}
|
||||
source = Buffer(dest!)
|
||||
}
|
||||
|
||||
struct InitializePointer<T> : PointerFunction {
|
||||
func call(rawMemory: UnsafePointer<T>) {
|
||||
// FIXME: maybe we should move here instead of copying?
|
||||
rawMemory.initialize(newValue)
|
||||
}
|
||||
|
||||
@transparent
|
||||
init(_ newValue: T) {
|
||||
self.newValue = newValue
|
||||
}
|
||||
|
||||
var newValue: T
|
||||
}
|
||||
|
||||
func _arrayAppend<Buffer: ArrayBufferType>(
|
||||
inout buffer: Buffer, newValue: Buffer.Element
|
||||
) {
|
||||
let oldCount = buffer.count
|
||||
var newBuffer = _demandUniqueMutableBuffer(&buffer, oldCount + 1)
|
||||
if _fastPath(!newBuffer) {
|
||||
(buffer.elementStorage + oldCount).initialize(newValue)
|
||||
}
|
||||
else {
|
||||
_arrayOutOfPlaceUpdate(
|
||||
&buffer, &newBuffer, oldCount, 1, InitializePointer(newValue))
|
||||
}
|
||||
}
|
||||
|
||||
struct IgnorePointer<T> : PointerFunction {
|
||||
func call(_:UnsafePointer<T>) {}
|
||||
}
|
||||
|
||||
func _arrayReserve<Buffer: ArrayBufferType>(
|
||||
inout buffer: Buffer, newCapacity: Int
|
||||
) {
|
||||
let oldCount = buffer.count
|
||||
var newBuffer = _demandUniqueMutableBuffer(&buffer, oldCount, minimumCapacity: newCapacity)
|
||||
if _slowPath(newBuffer) {
|
||||
_arrayOutOfPlaceUpdate(&buffer, &newBuffer, oldCount, 1, IgnorePointer())
|
||||
}
|
||||
}
|
||||
|
||||
func _extractOrCopyToNativeArrayBuffer<
|
||||
Buffer: ArrayBufferType where Buffer.GeneratorType.Element == Buffer.Element
|
||||
>(source: Buffer)
|
||||
-> NativeArrayBuffer<Buffer.Element>
|
||||
{
|
||||
if let n = source.requestNativeBuffer() {
|
||||
return n
|
||||
}
|
||||
return _copyCollectionToNativeArrayBuffer(source)
|
||||
}
|
||||
|
||||
/// Append items from newItems to buffer
|
||||
func _arrayAppendSequence<
|
||||
Buffer: ArrayBufferType,
|
||||
S: Sequence where S.GeneratorType.Element == Buffer.Element
|
||||
>(
|
||||
inout buffer: Buffer, newItems: S
|
||||
) {
|
||||
var stream = newItems.generate()
|
||||
var nextItem = stream.next()
|
||||
|
||||
if !nextItem {
|
||||
return
|
||||
}
|
||||
|
||||
// This will force uniqueness
|
||||
_arrayAppend(&buffer, nextItem!)
|
||||
var count = buffer.count
|
||||
nextItem = stream.next()
|
||||
while nextItem {
|
||||
let capacity = buffer.capacity
|
||||
let base = buffer.elementStorage
|
||||
|
||||
while nextItem && count < capacity {
|
||||
(base + count++).initialize(nextItem!)
|
||||
nextItem = stream.next()
|
||||
}
|
||||
buffer.count = count
|
||||
if nextItem {
|
||||
_arrayReserve(&buffer, capacity * 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true iff these arrays reference exactly the same elements.
|
||||
func ===<T: ArrayType, U: ArrayType>(lhs: T, rhs: U) -> Bool {
|
||||
let lhsCount = lhs.count
|
||||
if lhsCount != rhs.count {
|
||||
return false
|
||||
}
|
||||
|
||||
return lhsCount == 0 || lhs.buffer.identity == rhs.buffer.identity
|
||||
}
|
||||
|
||||
/// Returns false iff these arrays reference exactly the same
|
||||
/// elements.
|
||||
func !==<T: ArrayType, U: ArrayType>(lhs: T, rhs: U) -> Bool {
|
||||
return !(lhs === rhs)
|
||||
}
|
||||
|
||||
/// Returns an Array<Base> containing the same elements as a in
|
||||
/// O(1). Requires: Base is a base class or base @objc protocol (such
|
||||
/// as AnyObject) of Derived.
|
||||
func _arrayUpCast<Derived, Base>(a: Array<Derived>) -> Array<Base> {
|
||||
return Array(ArrayBuffer<Base>(castFrom: a.buffer, direction: .Up))
|
||||
}
|
||||
|
||||
/// Returns an Array<Derived> containing the same elements as a in
|
||||
/// O(1). Requires: a is known to contain only elements of type
|
||||
/// Derived, and Base is a base class or base @objc protocol (such as
|
||||
/// AnyObject) of Derived.
|
||||
func _arrayDownCast<Base, Derived>(a: Array<Base>) -> Array<Derived> {
|
||||
return Array(ArrayBuffer<Derived>(castFrom: a.buffer, direction: .Down))
|
||||
}
|
||||
|
||||
/// Return the most-derived element type known to be stored in a's
|
||||
/// buffer. O(1)
|
||||
func _arrayElementType<T>(a: Array<T>) -> Any.Type {
|
||||
return a.buffer.dynamicElementType
|
||||
}
|
||||
|
||||
/// Returns an Array<Derived> containing the same elements as a in
|
||||
/// O(1) iff a's buffer elements are dynamically known to have
|
||||
/// type Derived or a type derived from Derived.
|
||||
func _arrayCheckedDownCast<Base, Derived>(a: Array<Base>) -> Array<Derived>? {
|
||||
return _arrayDownCast(a)
|
||||
}
|
||||
|
||||
/// Convert a to its corresponding bridged array type.
|
||||
/// Precondition: T is bridged to objective C
|
||||
/// O(1) if T is bridged verbatim, O(N) otherwise
|
||||
func _arrayBridgeToObjectiveC<T: _BridgedToObjectiveC>(
|
||||
a: Array<T>
|
||||
) -> Array<T.ObjectiveCType> {
|
||||
return Array(ArrayBuffer(a.asCocoaArray()))
|
||||
}
|
||||
|
||||
// ${'Local Variables'}:
|
||||
// eval: (read-only-mode 1)
|
||||
// End:
|
||||
|
||||
|
||||
@@ -1,18 +1,193 @@
|
||||
// Classic C assert(), plus a message.
|
||||
func assert(fn : [auto_closure] () -> Bool, message : String = "") {
|
||||
}
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// These trap functions promise to emit the debugger trap instruction and not
|
||||
// print anything; therefore these functions clobber far fewer registers and
|
||||
// are more useful for debugging and automated crash reporting infrastructure.
|
||||
//
|
||||
// Fatal errors, which always stop the program regardless of build
|
||||
// configuration.
|
||||
//
|
||||
|
||||
// "Expensive" asserts that are debug only
|
||||
func debugTrap(fn : [auto_closure] () -> Bool = false, message : String = "") {
|
||||
}
|
||||
|
||||
// "Important" and/or cheap asserts that are always enabled
|
||||
func alwaysTrap(cond : Bool = false, message : String = "") {
|
||||
if !cond {
|
||||
/// A fatal error occurred and program execution must stop. In
|
||||
/// builds with assertions enabled, currently prints message to the
|
||||
/// console and executes a minimal debugger trap. In non-assert
|
||||
/// builds, just executes a minimal debugger trap.
|
||||
@transparent
|
||||
@noreturn
|
||||
func fatal(
|
||||
message: StaticString,
|
||||
file: StaticString = __FILE__, line: UWord = __LINE__
|
||||
) {
|
||||
if _isDebug() {
|
||||
_fatal_error_message("fatal error", message, file, line)
|
||||
} else if _isFast() {
|
||||
_conditionallyUnreachable()
|
||||
} else {
|
||||
Builtin.int_trap()
|
||||
}
|
||||
}
|
||||
|
||||
/// If condition is false, invoke `fatal(message)`
|
||||
@transparent
|
||||
func securityCheck<L: LogicValue>(
|
||||
condition: L,
|
||||
_ message: StaticString = StaticString(),
|
||||
file: StaticString = __FILE__, line: UWord = __LINE__
|
||||
) {
|
||||
if _isDebug() {
|
||||
if !_branchHint(condition.getLogicValue(), true) {
|
||||
_fatal_error_message("fatal error", message, file, line)
|
||||
}
|
||||
} else {
|
||||
if !_branchHint(condition.getLogicValue(), true) {
|
||||
Builtin.int_trap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If `error` is true, executes `fatal("Overflow/underflow")`.
|
||||
/// Otherwise returns `result`.
|
||||
@transparent
|
||||
func overflowChecked<T>(
|
||||
args: (T, Bool),
|
||||
file: StaticString = __FILE__, line: UWord = __LINE__
|
||||
) -> T {
|
||||
let (result, error) = args
|
||||
if _isDebug() {
|
||||
if _branchHint(error, false) {
|
||||
fatal("Overflow/underflow", file: file, line: line)
|
||||
}
|
||||
} else {
|
||||
Builtin.condfail(error.value)
|
||||
return result
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
//
|
||||
// Assertions, which may have no effect on program semantics,
|
||||
// depending on the build configuration
|
||||
//
|
||||
|
||||
// FIXME: Dispatching to this overload is needed as a workaround for
|
||||
// <rdar://problem/15889294>
|
||||
@transparent
|
||||
func assert(
|
||||
condition: @auto_closure () -> Bool, _ message: StaticString = StaticString(),
|
||||
file: StaticString = __FILE__, line: UWord = __LINE__
|
||||
) {
|
||||
// Only assert in debug mode.
|
||||
if _isDebug() {
|
||||
if !_branchHint(condition(), true) {
|
||||
_fatal_error_message("assertion failed", message, file, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Traditional C-style assert with an optional message.
|
||||
///
|
||||
/// When assertions are enabled and `condition` is false, stop program
|
||||
/// execution in a debuggable state after printing a message. When
|
||||
/// assertions are disabled, `condition` is not even evaluated.
|
||||
@transparent
|
||||
func assert<T : LogicValue>(
|
||||
condition: @auto_closure () -> T, _ message: StaticString = StaticString(),
|
||||
file: StaticString = __FILE__, line: UWord = __LINE__
|
||||
) {
|
||||
// Only in debug mode.
|
||||
if _isDebug() {
|
||||
assert(condition().getLogicValue(), message, file: file, line: line)
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal checks are to be used for checking correctness conditions in the
|
||||
/// standard library. They are only enable when the standard library is built
|
||||
/// with the build configuration INTERNAL_CHECKS_ENABLED enabled. Otherwise, the
|
||||
/// call to this function is a noop.
|
||||
@transparent
|
||||
func _internal_check(
|
||||
condition: @auto_closure () -> Bool, _ message: StaticString = StaticString(),
|
||||
file: StaticString = __FILE__, line: UWord = __LINE__
|
||||
) {
|
||||
#if INTERNAL_CHECKS_ENABLED
|
||||
if !_branchHint(condition(), true) {
|
||||
_fatal_error_message("internal check failed", message, file, line)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _internal_check<T : LogicValue>(
|
||||
condition: @auto_closure () -> T, _ message: StaticString = StaticString(),
|
||||
file: StaticString = __FILE__, line: UWord = __LINE__
|
||||
) {
|
||||
#if INTERNAL_CHECKS_ENABLED
|
||||
if !_branchHint(condition(), true) {
|
||||
_internal_check(condition().getLogicValue(), message, file: file, line: line)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Library precondition checks are enabled in debug and release mode but not in
|
||||
/// fast mode. In release mode they don't print an error message but just trap.
|
||||
/// In debug mode they print an error message and abort.
|
||||
@transparent
|
||||
func _precondition_safety_check(
|
||||
condition: @auto_closure () -> Bool, _ message: StaticString = StaticString(),
|
||||
file: StaticString = __FILE__, line: UWord = __LINE__
|
||||
) {
|
||||
// Only check in debug and release mode. In release mode just trap.
|
||||
if _isDebug() {
|
||||
if !_branchHint(condition(), true) {
|
||||
_fatal_error_message("precondition failed", message, file, line)
|
||||
}
|
||||
} else if _isRelease() {
|
||||
if !_branchHint(condition(), true) {
|
||||
Builtin.int_trap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _precondition_safety_check<T : LogicValue>(
|
||||
condition: @auto_closure () -> T, _ message: StaticString = StaticString(),
|
||||
file: StaticString = __FILE__, line: UWord = __LINE__
|
||||
) {
|
||||
// Only in debug and release mode.
|
||||
if _isDebug() || _isRelease() {
|
||||
_precondition_safety_check(condition().getLogicValue(), message, file: file, line: line)
|
||||
}
|
||||
}
|
||||
|
||||
/// Library partial safety checks are only enabled in debug mode and print an
|
||||
/// error message on failure.
|
||||
@transparent
|
||||
func _partial_safety_check(
|
||||
condition: @auto_closure () -> Bool, _ message: StaticString = StaticString(),
|
||||
file: StaticString = __FILE__, line: UWord = __LINE__
|
||||
) {
|
||||
// Only assert in debug and release mode.
|
||||
if _isDebug() {
|
||||
if !_branchHint(condition(), true) {
|
||||
_fatal_error_message("safety check failed", message, file, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _partial_safety_check<T : LogicValue>(
|
||||
condition: @auto_closure () -> T, _ message: StaticString = StaticString(),
|
||||
file: StaticString = __FILE__, line: UWord = __LINE__
|
||||
) {
|
||||
// Only in debug mode.
|
||||
if _isDebug() {
|
||||
_partial_safety_check(condition().getLogicValue(), message, file: file, line: line)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,86 @@
|
||||
/// True if we are going to print a message about a failed assertion.
|
||||
///
|
||||
/// FIXME: this should be an atomic bool.
|
||||
var _in_assert_fail : Bool = false
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
func _assert_fail(message: String, file: String, line: Int) {
|
||||
if _in_assert_fail {
|
||||
// Prevent recursive assertions. This can happen if the original one was
|
||||
// triggered by String or print().
|
||||
//
|
||||
// FIXME: this should be implemented with compare-and-exchange.
|
||||
abort()
|
||||
}
|
||||
_in_assert_fail = true
|
||||
if message.isEmpty() {
|
||||
print("assertion failed: file \(file), line \(line)\n")
|
||||
} else {
|
||||
print("assertion failed: \(message): file \(file), line \(line)\n")
|
||||
}
|
||||
// Implementation Note: this file intentionally uses very LOW-LEVEL
|
||||
// CONSTRUCTS, so that assert and fatal may be used liberally in
|
||||
// building library abstractions without fear of infinite recursion.
|
||||
//
|
||||
// FIXME: We could go farther with this simplification, e.g. avoiding
|
||||
// UnsafePointer
|
||||
|
||||
@transparent
|
||||
func _isDebug() -> Bool {
|
||||
// The values for the assert_configuration call are:
|
||||
// 0 .. Debug
|
||||
// 1 .. Release
|
||||
// 2 .. Fast
|
||||
return Int32(Builtin.assert_configuration()) == 0;
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _isRelease() -> Bool {
|
||||
// The values for the assert_configuration call are:
|
||||
// 0 .. Debug
|
||||
// 1 .. Release
|
||||
// 2 .. Fast
|
||||
return Int32(Builtin.assert_configuration()) == 1;
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _isFast() -> Bool {
|
||||
// The values for the assert_configuration call are:
|
||||
// 0 .. Debug
|
||||
// 1 .. Release
|
||||
// 2 .. Fast
|
||||
return Int32(Builtin.assert_configuration()) == 2;
|
||||
}
|
||||
|
||||
@asmname("swift_reportFatalError")
|
||||
func _reportFatalError(
|
||||
header: Builtin.RawPointer, headerLength: Builtin.Word,
|
||||
message: Builtin.RawPointer, messageLength: Builtin.Word,
|
||||
file: Builtin.RawPointer, fileLength: Builtin.Word,
|
||||
line: UWord)
|
||||
|
||||
@asmname("swift_reportUnimplementedInitializer")
|
||||
func _reportUnimplementedInitializer(
|
||||
className: Builtin.RawPointer, classNameLength: Builtin.Word,
|
||||
file: Builtin.RawPointer, fileLength: Builtin.Word,
|
||||
line: UWord, column: UWord,
|
||||
initName: Builtin.RawPointer, initNameLength: Builtin.Word)
|
||||
|
||||
@noreturn
|
||||
func _fatal_error_message(header: StaticString, message: StaticString,
|
||||
file: StaticString, line: UWord)
|
||||
{
|
||||
_reportFatalError(header.start, header.byteSize,
|
||||
message.start, message.byteSize,
|
||||
file.start, file.byteSize, line)
|
||||
|
||||
Builtin.int_trap()
|
||||
}
|
||||
|
||||
/// Prints a fatal error message when a unimplemented initializer gets
|
||||
/// called by the Objective-C runtime.
|
||||
@noreturn
|
||||
func _unimplemented_initializer(className: StaticString,
|
||||
file: StaticString = __FILE__,
|
||||
line: UWord = __LINE__,
|
||||
column: UWord = __LINE__,
|
||||
initName: StaticString = __FUNCTION__)
|
||||
{
|
||||
_reportUnimplementedInitializer(className.start, className.byteSize,
|
||||
file.start, file.byteSize, line, column,
|
||||
initName.start, initName.byteSize)
|
||||
|
||||
Builtin.int_trap()
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Used to index T? and SequenceOfOne<T>
|
||||
// Used to index SequenceOfOne<T>
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
enum Bit : Int, RandomAccessIndex {
|
||||
@@ -25,6 +25,14 @@ enum Bit : Int, RandomAccessIndex {
|
||||
assert(self == .one, "Can't decrement past zero")
|
||||
return .zero
|
||||
}
|
||||
|
||||
func distanceTo(other: Bit) -> Int {
|
||||
return toRaw().distanceTo(other.toRaw())
|
||||
}
|
||||
|
||||
func advancedBy(distance: Int) -> Bit {
|
||||
return toRaw().advancedBy(distance) > 0 ? one : zero
|
||||
}
|
||||
}
|
||||
|
||||
func == (lhs: Bit, rhs: Bit) -> Bool {
|
||||
@@ -35,38 +43,32 @@ func < (lhs: Bit, rhs: Bit) -> Bool {
|
||||
return lhs.toRaw() < rhs.toRaw()
|
||||
}
|
||||
|
||||
extension Bit : NumericOperations {
|
||||
static func _withOverflow(x: Int, b: Bool) -> (Bit, Bool) {
|
||||
extension Bit : IntegerArithmetic {
|
||||
static func _withOverflow(x: Int, _ b: Bool) -> (Bit, Bool) {
|
||||
return (Bit.fromRaw(x)!, b)
|
||||
}
|
||||
|
||||
static func add(lhs: Bit, rhs: Bit) -> (Bit, Bool) {
|
||||
return _withOverflow(Int.add(lhs.toRaw(), rhs.toRaw()))
|
||||
static func uncheckedAdd(lhs: Bit, _ rhs: Bit) -> (Bit, Bool) {
|
||||
return _withOverflow(Int.uncheckedAdd(lhs.toRaw(), rhs.toRaw()))
|
||||
}
|
||||
|
||||
static func sub(lhs: Bit, rhs: Bit) -> (Bit, Bool) {
|
||||
return _withOverflow(Int.add(lhs.toRaw(), rhs.toRaw()))
|
||||
static func uncheckedSubtract(lhs: Bit, _ rhs: Bit) -> (Bit, Bool) {
|
||||
return _withOverflow(Int.uncheckedSubtract(lhs.toRaw(), rhs.toRaw()))
|
||||
}
|
||||
|
||||
static func mul(lhs: Bit, rhs: Bit) -> (Bit, Bool) {
|
||||
return _withOverflow(Int.add(lhs.toRaw(), rhs.toRaw()))
|
||||
static func uncheckedMultiply(lhs: Bit, _ rhs: Bit) -> (Bit, Bool) {
|
||||
return _withOverflow(Int.uncheckedMultiply(lhs.toRaw(), rhs.toRaw()))
|
||||
}
|
||||
|
||||
static func div(lhs: Bit, rhs: Bit) -> (Bit, Bool) {
|
||||
return _withOverflow(Int.add(lhs.toRaw(), rhs.toRaw()))
|
||||
static func uncheckedDivide(lhs: Bit, _ rhs: Bit) -> (Bit, Bool) {
|
||||
return _withOverflow(Int.uncheckedDivide(lhs.toRaw(), rhs.toRaw()))
|
||||
}
|
||||
|
||||
static func rem(lhs: Bit, rhs: Bit) -> (Bit, Bool) {
|
||||
return _withOverflow(Int.add(lhs.toRaw(), rhs.toRaw()))
|
||||
static func uncheckedModulus(lhs: Bit, _ rhs: Bit) -> (Bit, Bool) {
|
||||
return _withOverflow(Int.uncheckedModulus(lhs.toRaw(), rhs.toRaw()))
|
||||
}
|
||||
|
||||
func toIntMax() -> IntMax {
|
||||
return IntMax(toRaw())
|
||||
}
|
||||
}
|
||||
|
||||
// This overload is needed to work around the ambiguity of the two
|
||||
// generic "-" operators for RandomAccessIndex.
|
||||
func - (lhs: Bit, rhs: Bit) -> Bit {
|
||||
return Bit.fromRaw( lhs.toRaw() - rhs.toRaw() )!
|
||||
}
|
||||
|
||||
@@ -1,36 +1,64 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Bool Datatype and Supporting Operators
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Bool is the standard way to reason about truth values.
|
||||
oneof Bool {
|
||||
false, true
|
||||
struct Bool {
|
||||
var value: Builtin.Int1
|
||||
|
||||
/// \brief Default-initialize Boolean value to \c false.
|
||||
constructor() { this = .false }
|
||||
@transparent
|
||||
init() { value = Builtin.trunc_Word_Int1(0.value) }
|
||||
|
||||
@transparent
|
||||
init(_ v : Builtin.Int1) { value = v }
|
||||
|
||||
static var false : Bool {
|
||||
@transparent
|
||||
get {
|
||||
return Bool()
|
||||
}
|
||||
}
|
||||
static var true : Bool {
|
||||
@transparent
|
||||
get {
|
||||
return Bool(Builtin.trunc_Word_Int1(1.value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Convert these to immutable vars when we have them.
|
||||
var true : Bool {
|
||||
@transparent
|
||||
get {
|
||||
return Bool.true
|
||||
}
|
||||
}
|
||||
var false : Bool {
|
||||
@transparent
|
||||
get {
|
||||
return Bool.false
|
||||
}
|
||||
}
|
||||
|
||||
extension Bool : LogicValue, ReplPrintable {
|
||||
@transparent func _getBuiltinLogicValue() -> Builtin.Int1 {
|
||||
return value
|
||||
}
|
||||
|
||||
// *private* helper function for forming Bools
|
||||
func [asmname="swift_getBool"] _getBool(v : Builtin.Int1) -> Bool;
|
||||
|
||||
|
||||
extension Bool : LogicValue {
|
||||
// FIXME: Implement pattern matching or equality testing to implement this.
|
||||
func [asmname="_TSb13getLogicValuefRSbFT_Bi1_"] _getBuiltinLogicValue() -> Builtin.Int1
|
||||
|
||||
func getLogicValue() -> Bool { return this }
|
||||
@transparent func getLogicValue() -> Bool { return self }
|
||||
|
||||
func replPrint() {
|
||||
if this {
|
||||
if self {
|
||||
print("true")
|
||||
} else {
|
||||
print("false")
|
||||
@@ -38,80 +66,68 @@ extension Bool : LogicValue {
|
||||
}
|
||||
|
||||
// Bool can be constructed from LogicValue
|
||||
constructor(v : LogicValue) {
|
||||
this = v.getLogicValue()
|
||||
init(_ v : LogicValue) {
|
||||
self = v.getLogicValue()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This is a magic entrypoint known to the compiler.
|
||||
@transparent func _getBool(v: Builtin.Int1) -> Bool { return Bool(v) }
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Standard Operators
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Unary bitwise complement.
|
||||
func [prefix] ~(a : Bool) -> Bool {
|
||||
@prefix @transparent func ~(a: Bool) -> Bool {
|
||||
return a ^ true
|
||||
}
|
||||
|
||||
// Unary logical complement.
|
||||
func [prefix] !(a : Bool) -> Bool {
|
||||
@prefix @transparent func !(a: Bool) -> Bool {
|
||||
return ~a
|
||||
}
|
||||
|
||||
@transparent
|
||||
func ==(lhs: Bool, rhs: Bool) -> Bool {
|
||||
return Bool(Builtin.cmp_eq_Int1(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
@transparent
|
||||
extension Bool : Equatable, Hashable {
|
||||
func __equal__(rhs: Bool) -> Bool {
|
||||
return _getBool(Builtin.cmp_eq_Int1(_getBuiltinLogicValue(),
|
||||
rhs._getBuiltinLogicValue()))
|
||||
}
|
||||
func hashValue() -> Int {
|
||||
return this? 1 : 0
|
||||
var hashValue: Int {
|
||||
return self ? 1 : 0
|
||||
}
|
||||
}
|
||||
|
||||
// Bitwise 'and'.
|
||||
func & (lhs : Bool, rhs : Bool) -> Bool {
|
||||
return _getBool(Builtin.and_Int1(lhs._getBuiltinLogicValue(),
|
||||
rhs._getBuiltinLogicValue()))
|
||||
@transparent func & (lhs: Bool, rhs: Bool) -> Bool {
|
||||
return Bool(Builtin.and_Int1(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
// Bitwise 'xor'.
|
||||
func ^ (lhs : Bool, rhs : Bool) -> Bool {
|
||||
return _getBool(Builtin.xor_Int1(lhs._getBuiltinLogicValue(),
|
||||
rhs._getBuiltinLogicValue()))
|
||||
@transparent func ^ (lhs: Bool, rhs: Bool) -> Bool {
|
||||
return Bool(Builtin.xor_Int1(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
// Bitwise 'or'.
|
||||
func | (lhs : Bool, rhs : Bool) -> Bool {
|
||||
return _getBool(Builtin.or_Int1(lhs._getBuiltinLogicValue(),
|
||||
rhs._getBuiltinLogicValue()))
|
||||
}
|
||||
|
||||
// Short circuiting logical operators.
|
||||
func && (lhs: Bool, rhs: [auto_closure] ()->Bool) -> Bool {
|
||||
if lhs {
|
||||
return rhs()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
func || (lhs: Bool, rhs: [auto_closure] ()->Bool) -> Bool {
|
||||
if lhs {
|
||||
return true
|
||||
}
|
||||
|
||||
return rhs()
|
||||
@transparent func | (lhs: Bool, rhs: Bool) -> Bool {
|
||||
return Bool(Builtin.or_Int1(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
// Compound assignment (with bitwise and)
|
||||
func [assignment] &= (lhs : [byref] Bool, rhs : Bool) {
|
||||
@assignment @transparent func &= (inout lhs: Bool, rhs: Bool) {
|
||||
lhs = lhs & rhs
|
||||
}
|
||||
|
||||
// Compound assignment (with bitwise or)
|
||||
func [assignment] |= (lhs : [byref] Bool, rhs : Bool) {
|
||||
@assignment @transparent func |= (inout lhs: Bool, rhs: Bool) {
|
||||
lhs = lhs | rhs
|
||||
}
|
||||
|
||||
// Compound assignment (with bitwise xor)
|
||||
func [assignment] ^= (lhs : [byref] Bool, rhs : Bool) {
|
||||
@assignment @transparent func ^= (inout lhs: Bool, rhs: Bool) {
|
||||
lhs = lhs ^ rhs
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +1,587 @@
|
||||
/// \brief A means of accepting "out" parameters from Objective-C
|
||||
/// functions taking the parameters by pointer
|
||||
func withOutArgument<T, Result>(
|
||||
arg: @inout T,
|
||||
f: (UnsafePointer<T>)->Result
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// \brief Invokes body with an UnsafePointer to arg and returns the
|
||||
/// result. Useful for calling Objective-C APIs that take "in/out"
|
||||
/// parameters (and default-constructible "out" parameters) by pointer
|
||||
func withUnsafePointer<T, Result>(
|
||||
inout arg: T,
|
||||
body: (UnsafePointer<T>)->Result
|
||||
) -> Result
|
||||
{
|
||||
return f(UnsafePointer<T>(Builtin.addressof(&arg)))
|
||||
return body(UnsafePointer<T>(Builtin.addressof(&arg)))
|
||||
}
|
||||
|
||||
/// \brief A means of accepting @autorelease "out" parameters from
|
||||
/// Objective-C functions, which can be tricky because they are
|
||||
/// not handed to us at +1 like other objects.
|
||||
func withAutoReleasedOutArgument<T, Result>(
|
||||
arg: @inout T?,
|
||||
f: (UnsafePointer<T>)->Result
|
||||
) -> Result
|
||||
{
|
||||
var buffer: Builtin.RawPointer = Builtin.inttoptr_Int64(0.value)
|
||||
var address = UnsafePointer<T>(Builtin.addressof(&buffer))
|
||||
var result = f(address)
|
||||
/// \brief Like withUnsafePointer, but passes pointers to arg0 and
|
||||
/// arg1
|
||||
func withUnsafePointers<A0, A1, Result>(
|
||||
inout arg0: A0,
|
||||
inout arg1: A1,
|
||||
body: (UnsafePointer<A0>, UnsafePointer<A1>)->Result
|
||||
) -> Result {
|
||||
return withUnsafePointer(&arg0) {
|
||||
arg0 in withUnsafePointer(&arg1) {
|
||||
arg1 in body(arg0, arg1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arg = Int64(Builtin.ptrtoint_Int64(buffer)) == 0
|
||||
? .None : .Some(address.get())
|
||||
/// \brief Like withUnsafePointer, but passes pointers to arg0, arg1,
|
||||
/// and arg2
|
||||
func withUnsafePointers<A0, A1, A2, Result>(
|
||||
inout arg0: A0,
|
||||
inout arg1: A1,
|
||||
inout arg2: A2,
|
||||
body: (UnsafePointer<A0>, UnsafePointer<A1>, UnsafePointer<A2>)->Result
|
||||
) -> Result {
|
||||
return withUnsafePointer(&arg0) {
|
||||
arg0 in withUnsafePointer(&arg1) {
|
||||
arg1 in withUnsafePointer(&arg2) {
|
||||
arg2 in body(arg0, arg1, arg2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// FIXME: workaround for <rdar://problem/15637771> Need a way to
|
||||
/// constrain a generic argument to being a class
|
||||
@class_protocol @objc
|
||||
protocol ObjCClassType {}
|
||||
|
||||
/// \brief Invokes body with an UnsafePointer to a nil T, sets arg to
|
||||
/// the value of that T (or .None if the T is still nil), and returns
|
||||
/// the result of the invocation
|
||||
///
|
||||
/// Useful for calling Objective-C APIs that take class instances by
|
||||
/// pointer as @autorelease "out" parameters.
|
||||
func withUnsafePointerToObject<T: AnyObject, Result>(
|
||||
inout arg: T?,
|
||||
body: (UnsafePointer<ImplicitlyUnwrappedOptional<T>>)->Result
|
||||
) -> Result {
|
||||
var buffer: Builtin.RawPointer = Builtin.inttoptr_Word(0.value)
|
||||
var address = UnsafePointer<ImplicitlyUnwrappedOptional<T>>(Builtin.addressof(&buffer))
|
||||
var result = body(address)
|
||||
arg = address.get()
|
||||
return result
|
||||
}
|
||||
|
||||
/// A Swift Array or Dictionary of types conforming to
|
||||
/// _BridgedToObjectiveC can be passed to ObjectiveC as an NSArray or
|
||||
/// NSDictionary, respectively. The elements of the resulting NSArray
|
||||
/// or NSDictionary will be the result of calling bridgeToObjectiveC
|
||||
/// on each elmeent of the source container.
|
||||
protocol _BridgedToObjectiveC {
|
||||
typealias ObjectiveCType: AnyObject
|
||||
func bridgeToObjectiveC() -> ObjectiveCType
|
||||
}
|
||||
|
||||
/// Whether a given type conforming to this protocol bridges to
|
||||
/// ObjectiveC is only knowable at runtime. Array<T> is an example;
|
||||
/// it is bridges to ObjectiveC iff T does, too.
|
||||
protocol _ConditionallyBridgedToObjectiveC : _BridgedToObjectiveC {
|
||||
class func isBridgedToObjectiveC() -> Bool
|
||||
}
|
||||
|
||||
/// Attempt to convert x to its ObjectiveC representation. If T
|
||||
/// conforms to _BridgedToObjectiveC, returns the result of calling its
|
||||
/// bridgeToObjectiveC() method. Otherwise, if T is a class type,
|
||||
/// returns x. Otherwise, the result is empty.
|
||||
@asmname("swift_bridgeToObjectiveC")
|
||||
func bridgeToObjectiveC<T>(x: T) -> AnyObject?
|
||||
|
||||
/// If T conforms to _ConditionallyBridgedToObjectiveC, returns
|
||||
/// T.isBridgedToObjectiveC(). Otherwise, if T conforms to
|
||||
/// _BridgedToObjectiveC or T is a class type, returns true
|
||||
@asmname("swift_isBridgedToObjectiveC")
|
||||
func isBridgedToObjectiveC<T>(_: T.Type) -> Bool
|
||||
|
||||
/// A type that's bridged "verbatim" does not conform to
|
||||
/// _BridgedToObjectiveC, and can have its bits reinterpreted as an
|
||||
/// AnyObject. This function does not necessarily detect all such
|
||||
/// types (there may be false negatives) but when it returns true, the
|
||||
/// storage Array<T> can be reinterpretCast as an array of AnyObject
|
||||
@asmname("swift_isBridgedVerbatimToObjectiveC")
|
||||
func isBridgedVerbatimToObjectiveC<T>(_: T.Type) -> Bool
|
||||
|
||||
// -- Pointer argument bridging
|
||||
|
||||
@transparent
|
||||
var _nilNativeObject: AnyObject? {
|
||||
return nil
|
||||
}
|
||||
@transparent
|
||||
var _nilRawPointer: Builtin.RawPointer {
|
||||
return Builtin.inttoptr_Word(0.value)
|
||||
}
|
||||
|
||||
/// A mutable C pointer argument.
|
||||
///
|
||||
/// This type has no operations of its own, but has implicit conversions
|
||||
/// to allow passing any of the following to a C or ObjC API:
|
||||
///
|
||||
/// - 'nil', which gets passed as a null pointer,
|
||||
/// - an inout argument of the referenced type, which gets passed as a pointer
|
||||
/// to the inout-ed lvalue (or its writeback temporary, if it is a computed
|
||||
/// lvalue),
|
||||
/// - an inout argument of the Array<T> type, which gets passed as a pointer
|
||||
/// to the beginning of the array,
|
||||
/// - an UnsafePointer<T>, which is passed as-is.
|
||||
///
|
||||
/// The value consists of an owner-value pair. During bridging, a strong
|
||||
/// reference to the owner is held for the duration of the call, and the pointer
|
||||
/// value is passed down to the C or Objective-C entry point. This allows
|
||||
/// types that own heap storage, such as Array, to convert themselves to
|
||||
/// a pointer and still guarantee that their storage will be held for the
|
||||
/// duration of the call.
|
||||
///
|
||||
/// Pointers to ObjC object pointer type ``NSFoo**`` are not mapped to this
|
||||
/// type; they instead get mapped to ObjCMutablePointer<T>. ``void*`` pointers
|
||||
/// are mapped to CMutableVoidPointer.
|
||||
struct CMutablePointer<T> : Equatable {
|
||||
let owner: AnyObject?
|
||||
let value: Builtin.RawPointer
|
||||
|
||||
/// Conversion from an inout scalar.
|
||||
@transparent
|
||||
static func __inout_conversion(inout scalar: T) -> CMutablePointer {
|
||||
// No owner pointer for an inout scalar; the lifetime guarantee of writeback
|
||||
// is sufficient.
|
||||
return CMutablePointer(owner: _nilNativeObject,
|
||||
value: Builtin.addressof(&scalar))
|
||||
}
|
||||
|
||||
/// Conversion from an inout array.
|
||||
@transparent
|
||||
static func __inout_conversion(inout a: Array<T>) -> CMutablePointer {
|
||||
assert(a.elementStorage != nil || a.count == 0)
|
||||
|
||||
// TODO: Putting a canary at the end of the array in checked builds might
|
||||
// be a good idea
|
||||
|
||||
// The callee that receives the pointer may mutate through it, so
|
||||
// force uniqueness by calling reserve(0).
|
||||
a.reserve(0)
|
||||
return CMutablePointer(owner: a.owner, value: a.elementStorage.value)
|
||||
}
|
||||
|
||||
/// True if this is a scoped pointer, meaning it has a owner reference
|
||||
/// that guarantees the lifetime of the referenced memory.
|
||||
@transparent
|
||||
var scoped: Bool {
|
||||
return owner.getLogicValue()
|
||||
}
|
||||
|
||||
/// Make the pointer available as an UnsafePointer within a closure.
|
||||
@transparent
|
||||
func withUnsafePointer<U>(f: UnsafePointer<T> -> U) -> U {
|
||||
let result = f(UnsafePointer<T>(value))
|
||||
// Ensure the owner pointer stays alive for the duration of the closure.
|
||||
_fixLifetime(owner)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@transparent
|
||||
func == <T> (lhs: CMutablePointer<T>, rhs: CMutablePointer<T>) -> Bool {
|
||||
return Bool(Builtin.cmp_eq_RawPointer(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
// Also make CMutablePointer comparable to CConstPointer.
|
||||
@transparent
|
||||
func == <T> (lhs: CMutablePointer<T>, rhs: CConstPointer<T>) -> Bool {
|
||||
return Bool(Builtin.cmp_eq_RawPointer(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
@transparent
|
||||
func == <T> (lhs: CConstPointer<T>, rhs: CMutablePointer<T>) -> Bool {
|
||||
return Bool(Builtin.cmp_eq_RawPointer(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
/// A mutable C void pointer argument.
|
||||
///
|
||||
/// This type has no operations of its own, but has implicit conversions
|
||||
/// to allow passing any of the following to a C or ObjC API:
|
||||
///
|
||||
/// - 'nil', which gets passed as a null pointer,
|
||||
/// - an inout argument of any type, which gets passed as a pointer
|
||||
/// to the inout-ed lvalue (or its writeback temporary, if it is a computed
|
||||
/// lvalue),
|
||||
/// - an inout argument of Array<T> type for any T, which gets passed as a
|
||||
/// pointer to the beginning of the array,
|
||||
/// - an UnsafePointer<T> for any T or COpaquePointer, which is passed as-is.
|
||||
///
|
||||
/// The value consists of an owner-value pair. During bridging, a strong
|
||||
/// reference to the owner is held for the duration of the call, and the pointer
|
||||
/// value is passed down to the C or Objective-C entry point. This allows
|
||||
/// types that own heap storage, such as Array, to convert themselves to
|
||||
/// a pointer and still guarantee that their storage will be held for the
|
||||
/// duration of the call.
|
||||
struct CMutableVoidPointer : Equatable {
|
||||
let owner: AnyObject?
|
||||
let value: Builtin.RawPointer
|
||||
|
||||
/// Conversion from an inout scalar.
|
||||
@transparent
|
||||
static func __inout_conversion<T>(inout scalar: T) -> CMutableVoidPointer {
|
||||
// No owner pointer for an inout scalar; the lifetime guarantee of writeback
|
||||
// is sufficient.
|
||||
return CMutableVoidPointer(owner: _nilNativeObject,
|
||||
value: Builtin.addressof(&scalar))
|
||||
}
|
||||
|
||||
/// Conversion from an inout array.
|
||||
@transparent
|
||||
static func __inout_conversion<T>(inout a: Array<T>)
|
||||
-> CMutableVoidPointer {
|
||||
assert(a.elementStorage != nil || a.count == 0)
|
||||
|
||||
// TODO: Putting a canary at the end of the array in checked builds might
|
||||
// be a good idea.
|
||||
|
||||
// The callee that receives the pointer may mutate through it, so
|
||||
// force uniqueness by calling reserve(0).
|
||||
a.reserve(0)
|
||||
return CMutableVoidPointer(owner: a.owner,
|
||||
value: a.elementStorage.value)
|
||||
}
|
||||
|
||||
/// True if this is a scoped pointer, meaning it has a owner reference
|
||||
/// that guarantees the lifetime of the referenced memory.
|
||||
@transparent
|
||||
var scoped: Bool {
|
||||
return owner.getLogicValue()
|
||||
}
|
||||
|
||||
/// Make the pointer available as an UnsafePointer within a closure.
|
||||
@transparent
|
||||
func withUnsafePointer<T, U>(f: UnsafePointer<T> -> U) -> U {
|
||||
let result = f(UnsafePointer(value))
|
||||
// Ensure the owner pointer stays alive for the duration of the closure.
|
||||
_fixLifetime(owner)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@transparent
|
||||
func == (lhs: CMutableVoidPointer, rhs: CMutableVoidPointer) -> Bool {
|
||||
return Bool(Builtin.cmp_eq_RawPointer(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
/// A mutable pointer-to-ObjC-pointer argument.
|
||||
///
|
||||
/// This type has implicit conversions to allow passing any of the following
|
||||
/// to a C or ObjC API:
|
||||
///
|
||||
/// - 'nil', which gets passed as a null pointer,
|
||||
/// - an inout argument of the referenced type, which gets passed as a pointer
|
||||
/// to a writeback temporary with autoreleasing ownership semantics,
|
||||
/// - an UnsafePointer<T>, which is passed as-is.
|
||||
///
|
||||
/// Unlike CMutablePointer, passing pointers to mutable arrays of ObjC class
|
||||
/// pointers is not directly supported. Unlike UnsafePointer<T>,
|
||||
/// ObjCMutablePointer must reference storage that does not own a reference
|
||||
/// count to the referenced value. UnsafePointer's operations, by contrast,
|
||||
/// assume that the referenced storage owns values loaded from or stored to it.
|
||||
///
|
||||
/// This type does not carry an owner pointer unlike the other C*Pointer types
|
||||
/// because it only needs to reference the results of inout conversions, which
|
||||
/// already have writeback-scoped lifetime.
|
||||
struct ObjCMutablePointer<T /* TODO : class */> : Equatable {
|
||||
let value: Builtin.RawPointer
|
||||
|
||||
@transparent
|
||||
init(_ value: Builtin.RawPointer) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
/// Create the writeback temporary for inout conversion.
|
||||
@transparent
|
||||
static func __writeback_conversion_get(x: T) -> Builtin.RawPointer {
|
||||
// Reinterpreting the object reference as a RawPointer gives us a
|
||||
// nonowning reference to the original value.
|
||||
return reinterpretCast(x)
|
||||
}
|
||||
|
||||
/// Commit the writeback temporary back to the original inout parameter.
|
||||
@transparent
|
||||
static func __writeback_conversion_set(x: Builtin.RawPointer) -> T {
|
||||
// Reinterpreting the RawPointer back to an object reference gives us a +1
|
||||
// reference to the object again.
|
||||
return reinterpretCast(x)
|
||||
}
|
||||
|
||||
/// Conversion from an inout scalar.
|
||||
///
|
||||
/// Variables always have strong ownership semantics in Swift, but "NSFoo**"
|
||||
/// pointers in ARC have autoreleasing ownership by default, so doing this
|
||||
/// properly requires a writeback temporary.
|
||||
@transparent
|
||||
static func __writeback_conversion(
|
||||
inout autoreleasingTemp: Builtin.RawPointer
|
||||
) -> ObjCMutablePointer {
|
||||
return ObjCMutablePointer(Builtin.addressof(&autoreleasingTemp))
|
||||
}
|
||||
|
||||
@transparent
|
||||
func isNull() -> Bool {
|
||||
return UnsafePointer<T>(self).isNull()
|
||||
}
|
||||
|
||||
/// Retrieve the value the pointer points to.
|
||||
@transparent
|
||||
func get() -> T {
|
||||
assert(!isNull())
|
||||
// We can do a strong load normally.
|
||||
return UnsafePointer<T>(self).get()
|
||||
}
|
||||
|
||||
/// Set the value the pointer points to, copying over the previous value.
|
||||
///
|
||||
/// ObjCMutablePointers are assumed to reference a value with __autoreleasing
|
||||
/// ownership semantics, like 'NSFoo**' in ARC. This autoreleases the
|
||||
/// argument before trivially storing it to the referenced memory.
|
||||
@transparent
|
||||
func set(newValue: T) {
|
||||
assert(!isNull())
|
||||
// Autorelease the object reference.
|
||||
Builtin.retain(reinterpretCast(newValue) as AnyObject?)
|
||||
Builtin.autorelease(reinterpretCast(newValue) as AnyObject?)
|
||||
// Trivially assign it as a COpaquePointer; the pointer references an
|
||||
// autoreleasing slot, so retains/releases of the original value are
|
||||
// unneeded.
|
||||
UnsafePointer<COpaquePointer>(UnsafePointer<T>(self))
|
||||
.set(reinterpretCast(newValue))
|
||||
}
|
||||
}
|
||||
|
||||
@transparent
|
||||
func == <T> (lhs: ObjCMutablePointer<T>, rhs: ObjCMutablePointer<T>) -> Bool {
|
||||
return Bool(Builtin.cmp_eq_RawPointer(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
/// A const C pointer argument.
|
||||
///
|
||||
/// This type has no operations of its own, but has implicit conversions
|
||||
/// to allow passing any of the following to a C or ObjC API:
|
||||
///
|
||||
/// - 'nil', which gets passed as a null pointer,
|
||||
/// - an inout argument of the referenced type, which gets passed as a pointer
|
||||
/// to the inout-ed lvalue (or its writeback temporary, if it is a computed
|
||||
/// lvalue),
|
||||
/// - a value argument of the Array<T> type, which gets passed as a pointer
|
||||
/// to the beginning of the array.
|
||||
///
|
||||
/// The value consists of an owner-value pair. During bridging, a strong
|
||||
/// reference to the owner is held for the duration of the call, and the pointer
|
||||
/// value is passed down to the C or Objective-C entry point. This allows
|
||||
/// types that own heap storage, such as Array, to convert themselves to
|
||||
/// a pointer and still guarantee that their storage will be held for the
|
||||
/// duration of the call.
|
||||
struct CConstPointer<T> : Equatable {
|
||||
// TODO: Owner should become AnyObject? when the new Array implementation
|
||||
// comes online.
|
||||
let owner: AnyObject?
|
||||
let value: Builtin.RawPointer
|
||||
|
||||
@transparent
|
||||
init(_ owner: AnyObject?, _ value: Builtin.RawPointer) {
|
||||
self.owner = owner
|
||||
self.value = value
|
||||
}
|
||||
|
||||
// Conversion from an inout scalar.
|
||||
@transparent
|
||||
static func __inout_conversion(inout scalar: T) -> CConstPointer {
|
||||
// No owner pointer for an inout scalar; the lifetime guarantee of writeback
|
||||
// is sufficient.
|
||||
return CConstPointer(_nilNativeObject, Builtin.addressof(&scalar))
|
||||
}
|
||||
|
||||
/// True if this is a scoped pointer, meaning it has a owner reference
|
||||
/// that guarantees the lifetime of the referenced memory.
|
||||
@transparent
|
||||
var scoped: Bool {
|
||||
return owner.getLogicValue()
|
||||
}
|
||||
|
||||
/// Make the pointer available as an UnsafePointer within a closure.
|
||||
@transparent
|
||||
func withUnsafePointer<U>(f: UnsafePointer<T> -> U) -> U {
|
||||
let result = f(UnsafePointer<T>(value))
|
||||
// Ensure the owner pointer stays alive for the duration of the closure.
|
||||
_fixLifetime(owner)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@transparent
|
||||
func == <T> (lhs: CConstPointer<T>, rhs: CConstPointer<T>) -> Bool {
|
||||
return Bool(Builtin.cmp_eq_RawPointer(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
struct CConstVoidPointer : Equatable {
|
||||
// TODO: Owner should become AnyObject? when the new Array implementation
|
||||
// comes online.
|
||||
let owner: AnyObject?
|
||||
let value: Builtin.RawPointer
|
||||
|
||||
@transparent
|
||||
init(_ owner: AnyObject?, _ value: Builtin.RawPointer) {
|
||||
self.owner = owner
|
||||
self.value = value
|
||||
}
|
||||
|
||||
// Conversion from an inout scalar.
|
||||
@transparent
|
||||
static func __inout_conversion<T>(inout scalar: T) -> CConstVoidPointer {
|
||||
// No owner pointer for an inout scalar; the lifetime guarantee of writeback
|
||||
// is sufficient.
|
||||
return CConstVoidPointer(_nilNativeObject, Builtin.addressof(&scalar))
|
||||
}
|
||||
|
||||
/// True if this is a scoped pointer, meaning it has a owner reference
|
||||
/// that guarantees the lifetime of the referenced memory.
|
||||
@transparent
|
||||
var scoped: Bool {
|
||||
return owner.getLogicValue()
|
||||
}
|
||||
|
||||
/// Make the pointer available as an UnsafePointer within a closure.
|
||||
@transparent
|
||||
func withUnsafePointer<T, U>(f: UnsafePointer<T> -> U) -> U {
|
||||
let result = f(UnsafePointer(value))
|
||||
// Ensure the owner pointer stays alive for the duration of the closure.
|
||||
_fixLifetime(owner)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@transparent
|
||||
func ==(lhs: CConstVoidPointer, rhs: CConstVoidPointer) -> Bool {
|
||||
return Bool(Builtin.cmp_eq_RawPointer(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
//
|
||||
// Conversions from nil to bridging pointer types.
|
||||
//
|
||||
|
||||
extension _Nil {
|
||||
@transparent @conversion
|
||||
func __conversion<T>() -> CMutablePointer<T> {
|
||||
return CMutablePointer(owner: _nilNativeObject, value: _nilRawPointer)
|
||||
}
|
||||
@transparent @conversion
|
||||
func __conversion() -> CMutableVoidPointer {
|
||||
return CMutableVoidPointer(owner: _nilNativeObject, value: _nilRawPointer)
|
||||
}
|
||||
@transparent @conversion
|
||||
func __conversion<T>() -> CConstPointer<T> {
|
||||
return CConstPointer(_nilNativeObject, _nilRawPointer)
|
||||
}
|
||||
@transparent @conversion
|
||||
func __conversion() -> CConstVoidPointer {
|
||||
return CConstVoidPointer(_nilNativeObject, _nilRawPointer)
|
||||
}
|
||||
@transparent @conversion
|
||||
func __conversion<T>() -> ObjCMutablePointer<T> {
|
||||
return ObjCMutablePointer(_nilRawPointer)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Conversions from COpaquePointer to C*VoidPointer
|
||||
//
|
||||
|
||||
extension COpaquePointer {
|
||||
@transparent @conversion
|
||||
func __conversion() -> CMutableVoidPointer {
|
||||
return CMutableVoidPointer(owner: _nilNativeObject, value: value)
|
||||
}
|
||||
|
||||
@transparent @conversion
|
||||
func __conversion() -> CConstVoidPointer {
|
||||
return CConstVoidPointer(_nilNativeObject, value)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Native-to-bridged conversion functions from C*Pointer to UnsafePointer
|
||||
//
|
||||
|
||||
@transparent
|
||||
func _convertCConstPointerToUnsafePointer<T>(p: CConstPointer<T>)
|
||||
-> UnsafePointer<T> {
|
||||
return UnsafePointer(p.value)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _convertCConstVoidPointerToCOpaquePointer(p: CConstVoidPointer)
|
||||
-> COpaquePointer {
|
||||
return COpaquePointer(p.value)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _convertCMutablePointerToUnsafePointer<T>(p: CMutablePointer<T>)
|
||||
-> UnsafePointer<T> {
|
||||
return UnsafePointer(p.value)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _convertCMutableVoidPointerToCOpaquePointer(p: CMutableVoidPointer)
|
||||
-> COpaquePointer {
|
||||
return COpaquePointer(p.value)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _convertObjCMutablePointerToUnsafePointer<T>(p: ObjCMutablePointer<T>)
|
||||
-> UnsafePointer<T> {
|
||||
return UnsafePointer(p.value)
|
||||
}
|
||||
|
||||
//
|
||||
// Bridged-to-native conversion functions from UnsafePointer to C*Pointer
|
||||
//
|
||||
|
||||
// UnsafePointers will be bridged back into C*Pointer types in argument
|
||||
// position, where they should reference storage lifetime-guaranteed for
|
||||
// the duration of the function being called. We can thus safely bridge
|
||||
// the arguments to C*Pointer types with nil owner references.
|
||||
|
||||
@transparent
|
||||
func _convertUnsafePointerToCConstPointer<T>(p: UnsafePointer<T>)
|
||||
-> CConstPointer<T> {
|
||||
return CConstPointer(_nilNativeObject, p.value)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _convertCOpaquePointerToCConstVoidPointer(p: COpaquePointer)
|
||||
-> CConstVoidPointer {
|
||||
return CConstVoidPointer(_nilNativeObject, p.value)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _convertUnsafePointerToCMutablePointer<T>(p: UnsafePointer<T>)
|
||||
-> CMutablePointer<T> {
|
||||
return CMutablePointer(owner: _nilNativeObject, value: p.value)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _convertCOpaquePointerToCMutableVoidPointer(p: COpaquePointer)
|
||||
-> CMutableVoidPointer {
|
||||
return CMutableVoidPointer(owner: _nilNativeObject, value: p.value)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _convertUnsafePointerToObjCMutablePointer<T>(p: UnsafePointer<T>)
|
||||
-> ObjCMutablePointer<T> {
|
||||
return ObjCMutablePointer(p.value)
|
||||
}
|
||||
|
||||
@@ -1,17 +1,138 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// \brief Definitions that make elements of Builtin usable in real
|
||||
/// code without gobs of boilerplate. These APIs will probably *not*
|
||||
/// be exposed outside the stdlib.
|
||||
|
||||
func sizeof<T>(_:T.metatype) -> Int {
|
||||
return Int(Word(Builtin.sizeof(T)))
|
||||
@transparent
|
||||
func sizeof<T>(_:T.Type) -> Int {
|
||||
return Int(Builtin.sizeof(T.self))
|
||||
}
|
||||
|
||||
func sizeof<T>(_:T) -> Int {
|
||||
return Int(Word(Builtin.sizeof(T)))
|
||||
@transparent
|
||||
func sizeofValue<T>(_:T) -> Int {
|
||||
return sizeof(T.self)
|
||||
}
|
||||
|
||||
|
||||
// FIXME: should be a constructor of UnsafePointer
|
||||
func addressof<T>(x: @inout T) -> UnsafePointer<T> {
|
||||
return UnsafePointer<T>(Builtin.addressof(&x))
|
||||
@transparent
|
||||
func alignof<T>(_:T.Type) -> Int {
|
||||
return Int(Builtin.alignof(T.self))
|
||||
}
|
||||
|
||||
@transparent
|
||||
func alignofValue<T>(_:T) -> Int {
|
||||
return alignof(T.self)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func strideof<T>(_:T.Type) -> Int {
|
||||
return Int(Builtin.strideof(T.self))
|
||||
}
|
||||
|
||||
@transparent
|
||||
func strideofValue<T>(_:T) -> Int {
|
||||
return strideof(T.self)
|
||||
}
|
||||
|
||||
func roundUpToAlignment(offset: Int, alignment: Int) -> Int {
|
||||
return (offset + alignment - 1) / alignment * alignment
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _canBeClass<T>(_: T.Type) -> Bool {
|
||||
return Bool(Builtin.canBeClass(T.self))
|
||||
}
|
||||
|
||||
/// A brutal bit-cast of something to anything of the same size
|
||||
@transparent
|
||||
func reinterpretCast<T, U>(var x: T) -> U {
|
||||
assert(sizeof(T.self) == sizeof(U.self),
|
||||
"can't reinterpretCast values of different sizes")
|
||||
return UnsafePointer<U>(Builtin.addressof(&x)).get()
|
||||
}
|
||||
|
||||
/// `reinterpretCast` something to `AnyObject`
|
||||
@transparent
|
||||
func _reinterpretCastToAnyObject<T>(x: T) -> AnyObject {
|
||||
return reinterpretCast(x)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func ==(lhs: Builtin.NativeObject, rhs: Builtin.NativeObject) -> Bool {
|
||||
return (reinterpretCast(lhs) as Int) == (reinterpretCast(rhs) as Int)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func !=(lhs: Builtin.NativeObject, rhs: Builtin.NativeObject) -> Bool {
|
||||
return (reinterpretCast(lhs) as Int) != (reinterpretCast(rhs) as Int)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func ==(lhs: Builtin.RawPointer, rhs: Builtin.RawPointer) -> Bool {
|
||||
return (reinterpretCast(lhs) as Int) == (reinterpretCast(rhs) as Int)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func !=(lhs: Builtin.RawPointer, rhs: Builtin.RawPointer) -> Bool {
|
||||
return (reinterpretCast(lhs) as Int) != (reinterpretCast(rhs) as Int)
|
||||
}
|
||||
|
||||
/// Tell the optimizer that this code is unreachable if condition is
|
||||
/// known at compile-time to be true. If condition is false, or true
|
||||
/// but not a compile-time constant, this call has no effect.
|
||||
@transparent
|
||||
func _unreachable(condition: Bool = true) {
|
||||
if condition {
|
||||
// FIXME: use a parameterized version of Builtin.unreachable when
|
||||
// <rdar://problem/16806232> is closed.
|
||||
Builtin.unreachable()
|
||||
}
|
||||
}
|
||||
|
||||
/// Tell the optimizer that this code is unreachable if this builtin is
|
||||
/// reachable after constant folding build configuration builtins.
|
||||
@transparent @noreturn
|
||||
func _conditionallyUnreachable() {
|
||||
Builtin.conditionallyUnreachable()
|
||||
}
|
||||
|
||||
@asmname("swift_isClassOrObjCExistential")
|
||||
func _swift_isClassOrObjCExistential<T>(x: T.Type) -> Bool
|
||||
|
||||
/// Returns true iff T is a class type
|
||||
func _isClassOrObjCExistential<T>(x: T.Type) -> Bool {
|
||||
return _canBeClass(x)
|
||||
// FIXME: Dirty hack; see <rdar://problem/16823238>
|
||||
&& sizeof(x) == sizeof(AnyObject)
|
||||
&& _swift_isClassOrObjCExistential(x)
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Branch hints
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@transparent
|
||||
func _branchHint<C: LogicValue>(actual: C, expected: Bool) -> Bool {
|
||||
return Bool(Builtin.int_expect_Int1(actual.getLogicValue().value, expected.value))
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _fastPath<C: LogicValue>(x: C) -> Bool {
|
||||
return _branchHint(x.getLogicValue(), true)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _slowPath<C: LogicValue>(x: C) -> Bool {
|
||||
return _branchHint(x.getLogicValue(), false)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,53 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CString Type
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// XXX FIXME: we need a clean memory management story here
|
||||
|
||||
struct CString : BuiltinStringLiteralConvertible, StringLiteralConvertible{
|
||||
struct CString :
|
||||
_BuiltinExtendedGraphemeClusterLiteralConvertible,
|
||||
ExtendedGraphemeClusterLiteralConvertible,
|
||||
_BuiltinStringLiteralConvertible, StringLiteralConvertible,
|
||||
ReplPrintable {
|
||||
var _bytesPtr : UnsafePointer<UInt8>
|
||||
|
||||
static func _convertFromBuiltinStringLiteral(value : Builtin.RawPointer,
|
||||
byteSize : Builtin.Int64,
|
||||
isASCII : Builtin.Int1) -> CString {
|
||||
return CString(UnsafePointer(value))
|
||||
@transparent
|
||||
init(_ _bytesPtr : UnsafePointer<UInt8>) {
|
||||
self._bytesPtr = _bytesPtr
|
||||
}
|
||||
|
||||
typealias StringLiteralType = CString
|
||||
static func convertFromStringLiteral(value : CString) -> CString {
|
||||
static func _convertFromBuiltinExtendedGraphemeClusterLiteral(
|
||||
start: Builtin.RawPointer,
|
||||
byteSize: Builtin.Word,
|
||||
isASCII: Builtin.Int1) -> CString {
|
||||
|
||||
return _convertFromBuiltinStringLiteral(start, byteSize: byteSize,
|
||||
isASCII: isASCII)
|
||||
}
|
||||
|
||||
static func convertFromExtendedGraphemeClusterLiteral(
|
||||
value: CString) -> CString {
|
||||
|
||||
return convertFromStringLiteral(value)
|
||||
}
|
||||
|
||||
static func _convertFromBuiltinStringLiteral(start: Builtin.RawPointer,
|
||||
byteSize: Builtin.Word,
|
||||
isASCII: Builtin.Int1) -> CString {
|
||||
return CString(UnsafePointer(start))
|
||||
}
|
||||
|
||||
static func convertFromStringLiteral(value: CString) -> CString {
|
||||
return value
|
||||
}
|
||||
|
||||
@@ -23,63 +56,63 @@ struct CString : BuiltinStringLiteralConvertible, StringLiteralConvertible{
|
||||
}
|
||||
|
||||
func replPrint() {
|
||||
print('"')
|
||||
print("\"")
|
||||
var i = 0
|
||||
while _bytesPtr[i] != 0 {
|
||||
var c = Char(UInt32(_bytesPtr[i]))
|
||||
c.replPrintCharBody()
|
||||
var c = UnicodeScalar(UInt32(_bytesPtr[i]))
|
||||
print(c.escape())
|
||||
i++
|
||||
}
|
||||
print('"')
|
||||
print("\"")
|
||||
}
|
||||
|
||||
/// \brief From a CString with possibly-transient lifetime, create a
|
||||
/// nul-terminated array of 'C' char.
|
||||
func persist() -> CChar[] {
|
||||
var length = _strlen(self)
|
||||
var result = new CChar[length + 1]
|
||||
for var i = 0; i < length; ++i {
|
||||
result[i] = CChar(_bytesPtr[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
func [asmname="strlen"] _strlen(arg : CString) -> Word
|
||||
func [asmname="strcpy"] _strcpy(dest : CString, src : CString) -> CString
|
||||
@asmname("strlen")
|
||||
func _strlen(arg : CString) -> Int
|
||||
@asmname("strcpy")
|
||||
func _strcpy(dest: CString, src: CString) -> CString
|
||||
@asmname("strcmp")
|
||||
func _strcmp(dest: CString, src: CString) -> Int
|
||||
|
||||
@transparent
|
||||
func ==(lhs: CString, rhs: CString) -> Bool {
|
||||
if lhs._bytesPtr == rhs._bytesPtr { return true }
|
||||
return _strcmp(lhs, rhs) == 0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func <(lhs: CString, rhs: CString) -> Bool {
|
||||
return _strcmp(lhs, rhs) < 0
|
||||
}
|
||||
|
||||
extension CString : Equatable, Hashable, Comparable {
|
||||
@transparent
|
||||
var hashValue: Int {
|
||||
return String.fromCString(self).hashValue
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
/// Creates a new String by copying the null-terminated data referenced by
|
||||
/// a CString.
|
||||
static func fromCString(cs : CString) -> String {
|
||||
static func fromCString(cs: CString) -> String {
|
||||
var len = Int(_strlen(cs))
|
||||
var buf = StringByteData.getNew(len + 1)
|
||||
_strcpy(CString(buf.base), cs)
|
||||
buf.length = len
|
||||
buf.setASCII(false)
|
||||
buf.setCString(true)
|
||||
return String(buf)
|
||||
return String(UTF8.self,
|
||||
input: UnsafeArray(start: cs._bytesPtr, length: len))
|
||||
}
|
||||
|
||||
static func fromCString(up : UnsafePointer<CChar>) -> String {
|
||||
static func fromCString(up: UnsafePointer<CChar>) -> String {
|
||||
return fromCString(CString(UnsafePointer<UInt8>(up)))
|
||||
}
|
||||
|
||||
func _toCString() -> CString {
|
||||
assert(str_value.isCString())
|
||||
return CString(str_value.base)
|
||||
}
|
||||
|
||||
func _toUnsafePointer() -> UnsafePointer<CChar> {
|
||||
assert(str_value.isCString())
|
||||
return UnsafePointer(str_value.base)
|
||||
}
|
||||
}
|
||||
|
||||
extension LifetimeManager {
|
||||
/// \brief Returns an equivalent CString; lifetime of the underlying storage
|
||||
/// is extended until the call to \c release().
|
||||
func getCString(s : String) -> CString {
|
||||
s._makeNulTerminated()
|
||||
this.put(s.str_value.owner)
|
||||
return s._toCString()
|
||||
}
|
||||
|
||||
/// \brief Returns an equivalent UnsafePointer<CChar>; lifetime of the
|
||||
/// underlying storage is extended until the call to \c release().
|
||||
func getCString(s : String) -> UnsafePointer<CChar> {
|
||||
s._makeNulTerminated()
|
||||
this.put(s.str_value.owner)
|
||||
return s._toUnsafePointer()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,148 +1,148 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// C Primitive Types
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// \brief The C 'char' type.
|
||||
/// The C 'char' type.
|
||||
///
|
||||
/// This will be the same as either \c CSignedChar (in the common
|
||||
/// case) or \c CUnsignedChar, depending on the platform.
|
||||
/// This will be the same as either `CSignedChar` (in the common
|
||||
/// case) or `CUnsignedChar`, depending on the platform.
|
||||
typealias CChar = Int8
|
||||
|
||||
/// \brief The C 'unsigned char' type.
|
||||
/// The C 'unsigned char' type.
|
||||
typealias CUnsignedChar = UInt8
|
||||
|
||||
/// \brief The C 'unsigned short' type.
|
||||
/// The C 'unsigned short' type.
|
||||
typealias CUnsignedShort = UInt16
|
||||
|
||||
/// \brief The C 'unsigned int' type.
|
||||
/// The C 'unsigned int' type.
|
||||
typealias CUnsignedInt = UInt32
|
||||
|
||||
/// \brief The C 'unsigned long' type.
|
||||
typealias CUnsignedLong = UInt64
|
||||
/// The C 'unsigned long' type.
|
||||
typealias CUnsignedLong = UInt
|
||||
|
||||
/// \brief The C 'unsigned long long' type.
|
||||
/// The C 'unsigned long long' type.
|
||||
typealias CUnsignedLongLong = UInt64
|
||||
|
||||
/// \brief The C 'unsigned __int128' extended integer type.
|
||||
typealias CUnsignedInt128 = UInt128
|
||||
|
||||
/// \brief The C 'signed char' type.
|
||||
/// The C 'signed char' type.
|
||||
typealias CSignedChar = Int8
|
||||
|
||||
/// \brief The C 'short' type.
|
||||
/// The C 'short' type.
|
||||
typealias CShort = Int16
|
||||
|
||||
/// \brief The C 'int' type.
|
||||
/// The C 'int' type.
|
||||
typealias CInt = Int32
|
||||
|
||||
/// \brief The C 'long' type.
|
||||
typealias CLong = Int64
|
||||
/// The C 'long' type.
|
||||
typealias CLong = Int
|
||||
|
||||
/// \brief The C 'long long' type.
|
||||
/// The C 'long long' type.
|
||||
typealias CLongLong = Int64
|
||||
|
||||
/// \brief The C '__int128' extended integer type.
|
||||
typealias CInt128 = Int128
|
||||
|
||||
/// \brief The C 'float' type.
|
||||
/// The C 'float' type.
|
||||
typealias CFloat = Float
|
||||
|
||||
/// \brief The C 'double' type.
|
||||
/// The C 'double' type.
|
||||
typealias CDouble = Double
|
||||
|
||||
/// FIXME: long double
|
||||
|
||||
/// \brief The C++ 'wchar_t' type.
|
||||
///
|
||||
/// FIXME: Is it actually UTF-32 on Darwin?
|
||||
typealias CWideChar = Char
|
||||
// FIXME: Is it actually UTF-32 on Darwin?
|
||||
//
|
||||
/// The C++ 'wchar_t' type.
|
||||
typealias CWideChar = UnicodeScalar
|
||||
|
||||
/// \brief The C++11 'char16_t' type, which has UTF-16 encoding.
|
||||
///
|
||||
/// FIXME: Swift should probably have a UTF-16 type other than UInt16.
|
||||
// FIXME: Swift should probably have a UTF-16 type other than UInt16.
|
||||
//
|
||||
/// The C++11 'char16_t' type, which has UTF-16 encoding.
|
||||
typealias CChar16 = UInt16
|
||||
|
||||
/// \brief The C++11 'char32_t' type, which has UTF-32 encoding.
|
||||
typealias CChar32 = Char
|
||||
/// The C++11 'char32_t' type, which has UTF-32 encoding.
|
||||
typealias CChar32 = UnicodeScalar
|
||||
|
||||
/// \brief The C '_Bool' and C++ 'bool' type.
|
||||
struct CBool {
|
||||
var value : UInt8
|
||||
/// The C '_Bool' and C++ 'bool' type.
|
||||
typealias CBool = Bool
|
||||
|
||||
/// \brief Allow use in a Boolean context.
|
||||
func getLogicValue() -> Bool {
|
||||
if value == 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/// \brief Implicit conversion from C Boolean type to Swift Boolean
|
||||
/// type.
|
||||
func [conversion] __conversion() -> Bool {
|
||||
return getLogicValue()
|
||||
}
|
||||
}
|
||||
|
||||
extension Bool {
|
||||
/// \brief Implicit conversion from Swift Boolean type to C Boolean
|
||||
/// type.
|
||||
func [conversion] __conversion() -> CBool {
|
||||
var result : CBool
|
||||
if this {
|
||||
result.value = 1
|
||||
} else {
|
||||
result.value = 0
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief A wrapper around an opaque C pointer.
|
||||
/// A wrapper around an opaque C pointer.
|
||||
///
|
||||
/// Opaque pointers are used to represent C pointers to types that
|
||||
/// cannot be represented in Swift, such as incomplete struct types.
|
||||
struct COpaquePointer : Equatable, Hashable {
|
||||
var value : Builtin.RawPointer
|
||||
|
||||
init() {
|
||||
var zero : Int = 0
|
||||
value = Builtin.inttoptr_Word(zero.value)
|
||||
}
|
||||
|
||||
init(_ v: Builtin.RawPointer) {
|
||||
value = v
|
||||
}
|
||||
|
||||
static func null() -> COpaquePointer {
|
||||
return COpaquePointer()
|
||||
}
|
||||
|
||||
/// \brief Determine whether the given pointer is null.
|
||||
/// Determine whether the given pointer is null.
|
||||
func isNull() -> Bool {
|
||||
return this == COpaquePointer.null()
|
||||
return self == COpaquePointer.null()
|
||||
}
|
||||
|
||||
func __equal__(rhs : COpaquePointer) -> Bool {
|
||||
return _getBool(Builtin.cmp_eq_RawPointer(value, rhs.value))
|
||||
}
|
||||
func hashValue() -> Int {
|
||||
return Int(Builtin.ptrtoint_Int64(value))
|
||||
var hashValue: Int {
|
||||
return Int(Builtin.ptrtoint_Word(value))
|
||||
}
|
||||
}
|
||||
|
||||
func ==(lhs: COpaquePointer, rhs: COpaquePointer) -> Bool {
|
||||
return Bool(Builtin.cmp_eq_RawPointer(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
extension COpaquePointer {
|
||||
/// \brief Convert a typed UnsafePointer to an opaque C pointer.
|
||||
/// FIXME: Make this an implicit conversion?
|
||||
/// FIXME: This shouldn't have to be in an extension.
|
||||
constructor<T>(from : UnsafePointer<T>) {
|
||||
// FIXME: Make this an implicit conversion?
|
||||
// FIXME: This shouldn't have to be in an extension.
|
||||
//
|
||||
/// Convert a typed UnsafePointer to an opaque C pointer.
|
||||
init<T>(_ from : UnsafePointer<T>) {
|
||||
value = from.value;
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
/// Returns an UnsafePointer to the base address of the string without
|
||||
/// copying. The pointed-to string is not guaranteed to be null terminated
|
||||
/// so cannot be safely passed to APIs that require a C string.
|
||||
func cAddress() -> UnsafePointer<CChar> {
|
||||
return UnsafePointer(str_value.base.value)
|
||||
// Make nil work with COpaquePointer.
|
||||
extension _Nil {
|
||||
@conversion func __conversion() -> COpaquePointer {
|
||||
return COpaquePointer()
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Access to the raw argc value from C.
|
||||
var C_ARGC : CInt
|
||||
// The C va_list type
|
||||
struct CVaListPointer {
|
||||
var value: UnsafePointer<Void>
|
||||
|
||||
/// \brief Access to the raw argv value from C. Accessing the argument vector
|
||||
init(fromUnsafePointer from: UnsafePointer<Void>) {
|
||||
value = from
|
||||
}
|
||||
|
||||
@conversion
|
||||
func __conversion() -> CMutableVoidPointer {
|
||||
return CMutableVoidPointer(owner: _nilNativeObject, value: value.value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Access to the raw argc value from C.
|
||||
var C_ARGC : CInt = CInt()
|
||||
|
||||
/// Access to the raw argv value from C. Accessing the argument vector
|
||||
/// through this pointer is unsafe.
|
||||
var C_ARGV : UnsafePointer<CString>
|
||||
var C_ARGV : UnsafePointer<CString> = UnsafePointer<CString>()
|
||||
|
||||
@asmname("memcpy")
|
||||
func c_memcpy(`dest: UnsafePointer<Void>, `src: UnsafePointer<Void>, `size: UInt)
|
||||
|
||||
@@ -1,18 +1,65 @@
|
||||
// \brief Character represents some Unicode grapheme cluster as
|
||||
// defined by a canonical, localized, or otherwise tailored
|
||||
// segmentation algorithm.
|
||||
enum Character {
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 IntEncoder : Sink {
|
||||
var asInt: UInt64 = 0
|
||||
var shift: UInt64 = 0
|
||||
mutating func put(x: UTF8.CodeUnit) {
|
||||
asInt |= UInt64(x) << shift
|
||||
shift += 8
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Character represents some Unicode grapheme cluster as
|
||||
/// defined by a canonical, localized, or otherwise tailored
|
||||
/// segmentation algorithm.
|
||||
enum Character :
|
||||
_BuiltinExtendedGraphemeClusterLiteralConvertible,
|
||||
ExtendedGraphemeClusterLiteralConvertible, Equatable {
|
||||
|
||||
// Fundamentally, it is just a String, but it is optimized for the
|
||||
// common case where the UTF-8 representation fits in 63 bits. The
|
||||
// remaining bit is used to discriminate between small and large
|
||||
// representations. In the small representation, the unused bytes
|
||||
// are filled with 0xFF
|
||||
case SmallRepresentation(Builtin.Int63)
|
||||
// representations. In the small representation, the unused bytes
|
||||
// are filled with 0xFF.
|
||||
//
|
||||
// If the grapheme cluster can be represented in SmallRepresentation, it
|
||||
// should be represented as such.
|
||||
case LargeRepresentation(OnHeap<String>)
|
||||
case SmallRepresentation(Builtin.Int63)
|
||||
|
||||
init(s: String) {
|
||||
var length = s.str_value.length
|
||||
alwaysTrap(length > 0, "Can't form a Character from an empty String")
|
||||
init(_ scalar: UnicodeScalar) {
|
||||
var IE = IntEncoder()
|
||||
UTF8.encode(scalar, output: &IE)
|
||||
IE.asInt |= (~0) << IE.shift
|
||||
self = SmallRepresentation(Builtin.trunc_Int64_Int63(IE.asInt.value))
|
||||
}
|
||||
|
||||
static func _convertFromBuiltinExtendedGraphemeClusterLiteral(
|
||||
start: Builtin.RawPointer,
|
||||
byteSize: Builtin.Word,
|
||||
isASCII: Builtin.Int1) -> Character {
|
||||
return Character(
|
||||
String._convertFromBuiltinExtendedGraphemeClusterLiteral(
|
||||
start, byteSize: byteSize, isASCII: isASCII))
|
||||
}
|
||||
|
||||
static func convertFromExtendedGraphemeClusterLiteral(
|
||||
value: Character) -> Character {
|
||||
return value
|
||||
}
|
||||
|
||||
init(_ s: String) {
|
||||
// The small representation can accept up to 8 code units as long
|
||||
// as the last one is a continuation. Since the high bit of the
|
||||
// last byte is used for the enum's discriminator, we have to
|
||||
@@ -22,28 +69,29 @@ enum Character {
|
||||
// one-byte code points there, we simplify decoding by banning
|
||||
// starting a code point in the last byte, and assuming that its
|
||||
// high bit is 1.
|
||||
if length < 8 || ((length == 8) && (s.str_value[7] >= 0x80)) {
|
||||
var asInt = -1 // Start with all bits set.
|
||||
securityCheck(
|
||||
s.core.count != 0, "Can't form a Character from an empty String")
|
||||
|
||||
// Read the string backwards, shifting code units into the low
|
||||
// byte
|
||||
while length-- != 0 {
|
||||
asInt <<= 8
|
||||
asInt |= Int(s.str_value[length])
|
||||
}
|
||||
self = SmallRepresentation(Builtin.trunc_Int64_Int63(asInt.value))
|
||||
var (count, initialUTF8) = s.core._encodeSomeUTF8(0)
|
||||
let bits = sizeofValue(initialUTF8) * 8 - 1
|
||||
if _fastPath(
|
||||
count == s.core.count && (initialUTF8 & (1 << numericCast(bits))) != 0) {
|
||||
self = SmallRepresentation(Builtin.trunc_Int64_Int63(initialUTF8.value))
|
||||
}
|
||||
else {
|
||||
self = LargeRepresentation(OnHeap(s))
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief return the index of the lowest byte that is 0xFF, or 8 if
|
||||
/// there is none
|
||||
static func _smallSize(value: UInt64) -> Int {
|
||||
var mask: UInt64 = 0xFF
|
||||
for (var i = 0; i < 8; ++i) {
|
||||
if (value & 0xFF) == 0xFF {
|
||||
if (value & mask) == mask {
|
||||
return i
|
||||
}
|
||||
value >>= 8
|
||||
mask <<= 8
|
||||
}
|
||||
return 8
|
||||
}
|
||||
@@ -51,17 +99,35 @@ enum Character {
|
||||
static func _smallValue(value: Builtin.Int63) -> UInt64 {
|
||||
return UInt64(Builtin.zext_Int63_Int64(value)) | (1<<63)
|
||||
}
|
||||
}
|
||||
|
||||
func [conversion] __conversion() -> String {
|
||||
switch self {
|
||||
extension String {
|
||||
init(_ c: Character) {
|
||||
switch c {
|
||||
case .SmallRepresentation(var _63bits):
|
||||
var value = Character._smallValue(_63bits)
|
||||
var size = Character._smallSize(value)
|
||||
var resultBytes = StringByteData(size)
|
||||
resultBytes.appendBytes(UnsafePointer(Builtin.addressof(&value)), size)
|
||||
return String(resultBytes)
|
||||
self = String(
|
||||
UTF8.self,
|
||||
input: UnsafeArray(
|
||||
start: UnsafePointer<UTF8.CodeUnit>(Builtin.addressof(&value)),
|
||||
length: size))
|
||||
case .LargeRepresentation(var value):
|
||||
return value
|
||||
self = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ==(lhs: Character, rhs: Character) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case (.LargeRepresentation(let lhsValue), .LargeRepresentation(let rhsValue)):
|
||||
return lhsValue == rhsValue
|
||||
|
||||
case (.SmallRepresentation(let lhsValue), .SmallRepresentation(let rhsValue)):
|
||||
return Character._smallValue(lhsValue) == Character._smallValue(rhsValue)
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,14 +30,14 @@ import SwiftShims
|
||||
protocol CocoaArray : ObjCClassType {
|
||||
func objectAtIndex(index: Int) -> AnyObject
|
||||
|
||||
func getObjects(UnsafePointer<AnyObject>) range(_SwiftNSRange)
|
||||
func getObjects(UnsafePointer<AnyObject>, range: _SwiftNSRange)
|
||||
|
||||
func countByEnumeratingWithState(
|
||||
state: UnsafePointer<_SwiftNSFastEnumerationState>)
|
||||
objects(buffer: UnsafePointer<AnyObject>)
|
||||
count(len: Int) -> Int
|
||||
state: UnsafePointer<_SwiftNSFastEnumerationState>,
|
||||
objects buffer: UnsafePointer<AnyObject>,
|
||||
count len: Int) -> Int
|
||||
|
||||
func copyWithZone(zone: COpaquePointer) -> CocoaArray
|
||||
func copyWithZone(COpaquePointer) -> CocoaArray
|
||||
|
||||
var count: Int {get}
|
||||
}
|
||||
@@ -71,9 +71,7 @@ struct CocoaArrayWrapper : Collection {
|
||||
/// implementation of countByEnumeratingWithState.
|
||||
func contiguousStorage(subRange: Range<Int>) -> UnsafePointer<AnyObject>
|
||||
{
|
||||
var enumerationState = _SwiftNSFastEnumerationState(
|
||||
0, nil, nil, (0,0,0,0,0))
|
||||
|
||||
var enumerationState = _makeSwiftNSFastEnumerationState()
|
||||
|
||||
// This function currently returns nil unless the first
|
||||
// subRange.endIndex items are stored contiguously. This is an
|
||||
@@ -87,6 +85,11 @@ struct CocoaArrayWrapper : Collection {
|
||||
? reinterpretCast(enumerationState.itemsPtr) + subRange.startIndex : nil
|
||||
}
|
||||
|
||||
@transparent
|
||||
init(_ buffer: CocoaArray) {
|
||||
self.buffer = buffer
|
||||
}
|
||||
|
||||
var buffer: CocoaArray
|
||||
}
|
||||
|
||||
|
||||
@@ -1,42 +1,86 @@
|
||||
protocol _Collection {
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 _CountElements {}
|
||||
func _countElements<Args>(a: Args) -> (_CountElements, Args) {
|
||||
return (_CountElements(), a)
|
||||
}
|
||||
// Default implementation of countElements for Collections
|
||||
// Do not use this operator directly; call countElements(x) instead
|
||||
func ~> <T: _Collection>(x:T, _:(_CountElements,()))
|
||||
-> T.IndexType.DistanceType
|
||||
{
|
||||
return distance(x.startIndex, x.endIndex)
|
||||
}
|
||||
|
||||
/// Return the number of elements in x. O(1) if T.IndexType is
|
||||
/// RandomAccessIndex; O(N) otherwise.
|
||||
func countElements <T: _Collection>(x: T) -> T.IndexType.DistanceType {
|
||||
return x~>_countElements()
|
||||
}
|
||||
|
||||
protocol _Collection : _Sequence {
|
||||
typealias IndexType : ForwardIndex
|
||||
|
||||
func startIndex() -> IndexType
|
||||
func endIndex() -> IndexType
|
||||
var startIndex: IndexType {get}
|
||||
var endIndex: IndexType {get}
|
||||
|
||||
// The declaration of Element and _subscript here is a trick used to
|
||||
// break a cyclic conformance/deduction that Swift can't handle. We
|
||||
// need something other than a Collection.StreamType.Element that can
|
||||
// be used as ContainedStream<T>'s Element. Here we arrange for the
|
||||
// need something other than a Collection.GeneratorType.Element that can
|
||||
// be used as IndexingGenerator<T>'s Element. Here we arrange for the
|
||||
// Collection itself to have an Element type that's deducible from
|
||||
// its __getitem__ function. Ideally we'd like to constrain this
|
||||
// Element to be the same as Collection.StreamType.Element (see
|
||||
// its subscript. Ideally we'd like to constrain this
|
||||
// Element to be the same as Collection.GeneratorType.Element (see
|
||||
// below), but we have no way of expressing it today.
|
||||
typealias _Element
|
||||
func __getitem__(i: IndexType) -> _Element
|
||||
subscript(i: IndexType) -> _Element {get}
|
||||
}
|
||||
|
||||
protocol Collection : _Collection, Sequence {
|
||||
func __getitem__(i: IndexType) -> StreamType.Element
|
||||
subscript(i: IndexType) -> GeneratorType.Element {get}
|
||||
|
||||
// Do not use this operator directly; call countElements(x) instead
|
||||
func ~> (_:Self, _:(_CountElements, ())) -> IndexType.DistanceType
|
||||
}
|
||||
|
||||
/// \brief A stream type that could serve for a Collection given that
|
||||
/// it already had an IndexType. Because of <rdar://problem/14396120>
|
||||
/// we've had to factor _Collection out of Collection to make it useful
|
||||
struct ContainedStream<C: _Collection> : Stream {
|
||||
init(seq: C) {
|
||||
// Default implementation of underestimateCount for Collections. Do not
|
||||
// use this operator directly; call underestimateCount(s) instead
|
||||
func ~> <T: _Collection>(x:T,_:(_UnderestimateCount,())) -> Int {
|
||||
return numericCast(x~>_countElements())
|
||||
}
|
||||
|
||||
protocol MutableCollection : Collection {
|
||||
subscript(i: IndexType) -> GeneratorType.Element {get set}
|
||||
}
|
||||
|
||||
/// A stream type that could serve for a Collection given that
|
||||
/// it already had an IndexType.
|
||||
struct IndexingGenerator<C: _Collection> : Generator, Sequence {
|
||||
// Because of <rdar://problem/14396120> we've had to factor _Collection out
|
||||
// of Collection to make it useful.
|
||||
|
||||
init(_ seq: C) {
|
||||
self._elements = seq
|
||||
self._position = seq.startIndex()
|
||||
self._position = seq.startIndex
|
||||
}
|
||||
|
||||
func generate() -> ContainedStream {
|
||||
func generate() -> IndexingGenerator {
|
||||
return self
|
||||
}
|
||||
|
||||
@mutating
|
||||
func next() -> C._Element? {
|
||||
return _position == _elements.endIndex()
|
||||
? .None : .Some(_elements.__getitem__(_position++))
|
||||
mutating func next() -> C._Element? {
|
||||
return _position == _elements.endIndex
|
||||
? .None : .Some(_elements[_position++])
|
||||
}
|
||||
var _elements: C
|
||||
var _position: C.IndexType
|
||||
@@ -44,98 +88,42 @@ struct ContainedStream<C: _Collection> : Stream {
|
||||
|
||||
func indices<
|
||||
Seq : Collection>(seq: Seq) -> Range<Seq.IndexType> {
|
||||
return Range(seq.startIndex(), seq.endIndex())
|
||||
return Range(start: seq.startIndex, end: seq.endIndex)
|
||||
}
|
||||
|
||||
struct IndexedStream<
|
||||
struct IndexedGenerator<
|
||||
Seq: Collection, Indices: Sequence
|
||||
where Seq.IndexType == Indices.StreamType.Element
|
||||
// FIXME: Commenting out "Stream," below causes all kinds of deserialization crashes
|
||||
> : Stream, Sequence, MultiPassStream {
|
||||
where Seq.IndexType == Indices.GeneratorType.Element
|
||||
> : Generator, Sequence {
|
||||
var seq : Seq
|
||||
var indices : Indices.StreamType
|
||||
var indices : Indices.GeneratorType
|
||||
|
||||
typealias Element = Seq.StreamType.Element
|
||||
typealias Element = Seq.GeneratorType.Element
|
||||
|
||||
@mutating
|
||||
func next() -> Element? {
|
||||
mutating func next() -> Element? {
|
||||
var result = indices.next()
|
||||
return result ? seq.__getitem__(result!) : .None
|
||||
return result ? seq[result!] : .None
|
||||
}
|
||||
|
||||
// Every Stream is also a single-pass Sequence
|
||||
typealias StreamType = IndexedStream
|
||||
func generate() -> StreamType {
|
||||
// Every Generator is also a single-pass Sequence
|
||||
typealias GeneratorType = IndexedGenerator
|
||||
func generate() -> GeneratorType {
|
||||
return self
|
||||
}
|
||||
|
||||
init(seq: Seq, indices: Indices) {
|
||||
init(sequence seq: Seq, indices: Indices) {
|
||||
self.seq = seq
|
||||
self.indices = indices.generate()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/// \brief Adapt an Collection into an Sequence
|
||||
struct CollectionSequence<Seq: Collection>
|
||||
: Sequence {
|
||||
var seq : Seq
|
||||
|
||||
typealias StreamType = ForwardCollectionStream<Seq>
|
||||
func generate() -> StreamType {
|
||||
return StreamType(self.seq)
|
||||
}
|
||||
|
||||
init(seq: Seq) {
|
||||
self.seq = seq
|
||||
}
|
||||
}
|
||||
|
||||
struct ReverseCollection<
|
||||
Seq: Collection
|
||||
where Seq.IndexType: BidirectionalIndex
|
||||
> : Collection {
|
||||
var seq : Seq
|
||||
|
||||
typealias StreamType = CollectionStream<Seq>
|
||||
func generate() -> StreamType {
|
||||
return StreamType(self.seq)
|
||||
}
|
||||
|
||||
init(seq: Seq) {
|
||||
self.seq = seq
|
||||
}
|
||||
}
|
||||
|
||||
func elements<
|
||||
Seq: Collection>(seq: Seq) -> CollectionSequence<Seq> {
|
||||
return CollectionSequence(seq)
|
||||
}
|
||||
|
||||
func reverse<
|
||||
Seq: Collection where Seq.IndexType: BidirectionalIndex
|
||||
>(seq: Seq) -> ReverseCollectionSequence<Seq> {
|
||||
return ReverseCollectionSequence(seq)
|
||||
}
|
||||
|
||||
func reverse<
|
||||
Seq: Collection where Seq.IndexType: BidirectionalIndex
|
||||
>(e: CollectionSequence<Seq>) -> ReverseCollectionSequence<Seq> {
|
||||
return ReverseCollectionSequence(e.seq)
|
||||
}
|
||||
|
||||
func reverse<
|
||||
Seq: Collection where Seq.IndexType: BidirectionalIndex
|
||||
>(e: ReverseCollectionSequence<Seq>) -> CollectionSequence<Seq> {
|
||||
return CollectionSequence(e.seq)
|
||||
}
|
||||
*/
|
||||
/// \brief A wrapper for a BidirectionalIndex that reverses its
|
||||
/// A wrapper for a BidirectionalIndex that reverses its
|
||||
/// direction of traversal
|
||||
struct ReverseIndex<I: BidirectionalIndex> : BidirectionalIndex {
|
||||
var _base: I
|
||||
|
||||
init(_ base: I) { self._base = base }
|
||||
|
||||
func succ() -> ReverseIndex {
|
||||
return ReverseIndex(_base.pred())
|
||||
}
|
||||
@@ -151,171 +139,53 @@ func == <I> (lhs: ReverseIndex<I>, rhs: ReverseIndex<I>) -> Bool {
|
||||
|
||||
struct Reverse<T: Collection where T.IndexType: BidirectionalIndex> : Collection {
|
||||
typealias IndexType = ReverseIndex<T.IndexType>
|
||||
typealias StreamType = ContainedStream<Reverse>
|
||||
typealias GeneratorType = IndexingGenerator<Reverse>
|
||||
|
||||
func generate() -> ContainedStream<Reverse> {
|
||||
return ContainedStream(self)
|
||||
init(_ base: T) {
|
||||
self._base = base
|
||||
}
|
||||
|
||||
func startIndex() -> IndexType {
|
||||
return ReverseIndex(_base.endIndex())
|
||||
func generate() -> IndexingGenerator<Reverse> {
|
||||
return IndexingGenerator(self)
|
||||
}
|
||||
|
||||
func endIndex() -> IndexType {
|
||||
return ReverseIndex(_base.startIndex())
|
||||
var startIndex: IndexType {
|
||||
return ReverseIndex(_base.endIndex)
|
||||
}
|
||||
|
||||
func __getitem__(i: IndexType) -> T.StreamType.Element {
|
||||
return _base.__getitem__(i._base.pred())
|
||||
var endIndex: IndexType {
|
||||
return ReverseIndex(_base.startIndex)
|
||||
}
|
||||
|
||||
subscript(i: IndexType) -> T.GeneratorType.Element {
|
||||
return _base[i._base.pred()]
|
||||
}
|
||||
|
||||
var _base: T
|
||||
}
|
||||
|
||||
protocol Sliceable: Collection {
|
||||
func __slice__(start: IndexType, finish: IndexType) -> Self
|
||||
protocol _Sliceable : Collection {}
|
||||
|
||||
protocol Sliceable : _Sliceable {
|
||||
// FIXME: SliceType should also be Sliceable but we can't express
|
||||
// that constraint (<rdar://problem/14375973> Include associated
|
||||
// type information in protocol witness tables) Instead we constrain
|
||||
// to _Sliceable; at least error messages will be more informative.
|
||||
typealias SliceType: _Sliceable
|
||||
subscript(_: Range<IndexType>) -> SliceType {get}
|
||||
}
|
||||
|
||||
func dropFirst<Seq : Sliceable>(seq: Seq) -> Seq {
|
||||
return seq.__slice__(seq.startIndex().succ(), seq.endIndex())
|
||||
protocol MutableSliceable : Sliceable, MutableCollection {
|
||||
subscript(_: Range<IndexType>) -> SliceType {get set}
|
||||
}
|
||||
|
||||
func dropFirst<Seq : Sliceable>(seq: Seq) -> Seq.SliceType {
|
||||
return seq[seq.startIndex.succ()...seq.endIndex]
|
||||
}
|
||||
|
||||
func dropLast<
|
||||
Seq: Sliceable
|
||||
where Seq.IndexType: BidirectionalIndex
|
||||
>(seq: Seq) -> Seq {
|
||||
return seq.__slice__(seq.startIndex(), seq.endIndex().pred())
|
||||
}
|
||||
|
||||
protocol ForwardIndex : Equatable {
|
||||
func succ() -> Self
|
||||
}
|
||||
|
||||
@prefix @assignment @transparent
|
||||
func ++ <T : ForwardIndex> (x: @inout T) -> T {
|
||||
x = x.succ()
|
||||
return x
|
||||
}
|
||||
|
||||
@postfix @assignment @transparent
|
||||
func ++ <T : ForwardIndex> (x: @inout T) -> T {
|
||||
var ret = x
|
||||
x = x.succ()
|
||||
return ret
|
||||
}
|
||||
|
||||
protocol BidirectionalIndex : ForwardIndex {
|
||||
func pred() -> Self
|
||||
}
|
||||
|
||||
@prefix @assignment @transparent
|
||||
func -- <T: BidirectionalIndex> (x: @inout T) -> T {
|
||||
x = x.pred()
|
||||
return x
|
||||
}
|
||||
|
||||
|
||||
@postfix @assignment @transparent
|
||||
func -- <T: BidirectionalIndex> (x: @inout T) -> T {
|
||||
var ret = x
|
||||
x = x.pred()
|
||||
return ret
|
||||
}
|
||||
|
||||
protocol RandomAccessIndex : BidirectionalIndex, NumericOperations {
|
||||
typealias DistanceType
|
||||
type func sub(lhs: Self, rhs: Self) -> (DistanceType, Bool)
|
||||
type func sub(lhs: Self, rhs: DistanceType) -> (Self, Bool)
|
||||
type func add(lhs: Self, rhs: DistanceType) -> (Self, Bool)
|
||||
// FIXME: Disabled pending <rdar://problem/14011860> (Default
|
||||
// implementations in protocols)
|
||||
func <(lhs: Self, rhs: Self) -> Bool /* {
|
||||
return (lhs.sub(rhs)).isNegative()
|
||||
|
||||
} */
|
||||
}
|
||||
|
||||
@transparent
|
||||
func - <T : RandomAccessIndex>(x: T, y: T) -> T.DistanceType {
|
||||
var tmp : (T.DistanceType, Bool) = T.sub(x, y)
|
||||
alwaysTrap(tmp.1 == false)
|
||||
return tmp.0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func &- <T : RandomAccessIndex>(x: T, y: T) -> T.DistanceType {
|
||||
return T.sub(x, y).0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func - <T : RandomAccessIndex>(x: T, y: T.DistanceType) -> T {
|
||||
var tmp = T.sub(x, y)
|
||||
alwaysTrap(tmp.1 == false)
|
||||
return tmp.0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func &- <T : RandomAccessIndex>(x: T, y: T.DistanceType) -> T {
|
||||
return T.sub(x, y).0
|
||||
}
|
||||
|
||||
@infix @assignment @transparent
|
||||
func += <T : RandomAccessIndex> (lhs: @inout T, rhs: T.DistanceType) {
|
||||
var tmp = T.add(lhs, rhs)
|
||||
alwaysTrap(tmp.1 == false)
|
||||
lhs = tmp.0
|
||||
}
|
||||
|
||||
@infix @assignment @transparent
|
||||
func -= <
|
||||
T: RandomAccessIndex where T.DistanceType: SignedNumber
|
||||
> (lhs: @inout T, rhs: T.DistanceType) {
|
||||
var tmp = T.add(lhs, -rhs)
|
||||
alwaysTrap(tmp.1 == false)
|
||||
lhs = tmp.0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func + <T : RandomAccessIndex> (lhs: T, rhs: T.DistanceType) -> T {
|
||||
var tmp = T.add(lhs, rhs)
|
||||
alwaysTrap(tmp.1 == false)
|
||||
return tmp.0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func + <T : RandomAccessIndex> (lhs: T.DistanceType, rhs: T) -> T {
|
||||
var tmp = T.add(rhs, lhs)
|
||||
alwaysTrap(tmp.1 == false)
|
||||
return tmp.0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func &+ <T : RandomAccessIndex> (lhs: T, rhs: T) -> T {
|
||||
return T.add(lhs, rhs).0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func &+ <T : RandomAccessIndex> (lhs: T, rhs: T.DistanceType) -> T {
|
||||
return T.add(lhs, rhs).0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func &+ <T : RandomAccessIndex> (lhs: T.DistanceType, rhs: T) -> T {
|
||||
return T.add(rhs, lhs).0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func - <T : RandomAccessIndex where T.DistanceType : SignedNumber> (
|
||||
lhs: T, rhs: T.DistanceType)
|
||||
-> T {
|
||||
var tmp = T.add(lhs, -rhs)
|
||||
alwaysTrap(tmp.1 == false)
|
||||
return tmp.0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func &- <T : RandomAccessIndex where T.DistanceType : SignedNumber> (
|
||||
lhs: T, rhs: T.DistanceType)
|
||||
-> T {
|
||||
return T.add(lhs, -rhs).0
|
||||
>(seq: Seq) -> Seq.SliceType {
|
||||
return seq[seq.startIndex...seq.endIndex.pred()]
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct GeneratorOfOne<T> : Generator, Sequence {
|
||||
init(_ elements: T?) {
|
||||
self.elements = elements
|
||||
}
|
||||
|
||||
func generate() -> GeneratorOfOne {
|
||||
return self
|
||||
}
|
||||
@@ -27,11 +31,15 @@ struct GeneratorOfOne<T> : Generator, Sequence {
|
||||
struct CollectionOfOne<T> : Collection {
|
||||
typealias IndexType = Bit
|
||||
|
||||
func startIndex() -> IndexType {
|
||||
init(_ element: T) {
|
||||
self.element = element
|
||||
}
|
||||
|
||||
var startIndex: IndexType {
|
||||
return .zero
|
||||
}
|
||||
|
||||
func endIndex() -> IndexType {
|
||||
var endIndex: IndexType {
|
||||
return .one
|
||||
}
|
||||
|
||||
@@ -39,14 +47,17 @@ struct CollectionOfOne<T> : Collection {
|
||||
return GeneratorOfOne(element)
|
||||
}
|
||||
|
||||
func __getitem__(i: IndexType) -> T {
|
||||
subscript(i: IndexType) -> T {
|
||||
assert(i == .zero, "Index out of range")
|
||||
return element
|
||||
}
|
||||
|
||||
subscript(i: IndexType) -> T {
|
||||
return __getitem__(i)
|
||||
}
|
||||
|
||||
val element: T
|
||||
let element: T
|
||||
}
|
||||
|
||||
// Specialization of countElements for CollectionOfOne<T>
|
||||
func ~> <T>(x:CollectionOfOne<T>, _:(_CountElements, ())) -> Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,126 +1,230 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Intrinsic protocols shared with the compiler
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// \brief Protocol describing types that can be used as array bounds.
|
||||
/// Protocol describing types that can be used as array bounds.
|
||||
///
|
||||
/// Types that conform to the \c ArrayBound protocol can be used as array bounds
|
||||
/// by providing an operation (\c getArrayBoundValue) that produces an integral
|
||||
/// Types that conform to the `ArrayBound` protocol can be used as array bounds
|
||||
/// by providing an operation (`getArrayBoundValue`) that produces an integral
|
||||
/// value.
|
||||
protocol ArrayBound {
|
||||
typealias ArrayBoundType
|
||||
func getArrayBoundValue() -> ArrayBoundType
|
||||
}
|
||||
|
||||
/// \brief Protocol describing types that can be used as logical values within
|
||||
/// Protocol describing types that can be used as logical values within
|
||||
/// a condition.
|
||||
///
|
||||
/// Types that conform to the \c LogicValue protocol can be used as
|
||||
/// condition in various control statements (\c if, \c while, C-style
|
||||
/// \c for) as well as other logical value contexts (e.g., case
|
||||
/// Types that conform to the `LogicValue` protocol can be used as
|
||||
/// condition in various control statements (`if`, `while`, C-style
|
||||
/// `for`) as well as other logical value contexts (e.g., `case`
|
||||
/// statement guards).
|
||||
protocol LogicValue {
|
||||
func getLogicValue() -> Bool
|
||||
}
|
||||
|
||||
protocol Generator {
|
||||
/// A `Generator` is a `Sequence` that is consumed when iterated.
|
||||
///
|
||||
/// While it is safe to copy a `Generator`, only one copy should be advanced
|
||||
/// with `next()`.
|
||||
///
|
||||
/// If an algorithm requires two `Generator`\ s for the same `Sequence` to be
|
||||
/// advanced at the same time, and the specific `Sequence` type supports
|
||||
/// that, then those `Generator` objects should be obtained from `Sequence` by
|
||||
/// two distinct calls to `generate(). However in that case the algorithm
|
||||
/// should probably require `Collection`, since `Collection` implies
|
||||
/// multi-pass.
|
||||
protocol Generator /* : Sequence */ {
|
||||
// FIXME: Refinement pending <rdar://problem/14396120>
|
||||
typealias Element
|
||||
func next() -> Element?
|
||||
mutating func next() -> Element?
|
||||
}
|
||||
|
||||
protocol Sequence {
|
||||
/// The `for...in` loop operates on `Sequence`\ s. It is unspecified whether
|
||||
/// `for...in` consumes the sequence on which it operates.
|
||||
protocol _Sequence {
|
||||
}
|
||||
|
||||
protocol _Sequence_ : _Sequence {
|
||||
typealias GeneratorType : Generator
|
||||
func enumerate() -> GeneratorType
|
||||
func generate() -> GeneratorType
|
||||
}
|
||||
|
||||
protocol Sequence : _Sequence_ {
|
||||
typealias GeneratorType : Generator
|
||||
func generate() -> GeneratorType
|
||||
|
||||
func ~> (_:Self,_:(_UnderestimateCount,())) -> Int
|
||||
|
||||
func ~>(
|
||||
_:Self, _: (_CopyToNativeArrayBuffer, ())
|
||||
) -> NativeArrayBuffer<Self.GeneratorType.Element>
|
||||
}
|
||||
|
||||
struct _CopyToNativeArrayBuffer {}
|
||||
func _copyToNativeArrayBuffer<Args>(args: Args)
|
||||
-> (_CopyToNativeArrayBuffer, Args)
|
||||
{
|
||||
return (_CopyToNativeArrayBuffer(), args)
|
||||
}
|
||||
|
||||
// Operation tags for underestimateCount. See Index.swift for an
|
||||
// explanation of operation tags.
|
||||
struct _UnderestimateCount {}
|
||||
func _underestimateCount<Args>(args: Args) -> (_UnderestimateCount, Args) {
|
||||
return (_UnderestimateCount(), args)
|
||||
}
|
||||
|
||||
// Default implementation of underestimateCount for Sequences. Do not
|
||||
// use this operator directly; call underestimateCount(s) instead
|
||||
func ~> <T: _Sequence>(s: T,_:(_UnderestimateCount, ())) -> Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
/// Return an underestimate of the number of elements in the given
|
||||
/// sequence, without consuming the sequence. For Sequences that are
|
||||
/// actually Collections, this will return countElements(x)
|
||||
func underestimateCount<T: Sequence>(x: T) -> Int {
|
||||
return x~>_underestimateCount()
|
||||
}
|
||||
|
||||
// Pending <rdar://problem/14011860> and <rdar://problem/14396120>,
|
||||
// pass a Generator through GeneratorSequence to give it "Sequence-ness"
|
||||
struct GeneratorSequence<G: Generator> : Generator, Sequence {
|
||||
init(_ base: G) {
|
||||
_base = base
|
||||
}
|
||||
|
||||
mutating func next() -> G.Element? {
|
||||
return _base.next()
|
||||
}
|
||||
|
||||
func generate() -> GeneratorSequence {
|
||||
return self
|
||||
}
|
||||
|
||||
var _base: G
|
||||
}
|
||||
|
||||
protocol RawRepresentable {
|
||||
typealias RawType
|
||||
static func fromRaw(_: RawType) -> Self?
|
||||
class func fromRaw(raw: RawType) -> Self?
|
||||
func toRaw() -> RawType
|
||||
}
|
||||
|
||||
// TODO: This is an incomplete implementation of our option sets vision.
|
||||
protocol RawOptionSet : RawRepresentable, LogicValue
|
||||
/*FIXME: , BitwiseOperations*/ {
|
||||
typealias RawType : BitwiseOperations
|
||||
// Workaround for our lack of circular conformance checking. Allow == to be
|
||||
// defined on _RawOptionSet in order to satisfy the Equatable requirement of
|
||||
// RawOptionSet without a circularity our type-checker can't yet handle.
|
||||
protocol _RawOptionSet: RawRepresentable {
|
||||
typealias RawType : BitwiseOperations, Equatable
|
||||
}
|
||||
|
||||
// TODO: This is an incomplete implementation of our option sets vision.
|
||||
protocol RawOptionSet : _RawOptionSet, LogicValue, Equatable
|
||||
/*FIXME: , BitwiseOperations*/ {
|
||||
// A non-failable version of RawRepresentable.fromRaw.
|
||||
static func fromMask(_: RawType) -> Self
|
||||
class func fromMask(raw: RawType) -> Self
|
||||
|
||||
// FIXME: Disabled pending <rdar://problem/14011860> (Default
|
||||
// implementations in protocols)
|
||||
// The Clang importer synthesizes these for imported NS_OPTIONS.
|
||||
|
||||
/* static func fromRaw(raw: RawType) -> Self? { return fromMask(raw) } */
|
||||
/* class func fromRaw(raw: RawType) -> Self? { return fromMask(raw) } */
|
||||
|
||||
/* func getLogicValue() -> Bool { return toRaw() != .allZeros() } */
|
||||
}
|
||||
|
||||
protocol BuiltinIntegerLiteralConvertible {
|
||||
static func _convertFromBuiltinIntegerLiteral(
|
||||
protocol _BuiltinIntegerLiteralConvertible {
|
||||
class func _convertFromBuiltinIntegerLiteral(
|
||||
value: MaxBuiltinIntegerType) -> Self
|
||||
}
|
||||
|
||||
protocol IntegerLiteralConvertible {
|
||||
typealias IntegerLiteralType : BuiltinIntegerLiteralConvertible
|
||||
static func convertFromIntegerLiteral(value: IntegerLiteralType) -> Self
|
||||
typealias IntegerLiteralType : _BuiltinIntegerLiteralConvertible
|
||||
class func convertFromIntegerLiteral(value: IntegerLiteralType) -> Self
|
||||
}
|
||||
|
||||
protocol BuiltinFloatLiteralConvertible {
|
||||
static func _convertFromBuiltinFloatLiteral(
|
||||
protocol _BuiltinFloatLiteralConvertible {
|
||||
class func _convertFromBuiltinFloatLiteral(
|
||||
value: MaxBuiltinFloatType) -> Self
|
||||
}
|
||||
|
||||
protocol FloatLiteralConvertible {
|
||||
typealias FloatLiteralType : BuiltinFloatLiteralConvertible
|
||||
static func convertFromFloatLiteral(value: FloatLiteralType) -> Self
|
||||
typealias FloatLiteralType : _BuiltinFloatLiteralConvertible
|
||||
class func convertFromFloatLiteral(value: FloatLiteralType) -> Self
|
||||
}
|
||||
|
||||
protocol BuiltinCharacterLiteralConvertible {
|
||||
static func _convertFromBuiltinCharacterLiteral(value: Builtin.Int21) -> Self
|
||||
protocol _BuiltinCharacterLiteralConvertible {
|
||||
class func _convertFromBuiltinCharacterLiteral(value: Builtin.Int32) -> Self
|
||||
}
|
||||
|
||||
protocol CharacterLiteralConvertible {
|
||||
typealias CharacterLiteralType : BuiltinCharacterLiteralConvertible
|
||||
static func convertFromCharacterLiteral(value: CharacterLiteralType) -> Self
|
||||
typealias CharacterLiteralType : _BuiltinCharacterLiteralConvertible
|
||||
class func convertFromCharacterLiteral(value: CharacterLiteralType) -> Self
|
||||
}
|
||||
|
||||
protocol BuiltinStringLiteralConvertible {
|
||||
static func _convertFromBuiltinStringLiteral(value: Builtin.RawPointer,
|
||||
byteSize: Builtin.Int64,
|
||||
protocol _BuiltinExtendedGraphemeClusterLiteralConvertible {
|
||||
class func _convertFromBuiltinExtendedGraphemeClusterLiteral(
|
||||
start: Builtin.RawPointer,
|
||||
byteSize: Builtin.Word,
|
||||
isASCII: Builtin.Int1) -> Self
|
||||
}
|
||||
|
||||
protocol StringLiteralConvertible {
|
||||
typealias StringLiteralType : BuiltinStringLiteralConvertible
|
||||
static func convertFromStringLiteral(value: StringLiteralType) -> Self
|
||||
protocol ExtendedGraphemeClusterLiteralConvertible {
|
||||
typealias ExtendedGraphemeClusterLiteralType : _BuiltinExtendedGraphemeClusterLiteralConvertible
|
||||
class func convertFromExtendedGraphemeClusterLiteral(
|
||||
value: ExtendedGraphemeClusterLiteralType) -> Self
|
||||
}
|
||||
|
||||
protocol _BuiltinStringLiteralConvertible : _BuiltinExtendedGraphemeClusterLiteralConvertible {
|
||||
class func _convertFromBuiltinStringLiteral(start: Builtin.RawPointer,
|
||||
byteSize: Builtin.Word,
|
||||
isASCII: Builtin.Int1) -> Self
|
||||
}
|
||||
|
||||
protocol _BuiltinUTF16StringLiteralConvertible : _BuiltinStringLiteralConvertible {
|
||||
class func _convertFromBuiltinUTF16StringLiteral(
|
||||
start: Builtin.RawPointer,
|
||||
numberOfCodeUnits: Builtin.Word) -> Self
|
||||
}
|
||||
|
||||
protocol StringLiteralConvertible : ExtendedGraphemeClusterLiteralConvertible {
|
||||
// FIXME: when we have default function implementations in protocols, provide
|
||||
// an implementation of convertFromExtendedGraphemeClusterLiteral().
|
||||
|
||||
typealias StringLiteralType : _BuiltinStringLiteralConvertible
|
||||
class func convertFromStringLiteral(value: StringLiteralType) -> Self
|
||||
}
|
||||
|
||||
protocol ArrayLiteralConvertible {
|
||||
typealias Element
|
||||
static func convertFromArrayLiteral(elements: Element...) -> Self
|
||||
class func convertFromArrayLiteral(elements: Element...) -> Self
|
||||
}
|
||||
|
||||
protocol DictionaryLiteralConvertible {
|
||||
typealias Key
|
||||
typealias Value
|
||||
static func convertFromDictionaryLiteral(elements: (Key, Value)...) -> Self
|
||||
class func convertFromDictionaryLiteral(elements: (Key, Value)...) -> Self
|
||||
}
|
||||
|
||||
protocol StringInterpolationConvertible {
|
||||
static func convertFromStringInterpolation(strings: Self...) -> Self
|
||||
class func convertFromStringInterpolation(strings: Self...) -> Self
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// REPL protocols
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// FIXME: This should be intrinsically available for any metatype--need a
|
||||
// metatype root type
|
||||
protocol ClassNameable {
|
||||
static func className() -> String
|
||||
}
|
||||
|
||||
protocol ReplPrintable {
|
||||
func replPrint()
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,48 +1,67 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//////////////////////////////////////////
|
||||
// FIXME: Workaround for inability to create existentials of protocols
|
||||
// with associated types <rdar://problem/11689181> and for the
|
||||
// inability to constrain nested generics based on the containing type
|
||||
// <rdar://problem/11700999>
|
||||
//
|
||||
// with associated types <rdar://problem/11689181>
|
||||
|
||||
// This file contains "existentials" for the protocols defined in
|
||||
// Policy.swift. Similar components should usually be defined next to
|
||||
// their respective protocols.
|
||||
struct GeneratorOf<T> : Generator {
|
||||
def next() -> T? {
|
||||
struct GeneratorOf<T> : Generator, Sequence {
|
||||
init(_ next: ()->T?) {
|
||||
self._next = next
|
||||
}
|
||||
|
||||
init<G: Generator where G.Element == T>(var _ self_: G) {
|
||||
self._next = { self_.next() }
|
||||
}
|
||||
|
||||
mutating func next() -> T? {
|
||||
return _next()
|
||||
}
|
||||
var _next : ()->T?
|
||||
}
|
||||
|
||||
def existential<G: Generator>(base: G)
|
||||
-> GeneratorOf<G.Element>
|
||||
{
|
||||
return GeneratorOf( { base.next() } )
|
||||
}
|
||||
|
||||
struct EnumerableOf<T> : Enumerable {
|
||||
def enumerate() -> GeneratorOf<T> {
|
||||
return _enumerate()
|
||||
func generate() -> GeneratorOf {
|
||||
return self
|
||||
}
|
||||
var _enumerate : ()->GeneratorOf<T>
|
||||
let _next: ()->T?
|
||||
}
|
||||
|
||||
def existential<E: Enumerable>(base: E)
|
||||
-> EnumerableOf<E.GeneratorType.Element>
|
||||
{
|
||||
return EnumerableOf<E.GeneratorType.Element>(
|
||||
{ existential(base.enumerate()) }
|
||||
)
|
||||
struct SequenceOf<T> : Sequence {
|
||||
init<G: Generator where G.Element == T>(_ generate: ()->G) {
|
||||
_generate = { GeneratorOf(generate()) }
|
||||
}
|
||||
init<S: Sequence where S.GeneratorType.Element == T>(_ self_: S) {
|
||||
self = SequenceOf({ self_.generate() })
|
||||
}
|
||||
|
||||
func generate() -> GeneratorOf<T> {
|
||||
return _generate()
|
||||
}
|
||||
|
||||
let _generate: ()->GeneratorOf<T>
|
||||
}
|
||||
|
||||
struct SinkOf<T> : Sink {
|
||||
def put(x: T) {
|
||||
init(_ put: (T)->()) {
|
||||
_put = put
|
||||
}
|
||||
|
||||
init<S: Sink where S.Element == T>(var _ base: S) {
|
||||
_put = { base.put($0) }
|
||||
}
|
||||
func put(x: T) {
|
||||
_put(x)
|
||||
}
|
||||
var _put : (T)->()
|
||||
let _put: (T)->()
|
||||
}
|
||||
|
||||
def existential<S: Sink>(base: S) -> SinkOf<S.Element> {
|
||||
return SinkOf( { base.put($0) } )
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@# -*- mode: swift -*-
|
||||
%# -*- mode: swift -*-
|
||||
|
||||
@# Ignore the following admonition; it applies to the resulting .swift file only
|
||||
%# Ignore the following admonition; it applies to the resulting .swift file only
|
||||
//// Automatically Generated From FixedPoint.gyb. Do Not Edit Directly!
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -14,7 +14,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@{
|
||||
%{
|
||||
#
|
||||
# Utility code for later in this template
|
||||
#
|
||||
@@ -65,62 +65,109 @@ def intName(name, signed):
|
||||
|
||||
def otherIntName(name, signed):
|
||||
return ('U' if signed else '') + baseIntName(name)
|
||||
}@
|
||||
}%
|
||||
|
||||
typealias IntMax = Int${maxBits}
|
||||
typealias UIntMax = UInt${maxBits}
|
||||
|
||||
@ for (name, bits, signed) in allInts():
|
||||
@ (sign, ext) = ('s', 'sext') if signed else ('u', 'zext')
|
||||
@ BuiltinName = builtinIntName(name)
|
||||
@ Self = intName(name, signed)
|
||||
@ OtherSelf = otherIntName(name, signed)
|
||||
@ ConstructIntType = 'Int' if Self != 'Int' else ''
|
||||
@ ArrayBound = 'ArrayBound, ' if bits <= 64 else ''
|
||||
protocol _Integer
|
||||
: _BuiltinIntegerLiteralConvertible,
|
||||
IntegerLiteralConvertible,
|
||||
ReplPrintable,
|
||||
ArrayBound,
|
||||
Hashable,
|
||||
IntegerArithmetic,
|
||||
BitwiseOperations,
|
||||
_Incrementable
|
||||
{
|
||||
}
|
||||
|
||||
struct ${Self} : BuiltinIntegerLiteralConvertible, IntegerLiteralConvertible,
|
||||
${ArrayBound}ReplPrintable {
|
||||
protocol Integer : _Integer, RandomAccessIndex {
|
||||
}
|
||||
|
||||
protocol _SignedInteger : _Integer, SignedNumber {
|
||||
func toIntMax() -> IntMax
|
||||
class func from(IntMax) -> Self
|
||||
}
|
||||
|
||||
protocol SignedInteger : _SignedInteger, Integer {
|
||||
}
|
||||
|
||||
protocol _UnsignedInteger : _Integer {
|
||||
func toUIntMax() -> UIntMax
|
||||
class func from(UIntMax) -> Self
|
||||
}
|
||||
|
||||
protocol UnsignedInteger : _UnsignedInteger, Integer {
|
||||
}
|
||||
|
||||
func numericCast<T : _SignedInteger, U : _SignedInteger>(x: T) -> U {
|
||||
return .from(x.toIntMax())
|
||||
}
|
||||
|
||||
func numericCast<T : _UnsignedInteger, U : _UnsignedInteger>(x: T) -> U {
|
||||
return .from(x.toUIntMax())
|
||||
}
|
||||
|
||||
func numericCast<T : _SignedInteger, U : _UnsignedInteger>(x: T) -> U {
|
||||
return .from(UIntMax(x.toIntMax()))
|
||||
}
|
||||
|
||||
func numericCast<T : _UnsignedInteger, U : _SignedInteger>(x: T) -> U {
|
||||
return .from(IntMax(x.toUIntMax()))
|
||||
}
|
||||
|
||||
% for (name, bits, signed) in allInts():
|
||||
% (sign, ext) = ('s', 'sext') if signed else ('u', 'zext')
|
||||
% BuiltinName = builtinIntName(name)
|
||||
% Self = intName(name, signed)
|
||||
% OtherSelf = otherIntName(name, signed)
|
||||
% ConstructIntType = 'Int' if Self != 'Int' else ''
|
||||
|
||||
struct ${Self} : ${'SignedInteger' if sign == 's' else 'UnsignedInteger'}
|
||||
{
|
||||
var value: Builtin.${BuiltinName}
|
||||
|
||||
@@transparent
|
||||
@transparent
|
||||
init() {
|
||||
var maxWidthZero: IntMax = 0
|
||||
value = Builtin.truncOrBitCast_Int${maxBits}_${BuiltinName}(maxWidthZero.value)
|
||||
}
|
||||
|
||||
@@transparent
|
||||
init(v: Builtin.${BuiltinName}) {
|
||||
@transparent
|
||||
init(_ v: Builtin.${BuiltinName}) {
|
||||
value = v
|
||||
}
|
||||
|
||||
@@transparent
|
||||
@transparent
|
||||
init(_ value: ${Self}) { self = value }
|
||||
|
||||
@transparent
|
||||
static func _convertFromBuiltinIntegerLiteral(value: Builtin.Int${builtinIntLiteralBits}) -> ${Self} {
|
||||
return ${Self}(Builtin.s_to_${sign}_checked_trunc_Int${builtinIntLiteralBits}_${BuiltinName}(value).0)
|
||||
}
|
||||
|
||||
@@transparent
|
||||
@transparent
|
||||
static func convertFromIntegerLiteral(value: ${Self}) -> ${Self} {
|
||||
return value
|
||||
}
|
||||
@ if ArrayBound:
|
||||
@@transparent
|
||||
@transparent
|
||||
func _getBuiltinArrayBoundValue() -> Builtin.Word {
|
||||
@ if bits < wordBits:
|
||||
% if bits < wordBits:
|
||||
return Builtin.${ext}OrBitCast_${BuiltinName}_Word(self.value)
|
||||
@ elif bits > wordBits:
|
||||
% elif bits > wordBits:
|
||||
return Builtin.truncOrBitCast_${BuiltinName}_Word(self.value)
|
||||
@ elif BuiltinName == 'Word':
|
||||
% elif BuiltinName == 'Word':
|
||||
return self.value
|
||||
@ else:
|
||||
% else:
|
||||
return Builtin.${CastToWord}(self.value)
|
||||
@ end
|
||||
% end
|
||||
}
|
||||
|
||||
typealias ArrayBoundType = ${Self}
|
||||
func getArrayBoundValue() -> ${Self} {
|
||||
return self
|
||||
}
|
||||
@ end
|
||||
|
||||
func replPrint() {
|
||||
print(${
|
||||
@@ -128,247 +175,236 @@ struct ${Self} : BuiltinIntegerLiteralConvertible, IntegerLiteralConvertible,
|
||||
else (('String' if bits > 64 else 'Int64' if signed else 'UInt64') + '(self)')})
|
||||
}
|
||||
|
||||
@ max = maskBits((bits - 1) if signed else bits)
|
||||
@@transparent
|
||||
% max = maskBits((bits - 1) if signed else bits)
|
||||
@transparent
|
||||
static var max: ${Self} { return ${max} }
|
||||
@@transparent
|
||||
@transparent
|
||||
static var min: ${Self} { return ${'-%s-1' % max if signed else '0'} }
|
||||
}
|
||||
|
||||
extension ${Self} : Hashable {
|
||||
func hashValue() -> Int {
|
||||
@ if bits < wordBits:
|
||||
var hashValue: Int {
|
||||
% if bits < wordBits:
|
||||
return Int(Builtin.sextOrBitCast_${BuiltinName}_Word(self.value))
|
||||
@ elif bits > wordBits:
|
||||
% elif bits > wordBits:
|
||||
var result: Int = 0
|
||||
for var i = 0; i < (sizeof(self) * 8); i += sizeof(Int.self) * 8 {
|
||||
for var i = 0; i < (sizeofValue(self) * 8); i += sizeof(Int.self) * 8 {
|
||||
result ^= Int(self >> ${Self}(i)) & ~0
|
||||
}
|
||||
return result
|
||||
@ elif BuiltinName == 'Word':
|
||||
% elif BuiltinName == 'Word':
|
||||
return Int(self.value)
|
||||
@ else:
|
||||
% else:
|
||||
return Int(Builtin.${CastToWord}(self.value))
|
||||
@ end
|
||||
% end
|
||||
}
|
||||
}
|
||||
|
||||
@@transparent
|
||||
@transparent
|
||||
extension ${Self} : RandomAccessIndex {
|
||||
@@transparent
|
||||
@transparent
|
||||
func succ() -> ${Self} {
|
||||
return self + 1
|
||||
}
|
||||
@@transparent
|
||||
@transparent
|
||||
func pred() -> ${Self} {
|
||||
return self - 1
|
||||
}
|
||||
@@transparent
|
||||
func distanceTo(other: ${Self}) -> Int {
|
||||
return ${ConstructIntType}(other - self)
|
||||
}
|
||||
typealias DistanceType = ${Self}
|
||||
@@transparent
|
||||
static func sub(lhs: ${Self}, rhs: ${Self}, reportOverflow: Bool) -> (DistanceType, Bool) {
|
||||
var tmp = Builtin.${sign}sub_with_overflow_${BuiltinName}(lhs.value, rhs.value, reportOverflow.value)
|
||||
return (${Self}(tmp.0), Bool(tmp.1))
|
||||
}
|
||||
@@transparent
|
||||
static func add(lhs: ${Self}, rhs: DistanceType, reportOverflow: Bool) -> (${Self}, Bool) {
|
||||
var tmp = Builtin.${sign}add_with_overflow_${BuiltinName}(lhs.value, rhs.value, reportOverflow.value)
|
||||
return (${Self}(tmp.0), Bool(tmp.1))
|
||||
}
|
||||
@@transparent
|
||||
static func mul(lhs: ${Self}, rhs: ${Self}, reportOverflow: Bool) -> (${Self}, Bool) {
|
||||
var tmp = Builtin.${sign}mul_with_overflow_${BuiltinName}(lhs.value, rhs.value, reportOverflow.value)
|
||||
return (${Self}(tmp.0), Bool(tmp.1))
|
||||
}
|
||||
@@transparent
|
||||
static func div(lhs: ${Self}, rhs: ${Self}, reportOverflow: Bool) -> (${Self}, Bool) {
|
||||
if rhs == 0 {
|
||||
return (0, true)
|
||||
}
|
||||
@ if signed:
|
||||
if lhs == ${Self}.min && rhs == -1 {
|
||||
return (lhs, true)
|
||||
}
|
||||
@ end
|
||||
var tmp = Builtin.${sign}div_${BuiltinName}(lhs.value, rhs.value)
|
||||
return (${Self}(tmp), false)
|
||||
}
|
||||
@@transparent
|
||||
static func rem(lhs: ${Self}, rhs: ${Self}, reportOverflow: Bool) -> (${Self}, Bool) {
|
||||
if rhs == 0 {
|
||||
return (0, true)
|
||||
}
|
||||
@ if signed:
|
||||
if lhs == ${Self}.min && rhs == -1 {
|
||||
return (0, true)
|
||||
}
|
||||
@ end
|
||||
var tmp = Builtin.${sign}rem_${BuiltinName}(lhs.value, rhs.value)
|
||||
return (${Self}(tmp), false)
|
||||
|
||||
@transparent
|
||||
func distanceTo(other: ${Self}) -> ${Self}.DistanceType {
|
||||
return numericCast((numericCast(other) as IntMax) - numericCast(self))
|
||||
}
|
||||
|
||||
@@transparent
|
||||
static func sub(lhs: ${Self}, rhs: ${Self}) -> (DistanceType, Bool) {
|
||||
return sub(lhs, rhs, true)
|
||||
@transparent
|
||||
func advancedBy(amount: ${Self}.DistanceType) -> ${Self} {
|
||||
return numericCast((numericCast(self) as IntMax) + numericCast(amount))
|
||||
}
|
||||
@@transparent
|
||||
static func add(lhs: ${Self}, rhs: DistanceType) -> (${Self}, Bool) {
|
||||
return add(lhs, rhs, true)
|
||||
|
||||
% for Method,op in [('Add', 'add'), ('Subtract', 'sub'), ('Multiply', 'mul')]:
|
||||
@transparent
|
||||
static func unchecked${Method}(lhs: ${Self}, _ rhs: ${Self}) -> (${Self}, Bool) {
|
||||
var tmp = Builtin.${sign}${op}_with_overflow_${BuiltinName}(lhs.value, rhs.value, false.value)
|
||||
return (${Self}(tmp.0), Bool(tmp.1))
|
||||
}
|
||||
@@transparent
|
||||
static func mul(lhs: ${Self}, rhs: ${Self}) -> (${Self}, Bool) {
|
||||
return mul(lhs, rhs, true)
|
||||
% end
|
||||
|
||||
% for Method,op in [('Divide', 'div'), ('Modulus', 'rem')]:
|
||||
@transparent
|
||||
static func unchecked${Method}(lhs: ${Self}, _ rhs: ${Self}) -> (${Self}, Bool) {
|
||||
if rhs == 0 {
|
||||
return (0, true)
|
||||
}
|
||||
@@transparent
|
||||
static func div(lhs: ${Self}, rhs: ${Self}) -> (${Self}, Bool) {
|
||||
return div(lhs, rhs, true)
|
||||
% if signed:
|
||||
if lhs == ${Self}.min && rhs == -1 {
|
||||
return (0, true)
|
||||
}
|
||||
@@transparent
|
||||
static func rem(lhs: ${Self}, rhs: ${Self}) -> (${Self}, Bool) {
|
||||
return rem(lhs, rhs, true)
|
||||
% end
|
||||
// FIXME: currently doesn't detect overflow -- blocked by:
|
||||
// <rdar://15735295> Need [su]{div,rem}_with_overflow IR
|
||||
var tmp = Builtin.${sign}${op}_${BuiltinName}(lhs.value, rhs.value)
|
||||
return (${Self}(tmp), false)
|
||||
}
|
||||
@@transparent
|
||||
%end
|
||||
|
||||
% U = '' if signed else 'U'
|
||||
@transparent
|
||||
func to${U}IntMax() -> ${U}IntMax {
|
||||
return ${'self' if Self == U+'Int%s'%maxBits else U+'IntMax(self)'}
|
||||
}
|
||||
% if not signed:
|
||||
func toIntMax() -> IntMax {
|
||||
return ${'self' if Self == 'Int%s' % maxBits else 'IntMax(self)'}
|
||||
return IntMax(toUIntMax())
|
||||
}
|
||||
% end
|
||||
@transparent
|
||||
static func from(x: ${U}IntMax) -> ${Self} {
|
||||
return ${'x' if Self == U+'Int%s'%maxBits else Self+'(x)'}
|
||||
}
|
||||
}
|
||||
|
||||
@ if signed:
|
||||
@@transparent
|
||||
extension ${Self} : SignedNumber {
|
||||
@@transparent
|
||||
static func negate(rhs: ${Self}) -> (${Self}, Bool) {
|
||||
return ${Self}.sub(0, rhs)
|
||||
}
|
||||
@@transparent
|
||||
static func abs(rhs: ${Self}) -> (${Self}, Bool) {
|
||||
return rhs.isNegative() ? ${Self}.negate(rhs) : (rhs, false)
|
||||
}
|
||||
@@transparent
|
||||
func isNegative() -> Bool { return self < 0 }
|
||||
}
|
||||
@ end
|
||||
% if signed:
|
||||
@transparent
|
||||
extension ${Self} : SignedNumber {}
|
||||
% end
|
||||
|
||||
@# FIXME: checked conversions of Word types
|
||||
%# FIXME: checked conversions of Word types
|
||||
// construction from other integer types
|
||||
@@transparent
|
||||
@transparent
|
||||
extension ${Self} {
|
||||
@ for (srcName, srcBits, srcSigned) in allInts():
|
||||
@ Src = intName(srcName, srcSigned)
|
||||
@ srcBuiltinName = builtinIntName(srcName)
|
||||
@ (srcSign, srcExt) = ('s', 'sext') if srcSigned else ('u', 'zext')
|
||||
@ if Self != Src:
|
||||
init(v: ${Src}) {
|
||||
@
|
||||
@ if srcBuiltinName == 'Word':
|
||||
% for (srcName, srcBits, srcSigned) in allInts():
|
||||
% Src = intName(srcName, srcSigned)
|
||||
% srcBuiltinName = builtinIntName(srcName)
|
||||
% (srcSign, srcExt) = ('s', 'sext') if srcSigned else ('u', 'zext')
|
||||
% if Self != Src:
|
||||
init(_ v: ${Src}) {
|
||||
%
|
||||
% if srcBuiltinName == 'Word':
|
||||
var srcNotWord = Builtin.${CastFromWord}(v.value)
|
||||
@ else:
|
||||
% else:
|
||||
var srcNotWord = v.value
|
||||
@ end
|
||||
@
|
||||
@ if srcBits == bits and srcSign == sign:
|
||||
% end
|
||||
%
|
||||
% if srcBits == bits and srcSign == sign:
|
||||
var dstNotWord = srcNotWord
|
||||
@
|
||||
@ elif srcBits == bits:
|
||||
%
|
||||
% elif srcBits == bits:
|
||||
var tmp = Builtin.${srcSign}_to_${sign}_checked_conversion_Int${srcBits}(srcNotWord)
|
||||
Builtin.condfail(tmp.1)
|
||||
var dstNotWord = tmp.0
|
||||
@
|
||||
@ elif srcBits > bits:
|
||||
%
|
||||
% elif srcBits > bits:
|
||||
var tmp = Builtin.${srcSign}_to_${sign}_checked_trunc_Int${srcBits}_Int${bits}(srcNotWord)
|
||||
Builtin.condfail(tmp.1)
|
||||
var dstNotWord = tmp.0
|
||||
@
|
||||
@ elif srcSigned and not signed:
|
||||
%
|
||||
% elif srcSigned and not signed:
|
||||
var tmp = Builtin.s_to_u_checked_conversion_Int${srcBits}(srcNotWord)
|
||||
Builtin.condfail(tmp.1)
|
||||
var dstNotWord = Builtin.${srcExt}_Int${srcBits}_Int${bits}(tmp.0)
|
||||
@
|
||||
@ else:
|
||||
%
|
||||
% else:
|
||||
var dstNotWord = Builtin.${srcExt}_Int${srcBits}_Int${bits}(srcNotWord)
|
||||
@ end
|
||||
@
|
||||
@ if BuiltinName == 'Word':
|
||||
% end
|
||||
%
|
||||
% if BuiltinName == 'Word':
|
||||
value = Builtin.${CastToWord}(dstNotWord)
|
||||
@ else:
|
||||
% else:
|
||||
value = dstNotWord
|
||||
@ end
|
||||
% end
|
||||
}
|
||||
|
||||
@ end
|
||||
@ end
|
||||
% end
|
||||
% end
|
||||
func as${'Unsigned' if signed else 'Signed'}() -> ${OtherSelf} {
|
||||
return ${OtherSelf}(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Operations with masking and non-masking versions
|
||||
@ for op,method in ('+','add'), ('*','mul'), ('-','sub'):
|
||||
@@transparent
|
||||
func &${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
|
||||
return ${Self}.${method}(lhs, rhs, false).0
|
||||
}
|
||||
@@transparent
|
||||
// Operations with potentially-static overflow checking
|
||||
//
|
||||
// FIXME: must use condfail in these operators, rather than
|
||||
// overflowChecked, pending <rdar://problem/16271923> so that we don't
|
||||
// foil static checking for numeric overflows.
|
||||
% for op,method in ('+','add'), ('*','mul'), ('-','sub'):
|
||||
@transparent
|
||||
func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
|
||||
var tmp = ${Self}.${method}(lhs, rhs)
|
||||
Builtin.condfail(tmp.1.value)
|
||||
return tmp.0
|
||||
let (result, error) = Builtin.${sign}${method}_with_overflow_${BuiltinName}(
|
||||
lhs.value, rhs.value, true.value)
|
||||
// return overflowChecked((${Self}(result), Bool(error)))
|
||||
Builtin.condfail(error)
|
||||
return ${Self}(result)
|
||||
}
|
||||
@ end
|
||||
% end
|
||||
|
||||
% for op,inst in [('/', 'div'), ('%', 'rem')]:
|
||||
@transparent
|
||||
func ${op}(lhs: ${Self}, rhs: ${Self}) -> ${Self} {
|
||||
Builtin.condfail((rhs == 0).value)
|
||||
% if signed:
|
||||
Builtin.condfail(((lhs == ${Self}.min) & (rhs == -1)).value)
|
||||
% end
|
||||
// FIXME: currently doesn't detect overflow -- blocked by:
|
||||
// <rdar://15735295> Need [su]{div,rem}_with_overflow IR
|
||||
var tmp = Builtin.${sign}${inst}_${BuiltinName}(lhs.value, rhs.value)
|
||||
return ${Self}(tmp)
|
||||
}
|
||||
%end
|
||||
|
||||
// Bitwise negate
|
||||
@@transparent @@prefix
|
||||
@transparent @prefix
|
||||
func ~(rhs: ${Self}) -> ${Self} {
|
||||
let mask = ${Self}.sub(0, 1).0
|
||||
let mask = ${Self}.uncheckedSubtract(0, 1).0
|
||||
return ${Self}(Builtin.xor_${BuiltinName}(rhs.value, mask.value))
|
||||
}
|
||||
|
||||
@ for op, name in (
|
||||
@ ('==','eq'), ('!=','ne'),
|
||||
@ ('<',sign+'lt'), ('<=',sign+'le'),
|
||||
@ ('>',sign+'gt'), ('>=',sign+'ge')):
|
||||
@@transparent
|
||||
% for op, name in (
|
||||
% ('==','eq'), ('!=','ne'),
|
||||
% ('<',sign+'lt'), ('<=',sign+'le'),
|
||||
% ('>',sign+'gt'), ('>=',sign+'ge')):
|
||||
@transparent
|
||||
func ${op} (lhs: ${Self}, rhs: ${Self}) -> Bool {
|
||||
return Bool(Builtin.cmp_${name}_${BuiltinName}(lhs.value, rhs.value))
|
||||
}
|
||||
@ end
|
||||
% end
|
||||
|
||||
@ for op, name in (('<<','shl'), ('>>','ashr' if signed else 'lshr')):
|
||||
@@transparent
|
||||
% for op, name in (('<<','shl'), ('>>','ashr' if signed else 'lshr')):
|
||||
@transparent
|
||||
func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
|
||||
@ if signed:
|
||||
assert(U${Self}(rhs) < U${Self}(sizeof(rhs) * 8))
|
||||
@ else:
|
||||
assert(rhs < ${Self}(sizeof(rhs) * 8))
|
||||
@ end
|
||||
% if signed:
|
||||
assert(U${Self}(rhs) < U${Self}(sizeofValue(rhs) * 8))
|
||||
% else:
|
||||
assert(rhs < ${Self}(sizeofValue(rhs) * 8))
|
||||
% end
|
||||
return ${Self}(Builtin.${name}_${BuiltinName}(lhs.value, rhs.value))
|
||||
}
|
||||
@ end
|
||||
% end
|
||||
|
||||
@ for op, name in (('&','and'), ('^','xor'), ('|','or')):
|
||||
@@transparent
|
||||
% for op, name in (('&','and'), ('^','xor'), ('|','or')):
|
||||
@transparent
|
||||
func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
|
||||
return ${Self}(Builtin.${name}_${BuiltinName}(lhs.value, rhs.value))
|
||||
}
|
||||
@ end
|
||||
% end
|
||||
|
||||
// bitwise operations
|
||||
@@transparent
|
||||
@transparent
|
||||
extension ${Self} : BitwiseOperations {
|
||||
static func allZeros() -> ${Self} { return 0 }
|
||||
}
|
||||
|
||||
// Compound assignments
|
||||
@ for op in '+', '-', '*', '<<', '>>', '&', '|', '^':
|
||||
@@transparent @@assignment
|
||||
% for op in '+', '-', '*', '<<', '>>', '&', '|', '^':
|
||||
@transparent @assignment
|
||||
func ${op}=(inout lhs: ${Self}, rhs: ${Self}) {
|
||||
lhs = lhs ${op} rhs
|
||||
}
|
||||
@ end
|
||||
@ end # for bits in allInts
|
||||
% end
|
||||
% end # for bits in allInts
|
||||
|
||||
typealias Word = Int
|
||||
typealias UWord = UInt
|
||||
|
||||
// ${'Local Variables'}:
|
||||
// eval: (read-only-mode 1)
|
||||
// End:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@# -*- mode: swift -*-
|
||||
%# -*- mode: swift -*-
|
||||
|
||||
@# Ignore the following admonition; it applies to the resulting .swift file only
|
||||
%# Ignore the following admonition; it applies to the resulting .swift file only
|
||||
//// Automatically Generated From FloatingPoint.gyb. Do Not Edit Directly
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -14,7 +14,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@{
|
||||
%{
|
||||
#
|
||||
# Utility code for later in this template
|
||||
#
|
||||
@@ -49,7 +49,12 @@ def intName(name, signed):
|
||||
return ('' if signed else 'U') + baseIntName(name)
|
||||
|
||||
def floatName(bits):
|
||||
return 'Float' + str(bits)
|
||||
if bits == 32:
|
||||
return 'Float'
|
||||
if bits == 64:
|
||||
return 'Double'
|
||||
if bits == 80:
|
||||
return 'Float80'
|
||||
|
||||
def cFuncSuffix(bits):
|
||||
if bits == 32:
|
||||
@@ -116,37 +121,40 @@ def getInfinityExponent(bits):
|
||||
return '0x7ff'
|
||||
return 'error'
|
||||
|
||||
}@
|
||||
}%
|
||||
|
||||
@ for bits in allFloatBits:
|
||||
@ Self = floatName(bits)
|
||||
% for bits in allFloatBits:
|
||||
% Self = floatName(bits)
|
||||
|
||||
struct ${Self} : ReplPrintable {
|
||||
var value: Builtin.FPIEEE${bits}
|
||||
|
||||
@@transparent
|
||||
@transparent
|
||||
init() {
|
||||
var zero: Int64 = 0
|
||||
value = Builtin.uitofp_Int64_FPIEEE${bits}(zero.value)
|
||||
}
|
||||
|
||||
@@transparent
|
||||
init(v: Builtin.FPIEEE${bits}) {
|
||||
@transparent
|
||||
init(_ v: Builtin.FPIEEE${bits}) {
|
||||
value = v
|
||||
}
|
||||
|
||||
func replPrint() {
|
||||
@if bits == 64:
|
||||
%if bits == 64:
|
||||
print(self)
|
||||
@else:
|
||||
%else:
|
||||
print(Double(self))
|
||||
@end
|
||||
%end
|
||||
}
|
||||
|
||||
@transparent
|
||||
init(_ value: ${Self}) { self = value }
|
||||
}
|
||||
|
||||
@ if bits in allIntBits:
|
||||
% if bits in allIntBits:
|
||||
// Not transparent because the compiler crashes in that case.
|
||||
//@@transparent
|
||||
//@transparent
|
||||
extension ${Self} : FloatingPointNumber {
|
||||
typealias _BitsType = UInt${bits}
|
||||
|
||||
@@ -283,10 +291,10 @@ extension ${Self} /* : FloatingPointNumber */ {
|
||||
}
|
||||
}
|
||||
}
|
||||
@ end
|
||||
% end
|
||||
|
||||
@@transparent
|
||||
extension ${Self} : BuiltinIntegerLiteralConvertible, IntegerLiteralConvertible {
|
||||
@transparent
|
||||
extension ${Self} : _BuiltinIntegerLiteralConvertible, IntegerLiteralConvertible {
|
||||
static func _convertFromBuiltinIntegerLiteral(value: Builtin.Int${builtinIntLiteralBits}) -> ${Self} {
|
||||
return ${Self}(Builtin.itofp_with_overflow_Int${builtinIntLiteralBits}_FPIEEE${bits}(value))
|
||||
}
|
||||
@@ -296,65 +304,65 @@ extension ${Self} : BuiltinIntegerLiteralConvertible, IntegerLiteralConvertible
|
||||
}
|
||||
}
|
||||
|
||||
@@transparent
|
||||
extension ${Self} : BuiltinFloatLiteralConvertible {
|
||||
@transparent
|
||||
extension ${Self} : _BuiltinFloatLiteralConvertible {
|
||||
static func _convertFromBuiltinFloatLiteral(value: Builtin.FPIEEE${builtinFloatLiteralBits}) -> ${Self} {
|
||||
@ if bits == builtinFloatLiteralBits:
|
||||
% if bits == builtinFloatLiteralBits:
|
||||
return ${Self}(value)
|
||||
@ elif bits < builtinFloatLiteralBits:
|
||||
% elif bits < builtinFloatLiteralBits:
|
||||
return ${Self}(Builtin.fptrunc_FPIEEE${builtinFloatLiteralBits}_FPIEEE${bits}(value))
|
||||
@ else:
|
||||
% else:
|
||||
// FIXME: This is actually losing precision <rdar://problem/14073102>.
|
||||
return ${Self}(Builtin.fpext_FPIEEE${builtinFloatLiteralBits}_FPIEEE${bits}(value))
|
||||
@ end
|
||||
% end
|
||||
}
|
||||
}
|
||||
|
||||
@@transparent
|
||||
@transparent
|
||||
extension ${Self} : FloatLiteralConvertible {
|
||||
static func convertFromFloatLiteral(value: ${Self}) -> ${Self} {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
@@transparent
|
||||
@transparent
|
||||
func ==(lhs: ${Self}, rhs: ${Self}) -> Bool {
|
||||
return Bool(Builtin.fcmp_oeq_FPIEEE${bits}(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
@@transparent
|
||||
@transparent
|
||||
func <(lhs: ${Self}, rhs: ${Self}) -> Bool {
|
||||
return Bool(Builtin.fcmp_olt_FPIEEE${bits}(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
@@transparent
|
||||
@transparent
|
||||
extension ${Self} : Comparable {
|
||||
}
|
||||
|
||||
extension ${Self} : Hashable {
|
||||
func hashValue() -> Int {
|
||||
var hashValue: Int {
|
||||
var asBuiltinInt = Builtin.bitcast_FPIEEE${bits}_Int${bits}(value)
|
||||
@ if bits >= 64:
|
||||
% if bits >= 64:
|
||||
return Int(Builtin.truncOrBitCast_Int${bits}_Word(asBuiltinInt))
|
||||
@ elif bits <= 32:
|
||||
% elif bits <= 32:
|
||||
return Int(Builtin.sextOrBitCast_Int${bits}_Word(asBuiltinInt))
|
||||
@ else:
|
||||
% else:
|
||||
error unhandled float size ${bits}
|
||||
@ end
|
||||
% end
|
||||
}
|
||||
}
|
||||
|
||||
extension ${Self} : SignedNumber {
|
||||
@@transparent
|
||||
static func negate(rhs: ${Self}) -> (${Self}, Bool) {
|
||||
return (${Self}(Builtin.fneg_FPIEEE${bits}(rhs.value)), false)
|
||||
@transparent
|
||||
extension ${Self} : AbsoluteValuable {
|
||||
@transparent
|
||||
static func abs(x: ${Self}) -> ${Self} {
|
||||
return ${Self}(Builtin.int_fabs_FPIEEE${bits}(x.value))
|
||||
}
|
||||
@@transparent
|
||||
static func abs(rhs: ${Self}) -> (${Self}, Bool) {
|
||||
return (${Self}(Builtin.int_fabs_FPIEEE${bits}(rhs.value)), false)
|
||||
}
|
||||
@@transparent
|
||||
func isNegative() -> Bool { return self < 0 }
|
||||
}
|
||||
|
||||
@prefix @transparent
|
||||
func -(x: ${Self}) -> ${Self} {
|
||||
return ${Self}(Builtin.fneg_FPIEEE${bits}(x.value))
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -362,33 +370,33 @@ extension ${Self} : SignedNumber {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Construction from integers.
|
||||
@@transparent
|
||||
@transparent
|
||||
extension ${Self} {
|
||||
@ for (srcBits, srcSigned) in allInts():
|
||||
@ That = intName(srcBits, srcSigned)
|
||||
@ ThatBuiltinName = builtinIntName(srcBits)
|
||||
@ sign = 's' if srcSigned else 'u'
|
||||
init(v: ${That}) {
|
||||
% for (srcBits, srcSigned) in allInts():
|
||||
% That = intName(srcBits, srcSigned)
|
||||
% ThatBuiltinName = builtinIntName(srcBits)
|
||||
% sign = 's' if srcSigned else 'u'
|
||||
init(_ v: ${That}) {
|
||||
value = Builtin.${sign}itofp_${ThatBuiltinName}_FPIEEE${bits}(v.value)
|
||||
}
|
||||
@ end
|
||||
% end
|
||||
}
|
||||
|
||||
// Construction from other floating point numbers.
|
||||
@@transparent
|
||||
@transparent
|
||||
extension ${Self} {
|
||||
@ for srcBits in allFloatBits:
|
||||
@ That = floatName(srcBits)
|
||||
@ if Self != That:
|
||||
init(v: ${That}) {
|
||||
@ if srcBits > bits:
|
||||
% for srcBits in allFloatBits:
|
||||
% That = floatName(srcBits)
|
||||
% if Self != That:
|
||||
init(_ v: ${That}) {
|
||||
% if srcBits > bits:
|
||||
value = Builtin.fptrunc_FPIEEE${srcBits}_FPIEEE${bits}(v.value)
|
||||
@ else:
|
||||
% else:
|
||||
value = Builtin.fpext_FPIEEE${srcBits}_FPIEEE${bits}(v.value)
|
||||
@ end
|
||||
% end
|
||||
}
|
||||
@ end
|
||||
@ end
|
||||
% end
|
||||
% end
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -396,31 +404,57 @@ extension ${Self} {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Unary plus
|
||||
@@transparent @@prefix
|
||||
@transparent @prefix
|
||||
func + (rhs: ${Self}) -> ${Self} { return rhs }
|
||||
|
||||
@@transparent @@prefix @@assignment
|
||||
@transparent @prefix @assignment
|
||||
func ++ (inout rhs: ${Self}) -> ${Self} { rhs += 1.0; return rhs }
|
||||
@@transparent @@prefix @@assignment
|
||||
@transparent @prefix @assignment
|
||||
func -- (inout rhs: ${Self}) -> ${Self} { rhs -= 1.0; return rhs }
|
||||
@@transparent @@postfix @@assignment
|
||||
@transparent @postfix @assignment
|
||||
func ++ (inout lhs: ${Self}) -> ${Self} { let tmp = lhs; lhs += 1.0; return tmp }
|
||||
@@transparent @@postfix @@assignment
|
||||
@transparent @postfix @assignment
|
||||
func -- (inout lhs: ${Self}) -> ${Self} { let tmp = lhs; lhs -= 1.0; return tmp }
|
||||
|
||||
@ for op, name in ('+','fadd'), ('-','fsub'),('*','fmul'), ('/','fdiv'):
|
||||
@@transparent
|
||||
|
||||
|
||||
@transparent
|
||||
extension ${Self} : RandomAccessIndex {
|
||||
@transparent
|
||||
func succ() -> ${Self} {
|
||||
return self + 1.0
|
||||
}
|
||||
@transparent
|
||||
func pred() -> ${Self} {
|
||||
return self - 1.0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func distanceTo(other: ${Self}) -> ${Self}.DistanceType {
|
||||
return Int(other-self)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func advancedBy(amount: ${Self}.DistanceType) -> ${Self} {
|
||||
return self + ${Self}(amount)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
% for op, name in ('+','fadd'), ('-','fsub'),('*','fmul'), ('/','fdiv'):
|
||||
@transparent
|
||||
func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
|
||||
return ${Self}(Builtin.${name}_FPIEEE${bits}(lhs.value, rhs.value))
|
||||
}
|
||||
@ end
|
||||
% end
|
||||
|
||||
// Binary Remainder.
|
||||
// The sign of the result matches the sign of the dividend.
|
||||
// 1) This is consistent with '%' in C#, D, Java, and JavaScript
|
||||
// 2) C99 requires this behavior for fmod*()
|
||||
// 3) C++11 requires this behavior for std::fmod*()
|
||||
@@asmname="fmod${cFuncSuffix(bits)}"
|
||||
@asmname("fmod${cFuncSuffix(bits)}")
|
||||
func % (lhs: ${Self}, rhs: ${Self}) -> ${Self}
|
||||
|
||||
// See Bool.swift for && and ||
|
||||
@@ -430,26 +464,32 @@ func % (lhs: ${Self}, rhs: ${Self}) -> ${Self}
|
||||
// In C, 100 is ?:
|
||||
// In C, 90 is =, *=, += etc.
|
||||
|
||||
@ for op in '+', '-', '*', '/', '%':
|
||||
@@transparent @@assignment
|
||||
% for op in '+', '-', '*', '/', '%':
|
||||
@transparent @assignment
|
||||
func ${op}= (inout lhs: ${Self}, rhs: ${Self}) { lhs = lhs ${op} rhs }
|
||||
@ end
|
||||
% end
|
||||
|
||||
@ end # for bits in allFloatBits
|
||||
% end # for bits in allFloatBits
|
||||
|
||||
// Construction of integers from floating point numbers.
|
||||
@ for (bits, signed) in allInts():
|
||||
@ sign = 's' if signed else 'u'
|
||||
@ Self = intName(bits, signed)
|
||||
@ BuiltinName = builtinIntName(bits)
|
||||
@@transparent
|
||||
% for (bits, signed) in allInts():
|
||||
% sign = 's' if signed else 'u'
|
||||
% Self = intName(bits, signed)
|
||||
% BuiltinName = builtinIntName(bits)
|
||||
@transparent
|
||||
extension ${Self} {
|
||||
@ for srcBits in allFloatBits:
|
||||
@ That = floatName(srcBits)
|
||||
init(v: ${That}) {
|
||||
% for srcBits in allFloatBits:
|
||||
% That = floatName(srcBits)
|
||||
init(_ v: ${That}) {
|
||||
assert(v >= ${That}(${Self}.min))
|
||||
assert(v <= ${That}(${Self}.max))
|
||||
value = Builtin.fpto${sign}i_FPIEEE${srcBits}_${BuiltinName}(v.value)
|
||||
}
|
||||
@ end
|
||||
% end
|
||||
}
|
||||
|
||||
@ end
|
||||
% end
|
||||
|
||||
// ${'Local Variables'}:
|
||||
// eval: (read-only-mode 1)
|
||||
// End:
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
enum IEEEFloatingPointClass {
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
enum FloatingPointClassification {
|
||||
case SignalingNaN
|
||||
case QuietNaN
|
||||
case NegativeInfinity
|
||||
@@ -12,19 +24,19 @@ enum IEEEFloatingPointClass {
|
||||
}
|
||||
|
||||
|
||||
extension IEEEFloatingPointClass : Equatable {}
|
||||
func ==(lhs: IEEEFloatingPointClass, rhs: IEEEFloatingPointClass) -> Bool {
|
||||
extension FloatingPointClassification : Equatable {}
|
||||
func ==(lhs: FloatingPointClassification, rhs: FloatingPointClassification) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case (.SignalingNaN, .SignalingNaN):
|
||||
case (.QuietNaN, .QuietNaN):
|
||||
case (.NegativeInfinity, .NegativeInfinity):
|
||||
case (.NegativeNormal, .NegativeNormal):
|
||||
case (.NegativeSubnormal, .NegativeSubnormal):
|
||||
case (.NegativeZero, .NegativeZero):
|
||||
case (.PositiveZero, .PositiveZero):
|
||||
case (.PositiveSubnormal, .PositiveSubnormal):
|
||||
case (.PositiveNormal, .PositiveNormal):
|
||||
case (.PositiveInfinity, .PositiveInfinity):
|
||||
case (.SignalingNaN, .SignalingNaN),
|
||||
(.QuietNaN, .QuietNaN),
|
||||
(.NegativeInfinity, .NegativeInfinity),
|
||||
(.NegativeNormal, .NegativeNormal),
|
||||
(.NegativeSubnormal, .NegativeSubnormal),
|
||||
(.NegativeZero, .NegativeZero),
|
||||
(.PositiveZero, .PositiveZero),
|
||||
(.PositiveSubnormal, .PositiveSubnormal),
|
||||
(.PositiveNormal, .PositiveNormal),
|
||||
(.PositiveInfinity, .PositiveInfinity):
|
||||
return true
|
||||
|
||||
default:
|
||||
@@ -33,29 +45,27 @@ func ==(lhs: IEEEFloatingPointClass, rhs: IEEEFloatingPointClass) -> Bool {
|
||||
}
|
||||
|
||||
|
||||
protocol IEEEFloatingPointNumber {
|
||||
protocol FloatingPointNumber {
|
||||
typealias _BitsType
|
||||
static func _fromBitPattern(bits: _BitsType) -> Self
|
||||
class func _fromBitPattern(bits: _BitsType) -> Self
|
||||
func _toBitPattern() -> _BitsType
|
||||
|
||||
// FIXME: make these readonly static properties.
|
||||
|
||||
/// Returns positive infinity.
|
||||
static func inf() -> Self
|
||||
class func inf() -> Self
|
||||
|
||||
/// Returns a quiet NaN.
|
||||
static func NaN() -> Self
|
||||
class func NaN() -> Self
|
||||
|
||||
static func quietNaN() -> Self
|
||||
static func signalingNaN() -> Self
|
||||
class func quietNaN() -> Self
|
||||
|
||||
/// @{
|
||||
/// IEEE 754-2008 Non-computational operations.
|
||||
|
||||
// IEEE 754 calls this 'class', but this name is a keyword, and is too
|
||||
// general.
|
||||
// FIXME: make readonly.
|
||||
var floatingPointClass: IEEEFloatingPointClass
|
||||
var floatingPointClass: FloatingPointClassification { get }
|
||||
|
||||
/// Returns true if this number has a negative sign.
|
||||
func isSignMinus() -> Bool
|
||||
|
||||
@@ -1,13 +1,27 @@
|
||||
// This is just here to provide a type off of which to hang swift_bufferAllocate.
|
||||
class RawBuffer {}
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
func [asmname="swift_isUniquelyReferenced"]
|
||||
swift_isUniquelyReferenced(objPtr: Builtin.ObjectPointer) -> CBool
|
||||
import SwiftShims
|
||||
typealias _HeapObject = SwiftShims.HeapObject
|
||||
|
||||
func [asmname="swift_bufferAllocate"]
|
||||
swift_bufferAllocate(bufferType: RawBuffer.metatype, size: Int) -> RawBuffer
|
||||
// Provides a common type off of which to hang swift_bufferAllocate.
|
||||
@objc class HeapBufferStorageBase {}
|
||||
|
||||
func [asmname="swift_bufferHeaderSize"] swift_bufferHeaderSize() -> Int
|
||||
@asmname("swift_bufferAllocate")
|
||||
func swift_bufferAllocate(
|
||||
bufferType: HeapBufferStorageBase.Type, size: Int) -> AnyObject
|
||||
|
||||
@asmname("malloc_size")
|
||||
func c_malloc_size(heapMemory: UnsafePointer<Void>) -> Int
|
||||
|
||||
/// \brief a class containing an ivar "value" of type Value, and
|
||||
/// containing storage for an array of Element whose size is
|
||||
@@ -18,7 +32,8 @@ func [asmname="swift_bufferHeaderSize"] swift_bufferHeaderSize() -> Int
|
||||
/// template <class Value, class Element>
|
||||
/// struct HeapBuffer {
|
||||
/// Value value;
|
||||
/// Element[]; // length determined at creation time
|
||||
/// Element elementStorage[]; // length determined at creation time
|
||||
///
|
||||
/// HeapBuffer() = delete
|
||||
/// static shared_ptr<HeapBuffer> create(Value init, int capacity);
|
||||
/// }
|
||||
@@ -27,66 +42,162 @@ func [asmname="swift_bufferHeaderSize"] swift_bufferHeaderSize() -> Int
|
||||
/// construct and---if necessary---destroy Elements there yourself,
|
||||
/// either in a derived class, or it can be in some manager object
|
||||
/// that owns the HeapBuffer.
|
||||
///
|
||||
/// If you need to construct and destroy Elements, using a derived
|
||||
/// class is a natural choice. However, don't add any ivars because we
|
||||
/// have no way in the runtime to get the base allocation size of an
|
||||
/// arbitrary class. As a result, we will fail to allocate memory for
|
||||
/// them, and their storage will collide with that of the stored
|
||||
/// Value.
|
||||
class HeapBuffer<Value,Element> : RawBuffer {
|
||||
|
||||
typealias Self = HeapBuffer<Value,Element>
|
||||
|
||||
static func roundUpToAlignment(offset: Int, alignment: Int) -> Int {
|
||||
return (offset + alignment - 1) / alignment * alignment
|
||||
@objc class HeapBufferStorage<Value,Element> : HeapBufferStorageBase {
|
||||
typealias Buffer = HeapBuffer<Value, Element>
|
||||
deinit {
|
||||
Buffer(self)._value.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
@asmname("_swift_isUniquelyReferenced")
|
||||
func _swift_isUniquelyReferenced(_: UnsafePointer<HeapObject>) -> Bool
|
||||
|
||||
// Return true if x is the only (strong) reference to the given RawBuffer
|
||||
//
|
||||
// This is an inout function for two reasons:
|
||||
//
|
||||
// 1. You should only call it when about to mutate the object.
|
||||
// Doing so otherwise implies a race condition if the buffer is
|
||||
// shared across threads.
|
||||
//
|
||||
// 2. When it is not an inout function, self is passed by
|
||||
// value... thus bumping the reference count and disturbing the
|
||||
// result we are trying to observe, Dr. Heisenberg!
|
||||
//
|
||||
// NOTE: this is not as safe as it could be; class types that come
|
||||
// from Cocoa don't have a reference count stored inline where we're
|
||||
// checking for it. However, we have no way to restrict T to being a
|
||||
// native Swift class, and in fact we have no reasonable way of
|
||||
// getting a class pointer out of some other types, such as an enum
|
||||
// whose first case is a native Swift object and is statically known
|
||||
// to be in that case, without affecting its reference count. Instead
|
||||
// we accept everything; reinterpretCast will at least catch
|
||||
// inappropriately-sized things at runtime.
|
||||
func isUniquelyReferenced<T>(inout x: T) -> Bool {
|
||||
return _swift_isUniquelyReferenced(reinterpretCast(x))
|
||||
}
|
||||
|
||||
struct HeapBuffer<Value, Element> : LogicValue, Equatable {
|
||||
typealias Storage = HeapBufferStorage<Value, Element>
|
||||
let storage: Storage?
|
||||
|
||||
static func _valueOffset() -> Int {
|
||||
return roundUpToAlignment(
|
||||
swift_bufferHeaderSize(), Int(Builtin.alignof(Value)))
|
||||
return roundUpToAlignment(sizeof(_HeapObject.self), alignof(Value.self))
|
||||
}
|
||||
|
||||
static func _elementOffset() -> Int {
|
||||
return roundUpToAlignment(
|
||||
_valueOffset() + Int(Builtin.sizeof(Value)), Int(Builtin.alignof(Element)))
|
||||
return roundUpToAlignment(_valueOffset() + sizeof(Value.self),
|
||||
alignof(Element.self))
|
||||
}
|
||||
|
||||
var _address: UnsafePointer<Int8> {
|
||||
return UnsafePointer<Int8>(
|
||||
Builtin.bridgeToRawPointer(Builtin.castToObjectPointer(this)))
|
||||
return UnsafePointer(
|
||||
Builtin.bridgeToRawPointer(self as Builtin.NativeObject))
|
||||
}
|
||||
|
||||
var _value: UnsafePointer<Value> {
|
||||
return UnsafePointer<Value>(
|
||||
Self._valueOffset() + _address)
|
||||
return UnsafePointer(
|
||||
HeapBuffer._valueOffset() + _address)
|
||||
}
|
||||
|
||||
var elementStorage: UnsafePointer<Element> {
|
||||
return UnsafePointer<Element>(Self._elementOffset() + _address)
|
||||
return UnsafePointer(HeapBuffer._elementOffset() + _address)
|
||||
}
|
||||
|
||||
static func create(initializer: Value, capacity: Int) -> Self {
|
||||
/// \brief Return the actual number of Elements we can possibly
|
||||
/// store.
|
||||
func _capacity() -> Int {
|
||||
let allocatedSize = c_malloc_size(UnsafePointer(_address))
|
||||
return (allocatedSize - HeapBuffer._elementOffset())
|
||||
/ Int(Builtin.strideof(Element.self))
|
||||
}
|
||||
|
||||
init() {
|
||||
self.storage = .None
|
||||
}
|
||||
|
||||
init(_ storage: Storage) {
|
||||
self.storage = storage
|
||||
}
|
||||
|
||||
/// \brief Create a HeapBuffer with self.value = initializer and
|
||||
/// self._capacity() >= capacity.
|
||||
init(
|
||||
_ storageClass: HeapBufferStorageBase.Type,
|
||||
_ initializer: Value, _ capacity: Int
|
||||
) {
|
||||
assert(capacity >= 0)
|
||||
|
||||
var totalSize = Self._elementOffset() + (
|
||||
capacity == 0 ? 0
|
||||
: (capacity - 1) * Int(Builtin.strideof(Element))
|
||||
+ Int(Builtin.sizeof(Element)))
|
||||
let totalSize = HeapBuffer._elementOffset() +
|
||||
capacity * Int(Builtin.strideof(Element.self))
|
||||
|
||||
var self = swift_bufferAllocate(Self, totalSize) as! Self
|
||||
self._value.init(initializer)
|
||||
return self
|
||||
}
|
||||
|
||||
destructor {
|
||||
this._value.destroy()
|
||||
self.storage = reinterpretCast(
|
||||
swift_bufferAllocate(storageClass, totalSize))
|
||||
self._value.initialize(initializer)
|
||||
}
|
||||
|
||||
var value : Value {
|
||||
get:
|
||||
get {
|
||||
return _value.get()
|
||||
set(newValue):
|
||||
}
|
||||
nonmutating set(newValue) {
|
||||
_value.set(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
func getLogicValue() -> Bool {
|
||||
return storage.getLogicValue()
|
||||
}
|
||||
|
||||
subscript(i: Int) -> Element {
|
||||
get {
|
||||
return elementStorage[i]
|
||||
}
|
||||
nonmutating set(newValue) {
|
||||
elementStorage[i] = newValue
|
||||
}
|
||||
}
|
||||
|
||||
@conversion
|
||||
func __conversion() -> Builtin.NativeObject {
|
||||
return reinterpretCast(storage)
|
||||
}
|
||||
|
||||
static func fromNativeObject(x: Builtin.NativeObject) -> HeapBuffer {
|
||||
return HeapBuffer(Builtin.castFromNativeObject(x) as Storage)
|
||||
}
|
||||
|
||||
mutating func isUniquelyReferenced() -> Bool {
|
||||
if !storage {
|
||||
return false
|
||||
}
|
||||
var workaroundForRadar16119895 = reinterpretCast(storage) as COpaquePointer
|
||||
return Swift.isUniquelyReferenced(&workaroundForRadar16119895)
|
||||
}
|
||||
}
|
||||
|
||||
// HeapBuffers are equal when they reference the same buffer
|
||||
func == <Value, Element> (
|
||||
lhs: HeapBuffer<Value, Element>,
|
||||
rhs: HeapBuffer<Value, Element>) -> Bool {
|
||||
return (lhs as Builtin.NativeObject) == (rhs as Builtin.NativeObject)
|
||||
}
|
||||
|
||||
// OnHeap<T>
|
||||
//
|
||||
// A way to store a value on the heap. These values are likely to be
|
||||
// implicitly shared, so it's safest if they're immutable.
|
||||
//
|
||||
struct OnHeap<T> {
|
||||
typealias Buffer = HeapBuffer<T, Void>
|
||||
|
||||
init(_ value: T) {
|
||||
_storage = HeapBuffer(Buffer.Storage.self, value, 0)
|
||||
}
|
||||
|
||||
@conversion func __conversion() -> T {
|
||||
return _storage._value.get()
|
||||
}
|
||||
|
||||
var _storage: Buffer
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ struct ImplicitlyUnwrappedOptional<T>: LogicValue, Reflectable {
|
||||
var value: T? = .None
|
||||
|
||||
init() { value = .None }
|
||||
init(v : T?) { value = v }
|
||||
init(_ v : T?) { value = v }
|
||||
|
||||
static var None : ImplicitlyUnwrappedOptional {
|
||||
@transparent get {
|
||||
|
||||
@@ -14,120 +14,252 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
protocol ForwardIndex : Equatable {
|
||||
//===----------------------------------------------------------------------===//
|
||||
//===--- Dispatching advance and distance functions -----------------------===//
|
||||
// These generic functions are for user consumption; they dispatch to the
|
||||
// appropriate implementation for T.
|
||||
|
||||
/// Measure the distance between start and end.
|
||||
///
|
||||
/// If T models RandomAccessIndex, requires that start and end are
|
||||
/// part of the same sequence and executes in O(1).
|
||||
///
|
||||
/// Otherwise, requires that end is reachable from start by
|
||||
/// incrementation, and executes in O(N), where N is the function's
|
||||
/// result.
|
||||
func distance<T: ForwardIndex>(start: T, end: T) -> T.DistanceType {
|
||||
return start~>_distanceTo(end)
|
||||
}
|
||||
|
||||
/// Return the result of moving start by n positions. If T models
|
||||
/// RandomAccessIndex, executes in O(1). Otherwise, executes in
|
||||
/// O(abs(n)). If T does not model BidirectionalIndex, requires that n
|
||||
/// is non-negative.
|
||||
func advance<T: ForwardIndex>(start: T, n: T.DistanceType) -> T {
|
||||
return start~>_advance(n)
|
||||
}
|
||||
|
||||
/// Return the result of moving start by n positions, or until it
|
||||
/// equals end. If T models RandomAccessIndex, executes in O(1).
|
||||
/// Otherwise, executes in O(abs(n)). If T does not model
|
||||
/// BidirectionalIndex, requires that n is non-negative.
|
||||
func advance<T: ForwardIndex>(start: T, n: T.DistanceType, end: T) -> T {
|
||||
return start~>_advance(n, end)
|
||||
}
|
||||
|
||||
/// Operation tags for distance and advance
|
||||
///
|
||||
/// Operation tags allow us to use a single operator (~>) for
|
||||
/// dispatching every generic function with a default implementation.
|
||||
/// Only authors of specialized distance implementations need to touch
|
||||
/// this tag.
|
||||
struct _Distance {}
|
||||
func _distanceTo<I>(end: I) -> (_Distance, (I)) {
|
||||
return (_Distance(), (end))
|
||||
}
|
||||
|
||||
struct _Advance {}
|
||||
func _advance<D>(n: D) -> (_Advance, (D)) {
|
||||
return (_Advance(), (n: n))
|
||||
}
|
||||
func _advance<D, I>(n: D, end: I) -> (_Advance, (D, I)) {
|
||||
return (_Advance(), (n, end))
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//===--- ForwardIndex -----------------------------------------------------===//
|
||||
|
||||
// Protocols with default implementations are broken into two parts, a
|
||||
// base and a more-refined part. From the user's point-of-view,
|
||||
// however, _ForwardIndex and ForwardIndex should look like a single
|
||||
// protocol. This technique gets used throughout the standard library
|
||||
// to break otherwise-cyclic protocol dependencies, which the compiler
|
||||
// isn't yet smart enough to handle.
|
||||
|
||||
protocol _Incrementable : Equatable {
|
||||
func succ() -> Self
|
||||
}
|
||||
|
||||
protocol _ForwardIndex : _Incrementable {
|
||||
typealias DistanceType : _SignedInteger = Int
|
||||
}
|
||||
|
||||
@prefix @assignment @transparent
|
||||
func ++ <T : ForwardIndex> (inout x: T) -> T {
|
||||
func ++ <T : _Incrementable> (inout x: T) -> T {
|
||||
x = x.succ()
|
||||
return x
|
||||
}
|
||||
|
||||
@postfix @assignment @transparent
|
||||
func ++ <T : ForwardIndex> (inout x: T) -> T {
|
||||
func ++ <T : _Incrementable> (inout x: T) -> T {
|
||||
var ret = x
|
||||
x = x.succ()
|
||||
return ret
|
||||
}
|
||||
|
||||
protocol BidirectionalIndex : ForwardIndex {
|
||||
protocol ForwardIndex : _ForwardIndex {
|
||||
// This requirement allows generic distance() to find default
|
||||
// implementations. Only the author of F and the author of a
|
||||
// refinement of F having a non-default distance implementation need
|
||||
// to know about it. These refinements are expected to be rare
|
||||
// (which is why defaulted requirements are a win)
|
||||
|
||||
// Do not use these operators directly; call distance(start, end)
|
||||
// and advance(start, n) instead
|
||||
func ~> (start:Self, _ : (_Distance, Self)) -> DistanceType
|
||||
func ~> (start:Self, _ : (_Advance, DistanceType)) -> Self
|
||||
func ~> (start:Self, _ : (_Advance, (DistanceType, Self))) -> Self
|
||||
}
|
||||
|
||||
// advance and distance implementations
|
||||
|
||||
/// Do not use this operator directly; call distance(start, end) instead
|
||||
func ~> <T: _ForwardIndex>(start:T, rest: (_Distance, T)) -> T.DistanceType {
|
||||
var p = start
|
||||
var count: T.DistanceType = 0
|
||||
let end = rest.1
|
||||
while p != end {
|
||||
++count
|
||||
++p
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
/// Do not use this operator directly; call advance(start, n) instead
|
||||
@transparent
|
||||
func ~> <T: _ForwardIndex>(
|
||||
start: T, rest: (_Advance, T.DistanceType)
|
||||
) -> T {
|
||||
let n = rest.1
|
||||
return _advanceForward(start, n)
|
||||
}
|
||||
|
||||
func _advanceForward<T: _ForwardIndex>(start: T, n: T.DistanceType) -> T {
|
||||
assert(n >= 0, "Only BidirectionalIndex can be advanced by a negative amount")
|
||||
var p = start
|
||||
for var i: T.DistanceType = 0; i != n; ++i {
|
||||
++p
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
/// Do not use this operator directly; call advance(start, n, end) instead
|
||||
@transparent
|
||||
func ~> <T: _ForwardIndex>(
|
||||
start:T, rest: ( _Advance, (T.DistanceType, T))
|
||||
) -> T {
|
||||
return _advanceForward(start, rest.1.0, rest.1.1)
|
||||
}
|
||||
|
||||
func _advanceForward<T: _ForwardIndex>(
|
||||
start: T, n: T.DistanceType, end: T
|
||||
) -> T {
|
||||
assert(n >= 0, "Only BidirectionalIndex can be advanced by a negative amount")
|
||||
var p = start
|
||||
for var i: T.DistanceType = 0; i != n && p != end; ++i {
|
||||
++p
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//===--- BidirectionalIndex -----------------------------------------------===//
|
||||
protocol _BidirectionalIndex : _ForwardIndex {
|
||||
func pred() -> Self
|
||||
}
|
||||
|
||||
protocol BidirectionalIndex : ForwardIndex, _BidirectionalIndex {
|
||||
}
|
||||
|
||||
@prefix @assignment @transparent
|
||||
func -- <T: BidirectionalIndex> (inout x: T) -> T {
|
||||
func -- <T: _BidirectionalIndex> (inout x: T) -> T {
|
||||
x = x.pred()
|
||||
return x
|
||||
}
|
||||
|
||||
|
||||
@postfix @assignment @transparent
|
||||
func -- <T: BidirectionalIndex> (inout x: T) -> T {
|
||||
func -- <T: _BidirectionalIndex> (inout x: T) -> T {
|
||||
var ret = x
|
||||
x = x.pred()
|
||||
return ret
|
||||
}
|
||||
|
||||
protocol RandomAccessIndex : BidirectionalIndex, NumericOperations {
|
||||
typealias DistanceType
|
||||
class func sub(lhs: Self, rhs: Self) -> (DistanceType, Bool)
|
||||
class func sub(lhs: Self, rhs: DistanceType) -> (Self, Bool)
|
||||
class func add(lhs: Self, rhs: DistanceType) -> (Self, Bool)
|
||||
|
||||
func < (lhs: Self, rhs: Self) -> Bool
|
||||
func <= (lhs: Self, rhs: Self) -> Bool
|
||||
func > (lhs: Self, rhs: Self) -> Bool
|
||||
func >= (lhs: Self, rhs: Self) -> Bool
|
||||
}
|
||||
// advance implementation
|
||||
|
||||
/// Do not use this operator directly; call advance(start, n) instead
|
||||
@transparent
|
||||
func - <T : RandomAccessIndex>(x: T, y: T) -> T.DistanceType {
|
||||
return overflowChecked(T.sub(x, y))
|
||||
func ~> <T: _BidirectionalIndex>(
|
||||
start:T , rest: (_Advance, T.DistanceType)
|
||||
) -> T {
|
||||
let n = rest.1
|
||||
if n >= 0 {
|
||||
return _advanceForward(start, n)
|
||||
}
|
||||
var p = start
|
||||
for var i: T.DistanceType = n; i != 0; ++i {
|
||||
--p
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
/// Do not use this operator directly; call advance(start, n, end) instead
|
||||
@transparent
|
||||
func &- <T : RandomAccessIndex>(x: T, y: T) -> T.DistanceType {
|
||||
return T.sub(x, y).0
|
||||
func ~> <T: _BidirectionalIndex>(
|
||||
start:T, rest: (_Advance, (T.DistanceType, T))
|
||||
) -> T {
|
||||
let n = rest.1.0
|
||||
let end = rest.1.1
|
||||
|
||||
if n >= 0 {
|
||||
return _advanceForward(start, n, end)
|
||||
}
|
||||
var p = start
|
||||
for var i: T.DistanceType = n; i != 0 && p != end; ++i {
|
||||
--p
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//===--- RandomAccessIndex ------------------------------------------------===//
|
||||
protocol _RandomAccessIndex : _BidirectionalIndex {
|
||||
func distanceTo(Self) -> DistanceType
|
||||
func advancedBy(DistanceType) -> Self
|
||||
}
|
||||
|
||||
protocol RandomAccessIndex : BidirectionalIndex, _RandomAccessIndex {
|
||||
/* typealias DistanceType : IntegerArithmetic*/
|
||||
}
|
||||
|
||||
// advance and distance implementations
|
||||
|
||||
/// Do not use this operator directly; call distance(start, end) instead
|
||||
@transparent
|
||||
func - <T : RandomAccessIndex>(x: T, y: T.DistanceType) -> T {
|
||||
return overflowChecked(T.sub(x, y))
|
||||
func ~> <T: _RandomAccessIndex>(start:T, rest:(_Distance, (T)))
|
||||
-> T.DistanceType {
|
||||
let end = rest.1
|
||||
return start.distanceTo(end)
|
||||
}
|
||||
|
||||
/// Do not use this operator directly; call advance(start, n) instead
|
||||
@transparent
|
||||
func &- <T : RandomAccessIndex>(x: T, y: T.DistanceType) -> T {
|
||||
return T.sub(x, y).0
|
||||
}
|
||||
|
||||
@infix @assignment @transparent
|
||||
func += <T : RandomAccessIndex> (inout lhs: T, rhs: T.DistanceType) {
|
||||
lhs = overflowChecked(T.add(lhs, rhs))
|
||||
}
|
||||
|
||||
@infix @assignment @transparent
|
||||
func -= <
|
||||
T: RandomAccessIndex where T.DistanceType: SignedNumber
|
||||
> (inout lhs: T, rhs: T.DistanceType) {
|
||||
lhs = overflowChecked(T.add(lhs, -rhs))
|
||||
func ~> <T: _RandomAccessIndex>(
|
||||
start:T, rest:(_Advance, (T.DistanceType))
|
||||
) -> T {
|
||||
let n = rest.1
|
||||
return start.advancedBy(n)
|
||||
}
|
||||
|
||||
/// Do not use this operator directly; call advance(start, n, end) instead
|
||||
@transparent
|
||||
func + <T : RandomAccessIndex> (lhs: T, rhs: T.DistanceType) -> T {
|
||||
return overflowChecked(T.add(lhs, rhs))
|
||||
func ~> <T: _RandomAccessIndex>(
|
||||
start:T, rest:(_Advance, (T.DistanceType, T))
|
||||
) -> T {
|
||||
let n = rest.1.0
|
||||
let end = rest.1.1
|
||||
|
||||
let d = start.distanceTo(end)
|
||||
return (n > 0 ? d < n : d > n) ? end : start.advancedBy(n)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func + <T : RandomAccessIndex> (lhs: T.DistanceType, rhs: T) -> T {
|
||||
return overflowChecked(T.add(rhs, lhs))
|
||||
}
|
||||
|
||||
@transparent
|
||||
func &+ <T : RandomAccessIndex> (lhs: T, rhs: T) -> T {
|
||||
return T.add(lhs, rhs).0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func &+ <T : RandomAccessIndex> (lhs: T, rhs: T.DistanceType) -> T {
|
||||
return T.add(lhs, rhs).0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func &+ <T : RandomAccessIndex> (lhs: T.DistanceType, rhs: T) -> T {
|
||||
return T.add(rhs, lhs).0
|
||||
}
|
||||
|
||||
@transparent
|
||||
func - <T : RandomAccessIndex where T.DistanceType : SignedNumber> (
|
||||
lhs: T, rhs: T.DistanceType)
|
||||
-> T {
|
||||
return overflowChecked(T.add(lhs, -rhs))
|
||||
}
|
||||
|
||||
@transparent
|
||||
func &- <T : RandomAccessIndex where T.DistanceType : SignedNumber> (
|
||||
lhs: T, rhs: T.DistanceType)
|
||||
-> T {
|
||||
return T.add(lhs, -rhs).0
|
||||
}
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
% (x[:-1], x[-1]) for x in
|
||||
% 'Add+ Subtract- Multiply* Divide/ Modulus%'.split()]
|
||||
|
||||
protocol _NumericOperations {
|
||||
protocol _IntegerArithmetic {
|
||||
% for name,_ in integerBinaryOps:
|
||||
class func unchecked${name}(lhs: Self, rhs: Self) -> (Self, Bool)
|
||||
class func unchecked${name}(lhs: Self, _ rhs: Self) -> (Self, Bool)
|
||||
% end
|
||||
}
|
||||
|
||||
protocol NumericOperations : _NumericOperations, Comparable {
|
||||
protocol IntegerArithmetic : _IntegerArithmetic, Comparable {
|
||||
// Checked arithmetic functions. Specific implementations in
|
||||
// FixedPoint.swift.gyb support static checking for integer types.
|
||||
% for _,op in integerBinaryOps:
|
||||
@@ -38,42 +38,84 @@ protocol NumericOperations : _NumericOperations, Comparable {
|
||||
|
||||
% for name,op in integerBinaryOps:
|
||||
@transparent
|
||||
func ${op} <T: _NumericOperations>(lhs: T, rhs: T) -> T {
|
||||
func ${op} <T: _IntegerArithmetic>(lhs: T, rhs: T) -> T {
|
||||
return overflowChecked(T.unchecked${name}(lhs, rhs))
|
||||
}
|
||||
|
||||
@transparent
|
||||
func &${op} <T: _NumericOperations>(lhs: T, rhs: T) -> T {
|
||||
func &${op} <T: _IntegerArithmetic>(lhs: T, rhs: T) -> T {
|
||||
return T.unchecked${name}(lhs, rhs).0
|
||||
}
|
||||
|
||||
@assignment @transparent
|
||||
func ${op}= <T: _NumericOperations>(inout lhs: T, rhs: T) {
|
||||
func ${op}= <T: _IntegerArithmetic>(inout lhs: T, rhs: T) {
|
||||
lhs = lhs ${op} rhs
|
||||
}
|
||||
% end
|
||||
|
||||
protocol SignedNumber {
|
||||
class func uncheckedNegate(_: Self) -> (Self, Bool)
|
||||
class func uncheckedAbs(_: Self) -> (Self, Bool)
|
||||
func isNegative() -> Bool
|
||||
//===--- SignedNumber -----------------------------------------------------===//
|
||||
// A numeric type that supports abs(x), +x and -x
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Base protocol containing all the non-defaulted implentations. This
|
||||
// protocol should be presented to users as part of SignedNumber.
|
||||
protocol _SignedNumber : Comparable, IntegerLiteralConvertible {
|
||||
// Subtraction is a requirement for SignedNumber
|
||||
@infix func - (lhs: Self, rhs: Self) -> Self
|
||||
}
|
||||
|
||||
@transparent
|
||||
func abs <T: SignedNumber>(x: T) -> T {
|
||||
return overflowChecked(T.uncheckedAbs(x))
|
||||
// SignedNumber itself contains only operator requirements having
|
||||
// default implementations on the base protocol.
|
||||
protocol SignedNumber : _SignedNumber {
|
||||
@prefix func - (x: Self) -> Self
|
||||
|
||||
// Do not use this operator directly; call abs(x) instead
|
||||
func ~> (_:Self,_:(_Abs, ())) -> Self
|
||||
}
|
||||
|
||||
// Unary negation in terms of subtraction. This is a default
|
||||
// implementation; models of SignedNumber can provide their own
|
||||
// implementations.
|
||||
@prefix @transparent
|
||||
func - <T: SignedNumber>(x: T) -> T {
|
||||
return overflowChecked(T.uncheckedNegate(x))
|
||||
func - <T : _SignedNumber>(x: T) -> T {
|
||||
return 0 - x
|
||||
}
|
||||
|
||||
// Unary +
|
||||
@prefix @transparent
|
||||
func + <T: SignedNumber>(x: T) -> T {
|
||||
func + <T: _SignedNumber>(x: T) -> T {
|
||||
return x
|
||||
}
|
||||
|
||||
//===--- abs(x) -----------------------------------------------------------===//
|
||||
struct _Abs {}
|
||||
func _abs<Args>(args: Args) -> (_Abs, Args) {
|
||||
return (_Abs(), args)
|
||||
}
|
||||
|
||||
// Do not use this operator directly; call abs(x) instead
|
||||
@transparent
|
||||
func ~> <T : _SignedNumber>(x:T,_:(_Abs, ())) -> T {
|
||||
return x < 0 ? -x : x
|
||||
}
|
||||
|
||||
protocol AbsoluteValuable : SignedNumber {
|
||||
class func abs(_:Self) -> Self
|
||||
}
|
||||
|
||||
// Do not use this operator directly; call abs(x) instead
|
||||
@transparent
|
||||
func ~> <T : AbsoluteValuable>(x:T,_:(_Abs, ())) -> T {
|
||||
return T.abs(x)
|
||||
}
|
||||
|
||||
// Absolute value. Concrete instances of SignedNumber can specialize
|
||||
// this function by conforming to AbsoluteValuable.
|
||||
@transparent
|
||||
func abs<T : SignedNumber>(x: T) -> T {
|
||||
return x~>_abs()
|
||||
}
|
||||
|
||||
// ${'Local Variables'}:
|
||||
// eval: (read-only-mode 1)
|
||||
// End:
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This function should be opaque to the optimizer.
|
||||
func [asmname="swift_keepAlive"] swift_keepAlive(objPtr : Builtin.ObjectPointer)
|
||||
// BLOCKED: <rdar://problem/16464507> This function will be unnecessary when
|
||||
// fix_lifetime is honored by the ARC optimizer.
|
||||
@asmname("swift_keepAlive")
|
||||
func swift_keepAlive<T>(inout _: T)
|
||||
|
||||
/// \brief An instance of this struct keeps the references registered with it
|
||||
/// at +1 reference count until the call to \c release().
|
||||
@@ -11,31 +26,99 @@ func [asmname="swift_keepAlive"] swift_keepAlive(objPtr : Builtin.ObjectPointer)
|
||||
/// This class can be used to extend lifetime of objects to pass UnsafePointers
|
||||
/// to them to C APIs.
|
||||
class LifetimeManager {
|
||||
var _managedRefs : Vector<Builtin.ObjectPointer>
|
||||
var _managedRefs : Builtin.NativeObject[]
|
||||
var _releaseCalled : Bool
|
||||
|
||||
constructor() {
|
||||
_managedRefs = Vector<Builtin.ObjectPointer>()
|
||||
init() {
|
||||
_managedRefs = Array<Builtin.NativeObject>()
|
||||
_releaseCalled = false
|
||||
}
|
||||
|
||||
destructor {
|
||||
alwaysTrap(_releaseCalled, "release() should have been called")
|
||||
deinit {
|
||||
if !_releaseCalled {
|
||||
fatal("release() should have been called")
|
||||
}
|
||||
}
|
||||
|
||||
func put(objPtr : Builtin.ObjectPointer) {
|
||||
func put(objPtr: Builtin.NativeObject) {
|
||||
_managedRefs.append(objPtr)
|
||||
}
|
||||
|
||||
// FIXME: Need class constraints for this to work properly.
|
||||
// func put<T>(obj : T) {
|
||||
// put(Builtin.castToObjectPointer(obj))
|
||||
// func put<T>(obj: T) {
|
||||
// put(Builtin.castToNativeObject(obj))
|
||||
// }
|
||||
|
||||
/// \brief Call this function to end the forced lifetime extension.
|
||||
func release() {
|
||||
swift_keepAlive(Builtin.castToObjectPointer(_managedRefs))
|
||||
_fixLifetime(_managedRefs.owner)
|
||||
_releaseCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Evaluate f() and return its result, ensuring that x is not
|
||||
/// destroyed before f returns.
|
||||
func withExtendedLifetime<T, Result>(
|
||||
x: T, f: ()->Result
|
||||
) -> Result {
|
||||
let result = f()
|
||||
_fixLifetime(x)
|
||||
return result
|
||||
}
|
||||
|
||||
/// \brief Evaluate f(x) and return its result, ensuring that x is not
|
||||
/// destroyed before f returns.
|
||||
func withExtendedLifetime<T, Result>(
|
||||
x: T, f: (T)->Result
|
||||
) -> Result {
|
||||
let result = f(x)
|
||||
_fixLifetime(x)
|
||||
return result
|
||||
}
|
||||
|
||||
// FIXME: this function can die once <rdar://problem/14497260> (need
|
||||
// support for CF bridging) is solved.
|
||||
|
||||
/// \brief Pass a given object as a COpaquePointer at +0 to the given
|
||||
/// function, returning its result. This function is useful for
|
||||
/// calling CoreFoundation functions on NS types that are toll-free
|
||||
/// bridged; you have to declare these functions as taking
|
||||
/// COpaquePointer, obviously.
|
||||
func withObjectAtPlusZero<Result>(x: AnyObject, f: (COpaquePointer)->Result) -> Result {
|
||||
return withExtendedLifetime(x) {
|
||||
return f(
|
||||
COpaquePointer(UnsafePointer<Void>(Builtin.bridgeToRawPointer(Builtin.castToNativeObject(x)))))
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
|
||||
/// \brief Invoke f on the contents of this string, represented as
|
||||
/// a nul-terminated array of char, ensuring that the array's
|
||||
/// lifetime extends through the execution of f
|
||||
func withCString<Result>(
|
||||
f: (CString)->Result
|
||||
) -> Result {
|
||||
var u8 = self.nulTerminatedUTF8()
|
||||
return u8.buffer.withUnsafePointerToElements {
|
||||
f(CString($0))
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Invoke f on the contents of this string, represented as
|
||||
/// a nul-terminated array of char, ensuring that the array's
|
||||
/// lifetime extends through the execution of f
|
||||
func withCString<Result>(
|
||||
f: (UnsafePointer<CChar>)->Result
|
||||
) -> Result {
|
||||
var u8 = self.nulTerminatedUTF8()
|
||||
return u8.buffer.withUnsafePointerToElements {
|
||||
f(UnsafePointer($0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@transparent
|
||||
func _fixLifetime<T>(var x: T) {
|
||||
swift_keepAlive(&x)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// LogicValue
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
@@ -9,20 +9,26 @@
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
struct MapGenerator<Base: Generator, T> : Generator, Sequence {
|
||||
|
||||
struct _MapGenerator<Base: Generator, T> : Generator, Sequence {
|
||||
mutating func next() -> T? {
|
||||
return base.next().map(transform)
|
||||
}
|
||||
|
||||
func generate() -> MapGenerator {
|
||||
func generate() -> _MapGenerator {
|
||||
return self
|
||||
}
|
||||
|
||||
init(_ base: Base, _ transform: (Base.Element)->T) {
|
||||
self.base = base
|
||||
self.transform = transform
|
||||
}
|
||||
|
||||
var base: Base
|
||||
var transform: (Base.Element)->T
|
||||
}
|
||||
|
||||
struct Map<Base: Collection, T> : Collection {
|
||||
struct _Map<Base: Collection, T> : Collection {
|
||||
var startIndex: Base.IndexType {
|
||||
return base.startIndex
|
||||
}
|
||||
@@ -35,8 +41,13 @@ struct Map<Base: Collection, T> : Collection {
|
||||
return transform(base[index])
|
||||
}
|
||||
|
||||
func generate() -> MapGenerator<Base.GeneratorType, T> {
|
||||
return MapGenerator(base.generate(), transform)
|
||||
func generate() -> _MapGenerator<Base.GeneratorType, T> {
|
||||
return _MapGenerator(base.generate(), transform)
|
||||
}
|
||||
|
||||
init(_ base: Base, transform: (Base.GeneratorType.Element)->T) {
|
||||
self.base = base
|
||||
self.transform = transform
|
||||
}
|
||||
|
||||
var base: Base
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
% for FloatSize in [32,64]:
|
||||
% Types.append( ('Float'+str(FloatSize),'.Float','Double($0)') )
|
||||
% Types.append(('String','.Text','$0'))
|
||||
% Types.append(('Bool','.Text','"\($0)"'))
|
||||
% Types.append(('Bool','.Logical','$0'))
|
||||
% Types.append(('Int','.Int','Int64($0)'))
|
||||
|
||||
% for Type in Types:
|
||||
|
||||
@@ -1,73 +1,73 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extern C functions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// FIXME: Once we have an FFI interface, make these have proper function bodies
|
||||
|
||||
// The C "abort" function
|
||||
func [asmname="abort"] abort()
|
||||
@asmname("abort") func _abort()
|
||||
|
||||
func [asmname="putchar"]
|
||||
c_putchar(val : Int32)
|
||||
func [asmname="print_int"]
|
||||
c_print_int(p : Builtin.RawPointer, buf_len : Int, x : Int128, Radix : Int,
|
||||
uppercase : Bool) -> UInt64
|
||||
func [asmname="print_uint"]
|
||||
c_print_uint(p : Builtin.RawPointer, buf_len : Int, x : UInt128, Radix : Int,
|
||||
uppercase : Bool) -> UInt64
|
||||
func [asmname="print_double"]
|
||||
c_print_double(p : Builtin.RawPointer, x : Double) -> UInt64
|
||||
@asmname("putchar")
|
||||
func c_putchar(value: Int32)
|
||||
@asmname("print_int")
|
||||
func c_print_int(p: Builtin.RawPointer, buf_len: Int, x: Int64, Radix: Int,
|
||||
uppercase: Bool) -> UInt64
|
||||
@asmname("print_uint")
|
||||
func c_print_uint(p: Builtin.RawPointer, buf_len: Int, x: UInt64, Radix: Int,
|
||||
uppercase: Bool) -> UInt64
|
||||
@asmname("print_double")
|
||||
func c_print_double(p: Builtin.RawPointer, x: Double) -> UInt64
|
||||
|
||||
func [asmname="mach_absolute_time"] mach_absolute_time() -> UInt64
|
||||
|
||||
func [asmname="swift_replOutputIsUTF8"] _isUTF8() -> Bool
|
||||
@asmname("swift_replOutputIsUTF8") func _isUTF8() -> Bool
|
||||
|
||||
// Some file stuff
|
||||
|
||||
func [asmname="swift_file_open"]
|
||||
c_file_open(filename : CString) -> CInt
|
||||
@asmname("write")
|
||||
func posix_write(fd: Int32, buf: Builtin.RawPointer, sz: Int) -> Int
|
||||
|
||||
func [asmname="swift_file_close"]
|
||||
c_file_close(fd : Int32) -> Int32
|
||||
@asmname("read")
|
||||
func posix_read(fd: Int32, buf: Builtin.RawPointer, sz: Int) -> Int
|
||||
|
||||
func [asmname="swift_file_read"]
|
||||
c_file_read(fd : Int32, buf : Builtin.RawPointer, sz : Int) -> Int
|
||||
@asmname("llvm.ctlz.i64")
|
||||
func __llvm_ctlz(value: Builtin.Int64, isZeroUndef: Builtin.Int1) -> Builtin.Int64
|
||||
|
||||
func [asmname="swift_file_size"]
|
||||
c_file_size(filename : Builtin.RawPointer) -> Int
|
||||
@transparent func countLeadingZeros(value: Int64) -> Int64 {
|
||||
return Int64(__llvm_ctlz(value.value, false.value))
|
||||
}
|
||||
|
||||
func [asmname="swift_fd_size"]
|
||||
c_fd_size(fd : Int32) -> Int
|
||||
@transparent func _autorelease(x: AnyObject) {
|
||||
Builtin.retain(x)
|
||||
Builtin.autorelease(x)
|
||||
}
|
||||
|
||||
func [asmname="opendir"]
|
||||
posix_opendir_hack(dir : Builtin.RawPointer) -> Builtin.RawPointer
|
||||
/// Check if a given object (of value or reference type) conforms to the given
|
||||
/// protocol.
|
||||
@asmname("swift_stdlib_conformsToProtocol")
|
||||
func _stdlib_conformsToProtocol<SourceType, DestType>(
|
||||
value: SourceType, _: DestType.Type
|
||||
) -> Bool
|
||||
|
||||
func [asmname="posix_readdir_hack"]
|
||||
posix_readdir_hack(handle : Builtin.RawPointer) -> (Builtin.RawPointer, Int)
|
||||
/// Cast the given object (of value or reference type) to the given protocol
|
||||
/// type. Traps if the object does not conform to the protocol.
|
||||
@asmname("swift_stdlib_dynamicCastToExistential1Unconditional")
|
||||
func _stdlib_dynamicCastToExistential1Unconditional<SourceType, DestType>(
|
||||
value: SourceType, _: DestType.Type
|
||||
) -> DestType
|
||||
|
||||
func [asmname="closedir"]
|
||||
posix_closedir_hack(handle : Builtin.RawPointer)
|
||||
/// Cast the given object (of value or reference type) to the given protocol
|
||||
/// type. Returns `.None` if the object does not conform to the protocol.
|
||||
@asmname("swift_stdlib_dynamicCastToExistential1")
|
||||
func _stdlib_dynamicCastToExistential1<SourceType, DestType>(
|
||||
value: SourceType, _: DestType.Type
|
||||
) -> DestType?
|
||||
|
||||
func [asmname="posix_isDirectory_hack"]
|
||||
posix_isDirectory_hack(handle : Builtin.RawPointer) -> Int
|
||||
|
||||
func [asmname="getchar"]
|
||||
getchar() -> Int32
|
||||
|
||||
func [asmname="open"]
|
||||
posix_open(filename : Builtin.RawPointer, mode : Int32, perm : Int) -> Int32
|
||||
|
||||
func [asmname="close"]
|
||||
posix_close(fd : Int32) -> Int32
|
||||
|
||||
func [asmname="lseek"]
|
||||
posix_seek(fd : Int32, offset : Int, whence : Int32) -> Int
|
||||
|
||||
func [asmname="write"]
|
||||
posix_write(fd : Int32, buf : Builtin.RawPointer, sz : Int) -> Int
|
||||
|
||||
func [asmname="read"]
|
||||
posix_read(fd : Int32, buf : Builtin.RawPointer, sz : Int) -> Int
|
||||
|
||||
func [asmname="dup"]
|
||||
posix_dup(fd : Int32) -> Int32
|
||||
|
||||
@@ -23,64 +23,68 @@ import SwiftShims
|
||||
// design.
|
||||
@objc
|
||||
class NSSwiftArray : HeapBufferStorageBase, CocoaArray {
|
||||
typealias Buffer = HeapBuffer<ArrayBody, AnyObject>
|
||||
typealias Buffer = HeapBuffer<_ArrayBody, AnyObject>
|
||||
|
||||
// Note: This method must be overridden by subclasses, and would be
|
||||
// marked @abstract if we had such a feature. Moreover, those
|
||||
// subclasses must be generic, so we can't allow this method to be @objc
|
||||
// (methods of generic classes can't be @objc), so we use a tuple in the
|
||||
// signature to prevent the inference of @objc here.
|
||||
func _objectAtIndex(indexAndUnused: (Int, Bool)) -> AnyObject {
|
||||
assert(false, "_objectAtIndex must be overridden")
|
||||
return self
|
||||
var dynamicElementType: Any.Type {
|
||||
fatal("This var must be overridden")
|
||||
}
|
||||
|
||||
/// Returns the object located at the specified index.
|
||||
func objectAtIndex(index: Int) -> AnyObject {
|
||||
return _objectAtIndex((index, true))
|
||||
let buffer = reinterpretCast(self) as Buffer
|
||||
// If used as an NSArray, the element type can have no fancy
|
||||
// bridging; just get it and return it
|
||||
assert(buffer.value.elementTypeIsBridgedVerbatim)
|
||||
return buffer[index]
|
||||
}
|
||||
|
||||
// Copies the objects contained in the array that fall within the
|
||||
// specified range to aBuffer.
|
||||
func getObjects(aBuffer: UnsafePointer<AnyObject>, range: _SwiftNSRange) {
|
||||
|
||||
// These objects are "returned" at +0, so treat them as values to
|
||||
// avoid retains.
|
||||
var dst = UnsafePointer<Word>(aBuffer)
|
||||
|
||||
let buffer = reinterpretCast(self) as Buffer
|
||||
// If used as an NSArray, the element type can have no fancy
|
||||
// bridging; just get it and return it
|
||||
assert(buffer.value.elementTypeIsBridgedVerbatim)
|
||||
|
||||
if _fastPath(buffer.value.elementTypeIsBridgedVerbatim) {
|
||||
dst.initializeFrom(
|
||||
UnsafePointer(buffer.elementStorage + range.location),
|
||||
count: range.length)
|
||||
}
|
||||
|
||||
func getObjects(
|
||||
objects: UnsafePointer<AnyObject>)range(range: _SwiftNSRange) {
|
||||
var dst = objects
|
||||
for i in range.location...range.location + range.length {
|
||||
dst++.initialize(_objectAtIndex((i, true)))
|
||||
dst++.initialize(reinterpretCast(buffer[i]))
|
||||
}
|
||||
}
|
||||
|
||||
func copyWithZone(_: COpaquePointer) -> CocoaArray {
|
||||
// Copy-on-write keeps us from modifying this as long as Cocoa can
|
||||
// see it.
|
||||
return self
|
||||
}
|
||||
|
||||
func countByEnumeratingWithState(
|
||||
state: UnsafePointer<_SwiftNSFastEnumerationState>)
|
||||
objects(UnsafePointer<AnyObject>) count(bufferSize: Int)
|
||||
-> Int {
|
||||
state: UnsafePointer<_SwiftNSFastEnumerationState>,
|
||||
objects: UnsafePointer<AnyObject>, count bufferSize: Int
|
||||
) -> Int {
|
||||
var enumerationState = state.get()
|
||||
|
||||
let my = reinterpretCast(self) as Buffer
|
||||
if _fastPath(my.value.elementTypeIsBridgedVerbatim) {
|
||||
let buffer = reinterpretCast(self) as Buffer
|
||||
// If used as an NSArray, the element type can have no fancy
|
||||
// bridging; just get it and return it
|
||||
assert(buffer.value.elementTypeIsBridgedVerbatim)
|
||||
|
||||
if enumerationState.state != 0 {
|
||||
return 0
|
||||
}
|
||||
enumerationState.mutationsPtr = reinterpretCast(self)
|
||||
enumerationState.itemsPtr = reinterpretCast(my.elementStorage)
|
||||
enumerationState.mutationsPtr = _fastEnumerationStorageMutationsPtr
|
||||
enumerationState.itemsPtr = reinterpretCast(buffer.elementStorage)
|
||||
enumerationState.state = 1
|
||||
state.set(enumerationState)
|
||||
return my.value.count
|
||||
}
|
||||
|
||||
// FIXME: Could optimize away this copy if we have a buffer that
|
||||
// already contains AnyObjects.
|
||||
let firstItem = Int(enumerationState.state)
|
||||
let numItemsToCopy = min(self.count - firstItem, bufferSize)
|
||||
getObjects(objects, range:_SwiftNSRange(firstItem, numItemsToCopy))
|
||||
enumerationState.mutationsPtr = reinterpretCast(self)
|
||||
enumerationState.itemsPtr = reinterpretCast(objects)
|
||||
enumerationState.state += CUnsignedLong(numItemsToCopy)
|
||||
state.set(enumerationState)
|
||||
return numItemsToCopy
|
||||
return buffer.value.count
|
||||
}
|
||||
|
||||
var count: Int {
|
||||
|
||||
@@ -15,28 +15,20 @@ import SwiftShims
|
||||
// The empty array prototype. We use the same object for all empty
|
||||
// [Native]Array<T>s.
|
||||
let emptyNSSwiftArray : NSSwiftArray
|
||||
= reinterpretCast(NativeArrayBuffer<Int>(0,0))
|
||||
= reinterpretCast(NativeArrayBuffer<Int>(count: 0, minimumCapacity: 0))
|
||||
|
||||
// The class that implements the storage for a NativeArray<T>
|
||||
@final class NativeArrayStorage<T> : NSSwiftArray {
|
||||
typealias Masquerade = HeapBufferStorage<ArrayBody,T>
|
||||
typealias Buffer = NativeArrayBuffer<T>
|
||||
|
||||
deinit {
|
||||
let b = HeapBuffer(
|
||||
reinterpretCast(self) as Masquerade
|
||||
)
|
||||
for i in 0...b.value.count {
|
||||
(b.elementStorage + i).destroy()
|
||||
}
|
||||
b._value.destroy()
|
||||
let b = Buffer(self)
|
||||
b.elementStorage.destroy(b.count)
|
||||
b.base._value.destroy()
|
||||
}
|
||||
|
||||
@override func _objectAtIndex(indexAndUnused: (Int, Bool)) -> AnyObject {
|
||||
let index = indexAndUnused.0
|
||||
let b = HeapBuffer(
|
||||
reinterpretCast(self) as Masquerade
|
||||
)
|
||||
|
||||
return bridgeToObjectiveC((b.elementStorage + index).get())!
|
||||
override var dynamicElementType: Any.Type {
|
||||
return T.self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,22 +41,22 @@ struct NativeArrayBuffer<T> : ArrayBufferType, LogicValue {
|
||||
{
|
||||
base = HeapBuffer(
|
||||
NativeArrayStorage<T>.self,
|
||||
ArrayBody(),
|
||||
_ArrayBody(),
|
||||
max(count, minimumCapacity))
|
||||
|
||||
base.value = ArrayBody(
|
||||
count, base._capacity(), isBridgedVerbatimToObjectiveC(T.self))
|
||||
var bridged = false
|
||||
if _canBeClass(T.self) {
|
||||
bridged = isBridgedVerbatimToObjectiveC(T.self)
|
||||
}
|
||||
|
||||
init(storage: NativeArrayStorage<T>?) {
|
||||
base.value = _ArrayBody(count: count, capacity: base._capacity(),
|
||||
elementTypeIsBridgedVerbatim: bridged)
|
||||
}
|
||||
|
||||
init(_ storage: NativeArrayStorage<T>?) {
|
||||
base = reinterpretCast(storage)
|
||||
}
|
||||
|
||||
/// Append x to this buffer, growing it by 1 element.
|
||||
mutating func append(x: T) {
|
||||
self += x
|
||||
}
|
||||
|
||||
func getLogicValue() -> Bool {
|
||||
return base.getLogicValue()
|
||||
}
|
||||
@@ -75,6 +67,12 @@ struct NativeArrayBuffer<T> : ArrayBufferType, LogicValue {
|
||||
return base ? base.elementStorage : nil
|
||||
}
|
||||
|
||||
/// A pointer to the first element, assuming that the elements are stored
|
||||
/// contiguously.
|
||||
var _unsafeElementStorage: UnsafePointer<T> {
|
||||
return base.elementStorage
|
||||
}
|
||||
|
||||
func withUnsafePointerToElements<R>(body: (UnsafePointer<T>)->R) -> R {
|
||||
let p = base.elementStorage
|
||||
return withExtendedLifetime(base) { body(p) }
|
||||
@@ -100,8 +98,8 @@ struct NativeArrayBuffer<T> : ArrayBufferType, LogicValue {
|
||||
}
|
||||
|
||||
/// Adopt the storage of x
|
||||
init(other: NativeArrayBuffer) {
|
||||
self = other
|
||||
init(_ buffer: NativeArrayBuffer) {
|
||||
self = buffer
|
||||
}
|
||||
|
||||
mutating func requestUniqueMutableBuffer(minimumCapacity: Int)
|
||||
@@ -117,21 +115,24 @@ struct NativeArrayBuffer<T> : ArrayBufferType, LogicValue {
|
||||
return self
|
||||
}
|
||||
|
||||
/// Convert to a NativeArrayBuffer storing the same elements.
|
||||
func toNativeBuffer() -> NativeArrayBuffer<Element> {
|
||||
return self
|
||||
}
|
||||
|
||||
/// Get/set the value of the ith element
|
||||
subscript(i: Int) -> T {
|
||||
get {
|
||||
assert(i >= 0 && i < count, "Array index out of range")
|
||||
return elementStorage[i]
|
||||
// If the index is in bounds, we can assume we have storage.
|
||||
return _unsafeElementStorage[i]
|
||||
}
|
||||
@!mutating
|
||||
set {
|
||||
nonmutating set {
|
||||
assert(i >= 0 && i < count, "Array index out of range")
|
||||
elementStorage[i] = newValue
|
||||
// If the index is in bounds, we can assume we have storage.
|
||||
|
||||
// FIXME: Manually swap because it makes the ARC optimizer happy. See
|
||||
// <rdar://problem/16831852> check retain/release order
|
||||
// _unsafeElementStorage[i] = newValue
|
||||
var nv = newValue
|
||||
let tmp = nv
|
||||
nv = _unsafeElementStorage[i]
|
||||
_unsafeElementStorage[i] = tmp
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,8 +141,7 @@ struct NativeArrayBuffer<T> : ArrayBufferType, LogicValue {
|
||||
get {
|
||||
return base ? base.value.count : 0
|
||||
}
|
||||
@!mutating
|
||||
set {
|
||||
nonmutating set {
|
||||
assert(newValue >= 0)
|
||||
|
||||
assert(
|
||||
@@ -176,6 +176,7 @@ struct NativeArrayBuffer<T> : ArrayBufferType, LogicValue {
|
||||
for i in subRange {
|
||||
dst++.initialize(src++.get())
|
||||
}
|
||||
_fixLifetime(owner)
|
||||
return dst
|
||||
}
|
||||
|
||||
@@ -184,10 +185,10 @@ struct NativeArrayBuffer<T> : ArrayBufferType, LogicValue {
|
||||
subscript(subRange: Range<Int>) -> SliceBuffer<T>
|
||||
{
|
||||
return SliceBuffer(
|
||||
base.storage,
|
||||
elementStorage + subRange.startIndex,
|
||||
subRange.endIndex - subRange.startIndex,
|
||||
true)
|
||||
owner: base.storage,
|
||||
start: elementStorage + subRange.startIndex,
|
||||
count: subRange.endIndex - subRange.startIndex,
|
||||
hasNativeBuffer: true)
|
||||
}
|
||||
|
||||
/// Return true iff this buffer's storage is uniquely-referenced.
|
||||
@@ -204,13 +205,20 @@ struct NativeArrayBuffer<T> : ArrayBufferType, LogicValue {
|
||||
return true
|
||||
}
|
||||
|
||||
/// Convert to an NSArray in O(1).
|
||||
/// Precondition: isBridgedToObjectiveC(Element.self)
|
||||
/// Convert to an NSArray.
|
||||
/// Precondition: T is bridged to Objective-C
|
||||
/// O(1) if T is bridged verbatim, O(N) otherwise
|
||||
func asCocoaArray() -> CocoaArray {
|
||||
assert(
|
||||
isBridgedToObjectiveC(T.self),
|
||||
"Array element type is not bridged to ObjectiveC")
|
||||
return count > 0 ? reinterpretCast(base.storage) : emptyNSSwiftArray
|
||||
if count == 0 {
|
||||
return emptyNSSwiftArray
|
||||
}
|
||||
if _fastPath(base.value.elementTypeIsBridgedVerbatim) {
|
||||
return reinterpretCast(base.storage)
|
||||
}
|
||||
return NativeArray(self).map { bridgeToObjectiveC($0)! }.buffer.storage!
|
||||
}
|
||||
|
||||
/// An object that keeps the elements stored in this buffer alive
|
||||
@@ -218,12 +226,23 @@ struct NativeArrayBuffer<T> : ArrayBufferType, LogicValue {
|
||||
return storage
|
||||
}
|
||||
|
||||
/// A value that identifies first mutable element, if any. Two
|
||||
/// arrays compare === iff they are both empty, or if their buffers
|
||||
/// have the same identity and count.
|
||||
var identity: Word {
|
||||
return reinterpretCast(elementStorage)
|
||||
}
|
||||
|
||||
var dynamicElementType: Any.Type {
|
||||
return storage ? storage!.dynamicElementType : T.self
|
||||
}
|
||||
|
||||
//===--- private --------------------------------------------------------===//
|
||||
var storage: NativeArrayStorage<T>? {
|
||||
return reinterpretCast(base.storage)
|
||||
}
|
||||
|
||||
typealias Base = HeapBuffer<ArrayBody,T>
|
||||
typealias Base = HeapBuffer<_ArrayBody, T>
|
||||
var base: Base
|
||||
}
|
||||
|
||||
@@ -241,9 +260,11 @@ func += <
|
||||
(lhs.elementStorage + oldCount).initializeFrom(rhs)
|
||||
}
|
||||
else {
|
||||
let newLHS = NativeArrayBuffer<T>(newCount, lhs.capacity * 2)
|
||||
let newLHS = NativeArrayBuffer<T>(count: newCount,
|
||||
minimumCapacity: lhs.capacity * 2)
|
||||
if lhs.base {
|
||||
newLHS.elementStorage.moveInitializeFrom(lhs.elementStorage, oldCount)
|
||||
newLHS.elementStorage.moveInitializeFrom(lhs.elementStorage,
|
||||
count: oldCount)
|
||||
lhs.base.value.count = 0
|
||||
}
|
||||
lhs.base = newLHS.base
|
||||
@@ -283,7 +304,7 @@ extension NativeArrayBuffer : Collection {
|
||||
func ~> <
|
||||
S: _Sequence_
|
||||
>(
|
||||
source: S, _: (_AsNativeArrayBuffer,())
|
||||
source: S, _: (_CopyToNativeArrayBuffer,())
|
||||
) -> NativeArrayBuffer<S.GeneratorType.Element>
|
||||
{
|
||||
var result = NativeArrayBuffer<S.GeneratorType.Element>()
|
||||
@@ -291,23 +312,21 @@ func ~> <
|
||||
// Using GeneratorSequence here essentially promotes the sequence to
|
||||
// a Sequence from _Sequence_ so we can iterate the elements
|
||||
for x in GeneratorSequence(source.generate()) {
|
||||
result.append(x)
|
||||
result += x
|
||||
}
|
||||
return result.take()
|
||||
}
|
||||
|
||||
func ~> <
|
||||
// FIXME: <rdar://problem/16466357> prevents this from being ":
|
||||
// Collection"
|
||||
C: protocol<_Collection,_Sequence_>
|
||||
C: Collection
|
||||
>(
|
||||
source: C, _:(_AsNativeArrayBuffer, ())
|
||||
source: C, _:(_CopyToNativeArrayBuffer, ())
|
||||
) -> NativeArrayBuffer<C.GeneratorType.Element>
|
||||
{
|
||||
return _collectionAsNativeArrayBuffer(source)
|
||||
return _copyCollectionToNativeArrayBuffer(source)
|
||||
}
|
||||
|
||||
func _collectionAsNativeArrayBuffer<C: protocol<_Collection,_Sequence_>>(
|
||||
func _copyCollectionToNativeArrayBuffer<C: protocol<_Collection,_Sequence_>>(
|
||||
source: C
|
||||
) -> NativeArrayBuffer<C.GeneratorType.Element>
|
||||
{
|
||||
@@ -335,21 +354,3 @@ protocol _ArrayType : Collection {
|
||||
typealias Buffer : ArrayBufferType
|
||||
var buffer: Buffer {get}
|
||||
}
|
||||
|
||||
/*
|
||||
// FIXME: Disabled pending <rdar://problem/16509573>
|
||||
func ~> <
|
||||
A: _ArrayType where A.Buffer.Element == A.Buffer.GeneratorType.Element
|
||||
>(
|
||||
source: A, _:(_AsNativeArrayBuffer,())
|
||||
) -> NativeArrayBuffer<A.Buffer.Element>
|
||||
{
|
||||
return _toNativeArrayBuffer(source.buffer)
|
||||
}
|
||||
*/
|
||||
|
||||
func asNativeArrayBuffer<S: Sequence>(source: S)
|
||||
-> NativeArrayBuffer<S.GeneratorType.Element>
|
||||
{
|
||||
return source~>_asNativeArrayBuffer()
|
||||
}
|
||||
|
||||
@@ -1,12 +1,47 @@
|
||||
@asmname="swift_makeUnsafeNil" func _makeUnsafeNil() -> AnyObject
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 _Nil {
|
||||
@conversion func __conversion() -> AnyObject {
|
||||
return _makeUnsafeNil()
|
||||
struct _Nil : Reflectable {
|
||||
|
||||
@conversion func __conversion<T: RawOptionSet>() -> T {
|
||||
return .fromMask(.allZeros())
|
||||
}
|
||||
|
||||
func getMirror() -> Mirror {
|
||||
return _NilMirror()
|
||||
}
|
||||
}
|
||||
|
||||
/// A null pointer constant.
|
||||
/// A null sentinel value.
|
||||
var nil : _Nil {
|
||||
return _Nil()
|
||||
}
|
||||
|
||||
struct _NilMirror : Mirror {
|
||||
var value: Any { return nil }
|
||||
|
||||
var valueType: Any.Type { return (nil as Any).dynamicType }
|
||||
|
||||
var objectIdentifier: ObjectIdentifier? { return .None }
|
||||
|
||||
var count: Int { return 0 }
|
||||
|
||||
subscript(i: Int) -> (String, Mirror) { fatal("a _NilMirror has no children") }
|
||||
|
||||
var summary: String { return "nil" }
|
||||
|
||||
var quickLookObject: QuickLookObject? { return .None }
|
||||
|
||||
var disposition: MirrorDisposition { return .Aggregate }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,109 +1,180 @@
|
||||
/* Optional<T>
|
||||
|
||||
Until we have working oneof types, we have this library-based oneof.
|
||||
|
||||
*/
|
||||
|
||||
// Users should never touch this type directly.
|
||||
struct __NoneType {
|
||||
func getLogicValue() -> Bool { return false }
|
||||
}
|
||||
func [prefix] !(x: __NoneType) -> Bool { return true }
|
||||
|
||||
extension __NoneType : Equatable {
|
||||
func __equal__(rhs: __NoneType) -> Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// This constant is for public consumption
|
||||
var None: __NoneType {
|
||||
return __NoneType()
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// FIXME: Until Swift supports partial ordering of generic functions,
|
||||
// these will cause ambiguities against more useful overloads like
|
||||
// those interactions with Optional<T>. Keep them on ice until then.
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
func == <T>(lhs: __NoneType, rhs: T) -> Bool {
|
||||
return rhs.isNone()
|
||||
}
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
func != <T>(lhs: __NoneType, rhs: Optional<T>) -> Bool {
|
||||
return !rhs.isNone()
|
||||
}
|
||||
// The compiler has special knowledge of Optional<T>, including the fact that
|
||||
// it is an enum with cases named 'None' and 'Some'.
|
||||
enum Optional<T>: LogicValue,Reflectable {
|
||||
case None
|
||||
case Some(T)
|
||||
|
||||
func == <T>(lhs: Optional<T>, rhs: __NoneType) -> Bool {
|
||||
return lhs.isNone()
|
||||
}
|
||||
init() { self = .None }
|
||||
|
||||
func != <T>(lhs: Optional<T>, rhs: __NoneType) -> Bool {
|
||||
return !lhs.isNone()
|
||||
}
|
||||
init(_ some: T) { self = .Some(some) }
|
||||
|
||||
*/
|
||||
|
||||
struct Optional<T>: Enumerable, LogicValue {
|
||||
typealias EnumeratorType = Slice<T>
|
||||
func getEnumeratorType() -> Slice<T> { return value }
|
||||
|
||||
constructor() {}
|
||||
|
||||
constructor(x: T) {
|
||||
value = new T[1]
|
||||
value[0] = x
|
||||
}
|
||||
|
||||
constructor(x: __NoneType) {}
|
||||
|
||||
/// \brief Allow use in a Boolean context.
|
||||
/// Allow use in a Boolean context.
|
||||
@transparent
|
||||
func getLogicValue() -> Bool {
|
||||
return value.length > 0
|
||||
switch self {
|
||||
case .Some:
|
||||
return true
|
||||
case .None:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func isNone() -> Bool {
|
||||
return !getLogicValue()
|
||||
/// Haskell's fmap, which was mis-named
|
||||
func map<U>(f: (T)->U) -> U? {
|
||||
switch self {
|
||||
case .Some(var y):
|
||||
return .Some(f(y))
|
||||
case .None:
|
||||
return .None
|
||||
}
|
||||
}
|
||||
|
||||
func get() -> T {
|
||||
assert(value.length > 0)
|
||||
return value[0]
|
||||
}
|
||||
|
||||
var value: T[]
|
||||
}
|
||||
|
||||
// Emulate .Some(x) tag constructor to be delivered by oneof
|
||||
func Some<T>(x: T) -> Optional<T> {
|
||||
return Optional(x)
|
||||
}
|
||||
|
||||
// FIXME: Has no effect pending <rdar://problem/13785669>
|
||||
extension __NoneType {
|
||||
func [conversion] __conversion<T> () -> Optional<T> {
|
||||
return Optional(None)
|
||||
func getMirror() -> Mirror {
|
||||
return _OptionalMirror(self)
|
||||
}
|
||||
}
|
||||
|
||||
func [prefix] ! <T>(x: Optional<T>) -> Bool {
|
||||
return !x.getLogicValue()
|
||||
// While this free function may seem obsolete, since an optional is
|
||||
// often expressed as (x as T), it can lead to cleaner usage, i.e.
|
||||
//
|
||||
// map(x as T) { ... }
|
||||
// vs
|
||||
// (x as T).map { ... }
|
||||
//
|
||||
/// Haskell's fmap for Optionals.
|
||||
func map<T, U>(x: T?, f: (T)->U) -> U? {
|
||||
switch x {
|
||||
case .Some(var y):
|
||||
return .Some(f(y))
|
||||
case .None:
|
||||
return .None
|
||||
}
|
||||
}
|
||||
|
||||
func == <T>(lhs: __NoneType, rhs: Optional<T>) -> Bool {
|
||||
return rhs.isNone()
|
||||
// Intrinsics for use by language features.
|
||||
@transparent
|
||||
func _doesOptionalHaveValue<T>(inout v: T?) -> Builtin.Int1 {
|
||||
return v.getLogicValue().value
|
||||
}
|
||||
|
||||
func != <T>(lhs: __NoneType, rhs: Optional<T>) -> Bool {
|
||||
return !rhs.isNone()
|
||||
@transparent
|
||||
func _getOptionalValue<T>(v: T?) -> T {
|
||||
switch v {
|
||||
case .Some(var x):
|
||||
return x
|
||||
case .None:
|
||||
fatal("Can't unwrap Optional.None")
|
||||
}
|
||||
}
|
||||
|
||||
func == <T>(lhs: Optional<T>, rhs: __NoneType) -> Bool {
|
||||
return lhs.isNone()
|
||||
@transparent
|
||||
func _injectValueIntoOptional<T>(v: T) -> Optional<T> {
|
||||
return .Some(v)
|
||||
}
|
||||
|
||||
func != <T>(lhs: Optional<T>, rhs: __NoneType) -> Bool {
|
||||
return !lhs.isNone()
|
||||
@transparent
|
||||
func _injectNothingIntoOptional<T>() -> Optional<T> {
|
||||
return .None
|
||||
}
|
||||
|
||||
// Comparisons
|
||||
func == <T: Equatable> (lhs: T?, rhs: T?) -> Bool {
|
||||
switch (lhs,rhs) {
|
||||
case (.Some(let l), .Some(let r)):
|
||||
return l == r
|
||||
case (.None, .None):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func != <T: Equatable> (lhs: T?, rhs: T?) -> Bool {
|
||||
return !(lhs == rhs)
|
||||
}
|
||||
|
||||
struct _OptionalMirror<T> : Mirror {
|
||||
let _value : Optional<T>
|
||||
|
||||
init(_ x : Optional<T>) {
|
||||
_value = x
|
||||
}
|
||||
|
||||
var value: Any { return _value }
|
||||
|
||||
var valueType: Any.Type { return (_value as Any).dynamicType }
|
||||
|
||||
var objectIdentifier: ObjectIdentifier? { return .None }
|
||||
|
||||
var count: Int { return _value ? 1 : 0 }
|
||||
|
||||
subscript(i: Int) -> (String, Mirror) {
|
||||
switch (_value,i) {
|
||||
case (.Some(let contents),0) : return ("Some",reflect(contents))
|
||||
default: fatal("cannot extract this child index")
|
||||
}
|
||||
}
|
||||
|
||||
var summary: String {
|
||||
switch _value {
|
||||
case .Some(let contents): return reflect(contents).summary
|
||||
default: return "nil"
|
||||
}
|
||||
}
|
||||
|
||||
var quickLookObject: QuickLookObject? { return .None }
|
||||
|
||||
var disposition: MirrorDisposition { return .Optional }
|
||||
}
|
||||
|
||||
|
||||
// FIXME: ordering comparison of Optionals disabled pending
|
||||
func < <T: _Comparable> (lhs: T?, rhs: T?) -> Bool {
|
||||
switch (lhs,rhs) {
|
||||
case (.Some(let l), .Some(let r)):
|
||||
return l < r
|
||||
case (.None, .Some):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func > <T: _Comparable>(lhs: T?, rhs: T?) -> Bool {
|
||||
switch (lhs,rhs) {
|
||||
case (.Some(let l), .Some(let r)):
|
||||
return l > r
|
||||
default:
|
||||
return rhs < lhs
|
||||
}
|
||||
}
|
||||
|
||||
func <= <T: _Comparable>(lhs: T?, rhs: T?) -> Bool {
|
||||
switch (lhs,rhs) {
|
||||
case (.Some(let l), .Some(let r)):
|
||||
return l <= r
|
||||
default:
|
||||
return !(rhs < lhs)
|
||||
}
|
||||
}
|
||||
|
||||
func >= <T: _Comparable>(lhs: T?, rhs: T?) -> Bool {
|
||||
switch (lhs,rhs) {
|
||||
case (.Some(let l), .Some(let r)):
|
||||
return l >= r
|
||||
default:
|
||||
return !(lhs < rhs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,113 +1,109 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// OutputStream and Formatting logic
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
extension Bool : FormattedPrintable {
|
||||
func format(kind : Char, layout : String) -> String {
|
||||
alwaysTrap(kind == 'v')
|
||||
return Format(layout).printToString(String(this))
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
securityCheck(kind == "v")
|
||||
return Format(layout).printToString(String(self))
|
||||
}
|
||||
}
|
||||
|
||||
extension Int8 : FormattedPrintable {
|
||||
func format(kind : Char, layout : String) -> String {
|
||||
return Int64(this).format(kind, layout)
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
return IntMax(self).format(kind, layout: layout)
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt8 : FormattedPrintable {
|
||||
func format(kind : Char, layout : String) -> String {
|
||||
return UInt64(this).format(kind, layout)
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
return UIntMax(self).format(kind, layout: layout)
|
||||
}
|
||||
}
|
||||
|
||||
extension Int16 : FormattedPrintable {
|
||||
func format(kind : Char, layout : String) -> String {
|
||||
return Int64(this).format(kind, layout)
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
return IntMax(self).format(kind, layout: layout)
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt16 : FormattedPrintable {
|
||||
func format(kind : Char, layout : String) -> String {
|
||||
return UInt64(this).format(kind, layout)
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
return UIntMax(self).format(kind, layout: layout)
|
||||
}
|
||||
}
|
||||
|
||||
extension Int32 : FormattedPrintable {
|
||||
func format(kind : Char, layout : String) -> String {
|
||||
return Int64(this).format(kind, layout)
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
return IntMax(self).format(kind, layout: layout)
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt32 : FormattedPrintable {
|
||||
func format(kind : Char, layout : String) -> String {
|
||||
return UInt64(this).format(kind, layout)
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
return UIntMax(self).format(kind, layout: layout)
|
||||
}
|
||||
}
|
||||
|
||||
extension Int64 : FormattedPrintable {
|
||||
func format(kind : Char, layout : String) -> String {
|
||||
var radix = 10
|
||||
var uppercase = false
|
||||
if kind == 'X' { uppercase = true; radix = 16 }
|
||||
else if kind == 'x' { radix = 16 }
|
||||
else if kind == 'o' { radix = 8 }
|
||||
else if kind != 'v' { alwaysTrap() }
|
||||
return Format(layout).printToString(
|
||||
String(this, radix : radix, uppercase : uppercase))
|
||||
extension Int : FormattedPrintable {
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
return IntMax(self).format(kind, layout: layout)
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt64 : FormattedPrintable {
|
||||
func format(kind : Char, layout : String) -> String {
|
||||
var radix = 10
|
||||
var uppercase = false
|
||||
if kind == 'X' { uppercase = true; radix = 16 }
|
||||
else if kind == 'x' { radix = 16 }
|
||||
else if kind == 'o' { radix = 8 }
|
||||
else if kind != 'v' { alwaysTrap() }
|
||||
return Format(layout).printToString(
|
||||
String(this, radix : radix, uppercase : uppercase))
|
||||
extension UInt : FormattedPrintable {
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
return UIntMax(self).format(kind, layout: layout)
|
||||
}
|
||||
}
|
||||
|
||||
extension Int128 : FormattedPrintable {
|
||||
func format(kind : Char, layout : String) -> String {
|
||||
extension IntMax : FormattedPrintable {
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
var radix = 10
|
||||
var uppercase = false
|
||||
if kind == 'X' { uppercase = true; radix = 16 }
|
||||
else if kind == 'x' { radix = 16 }
|
||||
else if kind == 'o' { radix = 8 }
|
||||
else if kind != 'v' { alwaysTrap() }
|
||||
if kind == "X" { uppercase = true; radix = 16 }
|
||||
else if kind == "x" { radix = 16 }
|
||||
else if kind == "o" { radix = 8 }
|
||||
else if kind != "v" { fatal("Invalid format chacacter") }
|
||||
return Format(layout).printToString(
|
||||
String(this, radix : radix, uppercase : uppercase))
|
||||
String(self, radix : radix, uppercase : uppercase))
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt128 : FormattedPrintable {
|
||||
func format(kind : Char, layout : String) -> String {
|
||||
extension UIntMax : FormattedPrintable {
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
var radix = 10
|
||||
var uppercase = false
|
||||
if kind == 'X' { uppercase = true; radix = 16 }
|
||||
else if kind == 'x' { radix = 16 }
|
||||
else if kind == 'o' { radix = 8 }
|
||||
else if kind != 'v' { alwaysTrap() }
|
||||
if kind == "X" { uppercase = true; radix = 16 }
|
||||
else if kind == "x" { radix = 16 }
|
||||
else if kind == "o" { radix = 8 }
|
||||
else if kind != "v" { fatal("Invalid format chacacter") }
|
||||
return Format(layout).printToString(
|
||||
String(this, radix : radix, uppercase : uppercase))
|
||||
String(self, radix : radix, uppercase : uppercase))
|
||||
}
|
||||
}
|
||||
|
||||
extension Float : FormattedPrintable {
|
||||
func format(kind : Char, layout : String) -> String {
|
||||
alwaysTrap(kind == 'v')
|
||||
return Format(layout).printToString(String(this))
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
securityCheck(kind == "v")
|
||||
return Format(layout).printToString(String(self))
|
||||
}
|
||||
}
|
||||
|
||||
extension Double : FormattedPrintable {
|
||||
func format(kind : Char, layout : String) -> String {
|
||||
alwaysTrap(kind == 'v')
|
||||
return Format(layout).printToString(String(this))
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
securityCheck(kind == "v")
|
||||
return Format(layout).printToString(String(self))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,35 +111,32 @@ extension Double : FormattedPrintable {
|
||||
// Formatted Printing
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct Format {
|
||||
struct Format : ReplPrintable {
|
||||
var width : Int
|
||||
var isValid : Bool
|
||||
var leftJustify : Bool
|
||||
|
||||
constructor(layout : String) {
|
||||
init(_ layout: String) {
|
||||
isValid = true
|
||||
leftJustify = false
|
||||
width = 0
|
||||
|
||||
if !layout.isEmpty() {
|
||||
if layout[0] == '-' {
|
||||
leftJustify = true
|
||||
layout = layout.substr(1)
|
||||
}
|
||||
|
||||
if !layout.isEmpty() {
|
||||
for c in layout.chars {
|
||||
leftJustify = layout.startsWith("-")
|
||||
var layoutSansJustification = layout.substr(leftJustify ? 1 : 0)
|
||||
if !layoutSansJustification.isEmpty() {
|
||||
for c in layoutSansJustification.unicodeScalars {
|
||||
if !c.isDigit() {
|
||||
isValid = false
|
||||
break
|
||||
}
|
||||
width = width * 10 + Int(UInt32(c) - UInt32('0'))
|
||||
width = width * 10 + Int(UInt32(c) - UInt32("0"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printString(s : String) {
|
||||
func printString(s: String) {
|
||||
|
||||
/* Causes problems due to <rdar://problem/11529601>
|
||||
if !isValid {
|
||||
@@ -153,26 +146,28 @@ struct Format {
|
||||
*/
|
||||
var padding = max(width - s.size(), 0)
|
||||
if !leftJustify {
|
||||
for i in 0..padding { print(' ') }
|
||||
for i in 0...padding { print(" ") }
|
||||
}
|
||||
print(s)
|
||||
if leftJustify {
|
||||
for i in 0..padding { print(' ') }
|
||||
for i in 0...padding { print(" ") }
|
||||
}
|
||||
}
|
||||
|
||||
func printToString(s : String) -> String {
|
||||
func printToString(s: String) -> String {
|
||||
if !isValid {
|
||||
return s
|
||||
}
|
||||
var r : String
|
||||
var r: String
|
||||
var padding = max(width - s.size(), 0)
|
||||
if !leftJustify {
|
||||
r = String(padding, ' ')
|
||||
r = String(count: padding, character: " ")
|
||||
} else {
|
||||
r = String()
|
||||
}
|
||||
r = r + s
|
||||
if leftJustify {
|
||||
r = r + String(padding, ' ')
|
||||
r = r + String(count: padding, character: " ")
|
||||
}
|
||||
return r
|
||||
}
|
||||
@@ -184,84 +179,120 @@ struct Format {
|
||||
|
||||
// Terminal input & output
|
||||
|
||||
class Console : Object {
|
||||
func write(buf : UInt8[]) -> Int {
|
||||
var r = posix_write(1, buf.base.value, buf.length)
|
||||
alwaysTrap(r != -1)
|
||||
@final class Console : OutputStreamable {
|
||||
init() { }
|
||||
|
||||
func write(inout buf: UInt8[]) -> Int {
|
||||
let count = buf.count
|
||||
var r = 0
|
||||
for var start = 0; start < count; start += 1024 {
|
||||
let slice = buf[start...min(start + 1024, count)]
|
||||
r = slice.withUnsafePointerToElements {
|
||||
posix_write(1, $0.value, slice.count)
|
||||
}
|
||||
if r == -1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func write(buf : String) -> Int {
|
||||
var r = posix_write(1, buf.str_value.base.value, buf.length)
|
||||
alwaysTrap(r != -1)
|
||||
func write(buf: String) -> Int {
|
||||
var r = 0
|
||||
let p = buf.contiguousUTF8
|
||||
|
||||
if p != nil {
|
||||
let r = posix_write(1, p.value, buf.core.count)
|
||||
}
|
||||
else {
|
||||
var a = NativeArray<UInt8>(count: 1024, value: 0)
|
||||
var count = 0
|
||||
|
||||
for u in buf.utf8 {
|
||||
a[count++] = u
|
||||
if count == a.count {
|
||||
r = a.withUnsafePointerToElements {
|
||||
posix_write(1, $0.value, count)
|
||||
}
|
||||
if r == -1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if count != 0 {
|
||||
r = a.withUnsafePointerToElements {
|
||||
posix_write(1, $0.value, count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
securityCheck(r != -1)
|
||||
return r
|
||||
}
|
||||
|
||||
func write(c : UInt8) {
|
||||
func write(c: UInt8) {
|
||||
var buf = new UInt8[1]
|
||||
buf[0] = c
|
||||
var r = write(buf)
|
||||
alwaysTrap(r == 1)
|
||||
var r = write(&buf)
|
||||
securityCheck(r == 1)
|
||||
}
|
||||
}
|
||||
|
||||
var con : Console = Console()
|
||||
|
||||
protocol FormattedPrintable {
|
||||
func format(kind : Char, layout : String) -> String
|
||||
func format(kind: UnicodeScalar, layout: String) -> String
|
||||
}
|
||||
|
||||
func splitFormat(format : String) -> (String, String, Char, String) {
|
||||
var (before, afterPercent, foundPercent) = format.splitFirst('%')
|
||||
func splitFormat(format: String) -> (String, String, UnicodeScalar, String) {
|
||||
var (before, afterPercent, foundPercent) = format.splitFirst("%")
|
||||
if !foundPercent {
|
||||
return (before, "", Char(0), afterPercent)
|
||||
return (before, "", UnicodeScalar(0), afterPercent)
|
||||
}
|
||||
|
||||
var (layout, kind, after, found) = afterPercent.splitFirstIf({ $0.isAlpha() })
|
||||
if !found {
|
||||
return (before, "", Char(0), afterPercent)
|
||||
return (before, "", UnicodeScalar(0), afterPercent)
|
||||
}
|
||||
|
||||
return (before, layout, kind, after)
|
||||
}
|
||||
|
||||
protocol OutputStreamable {
|
||||
func write(buf : UInt8[]) -> Int
|
||||
func write(inout buf: UInt8[]) -> Int
|
||||
// FIXME: Add default implementation when language allows it:
|
||||
func write(buf : String) -> Int
|
||||
// {return write(buf.asUInt8())}
|
||||
func write(buf: String) -> Int
|
||||
// {return write(buf.asUTF8())}
|
||||
}
|
||||
|
||||
// FIXME: Remove the FormattedPrintable[] overload if/when we can forward
|
||||
// variadic arguments.
|
||||
// BLOCKED: <rdar://problem/12134482> Can't forward variadic arguments
|
||||
func printf(out : OutputStreamable, format : String, args : FormattedPrintable[]) {
|
||||
func printf(out: OutputStreamable, format: String, args: FormattedPrintable[]) {
|
||||
var index = 0
|
||||
while !format.isEmpty() {
|
||||
var (before, layout, kind, after) = splitFormat(format)
|
||||
var remainingFormat = format
|
||||
while !remainingFormat.isEmpty() {
|
||||
var (before, layout, kind, after) = splitFormat(remainingFormat)
|
||||
out.write(before)
|
||||
if kind != Char(0) {
|
||||
out.write(args[index++].format(kind, layout))
|
||||
if kind != UnicodeScalar(0) {
|
||||
out.write(args[index++].format(kind, layout: layout))
|
||||
}
|
||||
format = after
|
||||
remainingFormat = after
|
||||
}
|
||||
}
|
||||
|
||||
func printf(out : OutputStreamable, format : String, args : FormattedPrintable...) {
|
||||
func printf(out: OutputStreamable, format: String, args: FormattedPrintable...) {
|
||||
printf(out, format, args)
|
||||
}
|
||||
|
||||
func printf(format : String, args : FormattedPrintable...) {
|
||||
func printf(format: String, args: FormattedPrintable...) {
|
||||
printf(con, format, args)
|
||||
}
|
||||
|
||||
// NOTE: the repl has builtin knowledge of this protocol
|
||||
protocol ReplPrintable {
|
||||
func replPrint()
|
||||
}
|
||||
// FIXME: This function shouldn't be necessary!
|
||||
func replPrint<E : Enumerable requires E.EnumeratorType.Element: ReplPrintable>(s : E) {
|
||||
print('[')
|
||||
func replPrint<E : Sequence where E.GeneratorType.Element: ReplPrintable>(s: E) {
|
||||
print("[")
|
||||
var first = true
|
||||
var total = 0
|
||||
for i in s {
|
||||
@@ -277,25 +308,42 @@ func replPrint<E : Enumerable requires E.EnumeratorType.Element: ReplPrintable>(
|
||||
return
|
||||
}
|
||||
}
|
||||
print(']')
|
||||
print("]")
|
||||
}
|
||||
|
||||
func print<E : Enumerable requires E.EnumeratorType.Element: ReplPrintable>(s : E) {
|
||||
func print<E : Sequence where E.GeneratorType.Element: ReplPrintable>(s: E) {
|
||||
replPrint(s)
|
||||
}
|
||||
|
||||
// Some very basic output functions.
|
||||
func [asmname="_TSs5printFT3valSi_T_"] print(val : Int)
|
||||
func [asmname="_TSs5printFT3valSu_T_"] print(val : UInt64)
|
||||
func [asmname="_TSs5printFT3valSd_T_"] print(val : Double)
|
||||
func print(val : String) {
|
||||
var len = val.byteLength()
|
||||
for var i = 0; i < len; ++i {
|
||||
c_putchar(Int32(val.str_value[i]))
|
||||
}
|
||||
@asmname("print_Int64") func print(value: Int64)
|
||||
@asmname("print_UInt64") func print(value: UInt64)
|
||||
@asmname("print_Double") func print(value: Double)
|
||||
|
||||
func print(value: Int) {
|
||||
print(Int64(value))
|
||||
}
|
||||
func print(val : Char) {
|
||||
var wc = UInt32(val)
|
||||
|
||||
func print(value: UInt) {
|
||||
print(UInt64(value))
|
||||
}
|
||||
|
||||
func print(value: Float) {
|
||||
print(Double(value))
|
||||
}
|
||||
|
||||
func print(value: String) {
|
||||
value._encode(UTF8.self, output: SinkOf<UTF8.CodeUnit> {
|
||||
c_putchar(Int32($0))
|
||||
})
|
||||
}
|
||||
|
||||
func print(value: Character) {
|
||||
print(String(value))
|
||||
}
|
||||
|
||||
func print(value: UnicodeScalar) {
|
||||
var wc = UInt32(value)
|
||||
if wc < 0x000080 {
|
||||
c_putchar(Int32(wc))
|
||||
return
|
||||
@@ -317,12 +365,12 @@ func print(val : Char) {
|
||||
c_putchar(Int32(0x80 | (wc & 0x00003F)))
|
||||
return
|
||||
}
|
||||
// print(Char(0xFFFD))
|
||||
alwaysTrap()
|
||||
// print(UnicodeScalar(0xFFFD))
|
||||
fatal("Invalid Unicode scalar")
|
||||
}
|
||||
|
||||
func print(val : Bool) {
|
||||
if val {
|
||||
func print(value: Bool) {
|
||||
if value {
|
||||
print("true")
|
||||
} else {
|
||||
print("false")
|
||||
@@ -330,40 +378,97 @@ func print(val : Bool) {
|
||||
}
|
||||
|
||||
// Some derived output functions.
|
||||
func println(val : Bool) {
|
||||
print(val)
|
||||
print('\n')
|
||||
func println(value: Bool) {
|
||||
print(value)
|
||||
print("\n")
|
||||
}
|
||||
func println(val : Int) {
|
||||
print(val)
|
||||
print('\n')
|
||||
func println(value: Int) {
|
||||
print(Int64(value))
|
||||
print("\n")
|
||||
}
|
||||
func println(val : UInt8) {
|
||||
print(UInt64(val))
|
||||
print('\n')
|
||||
func println(value: UInt) {
|
||||
print(UInt64(value))
|
||||
print("\n")
|
||||
}
|
||||
func println(val : UInt16) {
|
||||
print(UInt64(val))
|
||||
print('\n')
|
||||
func println(value: UInt8) {
|
||||
print(UInt64(value))
|
||||
print("\n")
|
||||
}
|
||||
func println(val : UInt32) {
|
||||
print(UInt64(val))
|
||||
print('\n')
|
||||
func println(value: UInt16) {
|
||||
print(UInt64(value))
|
||||
print("\n")
|
||||
}
|
||||
func println(val : UInt64) {
|
||||
print(val)
|
||||
print('\n')
|
||||
func println(value: UInt32) {
|
||||
print(UInt64(value))
|
||||
print("\n")
|
||||
}
|
||||
func println(val : Double) {
|
||||
print(val)
|
||||
print('\n')
|
||||
func println(value: UInt64) {
|
||||
print(value)
|
||||
print("\n")
|
||||
}
|
||||
func println(val : String) {
|
||||
print(val)
|
||||
print('\n')
|
||||
func println(value: Float) {
|
||||
print(value)
|
||||
print("\n")
|
||||
}
|
||||
func println(value: Double) {
|
||||
print(value)
|
||||
print("\n")
|
||||
}
|
||||
func println(value: String) {
|
||||
print(value)
|
||||
print("\n")
|
||||
}
|
||||
|
||||
func println(val : Char) {
|
||||
print(val)
|
||||
print('\n')
|
||||
func println(value: Character) {
|
||||
print(value)
|
||||
print("\n")
|
||||
}
|
||||
|
||||
func println(value: UnicodeScalar) {
|
||||
print(value)
|
||||
print("\n")
|
||||
}
|
||||
|
||||
func println() {
|
||||
print("\n")
|
||||
}
|
||||
|
||||
// FIXME: Proof-of-concept kludge to test the runtime basis for a generic
|
||||
// print method.
|
||||
|
||||
/// The runtime has disgustingly inappropriate knowledge of this protocol. If
|
||||
/// you change this, you must also change swift_printAny.
|
||||
protocol Printable {
|
||||
func printSelf()
|
||||
}
|
||||
|
||||
extension Int : Printable {
|
||||
func printSelf() {
|
||||
print(self)
|
||||
}
|
||||
}
|
||||
|
||||
extension String : Printable {
|
||||
func printSelf() {
|
||||
print(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Print any Swift object, using its Printable conformance if it has one,
|
||||
/// falling back to a default implementation.
|
||||
@asmname("swift_printAny") func printAny<T>(x: T)
|
||||
|
||||
extension Array : Printable {
|
||||
func printSelf() {
|
||||
print("[")
|
||||
if !isEmpty {
|
||||
printAny(self[0])
|
||||
for x in self[1...count] {
|
||||
print(", ")
|
||||
printAny(x)
|
||||
}
|
||||
}
|
||||
print("]")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,328 +1,193 @@
|
||||
// RUN: %swift %s -verify -parse-as-library
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Swift Standard Prolog Library.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import SwiftShims
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Standardized aliases
|
||||
//===----------------------------------------------------------------------===//
|
||||
typealias Void = ()
|
||||
typealias Int = Int64
|
||||
typealias UInt = UInt64
|
||||
typealias Float = Float32
|
||||
typealias Double = Float64
|
||||
|
||||
// FIXME/TBD: Consider adding "int", "double", etc as aliases for Int/Double.
|
||||
// They violate the naming convention but lower the barrier to entry.
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Default types for unconstrained number literals
|
||||
// Aliases for floating point types
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FIXME: it should be the other way round, Float = Float32, Double = Float64,
|
||||
// but the type checker loses sugar currently, and ends up displaying 'FloatXX'
|
||||
// in diagnostics.
|
||||
typealias Float32 = Float
|
||||
typealias Float64 = Double
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Default types for unconstrained literals
|
||||
//===----------------------------------------------------------------------===//
|
||||
typealias IntegerLiteralType = Int
|
||||
typealias FloatLiteralType = Double
|
||||
typealias CharacterLiteralType = Char
|
||||
// typealias CharacterLiteralType = ?
|
||||
typealias ExtendedGraphemeClusterType = String
|
||||
typealias StringLiteralType = String
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Default types for unconstrained number literals
|
||||
//===----------------------------------------------------------------------===//
|
||||
typealias MaxBuiltinIntegerType = Builtin.Int128
|
||||
// Integer literals are limited to 2048 bits.
|
||||
// The intent is to have arbitrary-precision literals, but implementing that
|
||||
// requires more work.
|
||||
//
|
||||
// Rationale: 1024 bits are enough to represent the absolute value of min/max
|
||||
// IEEE Binary64, and we need 1 bit to represent the sign. Instead of using
|
||||
// 1025, we use the next round number -- 2048.
|
||||
typealias MaxBuiltinIntegerType = Builtin.Int2048
|
||||
typealias MaxBuiltinFloatType = Builtin.FPIEEE64
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Standard "typeof" function
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
func typeof<T>(x:T) -> T.metatype { return Builtin.typeof(x) }
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Standard protocols
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
typealias Any = protocol<>
|
||||
@class_protocol @objc
|
||||
protocol AnyObject {}
|
||||
|
||||
// FIXME: These protocols are a workaround for
|
||||
// <rdar://problem/13251236> remapping bound function type not
|
||||
// implemented yet
|
||||
protocol Callable {
|
||||
typealias Arguments
|
||||
typealias Result
|
||||
func __call__(args: Arguments) -> Result
|
||||
typealias AnyClass = AnyObject.Type
|
||||
|
||||
func === (lhs: AnyObject?, rhs: AnyObject?) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case (.Some(let l), .Some(let r)):
|
||||
return Bool(Builtin.cmp_eq_RawPointer(
|
||||
Builtin.bridgeToRawPointer(Builtin.castToNativeObject(l)),
|
||||
Builtin.bridgeToRawPointer(Builtin.castToNativeObject(r))
|
||||
))
|
||||
case (.None, .None):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
protocol Predicate : Callable {
|
||||
typealias Result : LogicValue
|
||||
}
|
||||
|
||||
func apply<F: Callable>(f: F, args: F.Arguments) -> F.Result {
|
||||
return f.__call__(args)
|
||||
}
|
||||
|
||||
//
|
||||
// Identifiable
|
||||
//
|
||||
protocol Identifiable {
|
||||
func __eq__(rhs: This) -> Bool
|
||||
}
|
||||
|
||||
func ===<T: Identifiable>(lhs: T, rhs: T) -> Bool {
|
||||
return lhs.__eq__(rhs)
|
||||
}
|
||||
func !==<T: Identifiable>(lhs: T, rhs: T) -> Bool {
|
||||
return !lhs.__eq__(rhs)
|
||||
func !== (lhs: AnyObject?, rhs: AnyObject?) -> Bool {
|
||||
return !(lhs === rhs)
|
||||
}
|
||||
|
||||
//
|
||||
// Equatable
|
||||
//
|
||||
protocol Equatable {
|
||||
func __equal__(rhs: This) -> Bool
|
||||
func == (lhs: Self, rhs: Self) -> Bool
|
||||
}
|
||||
|
||||
func == <T: Equatable>(lhs: T, rhs: T) -> Bool {
|
||||
return lhs.__equal__(rhs)
|
||||
}
|
||||
func != <T: Equatable>(lhs: T, rhs: T) -> Bool {
|
||||
return !lhs.__equal__(rhs)
|
||||
func != <T : Equatable>(lhs: T, rhs: T) -> Bool {
|
||||
return !(lhs == rhs)
|
||||
}
|
||||
|
||||
//
|
||||
// Comparable
|
||||
//
|
||||
protocol Comparable : Equatable {
|
||||
func __less__(rhs : This) -> Bool
|
||||
}
|
||||
func < <T: Comparable>(lhs: T, rhs: T) -> Bool {
|
||||
return lhs.__less__(rhs)
|
||||
}
|
||||
func > <T: Comparable>(lhs: T, rhs: T) -> Bool {
|
||||
return rhs.__less__(lhs)
|
||||
}
|
||||
func <= <T: Comparable>(lhs: T, rhs: T) -> Bool {
|
||||
return !rhs.__less__(lhs)
|
||||
}
|
||||
func >= <T: Comparable>(lhs: T, rhs: T) -> Bool {
|
||||
return !lhs.__less__(rhs)
|
||||
protocol _Comparable {
|
||||
func <(lhs: Self, rhs: Self) -> Bool
|
||||
}
|
||||
|
||||
protocol ForwardIndex : Equatable {
|
||||
func succ() -> This
|
||||
func > <T : _Comparable>(lhs: T, rhs: T) -> Bool {
|
||||
return rhs < lhs
|
||||
}
|
||||
func <= <T : _Comparable>(lhs: T, rhs: T) -> Bool {
|
||||
return !(rhs < lhs)
|
||||
}
|
||||
func >= <T : _Comparable>(lhs: T, rhs: T) -> Bool {
|
||||
return !(lhs < rhs)
|
||||
}
|
||||
|
||||
func [prefix, assignment]
|
||||
++ <T: ForwardIndex> (x: [byref] T)
|
||||
-> T {
|
||||
x = x.succ()
|
||||
return x
|
||||
protocol Comparable : _Comparable, Equatable {
|
||||
func <=(lhs: Self, rhs: Self) -> Bool
|
||||
func >=(lhs: Self, rhs: Self) -> Bool
|
||||
func >(lhs: Self, rhs: Self) -> Bool
|
||||
}
|
||||
|
||||
protocol BitwiseOperations {
|
||||
func & (_: Self, _: Self) -> Self
|
||||
func |(_: Self, _: Self) -> Self
|
||||
func ^(_: Self, _: Self) -> Self
|
||||
@prefix func ~(_: Self) -> Self
|
||||
|
||||
func [postfix, assignment]
|
||||
++ <T: ForwardIndex> (x: [byref] T)
|
||||
-> T {
|
||||
var ret = x
|
||||
x = x.succ()
|
||||
return ret
|
||||
}
|
||||
|
||||
protocol BidirectionalIndex : ForwardIndex {
|
||||
func pred() -> This
|
||||
}
|
||||
|
||||
func [prefix, assignment]
|
||||
-- <T: BidirectionalIndex> (x: [byref] T)
|
||||
-> T {
|
||||
x = x.pred()
|
||||
return x
|
||||
}
|
||||
|
||||
|
||||
func [postfix, assignment]
|
||||
-- <T: BidirectionalIndex> (x: [byref] T)
|
||||
-> T {
|
||||
var ret = x
|
||||
x = x.pred()
|
||||
return ret
|
||||
}
|
||||
|
||||
protocol RandomAccessIndex : BidirectionalIndex, Comparable {
|
||||
typealias DistanceType
|
||||
func __sub__(rhs: This) -> DistanceType
|
||||
func __sub__(rhs: DistanceType) -> This
|
||||
func __add__(offset: DistanceType) -> This
|
||||
// FIXME: Disabled pending <rdar://problem/14011860> (Default
|
||||
// implementations in protocols)
|
||||
func __less__(rhs: This) -> Bool /* {
|
||||
return (lhs.__sub__(rhs)).isNegative()
|
||||
|
||||
} */
|
||||
}
|
||||
|
||||
func [infix] - <T: RandomAccessIndex>(x: T, y: T) -> T.DistanceType {
|
||||
return x.__sub__(y)
|
||||
}
|
||||
|
||||
func [infix] - <T: RandomAccessIndex>(x: T, y: T.DistanceType) -> T {
|
||||
return x.__sub__(y)
|
||||
}
|
||||
|
||||
protocol SignedNumber {
|
||||
func __negate__() -> This
|
||||
func isNegative() -> Bool
|
||||
}
|
||||
|
||||
func [prefix] - <T: SignedNumber> (x: T) -> T {
|
||||
return x.__negate__()
|
||||
}
|
||||
|
||||
func [infix, assignment] +=
|
||||
<T: RandomAccessIndex> (lhs: [byref] T, rhs: T.DistanceType) {
|
||||
lhs = lhs.__add__(rhs)
|
||||
}
|
||||
|
||||
func [infix, assignment] -= <
|
||||
T: RandomAccessIndex requires T.DistanceType: SignedNumber
|
||||
> (lhs: [byref] T, rhs: T.DistanceType) {
|
||||
lhs = lhs.__add__(-rhs)
|
||||
}
|
||||
|
||||
func [infix] +
|
||||
<T: RandomAccessIndex> (lhs: T, rhs: T.DistanceType)
|
||||
-> T {
|
||||
return lhs.__add__(rhs)
|
||||
}
|
||||
|
||||
func [infix] +
|
||||
<T: RandomAccessIndex> (lhs: T.DistanceType, rhs: T)
|
||||
-> T {
|
||||
return rhs.__add__(lhs)
|
||||
}
|
||||
|
||||
func [infix] -
|
||||
<T: RandomAccessIndex requires T.DistanceType: SignedNumber> (
|
||||
lhs: T, rhs: T.DistanceType)
|
||||
-> T {
|
||||
return lhs.__add__(-rhs)
|
||||
/// The identity value for "|" and "^", and the fixed point for "&".
|
||||
///
|
||||
/// ::
|
||||
///
|
||||
/// x | allZeros() == x
|
||||
/// x ^ allZeros() == x
|
||||
/// x & allZeros() == allZeros()
|
||||
/// x & ~allZeros() == x
|
||||
///
|
||||
///
|
||||
/// FIXME: Should be a static property when we support those on protocols.
|
||||
class func allZeros() -> Self
|
||||
}
|
||||
|
||||
protocol Hashable : Equatable {
|
||||
func hashValue() -> Int
|
||||
/// Returns the hash value. The hash value is not guaranteed to be stable
|
||||
/// across different invocations of the same program. Do not persist the hash
|
||||
/// value across program runs.
|
||||
var hashValue: Int { get }
|
||||
}
|
||||
|
||||
/// \brief Protocol describing types that can be used as array bounds.
|
||||
///
|
||||
/// Types that conform to the \c ArrayBound protocol can be used as array bounds
|
||||
/// by providing an operation (\c getArrayBoundValue) that produces an integral
|
||||
/// value.
|
||||
protocol ArrayBound {
|
||||
typealias ArrayBoundType
|
||||
func getArrayBoundValue() -> ArrayBoundType
|
||||
}
|
||||
|
||||
/// \brief Protocol describing types that can be used as logical values within
|
||||
/// a condition.
|
||||
///
|
||||
/// Types that conform to the \c LogicValue protocol can be used as
|
||||
/// condition in various control statements (\c if, \c while, C-style
|
||||
/// \c for) as well as other logical value contexts (e.g., case
|
||||
/// statement guards).
|
||||
protocol LogicValue {
|
||||
func getLogicValue() -> Bool
|
||||
}
|
||||
|
||||
// NOTE: the compiler has builtin knowledge of this protocol
|
||||
protocol Enumerator {
|
||||
// The opposite of a Generator (like an Output Iterator)
|
||||
protocol Sink {
|
||||
typealias Element
|
||||
func isEmpty() -> Bool
|
||||
func next() -> Element
|
||||
mutating func put(x: Element)
|
||||
}
|
||||
|
||||
// NOTE: the compiler has builtin knowledge of this protocol
|
||||
protocol Enumerable {
|
||||
typealias EnumeratorType : Enumerator
|
||||
func getEnumeratorType() -> EnumeratorType
|
||||
func == <T: _RawOptionSet>(a: T, b: T) -> Bool {
|
||||
return a.toRaw() == b.toRaw()
|
||||
}
|
||||
|
||||
// NOTE: the compiler has builtin knowledge of this protocol
|
||||
protocol BuiltinIntegerLiteralConvertible {
|
||||
static func _convertFromBuiltinIntegerLiteral(
|
||||
value : MaxBuiltinIntegerType) -> This
|
||||
/* FIXME: These should be default implementations of the BitwiseOperations
|
||||
conformance for RawOptionSet. */
|
||||
func & <T: RawOptionSet>(a: T, b: T) -> T {
|
||||
return T.fromMask(a.toRaw() & b.toRaw())
|
||||
}
|
||||
func | <T: RawOptionSet>(a: T, b: T) -> T {
|
||||
return T.fromMask(a.toRaw() | b.toRaw())
|
||||
}
|
||||
func ^ <T: RawOptionSet>(a: T, b: T) -> T {
|
||||
return T.fromMask(a.toRaw() ^ b.toRaw())
|
||||
}
|
||||
@prefix func ~ <T: RawOptionSet>(a: T) -> T {
|
||||
return T.fromMask(~a.toRaw())
|
||||
}
|
||||
|
||||
// NOTE: the compiler has builtin knowledge of this protocol
|
||||
protocol IntegerLiteralConvertible {
|
||||
typealias IntegerLiteralType : BuiltinIntegerLiteralConvertible
|
||||
static func convertFromIntegerLiteral(value : IntegerLiteralType) -> This
|
||||
}
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Standard pattern matching forms
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// NOTE: the compiler has builtin knowledge of this protocol
|
||||
protocol BuiltinFloatLiteralConvertible {
|
||||
static func _convertFromBuiltinFloatLiteral(
|
||||
value : MaxBuiltinFloatType) -> This
|
||||
}
|
||||
|
||||
// NOTE: the compiler has builtin knowledge of this protocol
|
||||
protocol FloatLiteralConvertible {
|
||||
typealias FloatLiteralType : BuiltinFloatLiteralConvertible
|
||||
static func convertFromFloatLiteral(value : FloatLiteralType) -> This
|
||||
}
|
||||
|
||||
// NOTE: the compiler has builtin knowledge of this protocol
|
||||
protocol BuiltinCharacterLiteralConvertible {
|
||||
static func _convertFromBuiltinCharacterLiteral(value : Builtin.Int32) -> This
|
||||
}
|
||||
|
||||
// NOTE: the compiler has builtin knowledge of this protocol
|
||||
protocol CharacterLiteralConvertible {
|
||||
typealias CharacterLiteralType : BuiltinCharacterLiteralConvertible
|
||||
static func convertFromCharacterLiteral(value : CharacterLiteralType) -> This
|
||||
}
|
||||
|
||||
// NOTE: the compiler has builtin knowledge of this protocol
|
||||
protocol BuiltinStringLiteralConvertible {
|
||||
static func _convertFromBuiltinStringLiteral(value : Builtin.RawPointer,
|
||||
byteSize : Builtin.Int64,
|
||||
isASCII: Builtin.Int1) -> This
|
||||
}
|
||||
|
||||
// NOTE: the compiler has builtin knowledge of this protocol
|
||||
protocol StringLiteralConvertible {
|
||||
typealias StringLiteralType : BuiltinStringLiteralConvertible
|
||||
static func convertFromStringLiteral(value : StringLiteralType) -> This
|
||||
}
|
||||
|
||||
// NOTE: the compiler has builtin knowledge of this protocol
|
||||
protocol ArrayLiteralConvertible {
|
||||
typealias Element
|
||||
static func convertFromArrayLiteral(elements : Element...) -> This
|
||||
}
|
||||
|
||||
// NOTE: the compiler has builtin knowledge of this protocol
|
||||
protocol DictionaryLiteralConvertible {
|
||||
typealias Key
|
||||
typealias Value
|
||||
static func convertFromDictionaryLiteral(elements:(Key, Value)...) -> This
|
||||
}
|
||||
|
||||
// NOTE: the compiler has builtin knowledge of this protocol
|
||||
protocol StringInterpolationConvertible {
|
||||
static func convertFromStringInterpolation(strings : This...) -> This
|
||||
}
|
||||
|
||||
// NOTE: the repl has builtin knowledge of this protocol
|
||||
// FIXME: This should be intrinsically available for any metatype--need a
|
||||
// metatype root type
|
||||
protocol ClassNameable {
|
||||
static func className() -> String
|
||||
// Equatable types can be matched in patterns by value equality.
|
||||
@transparent @infix
|
||||
func ~= <T : Equatable> (a: T, b: T) -> Bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Standard operators
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Standard postfix operators.
|
||||
operator postfix ++ {}
|
||||
operator postfix -- {}
|
||||
|
||||
// Optional<T> unwrapping operator is built into the compiler as a part of
|
||||
// postfix expression grammar.
|
||||
//
|
||||
// operator postfix ! {}
|
||||
|
||||
// Standard prefix operators.
|
||||
operator prefix ++ {}
|
||||
operator prefix -- {}
|
||||
operator prefix ! {}
|
||||
@@ -330,154 +195,89 @@ operator prefix ~ {}
|
||||
operator prefix + {}
|
||||
operator prefix - {}
|
||||
|
||||
operator infix * {
|
||||
associativity left
|
||||
precedence 200
|
||||
}
|
||||
operator infix / {
|
||||
associativity left
|
||||
precedence 200
|
||||
}
|
||||
operator infix % {
|
||||
associativity left
|
||||
precedence 200
|
||||
}
|
||||
// Standard infix operators.
|
||||
|
||||
operator infix + {
|
||||
associativity left
|
||||
precedence 190
|
||||
}
|
||||
operator infix - {
|
||||
associativity left
|
||||
precedence 190
|
||||
}
|
||||
// "Exponentiative"
|
||||
|
||||
operator infix << {
|
||||
associativity none
|
||||
precedence 180
|
||||
}
|
||||
operator infix >> {
|
||||
associativity none
|
||||
precedence 180
|
||||
}
|
||||
operator infix << { associativity none precedence 160 }
|
||||
operator infix >> { associativity none precedence 160 }
|
||||
|
||||
operator infix .. {
|
||||
associativity none
|
||||
precedence 175
|
||||
}
|
||||
// "Multiplicative"
|
||||
|
||||
operator infix < {
|
||||
associativity none
|
||||
precedence 170
|
||||
}
|
||||
operator infix <= {
|
||||
associativity none
|
||||
precedence 170
|
||||
}
|
||||
operator infix > {
|
||||
associativity none
|
||||
precedence 170
|
||||
}
|
||||
operator infix >= {
|
||||
associativity none
|
||||
precedence 170
|
||||
}
|
||||
operator infix * { associativity left precedence 150 }
|
||||
operator infix &* { associativity left precedence 150 }
|
||||
operator infix / { associativity left precedence 150 }
|
||||
operator infix &/ { associativity left precedence 150 }
|
||||
operator infix % { associativity left precedence 150 }
|
||||
operator infix &% { associativity left precedence 150 }
|
||||
operator infix & { associativity left precedence 150 }
|
||||
|
||||
operator infix == {
|
||||
associativity none
|
||||
precedence 160
|
||||
}
|
||||
operator infix != {
|
||||
associativity none
|
||||
precedence 160
|
||||
}
|
||||
operator infix === {
|
||||
associativity none
|
||||
precedence 160
|
||||
}
|
||||
operator infix !== {
|
||||
associativity none
|
||||
precedence 160
|
||||
}
|
||||
// "Additive"
|
||||
|
||||
operator infix & {
|
||||
associativity left
|
||||
precedence 150
|
||||
}
|
||||
operator infix + { associativity left precedence 140 }
|
||||
operator infix &+ { associativity left precedence 140 }
|
||||
operator infix - { associativity left precedence 140 }
|
||||
operator infix &- { associativity left precedence 140 }
|
||||
operator infix | { associativity left precedence 140 }
|
||||
operator infix ^ { associativity left precedence 140 }
|
||||
|
||||
operator infix ^ {
|
||||
associativity left
|
||||
precedence 140
|
||||
}
|
||||
// FIXME: is this the right precedence level for "..." ?
|
||||
operator infix ... { associativity none precedence 135 }
|
||||
operator infix .. { associativity none precedence 135 }
|
||||
|
||||
operator infix | {
|
||||
associativity left
|
||||
precedence 130
|
||||
}
|
||||
// The cast operators 'as' and 'is' are hardcoded as if they had the
|
||||
// following attributes:
|
||||
// operator infix as { associativity none precedence 132 }
|
||||
|
||||
operator infix && {
|
||||
associativity left
|
||||
precedence 120
|
||||
}
|
||||
// "Comparative"
|
||||
|
||||
operator infix < { associativity none precedence 130 }
|
||||
operator infix <= { associativity none precedence 130 }
|
||||
operator infix > { associativity none precedence 130 }
|
||||
operator infix >= { associativity none precedence 130 }
|
||||
operator infix == { associativity none precedence 130 }
|
||||
operator infix != { associativity none precedence 130 }
|
||||
operator infix === { associativity none precedence 130 }
|
||||
operator infix !== { associativity none precedence 130 }
|
||||
// FIXME: ~= will be built into the compiler.
|
||||
operator infix ~= { associativity none precedence 130 }
|
||||
|
||||
// "Conjunctive"
|
||||
|
||||
operator infix && { associativity left precedence 120 }
|
||||
|
||||
// "Disjunctive"
|
||||
|
||||
operator infix || { associativity left precedence 110 }
|
||||
|
||||
operator infix || {
|
||||
associativity left
|
||||
precedence 110
|
||||
}
|
||||
|
||||
// User-defined ternary operators are not supported. The ? : operator is
|
||||
// hardcoded as if it had the following attributes:
|
||||
// operator ternary ? : {
|
||||
// associativity right
|
||||
// precedence 100
|
||||
// }
|
||||
// operator ternary ? : { associativity right precedence 100 }
|
||||
|
||||
operator infix *= {
|
||||
associativity right
|
||||
precedence 90
|
||||
}
|
||||
operator infix /= {
|
||||
associativity right
|
||||
precedence 90
|
||||
}
|
||||
operator infix %= {
|
||||
associativity right
|
||||
precedence 90
|
||||
}
|
||||
operator infix += {
|
||||
associativity right
|
||||
precedence 90
|
||||
}
|
||||
operator infix -= {
|
||||
associativity right
|
||||
precedence 90
|
||||
}
|
||||
operator infix <<= {
|
||||
associativity right
|
||||
precedence 90
|
||||
}
|
||||
operator infix >>= {
|
||||
associativity right
|
||||
precedence 90
|
||||
}
|
||||
operator infix &= {
|
||||
associativity right
|
||||
precedence 90
|
||||
}
|
||||
operator infix ^= {
|
||||
associativity right
|
||||
precedence 90
|
||||
}
|
||||
operator infix |= {
|
||||
associativity right
|
||||
precedence 90
|
||||
}
|
||||
operator infix &&= {
|
||||
associativity right
|
||||
precedence 90
|
||||
}
|
||||
operator infix ||= {
|
||||
associativity right
|
||||
precedence 90
|
||||
}
|
||||
// User-defined assignment operators are not supported. The = operator is
|
||||
// hardcoded as if it had the following attributes:
|
||||
// operator infix = { associativity right precedence 90 }
|
||||
|
||||
// Compound
|
||||
|
||||
operator infix *= { associativity right precedence 90 }
|
||||
operator infix /= { associativity right precedence 90 }
|
||||
operator infix %= { associativity right precedence 90 }
|
||||
operator infix += { associativity right precedence 90 }
|
||||
operator infix -= { associativity right precedence 90 }
|
||||
operator infix <<= { associativity right precedence 90 }
|
||||
operator infix >>= { associativity right precedence 90 }
|
||||
operator infix &= { associativity right precedence 90 }
|
||||
operator infix ^= { associativity right precedence 90 }
|
||||
operator infix |= { associativity right precedence 90 }
|
||||
operator infix &&= { associativity right precedence 90 }
|
||||
operator infix ||= { associativity right precedence 90 }
|
||||
|
||||
// Workaround for <rdar://problem/14011860> SubTLF: Default
|
||||
// implementations in protocols. Library authors should ensure
|
||||
// that this operator never needs to be seen by end-users. See
|
||||
// test/Prototypes/GenericDispatch.swift for a fully documented
|
||||
// example of how this operator is used, and how its use can be hidden
|
||||
// from users.
|
||||
operator infix ~> { associativity left precedence 255 }
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 _Process {
|
||||
// This variable gets (re-)initialized on-demand to reflect the actual argument vector
|
||||
var _arguments : String[]
|
||||
// Use lazy initialization of static properties to safely initialize the
|
||||
// public 'arguments' property on first use.
|
||||
static var _arguments: String[] = {
|
||||
// FIXME: Use a by-index-initializing constructor of Array here when we
|
||||
// have that, so we don't need this awkward closure initialization.
|
||||
var _args = new String[Int(C_ARGC)]
|
||||
for i in 0...Int(C_ARGC) {
|
||||
_args[i] = String.fromCString(C_ARGV[i])
|
||||
}
|
||||
return _args
|
||||
}()
|
||||
|
||||
var arguments : String[] {
|
||||
// FIXME: this is not thread-safe. rdar://14193840
|
||||
if _arguments.length == 0 {
|
||||
_arguments = new String[Int(C_ARGC)]
|
||||
for i in 0..Int(C_ARGC) {
|
||||
_arguments[i] = String.fromCString(C_ARGV[i])
|
||||
}
|
||||
}
|
||||
return _arguments
|
||||
return _Process._arguments
|
||||
}
|
||||
}
|
||||
|
||||
var Process : _Process
|
||||
var Process : _Process = _Process()
|
||||
|
||||
@@ -1,18 +1,32 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// FIXME: Function types don't work yet as generic parameters
|
||||
struct REPLExitHandler {
|
||||
struct _REPLExitHandler {
|
||||
var f : () -> ()
|
||||
|
||||
init(_ f: () -> ()) {
|
||||
self.f = f
|
||||
}
|
||||
}
|
||||
|
||||
var replExitHandlers : Vector<REPLExitHandler> = Vector<REPLExitHandler>()
|
||||
var _replExitHandlers = _REPLExitHandler[]()
|
||||
|
||||
func atREPLExit(handler:() -> ()) {
|
||||
replExitHandlers.append(REPLExitHandler(handler))
|
||||
func _atREPLExit(handler: () -> ()) {
|
||||
_replExitHandlers.append(_REPLExitHandler(handler))
|
||||
}
|
||||
|
||||
func replExit() {
|
||||
while replExitHandlers.length > 0 {
|
||||
var handler = replExitHandlers[replExitHandlers.length-1]
|
||||
replExitHandlers.popBack()
|
||||
func _replExit() {
|
||||
for handler in Reverse(_replExitHandlers) {
|
||||
handler.f()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,305 +1,199 @@
|
||||
struct RangeEnumerator<T: ForwardIndex> : Enumerator, Enumerable {
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 RangeGenerator<T: ForwardIndex> : Generator, Sequence {
|
||||
typealias Element = T
|
||||
|
||||
constructor(begin: T, end: T) {
|
||||
this.begin_.value = begin
|
||||
this.end_.value = end
|
||||
@transparent
|
||||
init(_ bounds: Range<T>) {
|
||||
self.startIndex = bounds.startIndex
|
||||
self.endIndex = bounds.endIndex
|
||||
}
|
||||
|
||||
func isEmpty() -> Bool {
|
||||
return begin_.value == end_.value
|
||||
mutating func next() -> Element? {
|
||||
if startIndex == endIndex {
|
||||
return .None
|
||||
}
|
||||
return startIndex++
|
||||
}
|
||||
|
||||
func next() -> Element {
|
||||
var ret = begin_.value
|
||||
begin_.value = begin_.value.succ()
|
||||
// Every Generator is also a single-pass Sequence
|
||||
typealias GeneratorType = RangeGenerator<T>
|
||||
func generate() -> GeneratorType {
|
||||
return self
|
||||
}
|
||||
|
||||
var startIndex: T
|
||||
var endIndex: T
|
||||
}
|
||||
|
||||
struct StridedRangeGenerator<T: ForwardIndex> : Generator, Sequence {
|
||||
typealias Element = T
|
||||
|
||||
@transparent
|
||||
init(_ bounds: Range<T>, stride: T.DistanceType) {
|
||||
self._bounds = bounds
|
||||
self._stride = stride
|
||||
}
|
||||
|
||||
mutating func next() -> Element? {
|
||||
if !_bounds {
|
||||
return .None
|
||||
}
|
||||
let ret = _bounds.startIndex
|
||||
_bounds.startIndex = advance(_bounds.startIndex, _stride, _bounds.endIndex)
|
||||
return ret
|
||||
}
|
||||
|
||||
// Every Enumerator is also a single-pass Enumerable
|
||||
typealias EnumeratorType = RangeEnumerator<T>
|
||||
func getEnumeratorType() -> EnumeratorType {
|
||||
return this
|
||||
// Every Generator is also a single-pass Sequence
|
||||
typealias GeneratorType = StridedRangeGenerator
|
||||
func generate() -> GeneratorType {
|
||||
return self
|
||||
}
|
||||
|
||||
var begin_, end_: GenericIVar<T>
|
||||
var _bounds: Range<T>
|
||||
var _stride: T.DistanceType
|
||||
}
|
||||
|
||||
struct Range<T: ForwardIndex> : Enumerable {
|
||||
constructor(begin: T, end: T) {
|
||||
this.begin_.value = begin
|
||||
this.end_.value = end
|
||||
struct Range<T: ForwardIndex> : LogicValue, Sliceable {
|
||||
@transparent
|
||||
init(start: T, end: T) {
|
||||
_startIndex = start
|
||||
_endIndex = end
|
||||
}
|
||||
|
||||
func isEmpty() -> Bool {
|
||||
return begin_.value == end_.value
|
||||
return startIndex == endIndex
|
||||
}
|
||||
|
||||
func begin() -> T {
|
||||
return begin_.value
|
||||
}
|
||||
func end() -> T {
|
||||
return end_.value
|
||||
func getLogicValue() -> Bool {
|
||||
return !isEmpty()
|
||||
}
|
||||
|
||||
typealias EnumeratorType = RangeEnumerator<T>
|
||||
func getEnumeratorType() -> EnumeratorType {
|
||||
return EnumeratorType(begin_.value, end_.value)
|
||||
subscript(i: T) -> T {
|
||||
return i
|
||||
}
|
||||
|
||||
var begin_, end_: GenericIVar<T>
|
||||
subscript(x: Range<T>) -> Range {
|
||||
return Range(start: x.startIndex, end: x.endIndex)
|
||||
}
|
||||
|
||||
typealias GeneratorType = RangeGenerator<T>
|
||||
func generate() -> RangeGenerator<T> {
|
||||
return GeneratorType(self)
|
||||
}
|
||||
|
||||
func by(stride: T.DistanceType) -> StridedRangeGenerator<T> {
|
||||
return StridedRangeGenerator(self, stride: stride)
|
||||
}
|
||||
|
||||
var startIndex: T {
|
||||
get {
|
||||
return _startIndex
|
||||
}
|
||||
set(newValue) {
|
||||
_startIndex = newValue
|
||||
}
|
||||
}
|
||||
|
||||
var endIndex: T {
|
||||
get {
|
||||
return _endIndex
|
||||
}
|
||||
set(newValue) {
|
||||
_endIndex = newValue
|
||||
}
|
||||
}
|
||||
|
||||
var _startIndex: T
|
||||
var _endIndex: T
|
||||
}
|
||||
|
||||
/// \brief Any model of ForwardIndex can be turned into a Range with min..max
|
||||
func .. <Pos: ForwardIndex> (min : Pos, max : Pos) -> Range<Pos> {
|
||||
return Range(min, max)
|
||||
func count<I: RandomAccessIndex>(r: Range<I>) -> I.DistanceType {
|
||||
return r.startIndex.distanceTo(r.endIndex)
|
||||
}
|
||||
|
||||
struct ReverseRangeEnumerator<T: BidirectionalIndex> : Enumerator, Enumerable {
|
||||
/// \brief Any model of ForwardIndex can be turned into a Range with min...max
|
||||
@transparent
|
||||
func ... <Pos : ForwardIndex> (min: Pos, max: Pos) -> Range<Pos> {
|
||||
return Range(start: min, end: max)
|
||||
}
|
||||
|
||||
@transparent
|
||||
func .. <Pos : ForwardIndex> (min: Pos, max: Pos) -> Range<Pos> {
|
||||
return Range(start: min, end: max.succ())
|
||||
}
|
||||
|
||||
struct ReverseRangeGenerator<T: BidirectionalIndex> : Generator, Sequence {
|
||||
typealias Element = T
|
||||
|
||||
constructor(begin: T, end: T) {
|
||||
this.begin_.value = begin
|
||||
this.end_.value = end
|
||||
@transparent
|
||||
init(start: T, pastEnd: T) {
|
||||
self._bounds = (start,pastEnd)
|
||||
}
|
||||
|
||||
mutating func next() -> Element? {
|
||||
if _bounds.0 == _bounds.1 { return .None }
|
||||
_bounds.1 = _bounds.1.pred()
|
||||
return _bounds.1
|
||||
}
|
||||
|
||||
// Every Generator is also a single-pass Sequence
|
||||
typealias GeneratorType = ReverseRangeGenerator<T>
|
||||
func generate() -> GeneratorType {
|
||||
return self
|
||||
}
|
||||
|
||||
var _bounds: (T, T)
|
||||
}
|
||||
|
||||
struct ReverseRange<T: BidirectionalIndex> : Sequence {
|
||||
init(start: T, pastEnd: T) {
|
||||
self._bounds = (start, pastEnd)
|
||||
}
|
||||
|
||||
init(range fwd: Range<T>) {
|
||||
self._bounds = (fwd.startIndex, fwd.endIndex)
|
||||
}
|
||||
|
||||
func isEmpty() -> Bool {
|
||||
return begin_.value == end_.value
|
||||
return _bounds.0 == _bounds.1
|
||||
}
|
||||
|
||||
func next() -> Element {
|
||||
end_.value = end_.value.pred()
|
||||
return end_.value
|
||||
func bounds() -> (T, T) {
|
||||
return _bounds
|
||||
}
|
||||
|
||||
// Every Enumerator is also a single-pass Enumerable
|
||||
typealias EnumeratorType = ReverseRangeEnumerator<T>
|
||||
func getEnumeratorType() -> EnumeratorType {
|
||||
return this
|
||||
typealias GeneratorType = ReverseRangeGenerator<T>
|
||||
func generate() -> GeneratorType {
|
||||
return GeneratorType(start: _bounds.0, pastEnd: _bounds.1)
|
||||
}
|
||||
|
||||
var begin_, end_: GenericIVar<T>
|
||||
var _bounds: (T, T)
|
||||
}
|
||||
|
||||
struct ReverseRange<T: BidirectionalIndex> : Enumerable {
|
||||
constructor(begin: T, end: T) {
|
||||
this.begin_.value = begin
|
||||
this.end_.value = end
|
||||
}
|
||||
//
|
||||
// Pattern matching support for ranges
|
||||
//
|
||||
// Ranges can be used to match values contained within the range, e.g.:
|
||||
// switch x {
|
||||
// case 0...10:
|
||||
// println("single digit")
|
||||
// case _:
|
||||
// println("too big")
|
||||
// }
|
||||
|
||||
constructor(fwd: Range<T>) {
|
||||
this.begin_.value = fwd.begin()
|
||||
this.end_.value = fwd.end()
|
||||
}
|
||||
|
||||
func isEmpty() -> Bool {
|
||||
return begin_.value == end_.value
|
||||
}
|
||||
|
||||
func begin() -> T {
|
||||
return begin_.value
|
||||
}
|
||||
|
||||
func end() -> T {
|
||||
return end_.value
|
||||
}
|
||||
|
||||
typealias EnumeratorType = ReverseRangeEnumerator<T>
|
||||
func getEnumeratorType() -> EnumeratorType {
|
||||
return EnumeratorType(begin_.value, end_.value)
|
||||
}
|
||||
|
||||
var begin_, end_: GenericIVar<T>
|
||||
}
|
||||
|
||||
// FIXME: make generic
|
||||
// BLOCKED: <rdar://problem/12780068> Crash while trying to make iteration generic
|
||||
struct IntEnumeratorType : Enumerator, Enumerable {
|
||||
typealias Element = Int
|
||||
var min : Int
|
||||
var max : Int
|
||||
var stride : Int
|
||||
|
||||
// FIXME: each/reduce should be moved out to generic methods, or methods that
|
||||
// take the range as a protocol'd "enumeration/iterator" value.
|
||||
func each(f : (Int) -> Void) {
|
||||
for i in this { f(i) }
|
||||
}
|
||||
|
||||
func reduce(val : Int, f : (Int, Int) -> Int) -> Int {
|
||||
for i in this { val = f(val, i) }
|
||||
return val
|
||||
}
|
||||
|
||||
func by(s : Int) -> IntEnumeratorType {
|
||||
var result = this
|
||||
result.stride = s
|
||||
return result
|
||||
}
|
||||
|
||||
func isEmpty() -> Bool {
|
||||
return min >= max
|
||||
}
|
||||
func contains(x : Int) -> Bool {
|
||||
return min <= x && x < max
|
||||
}
|
||||
|
||||
func next() -> Int {
|
||||
var prev = min
|
||||
min += stride
|
||||
return prev
|
||||
}
|
||||
|
||||
typealias EnumeratorType = IntEnumeratorType
|
||||
func getEnumeratorType() -> IntEnumeratorType {
|
||||
return this
|
||||
}
|
||||
|
||||
func replPrint() {
|
||||
print("\(min)..\(max)")
|
||||
if stride != 1 {
|
||||
print(" by \(stride)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension IntEnumeratorType : Equatable, Hashable {
|
||||
func __equal__(rhs: IntEnumeratorType) -> Bool {
|
||||
return min == rhs.min && max == rhs.max && stride == rhs.stride
|
||||
}
|
||||
func hashValue() -> Int {
|
||||
return min ^ max
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: make generic
|
||||
// BLOCKED: <rdar://problem/12780068> Crash while trying to make iteration generic
|
||||
struct ReverseIntEnumeratorType : Enumerator, Enumerable {
|
||||
typealias Element = Int
|
||||
var min : Int
|
||||
var max : Int
|
||||
var stride : Int
|
||||
|
||||
// FIXME: each/reduce should be moved out to generic methods, or methods that
|
||||
// take the range as a protocol'd "enumeration/iterator" value.
|
||||
func each(f : (Int) -> Void) {
|
||||
for i in this { f(i) }
|
||||
}
|
||||
|
||||
func reduce(val : Int, f : (Int, Int) -> Int) -> Int {
|
||||
for i in this { val = f(val, i) }
|
||||
return val
|
||||
}
|
||||
|
||||
func isEmpty() -> Bool {
|
||||
return min >= max
|
||||
}
|
||||
func contains(x : Int) -> Bool {
|
||||
return min <= x && x < max
|
||||
}
|
||||
func next() -> Int {
|
||||
max -= stride
|
||||
return max
|
||||
}
|
||||
|
||||
typealias EnumeratorType = ReverseIntEnumeratorType
|
||||
func getEnumeratorType() -> ReverseIntEnumeratorType {
|
||||
return this
|
||||
}
|
||||
|
||||
func replPrint() {
|
||||
print("reverse(\(min)..\(max))")
|
||||
if stride != 1 {
|
||||
print(" by \(stride)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ReverseIntEnumeratorType : Equatable, Hashable {
|
||||
func __equal__(rhs: ReverseIntEnumeratorType) -> Bool {
|
||||
return min == rhs.min && max == rhs.max && stride == rhs.stride
|
||||
}
|
||||
func hashValue() -> Int {
|
||||
return min ^ max
|
||||
}
|
||||
}
|
||||
|
||||
func reverse<T: BidirectionalIndex>(rng: Range<T>) -> ReverseRange<T> {
|
||||
return ReverseRange(rng.begin(), rng.end())
|
||||
}
|
||||
|
||||
func reverse<T: BidirectionalIndex>(rng: ReverseRange<T>) -> Range<T> {
|
||||
return Range(rng.begin(), rng.end())
|
||||
}
|
||||
|
||||
func reverse(rng : IntEnumeratorType) -> ReverseIntEnumeratorType {
|
||||
return ReverseIntEnumeratorType(rng.min, rng.max, rng.stride)
|
||||
}
|
||||
|
||||
func reverse(rng : ReverseIntEnumeratorType) -> IntEnumeratorType {
|
||||
return IntEnumeratorType(rng.min, rng.max, rng.stride)
|
||||
}
|
||||
|
||||
func .. (min : Int, max : Int) -> IntEnumeratorType {
|
||||
return IntEnumeratorType(min, max, 1)
|
||||
}
|
||||
|
||||
// FIXME: make generic
|
||||
// BLOCKED: <rdar://problem/12780068> Crash while trying to make iteration generic
|
||||
struct DoubleEnumeratorType : Enumerator, Enumerable {
|
||||
typealias Element = Double
|
||||
var min : Double,
|
||||
max : Double,
|
||||
stride : Double
|
||||
|
||||
// FIXME: each/reduce should be moved out to generic methods, or methods that
|
||||
// take the range as a protocol'd "enumeration/iterator" value.
|
||||
func each(f : (Double) -> Void) {
|
||||
for i in this { f(i) }
|
||||
}
|
||||
|
||||
func reduce(val : Double, f : (Double, Double) -> Double) -> Double {
|
||||
for i in this { val = f(val, i) }
|
||||
return val
|
||||
}
|
||||
|
||||
func by(s : Double) -> DoubleEnumeratorType {
|
||||
var result = this
|
||||
result.stride = s
|
||||
return result
|
||||
}
|
||||
|
||||
func isEmpty() -> Bool {
|
||||
return min >= max
|
||||
}
|
||||
func next() -> Double {
|
||||
var prev = min
|
||||
min += stride
|
||||
return prev
|
||||
}
|
||||
|
||||
typealias EnumeratorType = DoubleEnumeratorType
|
||||
func getEnumeratorType() -> DoubleEnumeratorType {
|
||||
return this
|
||||
}
|
||||
|
||||
func replPrint() {
|
||||
print("\(min)..\(max)")
|
||||
if stride != 1.0 {
|
||||
print(" by \(stride)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension DoubleEnumeratorType : Equatable, Hashable {
|
||||
func __equal__(rhs: DoubleEnumeratorType) -> Bool {
|
||||
return min == rhs.min && max == rhs.max && stride == rhs.stride
|
||||
}
|
||||
func hashValue() -> Int {
|
||||
return min.hashValue() ^ max.hashValue()
|
||||
}
|
||||
}
|
||||
|
||||
func .. (min : Double, max : Double) -> DoubleEnumeratorType {
|
||||
return DoubleEnumeratorType(min, max, 1.0)
|
||||
@infix func ~= <T: RandomAccessIndex where T.DistanceType : SignedInteger>(x: Range<T>, y: T) -> Bool {
|
||||
let a = x.startIndex.distanceTo(y) >= 0
|
||||
let b = y.distanceTo(x.endIndex) > 0
|
||||
return a && b
|
||||
}
|
||||
|
||||
@@ -21,83 +21,392 @@ protocol Reflectable {
|
||||
}
|
||||
|
||||
/// A unique identifier for a class instance. This can be used by reflection
|
||||
/// clients to avoid visiting cycles in the object graph.
|
||||
/// clients to recognize cycles in the object graph.
|
||||
///
|
||||
/// In Swift, only class instances have unique identities. There is no notion
|
||||
/// of identity for structs, enums, or tuples.
|
||||
struct ObjectIdentifier : Hashable {
|
||||
val value: Builtin.RawPointer
|
||||
let value: Builtin.RawPointer
|
||||
|
||||
func uintValue() -> UInt {
|
||||
return UInt(Builtin.ptrtoint_Word(value))
|
||||
}
|
||||
|
||||
// FIXME: Better hashing algorithm
|
||||
func hashValue() -> Int {
|
||||
var hashValue: Int {
|
||||
return Int(Builtin.ptrtoint_Word(value))
|
||||
}
|
||||
|
||||
init(_ x: AnyObject) {
|
||||
self.value = reinterpretCast(x)
|
||||
}
|
||||
}
|
||||
func ==(x: ObjectIdentifier, y: ObjectIdentifier) -> Bool {
|
||||
return Bool(Builtin.cmp_eq_RawPointer(x.value, y.value))
|
||||
}
|
||||
|
||||
/// The sum of types that can be used as a quick look representation.
|
||||
///
|
||||
/// This type must be binary-compatible with the 'QuickLookObject' struct in
|
||||
/// stdlib/Runtime/Reflection.mm, and 'QuickLookObject?' must be binary
|
||||
/// compatible with 'OptionalQuickLookObject' from the same.
|
||||
///
|
||||
/// NB: This type is somewhat carefully laid out to *suppress* enum layout
|
||||
/// optimization so that it is easier to manufacture in the C++ runtime
|
||||
/// implementation.
|
||||
enum QuickLookObject {
|
||||
/// Plain text.
|
||||
case Text(String)
|
||||
|
||||
/// An integer numeric value.
|
||||
case Int(Int64)
|
||||
|
||||
/// An unsigned integer numeric value.
|
||||
case UInt(UInt64)
|
||||
|
||||
/// A floating-point numeric value.
|
||||
case Float(Double)
|
||||
|
||||
/// An image.
|
||||
/// FIXME: Uses an Any to avoid coupling a particular Cocoa type.
|
||||
case Image(Any)
|
||||
|
||||
/// A sound.
|
||||
/// FIXME: Uses an Any to avoid coupling a particular Cocoa type.
|
||||
case Sound(Any)
|
||||
|
||||
/// A color.
|
||||
/// FIXME: Uses an Any to avoid coupling a particular Cocoa type.
|
||||
case Color(Any)
|
||||
|
||||
/// A bezier path.
|
||||
/// FIXME: Uses an Any to avoid coupling a particular Cocoa type.
|
||||
case BezierPath(Any)
|
||||
|
||||
/// An attributed string.
|
||||
/// FIXME: Uses an Any to avoid coupling a particular Cocoa type.
|
||||
case AttributedString(Any)
|
||||
|
||||
/// A rectangle
|
||||
/// Uses explicit coordinates to avoid coupling a particular Cocoa type.
|
||||
case Rectangle(Double,Double,Double,Double)
|
||||
|
||||
/// A point
|
||||
/// Uses explicit coordinates to avoid coupling a particular Cocoa type.
|
||||
case Point(Double,Double)
|
||||
|
||||
/// A size
|
||||
/// Uses explicit coordinates to avoid coupling a particular Cocoa type.
|
||||
case Size(Double,Double)
|
||||
|
||||
/// A logical value
|
||||
case Logical(Bool)
|
||||
|
||||
/// A range
|
||||
/// Uses explicit values to avoid coupling a particular Cocoa type.
|
||||
case Range(UInt64, UInt64)
|
||||
|
||||
/// A GUI view
|
||||
/// Uses an Any to avoid coupling a particular Cocoa type.
|
||||
case View(Any)
|
||||
|
||||
/// A graphical sprite
|
||||
/// Uses an Any to avoid coupling a particular Cocoa type.
|
||||
case Sprite(Any)
|
||||
|
||||
/// A Uniform Resource Locator
|
||||
case URL(String)
|
||||
|
||||
/// Raw data that has already been encoded in a format the IDE understands.
|
||||
case _Raw(UInt8[], String)
|
||||
}
|
||||
|
||||
/// How children of this value should be presented in the IDE.
|
||||
enum MirrorDisposition {
|
||||
/// As a struct.
|
||||
case Struct
|
||||
/// As a class.
|
||||
case Class
|
||||
/// As an enum.
|
||||
case Enum
|
||||
/// As a tuple.
|
||||
case Tuple
|
||||
/// As a miscellaneous aggregate with a fixed set of children.
|
||||
case Aggregate
|
||||
/// As a container that is accessed by index.
|
||||
case IndexContainer
|
||||
/// As a container that is accessed by key.
|
||||
case KeyContainer
|
||||
/// As a container that represents membership of its values.
|
||||
case MembershipContainer
|
||||
/// As a miscellaneous container with a variable number of children.
|
||||
case Container
|
||||
/// An Optional which can have either zero or one children.
|
||||
case Optional
|
||||
}
|
||||
|
||||
/// A protocol that provides a reflection interface to an underlying value.
|
||||
protocol Mirror {
|
||||
// The runtime has inappropriate knowledge of this protocol and how its
|
||||
// witness tables are laid out. Changing this protocol requires a
|
||||
// corresponding change to Reflection.cpp.
|
||||
|
||||
// FIXME: Most or all of these should be properties and subscripts when we
|
||||
// can have those in protocols.
|
||||
|
||||
/// Copy the value out as an Any.
|
||||
func getValue() -> Any
|
||||
var value: Any { get }
|
||||
|
||||
/// Get the type of the value.
|
||||
func getType() -> Any.metatype
|
||||
var valueType: Any.Type { get }
|
||||
|
||||
/// Get the unique identifier for this value, if it has one.
|
||||
/// Always returns Some value for class instances, and always returns None
|
||||
/// for value types.
|
||||
func getObjectIdentifier() -> ObjectIdentifier?
|
||||
var objectIdentifier: ObjectIdentifier? { get }
|
||||
|
||||
/// Get the number of logical children this value has.
|
||||
func getCount() -> Int
|
||||
var count: Int { get }
|
||||
|
||||
/// Get a mirror for one of this value's children.
|
||||
///
|
||||
/// Returns a pair of the child's name and its mirror.
|
||||
func getChild(i: Int) -> (String, Mirror)
|
||||
subscript(i: Int) -> (String, Mirror) { get }
|
||||
|
||||
/// Get a string description of this value.
|
||||
func getString() -> String
|
||||
var summary: String { get }
|
||||
|
||||
/// Get a rich representation of this value for the IDE, if it has one.
|
||||
func getIDERepresentation() -> IDERepresentable?
|
||||
var quickLookObject: QuickLookObject? { get }
|
||||
|
||||
/// Get the disposition of the value.
|
||||
var disposition: MirrorDisposition { get }
|
||||
}
|
||||
|
||||
/// A protocol for objects that can be used as rich representations by the IDE.
|
||||
/// These are serialized into a data type identifier and an array of bytes
|
||||
/// for the IDE's consumption.
|
||||
protocol IDERepresentable {
|
||||
/// Get a string that describes the type of data.
|
||||
func getTypeString() -> String
|
||||
|
||||
/// Get the raw data.
|
||||
func getData() -> UInt8[]
|
||||
/// An entry point that can be called from C++ code to get the summary string
|
||||
/// for an arbitrary object. The memory pointed to by "out" is initialized with
|
||||
/// the summary string.
|
||||
@asmname("swift_getSummary") func _getSummary<T>(out: UnsafePointer<String>,
|
||||
x: T) {
|
||||
out.initialize(reflect(x).summary)
|
||||
}
|
||||
|
||||
/// Produce a mirror for any value. If the value's type conforms to Reflectable,
|
||||
/// invoke its getMirror() method; otherwise, fall back to an implementation
|
||||
/// in the runtime that structurally reflects values of any type.
|
||||
@asmname="swift_reflectAny" func reflect<T>(x: T) -> Mirror
|
||||
@asmname("swift_reflectAny") func reflect<T>(x: T) -> Mirror
|
||||
|
||||
/// Unsafely produce a mirror for a value in memory whose lifetime is
|
||||
/// guaranteed by holding a strong reference to a heap object.
|
||||
/// This lets containers with heap storage vend mirrors for their elements
|
||||
/// without unnecessary copying of the underlying value.
|
||||
@asmname("swift_unsafeReflectAny") func unsafeReflect<T>(
|
||||
owner: Builtin.NativeObject,
|
||||
ptr: UnsafePointer<T>
|
||||
) -> Mirror
|
||||
|
||||
/// Dump an object's contents using its mirror.
|
||||
func dump<T>(x: T, name: String? = nil, indent: Int = 0,
|
||||
maxDepth: Int = .max, maxItems: Int = .max) -> T {
|
||||
var maxItemCounter = maxItems
|
||||
var visitedItems = Dictionary<ObjectIdentifier, Int>()
|
||||
_dumpWithMirror(reflect(x), name, indent, maxDepth,
|
||||
&maxItemCounter, &visitedItems)
|
||||
return x
|
||||
}
|
||||
|
||||
/// Dump an object's contents using a mirror. User code should use dump().
|
||||
func _dumpWithMirror(mirror: Mirror, name: String?,
|
||||
indent: Int, maxDepth: Int,
|
||||
inout maxItemCounter: Int,
|
||||
inout visitedItems: Dictionary<ObjectIdentifier, Int>) {
|
||||
if maxItemCounter <= 0 { return }
|
||||
--maxItemCounter
|
||||
|
||||
for _ in 0...indent { print(" ") }
|
||||
|
||||
let count = mirror.count
|
||||
let bullet = count == 0 ? "-"
|
||||
: maxDepth <= 0 ? "▹" : "▿"
|
||||
print("\(bullet) ")
|
||||
|
||||
if let nam = name {
|
||||
print("\(nam): ")
|
||||
}
|
||||
print(mirror.summary)
|
||||
|
||||
if let id = mirror.objectIdentifier {
|
||||
if let previous = visitedItems.find(id) {
|
||||
println(" #\(previous)")
|
||||
return
|
||||
}
|
||||
let identifier = visitedItems.count
|
||||
visitedItems[id] = identifier
|
||||
print(" #\(identifier)")
|
||||
}
|
||||
|
||||
println()
|
||||
|
||||
if maxDepth <= 0 { return }
|
||||
|
||||
for i in 0...count {
|
||||
if maxItemCounter <= 0 {
|
||||
for _ in 0...(indent+4) { print(" ") }
|
||||
let remainder = count - i
|
||||
print("(\(remainder)")
|
||||
if i > 0 { print(" more") }
|
||||
if remainder == 1 {
|
||||
println(" child)")
|
||||
} else {
|
||||
println(" children)")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let (name, child) = mirror[i]
|
||||
_dumpWithMirror(child, name, indent + 2, maxDepth - 1,
|
||||
&maxItemCounter, &visitedItems)
|
||||
}
|
||||
}
|
||||
|
||||
// -- Mirror implementations for basic data types
|
||||
|
||||
/// A mirror for a value that is represented as a simple value with no
|
||||
/// children.
|
||||
struct _LeafMirror<T>: Mirror {
|
||||
let _value: T
|
||||
let summaryFunction: T -> String
|
||||
let quickLookFunction: T -> QuickLookObject?
|
||||
|
||||
init(_ value: T, _ summaryFunction: T -> String,
|
||||
_ quickLookFunction: T -> QuickLookObject?) {
|
||||
self._value = value
|
||||
self.summaryFunction = summaryFunction
|
||||
self.quickLookFunction = quickLookFunction
|
||||
}
|
||||
|
||||
var value: Any { return _value }
|
||||
var valueType: Any.Type { return value.dynamicType }
|
||||
var objectIdentifier: ObjectIdentifier? { return nil }
|
||||
var count: Int { return 0 }
|
||||
subscript(i: Int) -> (String, Mirror) { fatal("no children") }
|
||||
var summary: String { return summaryFunction(_value) }
|
||||
var quickLookObject: QuickLookObject? { return quickLookFunction(_value) }
|
||||
var disposition: MirrorDisposition { return .Aggregate }
|
||||
}
|
||||
|
||||
// -- Implementation details for the runtime's Mirror implementation
|
||||
|
||||
/// Implementation detail of the runtime mirror implementation.
|
||||
/// If this is changed, Reflection.cpp in the runtime must be changed to
|
||||
/// correspond.
|
||||
struct _MagicMirrorData {
|
||||
val owner: Builtin.ObjectPointer
|
||||
val ptr: Builtin.RawPointer
|
||||
val metadata: Any.metatype
|
||||
let owner: Builtin.NativeObject
|
||||
let ptr: Builtin.RawPointer
|
||||
let metadata: Any.Type
|
||||
|
||||
var value: Any {
|
||||
@asmname("swift_MagicMirrorData_value") get
|
||||
}
|
||||
var valueType: Any.Type {
|
||||
@asmname("swift_MagicMirrorData_valueType") get
|
||||
}
|
||||
|
||||
var objcValue: Any {
|
||||
@asmname("swift_MagicMirrorData_objcValue") get
|
||||
}
|
||||
var objcValueType: Any.Type {
|
||||
@asmname("swift_MagicMirrorData_objcValueType") get
|
||||
}
|
||||
|
||||
func _loadValue<T>() -> T {
|
||||
return Builtin.load(ptr) as T
|
||||
}
|
||||
}
|
||||
|
||||
/// A thunk that returns a String by value, for C entry points.
|
||||
func _returnString(inout s: String) -> String {
|
||||
return s
|
||||
struct _OpaqueMirror: Mirror {
|
||||
let data: _MagicMirrorData
|
||||
|
||||
var value: Any { return data.value }
|
||||
var valueType: Any.Type { return data.valueType }
|
||||
var objectIdentifier: ObjectIdentifier? { return nil }
|
||||
var count: Int { return 0 }
|
||||
subscript(i: Int) -> (String, Mirror) { fatal("no children") }
|
||||
var summary: String { return "<opaque>" }
|
||||
var quickLookObject: QuickLookObject? { return nil }
|
||||
var disposition: MirrorDisposition { return .Aggregate }
|
||||
}
|
||||
|
||||
struct _TupleMirror: Mirror {
|
||||
let data: _MagicMirrorData
|
||||
|
||||
var value: Any { return data.value }
|
||||
var valueType: Any.Type { return data.valueType }
|
||||
var objectIdentifier: ObjectIdentifier? { return nil }
|
||||
var count: Int {
|
||||
@asmname("swift_TupleMirror_count") get
|
||||
}
|
||||
subscript(i: Int) -> (String, Mirror) {
|
||||
@asmname("swift_TupleMirror_subscript") get
|
||||
}
|
||||
var summary: String { return "(\(count) elements)" }
|
||||
var quickLookObject: QuickLookObject? { return nil }
|
||||
var disposition: MirrorDisposition { return .Tuple }
|
||||
}
|
||||
|
||||
struct _StructMirror: Mirror {
|
||||
let data: _MagicMirrorData
|
||||
|
||||
var value: Any { return data.value }
|
||||
var valueType: Any.Type { return data.valueType }
|
||||
var objectIdentifier: ObjectIdentifier? { return nil }
|
||||
var count: Int {
|
||||
@asmname("swift_StructMirror_count") get
|
||||
}
|
||||
subscript(i: Int) -> (String, Mirror) {
|
||||
@asmname("swift_StructMirror_subscript") get
|
||||
}
|
||||
|
||||
// FIXME: put the type name here
|
||||
var summary: String { return "(\(count) elements)" }
|
||||
var quickLookObject: QuickLookObject? { return nil }
|
||||
var disposition: MirrorDisposition { return .Struct }
|
||||
}
|
||||
|
||||
@asmname("swift_ClassMirror_count")
|
||||
func _getClassCount(_MagicMirrorData) -> Int
|
||||
@asmname("swift_ClassMirror_subscript")
|
||||
func _getClassChild(Int, _MagicMirrorData) -> (String, Mirror)
|
||||
|
||||
struct _ClassMirror: Mirror {
|
||||
let data: _MagicMirrorData
|
||||
|
||||
var value: Any { return data.value }
|
||||
var valueType: Any.Type { return data.valueType }
|
||||
var objectIdentifier: ObjectIdentifier? {
|
||||
return data._loadValue() as ObjectIdentifier
|
||||
}
|
||||
var count: Int {
|
||||
return _getClassCount(data)
|
||||
}
|
||||
subscript(i: Int) -> (String, Mirror) {
|
||||
return _getClassChild(i, data)
|
||||
}
|
||||
|
||||
// FIXME: put the type name here
|
||||
var summary: String { return "(\(count) elements)" }
|
||||
var quickLookObject: QuickLookObject? { return nil }
|
||||
var disposition: MirrorDisposition { return .Class }
|
||||
}
|
||||
|
||||
struct _ClassSuperMirror: Mirror {
|
||||
let data: _MagicMirrorData
|
||||
|
||||
var value: Any { return data.value }
|
||||
var valueType: Any.Type { return data.valueType }
|
||||
|
||||
// Suppress the value identifier for super mirrors.
|
||||
var objectIdentifier: ObjectIdentifier? {
|
||||
return nil
|
||||
}
|
||||
var count: Int {
|
||||
return _getClassCount(data)
|
||||
}
|
||||
subscript(i: Int) -> (String, Mirror) {
|
||||
return _getClassChild(i, data)
|
||||
}
|
||||
// FIXME: put the type name here
|
||||
var summary: String { return "(\(count) elements)" }
|
||||
var quickLookObject: QuickLookObject? { return nil }
|
||||
var disposition: MirrorDisposition { return .Class }
|
||||
}
|
||||
|
||||
@@ -21,3 +21,14 @@ func _makeSwiftNSFastEnumerationState() -> _SwiftNSFastEnumerationState {
|
||||
extra: (0, 0, 0, 0, 0))
|
||||
}
|
||||
|
||||
/// A dummy value that is be used as the target for `mutationsPtr` in fast
|
||||
/// enumeration implementations.
|
||||
var _fastEnumerationStorageMutationsTarget: CUnsignedLong = 0
|
||||
|
||||
/// A dummy pointer to be used as `mutationsPtr` in fast enumeration
|
||||
/// implementations.
|
||||
var _fastEnumerationStorageMutationsPtr: UnsafePointer<CUnsignedLong> {
|
||||
return UnsafePointer(
|
||||
Builtin.addressof(&_fastEnumerationStorageMutationsTarget))
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Buffer type for Slice<T>
|
||||
struct SliceBuffer<T> : ArrayBufferType {
|
||||
typealias Element = T
|
||||
typealias NativeStorage = NativeArrayStorage<T>
|
||||
@@ -33,10 +34,10 @@ struct SliceBuffer<T> : ArrayBufferType {
|
||||
_invariantCheck()
|
||||
}
|
||||
|
||||
init(x: NativeBuffer) {
|
||||
owner = x.storage
|
||||
start = x.elementStorage
|
||||
_countAndFlags = (UInt(x.count) << 1) | 1
|
||||
init(_ buffer: NativeBuffer) {
|
||||
owner = buffer.storage
|
||||
start = buffer.elementStorage
|
||||
_countAndFlags = (UInt(buffer.count) << 1) | 1
|
||||
_invariantCheck()
|
||||
}
|
||||
|
||||
@@ -62,31 +63,51 @@ struct SliceBuffer<T> : ArrayBufferType {
|
||||
return NativeBuffer(owner as NativeStorage)
|
||||
}
|
||||
|
||||
/// A value that identifies first mutable element, if any. Two
|
||||
/// arrays compare === iff they are both empty, or if their buffers
|
||||
/// have the same identity and count.
|
||||
var identity: Word {
|
||||
return reinterpretCast(start)
|
||||
}
|
||||
|
||||
|
||||
/// An object that keeps the elements stored in this buffer alive
|
||||
var owner: AnyObject?
|
||||
var start: UnsafePointer<T>
|
||||
var _countAndFlags: UInt
|
||||
|
||||
//===--- Non-essential bits ---------------------------------------------===//
|
||||
//extension SliceBuffer : ArrayBufferType {
|
||||
|
||||
func asCocoaArray() -> CocoaArray {
|
||||
// It's tempting to allocate a new instance of an NSArray subclass
|
||||
// that just wraps this Slice. However, since we don't have a
|
||||
// managedByCopyOnWrite bit in the dynamically-allocated storage,
|
||||
// and we are in principle part of a mutable object, we need to
|
||||
// copy eagerly in most cases. The one exception is when our
|
||||
// owner is nil. We could think about doing that optimization
|
||||
// someday.
|
||||
assert(
|
||||
isBridgedToObjectiveC(T.self),
|
||||
"Array element type is not bridged to ObjectiveC")
|
||||
_invariantCheck()
|
||||
|
||||
// FIXME: can't write this pending <rdar://problem/16397774>:
|
||||
// return asArray(UnsafeArray(start, count)) as NativeArray<T>
|
||||
var result = NativeArrayBuffer<T>()
|
||||
result += UnsafeArray(start, count)
|
||||
return result.asCocoaArray()
|
||||
return _extractOrCopyToNativeArrayBuffer(self).asCocoaArray()
|
||||
}
|
||||
|
||||
mutating func requestUniqueMutableBuffer(minimumCapacity: Int)
|
||||
-> NativeBuffer?
|
||||
{
|
||||
_invariantCheck()
|
||||
if _fastPath(_hasNativeBuffer && Swift.isUniquelyReferenced(&owner)) {
|
||||
if capacity >= minimumCapacity {
|
||||
return reinterpretCast(owner) as NativeBuffer
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/// If this buffer is backed by a NativeArrayBuffer, return it.
|
||||
/// Otherwise, return nil. Note: the result's elementStorage may
|
||||
/// not match ours, since we are a SliceBuffer.
|
||||
func requestNativeBuffer() -> NativeArrayBuffer<Element>? {
|
||||
_invariantCheck()
|
||||
if _fastPath(_hasNativeBuffer) {
|
||||
return reinterpretCast(owner) as NativeBuffer
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func _uninitializedCopy(
|
||||
@@ -102,6 +123,10 @@ struct SliceBuffer<T> : ArrayBufferType {
|
||||
return target
|
||||
}
|
||||
|
||||
var elementStorage: UnsafePointer<T> {
|
||||
return start
|
||||
}
|
||||
|
||||
var count: Int {
|
||||
get {
|
||||
return Int(_countAndFlags >> 1)
|
||||
@@ -133,20 +158,15 @@ struct SliceBuffer<T> : ArrayBufferType {
|
||||
return Swift.isUniquelyReferenced(&owner)
|
||||
}
|
||||
|
||||
func isMutable() -> Bool {
|
||||
return _hasNativeBuffer
|
||||
}
|
||||
|
||||
subscript(i: Int) -> T {
|
||||
get {
|
||||
assert(i >= 0, "negative slice index is out of range")
|
||||
assert(i < count, "slice index out of range")
|
||||
return start[i]
|
||||
}
|
||||
set {
|
||||
nonmutating set {
|
||||
assert(i >= 0, "negative slice index is out of range")
|
||||
assert(i < count, "slice index out of range")
|
||||
assert(isMutable())
|
||||
start[i] = newValue
|
||||
}
|
||||
}
|
||||
@@ -156,7 +176,27 @@ struct SliceBuffer<T> : ArrayBufferType {
|
||||
assert(subRange.endIndex >= subRange.startIndex)
|
||||
assert(subRange.endIndex <= count)
|
||||
return SliceBuffer(
|
||||
owner, start + subRange.startIndex,
|
||||
subRange.endIndex - subRange.startIndex, _hasNativeBuffer)
|
||||
owner: owner, start: start + subRange.startIndex,
|
||||
count: subRange.endIndex - subRange.startIndex,
|
||||
hasNativeBuffer: _hasNativeBuffer)
|
||||
}
|
||||
|
||||
//===--- Collection conformance -----------------------------------------===//
|
||||
var startIndex: Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
var endIndex: Int {
|
||||
return count
|
||||
}
|
||||
|
||||
func generate() -> IndexingGenerator<SliceBuffer> {
|
||||
return IndexingGenerator(self)
|
||||
}
|
||||
|
||||
//===--- misc -----------------------------------------------------------===//
|
||||
func withUnsafePointerToElements<R>(body: (UnsafePointer<T>)->R) -> R {
|
||||
let start = self.start
|
||||
return owner ? withExtendedLifetime(owner!) { body(start) } : body(start)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// \brief An extremely simple string designed to represent something
|
||||
/// "statically knowable".
|
||||
|
||||
@@ -7,36 +19,47 @@
|
||||
// types, we are guaranteed that no assertions are involved in its
|
||||
// construction. This feature is crucial for preventing infinite
|
||||
// recursion even in non-asserting cases.
|
||||
struct StaticString : BuiltinStringLiteralConvertible, StringLiteralConvertible {
|
||||
struct StaticString
|
||||
: _BuiltinExtendedGraphemeClusterLiteralConvertible,
|
||||
ExtendedGraphemeClusterLiteralConvertible,
|
||||
_BuiltinStringLiteralConvertible, StringLiteralConvertible {
|
||||
var start: Builtin.RawPointer
|
||||
var byteCount: Builtin.Word
|
||||
var byteSize: Builtin.Word
|
||||
var isASCII: Builtin.Int1
|
||||
|
||||
init() {
|
||||
self = ""
|
||||
}
|
||||
|
||||
init(start: Builtin.RawPointer, byteCount: Builtin.Word, isASCII: Builtin.Int1) {
|
||||
init(
|
||||
start: Builtin.RawPointer, byteSize: Builtin.Word, isASCII: Builtin.Int1
|
||||
) {
|
||||
self.start = start
|
||||
self.byteCount = byteCount
|
||||
self.byteSize = byteSize
|
||||
self.isASCII = isASCII
|
||||
}
|
||||
|
||||
// FIXME: this is a hackaround for <rdar://problem/15888736> fatal()
|
||||
// can't take a StaticString?!
|
||||
init(nulTerminated: CString) {
|
||||
self.start = nulTerminated._bytesPtr.value
|
||||
self.byteCount = _strlen(nulTerminated).value
|
||||
self.isASCII = false.value
|
||||
static func _convertFromBuiltinExtendedGraphemeClusterLiteral(
|
||||
start: Builtin.RawPointer,
|
||||
byteSize: Builtin.Word,
|
||||
isASCII: Builtin.Int1) -> StaticString {
|
||||
|
||||
return _convertFromBuiltinStringLiteral(
|
||||
start, byteSize: byteSize, isASCII: isASCII)
|
||||
}
|
||||
|
||||
type func _convertFromBuiltinStringLiteral(
|
||||
start: Builtin.RawPointer, byteCount: Builtin.Word, isASCII: Builtin.Int1
|
||||
static func convertFromExtendedGraphemeClusterLiteral(
|
||||
value: StaticString) -> StaticString {
|
||||
return value
|
||||
}
|
||||
|
||||
static func _convertFromBuiltinStringLiteral(
|
||||
start: Builtin.RawPointer, byteSize: Builtin.Word, isASCII: Builtin.Int1
|
||||
) -> StaticString {
|
||||
return StaticString(start: start, byteCount: byteCount, isASCII: isASCII)
|
||||
return StaticString(start: start, byteSize: byteSize, isASCII: isASCII)
|
||||
}
|
||||
|
||||
type func convertFromStringLiteral(value: StaticString) -> StaticString {
|
||||
static func convertFromStringLiteral(value: StaticString) -> StaticString {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,45 +1,89 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Swift's String bridges NSString via this protocol and these
|
||||
// variables, allowing the core stdlib to remain decoupled from
|
||||
// Foundation.
|
||||
|
||||
/// \brief Effectively a proxy for NSString that doesn't mention it by
|
||||
/// name. NSString's conformance to this protocol is declared in
|
||||
/// Foundation.
|
||||
@class_protocol @objc protocol _CocoaString {}
|
||||
|
||||
/// \brief Loading Foundation initializes these function variables
|
||||
/// with useful values
|
||||
|
||||
func _cocoaStringBridgeNotInitialized<A,R>() -> (A)->R {
|
||||
// FIXME: returning a closure as a workaround for
|
||||
// <rdar://problem/15921334>
|
||||
return {
|
||||
(args:A) -> R in
|
||||
fatal("Swift <==> Cocoa string bridge not initialized")
|
||||
return (.None as R?)!
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief produces a ContiguousString from a given subrange of a source
|
||||
/// \brief produces a _StringBuffer from a given subrange of a source
|
||||
/// _CocoaString, having the given minimum capacity.
|
||||
var __swift_cocoaStringToContiguousString : (
|
||||
var _cocoaStringToContiguous: (
|
||||
source: _CocoaString, range: Range<Int>, minimumCapacity: Int
|
||||
) -> ContiguousString = _cocoaStringBridgeNotInitialized()
|
||||
) -> _StringBuffer = _cocoaStringToContiguousNotInitialized
|
||||
|
||||
func _cocoaStringToContiguousNotInitialized(
|
||||
source: _CocoaString, range: Range<Int>, minimumCapacity: Int
|
||||
) -> _StringBuffer {
|
||||
fatal("_cocoaStringToContiguous not initialized")
|
||||
}
|
||||
|
||||
/// \brief reads the entire contents of a _CocoaString into contiguous
|
||||
/// storage of sufficient capacity.
|
||||
var __swift_cocoaStringReadAll : (
|
||||
var _cocoaStringReadAll: (
|
||||
source: _CocoaString, destination: UnsafePointer<UTF16.CodeUnit>
|
||||
) -> Void = _cocoaStringBridgeNotInitialized()
|
||||
) -> Void = _cocoaStringReadAllNotInitialized
|
||||
|
||||
// FIXME: This will probably go away but is needed at least
|
||||
// temporarily as a bridge to StringCore
|
||||
var __swift_cocoaStringLength: (
|
||||
func _cocoaStringReadAllNotInitialized(
|
||||
source: _CocoaString, destination: UnsafePointer<UTF16.CodeUnit>
|
||||
) -> Void {
|
||||
fatal("_cocoaStringReadAll not initialized")
|
||||
}
|
||||
|
||||
var _cocoaStringLength: (
|
||||
source: _CocoaString
|
||||
) -> Int = _cocoaStringBridgeNotInitialized()
|
||||
) -> Int = _cocoaStringLengthNotInitialized
|
||||
|
||||
var _appendCocoaString : (
|
||||
target: @inout String, rhs: String
|
||||
) -> Void
|
||||
// FIXME: Explicit default value is a workaround for <rdar://problem/15921520>
|
||||
= { x,y in fatal("Swift <==> Cocoa string bridge not initialized") }
|
||||
func _cocoaStringLengthNotInitialized(
|
||||
source: _CocoaString
|
||||
) -> Int {
|
||||
fatal("_cocoaStringLength not initialized")
|
||||
}
|
||||
|
||||
var _sliceCocoaString : (
|
||||
target: StringCore, subRange: Range<Int>
|
||||
) -> StringCore = _cocoaStringBridgeNotInitialized()
|
||||
var _cocoaStringSlice: (
|
||||
target: _StringCore, subRange: Range<Int>
|
||||
) -> _StringCore = _cocoaStringSliceNotInitialized
|
||||
|
||||
var _indexCocoaString : (
|
||||
target: StringCore, position: Int
|
||||
) -> UTF16.CodeUnit = _cocoaStringBridgeNotInitialized()
|
||||
func _cocoaStringSliceNotInitialized(
|
||||
target: _StringCore, subRange: Range<Int>
|
||||
) -> _StringCore {
|
||||
fatal("_cocoaStringSlice not initialized")
|
||||
}
|
||||
|
||||
var _cocoaStringSubscript: (
|
||||
target: _StringCore, position: Int
|
||||
) -> UTF16.CodeUnit = _cocoaStringSubscriptNotInitialized
|
||||
|
||||
func _cocoaStringSubscriptNotInitialized(
|
||||
target: _StringCore, position: Int
|
||||
) -> UTF16.CodeUnit {
|
||||
fatal("_cocoaStringSubscript not initialized")
|
||||
}
|
||||
|
||||
var _cocoaStringEncodeSomeUTF8: (
|
||||
target: _StringCore, position: Int
|
||||
) -> (_StringCore.IndexType, _StringCore.UTF8Chunk)
|
||||
= _cocoaStringEncodeSomeUTF8NotInitialized
|
||||
|
||||
func _cocoaStringEncodeSomeUTF8NotInitialized(
|
||||
target: _StringCore, position: Int
|
||||
) -> (_StringCore.IndexType, _StringCore.UTF8Chunk) {
|
||||
fatal("_cocoaStringEncodeSomeUTF8 not initialized")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,103 +1,180 @@
|
||||
struct StringBufferIVars {
|
||||
init() {
|
||||
used = .null()
|
||||
capacity = .null()
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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) {
|
||||
assert(elementWidth == 1 || elementWidth == 2)
|
||||
usedEnd = .null()
|
||||
capacityAndElementShift = elementWidth - 1
|
||||
}
|
||||
|
||||
init(
|
||||
used: UnsafePointer<UTF16.CodeUnit>,
|
||||
capacity: UnsafePointer<UTF16.CodeUnit>
|
||||
usedEnd: UnsafePointer<RawByte>,
|
||||
byteCapacity: Int,
|
||||
elementWidth: Int
|
||||
) {
|
||||
self.used = used
|
||||
self.capacity = capacity
|
||||
assert(elementWidth == 1 || elementWidth == 2)
|
||||
assert((byteCapacity & 0x1) == 0)
|
||||
self.usedEnd = usedEnd
|
||||
self.capacityAndElementShift = byteCapacity + (elementWidth - 1)
|
||||
}
|
||||
|
||||
var used, capacity: UnsafePointer<UTF16.CodeUnit>
|
||||
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
|
||||
// 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.
|
||||
struct StringBuffer {
|
||||
typealias _Storage = HeapBuffer<StringBufferIVars, UTF16.CodeUnit>
|
||||
struct _StringBuffer {
|
||||
|
||||
// Make this a buffer of UTF16 code units so that it's properly
|
||||
// aligned for them if that's what we store.
|
||||
typealias _Storage = HeapBuffer<_StringBufferIVars, UTF16.CodeUnit>
|
||||
|
||||
@conversion
|
||||
func __conversion() -> _Storage {
|
||||
return _storage
|
||||
}
|
||||
|
||||
init(storage: _Storage) {
|
||||
init(_ storage: _Storage) {
|
||||
_storage = storage
|
||||
}
|
||||
|
||||
init(capacity: Int, initialSize: Int = 0) {
|
||||
_storage = _Storage.create(StringBufferIVars(), capacity)
|
||||
self.used = _storage.elementStorage + initialSize
|
||||
self.capacity = _storage.elementStorage + capacity
|
||||
init(capacity: Int, initialSize: Int, elementWidth: Int) {
|
||||
assert(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
|
||||
}
|
||||
|
||||
init<
|
||||
Encoding: UnicodeCodec, Input: Collection
|
||||
where Input.StreamType.Element == Encoding.CodeUnit
|
||||
where Input.GeneratorType.Element == Encoding.CodeUnit
|
||||
>(
|
||||
encoding: Encoding.metatype, input: Input, minimumCapacity: Int = 0
|
||||
encoding: Encoding.Type, input: Input, minimumCapacity: Int = 0
|
||||
) {
|
||||
// Determine how many UTF16 code units we'll need
|
||||
var utf16Count = 0
|
||||
transcode(encoding, UTF16, input.generate(), SinkOf<UTF16.CodeUnit>({
|
||||
_ in ++utf16Count;()
|
||||
}))
|
||||
var inputStream = input.generate()
|
||||
var (utf16Count, isAscii) = UTF16.measure(encoding, input: inputStream)
|
||||
|
||||
// Allocate storage
|
||||
self = StringBuffer(max(utf16Count, minimumCapacity))
|
||||
self = _StringBuffer(
|
||||
capacity: max(utf16Count, minimumCapacity),
|
||||
initialSize: utf16Count,
|
||||
elementWidth: isAscii ? 1 : 2)
|
||||
|
||||
var used = self.used
|
||||
// Fill the storage
|
||||
transcode(encoding, UTF16, input.generate(), SinkOf<UTF16.CodeUnit>( {
|
||||
(used++).set($0)
|
||||
} ))
|
||||
self.used = used
|
||||
if isAscii {
|
||||
var p = UnsafePointer<UTF8.CodeUnit>(start)
|
||||
transcode(encoding, UTF32.self, input.generate(), SinkOf {
|
||||
(p++).set(UTF8.CodeUnit($0))
|
||||
})
|
||||
}
|
||||
else {
|
||||
var p = _storage.elementStorage
|
||||
transcode(encoding, UTF16.self, input.generate(), SinkOf {
|
||||
(p++).set($0)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var start : UnsafePointer<UTF16.CodeUnit> {
|
||||
return _storage.elementStorage
|
||||
/// \brief a pointer to the start of this buffer's data area
|
||||
var start: UnsafePointer<RawByte> {
|
||||
return UnsafePointer(_storage.elementStorage)
|
||||
}
|
||||
|
||||
var used : UnsafePointer<UTF16.CodeUnit> {
|
||||
return _storage.value.used
|
||||
set(newValue):
|
||||
_storage.value.used = newValue
|
||||
/// \brief 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 capacity : UnsafePointer<UTF16.CodeUnit> {
|
||||
return _storage.value.capacity
|
||||
set(newValue):
|
||||
_storage.value.capacity = newValue
|
||||
var usedCount: Int {
|
||||
return (usedEnd - start) >> elementShift
|
||||
}
|
||||
|
||||
@mutating
|
||||
func grow(
|
||||
oldUsed: UnsafePointer<UTF16.CodeUnit>,
|
||||
newUsed: UnsafePointer<UTF16.CodeUnit>
|
||||
) -> Bool {
|
||||
if capacity < newUsed {
|
||||
/// \brief a past-the-end pointer for this buffer's available storage
|
||||
var capacityEnd: UnsafePointer<RawByte> {
|
||||
return start + _storage.value.byteCapacity
|
||||
}
|
||||
|
||||
/// \brief The number of elements that can be stored in this buffer
|
||||
var capacity: Int {
|
||||
return _storage.value.byteCapacity >> elementShift
|
||||
}
|
||||
|
||||
/// \brief 1 if the buffer stores UTF16; 0 otherwise
|
||||
var elementShift: Int {
|
||||
return _storage.value.elementShift
|
||||
}
|
||||
|
||||
/// \brief 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, or we can fall back to
|
||||
// checking isUniquelyReferenced, which is more conservative.
|
||||
if used == oldUsed {
|
||||
used = newUsed
|
||||
// assignment below should be replaced by a CAS
|
||||
if usedEnd == oldUsedEnd {
|
||||
usedEnd = newUsedEnd
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@conversion
|
||||
func __conversion() -> AnyObject {
|
||||
return _storage
|
||||
func __conversion() -> AnyObject? {
|
||||
return _storage.storage ? .Some(_storage.storage!) : .None
|
||||
}
|
||||
|
||||
var _storage: HeapBuffer<StringBufferIVars, UTF16.CodeUnit>
|
||||
var _storage: _Storage
|
||||
}
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/// \brief The core implementation of a highly-optimizable String that
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// The core implementation of a highly-optimizable String that
|
||||
/// can store both ASCII and UTF-16, and can wrap native Swift
|
||||
/// StringBuffer or NSString instances.
|
||||
/// _StringBuffer or NSString instances.
|
||||
///
|
||||
/// Usage note: when elements are 8 bits wide, this code may
|
||||
/// dereference one past the end of the byte array that it owns, so
|
||||
@@ -12,134 +24,460 @@
|
||||
// size with the ternary operator. This is also the cause of the
|
||||
// extra element requirement for 8 bit elements. See the
|
||||
// implementation of subscript(Int) -> UTF16.CodeUnit below for details.
|
||||
struct StringCore {
|
||||
var baseAddress: COpaquePointer
|
||||
struct _StringCore {
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Internals
|
||||
var _baseAddress: COpaquePointer
|
||||
var _countAndFlags: UWord
|
||||
var owner: AnyObject?
|
||||
var _owner: AnyObject?
|
||||
|
||||
/// \brief (private) create the implementation of a string from its
|
||||
/// component parts.
|
||||
/// (private) create the implementation of a string from its component parts.
|
||||
init(
|
||||
baseAddress: COpaquePointer,
|
||||
_countAndFlags: UWord,
|
||||
owner: AnyObject?
|
||||
) {
|
||||
self.baseAddress = baseAddress
|
||||
self._baseAddress = baseAddress
|
||||
self._countAndFlags = _countAndFlags
|
||||
self.owner = owner
|
||||
self._owner = owner
|
||||
_invariantCheck()
|
||||
}
|
||||
|
||||
init(
|
||||
baseAddress: COpaquePointer,
|
||||
count: Int,
|
||||
elementShift: Int,
|
||||
hasOpaqueBuffer: Bool,
|
||||
owner: AnyObject?
|
||||
) {
|
||||
assert(elementShift == 0 || elementShift == 1)
|
||||
self.baseAddress = baseAddress
|
||||
self._countAndFlags = (UWord(elementShift) << (UWord.bitSize() - 1))
|
||||
| ((hasOpaqueBuffer ? 1 : 0) << (UWord.bitSize() - 2))
|
||||
| UWord(count)
|
||||
self.owner = owner
|
||||
assert(UWord(count) & _flagMask == 0)
|
||||
func _invariantCheck() {
|
||||
assert(count >= 0)
|
||||
|
||||
if _baseAddress == .null() {
|
||||
assert(cocoaBuffer,
|
||||
"Only opaque cocoa strings may have a null base pointer")
|
||||
assert(elementWidth == 2,
|
||||
"Opaque cocoa strings should have an elementWidth of 2")
|
||||
}
|
||||
else if _baseAddress == _emptyStringBase {
|
||||
assert(count == 0, "Empty string storage with non-zero length")
|
||||
assert(!_owner, "String pointing at empty storage has owner")
|
||||
}
|
||||
else if let buffer = nativeBuffer {
|
||||
assert(elementWidth == buffer.elementWidth,
|
||||
"_StringCore elementWidth doesn't match its buffer's")
|
||||
assert(UnsafePointer(_baseAddress) >= buffer.start)
|
||||
assert(UnsafePointer(_baseAddress) <= buffer.usedEnd)
|
||||
assert(UnsafePointer(_pointerToNth(count)) <= buffer.usedEnd)
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Create the implementation of an empty string. NOTE:
|
||||
/// there is no null terminator in an empty string!
|
||||
init() {
|
||||
self.baseAddress = COpaquePointer()
|
||||
self._countAndFlags = 0
|
||||
self.owner = .None
|
||||
}
|
||||
|
||||
/// \brief bitmask for the count part of _countAndFlags
|
||||
/// Bitmask for the count part of _countAndFlags
|
||||
var _countMask: UWord {
|
||||
return UWord.max >> 2
|
||||
}
|
||||
|
||||
/// \brief bitmask for the flags part of _countAndFlags
|
||||
/// Bitmask for the flags part of _countAndFlags
|
||||
var _flagMask: UWord {
|
||||
return ~_countMask
|
||||
}
|
||||
|
||||
/// \brief the number of elements stored
|
||||
var count: Int {
|
||||
return Int(_countAndFlags & _countMask)
|
||||
set(newValue):
|
||||
assert(UWord(newValue) & _flagMask == 0)
|
||||
_countAndFlags = (_countAndFlags & _flagMask) | UWord(newValue)
|
||||
}
|
||||
|
||||
/// \brief left shift amount to apply to an offset N so that when
|
||||
/// added to a UnsafePointer<RawByte>, it traverses N elements
|
||||
var elementShift: Int {
|
||||
return Int(_countAndFlags >> (UWord.bitSize() - 1))
|
||||
}
|
||||
|
||||
/// \brief the number of bytes per element
|
||||
var elementSize: Int {
|
||||
return elementShift + 1
|
||||
}
|
||||
|
||||
/// \brief are we using an opaque NSString for storage?
|
||||
var hasOpaqueBuffer: Bool {
|
||||
return Word((_countAndFlags << 1).value) < 0
|
||||
}
|
||||
|
||||
/// \brief Return the given sub-StringCore
|
||||
subscript(subRange: Range<Int>) -> StringCore {
|
||||
|
||||
assert(subRange.startIndex() >= 0)
|
||||
assert(subRange.endIndex() <= count)
|
||||
|
||||
let newCount = subRange.endIndex() - subRange.startIndex()
|
||||
assert(UWord(newCount) & _flagMask == 0)
|
||||
|
||||
if (!hasOpaqueBuffer) {
|
||||
return StringCore(
|
||||
baseAddress: COpaquePointer(
|
||||
UnsafePointer<RawByte>(baseAddress.value)
|
||||
+ (subRange.startIndex() << elementShift)
|
||||
),
|
||||
_countAndFlags: (_countAndFlags & _flagMask) | UWord(newCount),
|
||||
owner: owner)
|
||||
}
|
||||
return _opaqueSlice(subRange, newCount)
|
||||
}
|
||||
|
||||
/// \brief helper function for the slicing subscript above.
|
||||
/// Implements the slow path
|
||||
func _opaqueSlice(subRange: Range<Int>, newCount: Int) -> StringCore {
|
||||
alwaysTrap("IMPLEMENT ME")
|
||||
}
|
||||
|
||||
/// \brief value by which to multiply a 2nd byte fetched in order to
|
||||
/// Value by which to multiply a 2nd byte fetched in order to
|
||||
/// assemble a UTF16 code unit from our contiguous storage. If we
|
||||
/// store ASCII, this will be zero. Otherwise, it will be 0x100
|
||||
var _highByteMultiplier: UTF16.CodeUnit {
|
||||
return UTF16.CodeUnit(elementShift) << 8
|
||||
}
|
||||
|
||||
/// \brief Get the Nth UTF16 Code Unit stored
|
||||
/// Return a pointer to the Nth element of contiguous
|
||||
/// storage. Caveats: The string must have contiguous storage; the
|
||||
/// element may be 1 or 2 bytes wide, depending on elementWidth; the
|
||||
/// result may be null if the string is empty.
|
||||
func _pointerToNth(n: Int) -> COpaquePointer {
|
||||
assert(hasContiguousStorage && n >= 0 && n <= count)
|
||||
return COpaquePointer(
|
||||
UnsafePointer<RawByte>(_baseAddress) + (n << elementShift))
|
||||
}
|
||||
|
||||
static func _copyElements(
|
||||
srcStart: COpaquePointer, srcElementWidth: Int,
|
||||
dstStart: COpaquePointer, dstElementWidth: Int,
|
||||
count: Int
|
||||
) {
|
||||
// Copy the old stuff into the new storage
|
||||
if _fastPath(srcElementWidth == dstElementWidth) {
|
||||
// No change in storage width; we can use memcpy
|
||||
c_memcpy(
|
||||
dest: UnsafePointer(dstStart),
|
||||
src: UnsafePointer(srcStart),
|
||||
size: UInt(count << (srcElementWidth - 1)))
|
||||
}
|
||||
else if (srcElementWidth < dstElementWidth) {
|
||||
// Widening ASCII to UTF16; we need to copy the bytes manually
|
||||
var dest = UnsafePointer<UTF16.CodeUnit>(dstStart)
|
||||
var src = UnsafePointer<UTF8.CodeUnit>(srcStart)
|
||||
let srcEnd = src + count
|
||||
while (src != srcEnd) {
|
||||
dest++.set(UTF16.CodeUnit(src++.get()))
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Narrowing UTF16 to ASCII; we need to copy the bytes manually
|
||||
var dest = UnsafePointer<UTF8.CodeUnit>(dstStart)
|
||||
var src = UnsafePointer<UTF16.CodeUnit>(srcStart)
|
||||
let srcEnd = src + count
|
||||
while (src != srcEnd) {
|
||||
dest++.set(UTF8.CodeUnit(src++.get()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Initialization
|
||||
init(
|
||||
baseAddress: COpaquePointer,
|
||||
count: Int,
|
||||
elementShift: Int,
|
||||
hasCocoaBuffer: Bool,
|
||||
owner: AnyObject?
|
||||
) {
|
||||
assert(elementShift == 0 || elementShift == 1)
|
||||
self._baseAddress = baseAddress
|
||||
|
||||
self._countAndFlags
|
||||
= (UWord(elementShift) << UWord(sizeof(UWord.self) * 8 - 1))
|
||||
| ((hasCocoaBuffer ? 1 : 0) << UWord(sizeof(UWord.self) * 8 - 2))
|
||||
| UWord(count)
|
||||
|
||||
self._owner = owner
|
||||
assert(UWord(count) & _flagMask == 0, "String too long to represent")
|
||||
_invariantCheck()
|
||||
}
|
||||
|
||||
/// Create a _StringCore that covers the entire length of the _StringBuffer.
|
||||
init(_ buffer: _StringBuffer) {
|
||||
self = _StringCore(
|
||||
baseAddress: COpaquePointer(buffer.start),
|
||||
count: buffer.usedCount,
|
||||
elementShift: buffer.elementShift,
|
||||
hasCocoaBuffer: false,
|
||||
owner: buffer
|
||||
)
|
||||
}
|
||||
|
||||
/// Create the implementation of an empty string.
|
||||
/// NOTE: there is no null terminator in an empty string!
|
||||
init() {
|
||||
self._baseAddress = _emptyStringBase
|
||||
self._countAndFlags = 0
|
||||
self._owner = .None
|
||||
_invariantCheck()
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Properties
|
||||
|
||||
/// The number of elements stored
|
||||
var count: Int {
|
||||
get {
|
||||
return Int(_countAndFlags & _countMask)
|
||||
}
|
||||
set(newValue) {
|
||||
assert(UWord(newValue) & _flagMask == 0)
|
||||
_countAndFlags = (_countAndFlags & _flagMask) | UWord(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
/// left shift amount to apply to an offset N so that when
|
||||
/// added to a UnsafePointer<RawByte>, it traverses N elements
|
||||
var elementShift: Int {
|
||||
return Int(_countAndFlags >> UWord(sizeof(UWord.self) * 8 - 1))
|
||||
}
|
||||
|
||||
/// the number of bytes per element
|
||||
var elementWidth: Int {
|
||||
return elementShift + 1
|
||||
}
|
||||
|
||||
var hasContiguousStorage: Bool {
|
||||
return _fastPath(_baseAddress != .null())
|
||||
}
|
||||
|
||||
/// are we using an NSString for storage?
|
||||
var hasCocoaBuffer: Bool {
|
||||
return Word((_countAndFlags << 1).value) < 0
|
||||
}
|
||||
|
||||
var startASCII: UnsafePointer<UTF8.CodeUnit> {
|
||||
assert(elementWidth == 1, "String does not contain contiguous ASCII")
|
||||
return UnsafePointer(_baseAddress)
|
||||
}
|
||||
|
||||
var startUTF16: UnsafePointer<UTF16.CodeUnit> {
|
||||
assert(
|
||||
count == 0 || elementWidth == 2,
|
||||
"String does not contain contiguous UTF16")
|
||||
return UnsafePointer(_baseAddress)
|
||||
}
|
||||
|
||||
/// the native _StringBuffer, if any, or .None.
|
||||
var nativeBuffer: _StringBuffer? {
|
||||
if !hasCocoaBuffer {
|
||||
return _owner.map {
|
||||
reinterpretCast($0) as _StringBuffer
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/// the Cocoa String buffer, if any, or .None.
|
||||
var cocoaBuffer: _CocoaString? {
|
||||
if hasCocoaBuffer {
|
||||
return _owner.map {
|
||||
reinterpretCast($0) as _CocoaString
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// slicing
|
||||
|
||||
/// Return the given sub-_StringCore
|
||||
subscript(subRange: Range<Int>) -> _StringCore {
|
||||
|
||||
assert(subRange.startIndex >= 0)
|
||||
assert(subRange.endIndex <= count)
|
||||
|
||||
let newCount = subRange.endIndex - subRange.startIndex
|
||||
assert(UWord(newCount) & _flagMask == 0)
|
||||
|
||||
if hasContiguousStorage {
|
||||
return _StringCore(
|
||||
baseAddress: _pointerToNth(subRange.startIndex),
|
||||
_countAndFlags: (_countAndFlags & _flagMask) | UWord(newCount),
|
||||
owner: _owner)
|
||||
}
|
||||
return _cocoaStringSlice(target: self, subRange: subRange)
|
||||
}
|
||||
|
||||
/// Get the Nth UTF16 Code Unit stored
|
||||
subscript(position: Int) -> UTF16.CodeUnit {
|
||||
assert(position >= 0)
|
||||
assert(position <= count)
|
||||
|
||||
if (!hasOpaqueBuffer) {
|
||||
let p = UnsafePointer<UInt8>(baseAddress.value) + (position << elementShift)
|
||||
if (_baseAddress != .null()) {
|
||||
let p = UnsafePointer<UInt8>(_pointerToNth(position).value)
|
||||
// Always dereference two bytes, but when elements are 8 bits we
|
||||
// multiply the high byte by 0.
|
||||
return UTF16.CodeUnit(p.get())
|
||||
+ UTF16.CodeUnit((p + 1).get()) * _highByteMultiplier
|
||||
}
|
||||
|
||||
return _opaqueSubscript(position)
|
||||
return _cocoaStringSubscript(target: self, position: position)
|
||||
}
|
||||
|
||||
/// \brief helper function for ordinary subscript above. Implements
|
||||
/// the slow path
|
||||
func _opaqueSubscript(position: Int) -> UTF16.CodeUnit {
|
||||
alwaysTrap("IMPLEMENT ME")
|
||||
/// Write the string, in the given encoding, to output.
|
||||
func encode<
|
||||
Encoding: UnicodeCodec,
|
||||
Output: Sink
|
||||
where Encoding.CodeUnit == Output.Element
|
||||
>(encoding: Encoding.Type, output: Output)
|
||||
{
|
||||
if _fastPath(_baseAddress != .null()) {
|
||||
if _fastPath(elementWidth == 1) {
|
||||
var out = output
|
||||
for x in UnsafeArray(
|
||||
start: UnsafePointer<UTF8.CodeUnit>(_baseAddress), length: count
|
||||
) {
|
||||
Encoding.encode(UnicodeScalar(UInt32(x)), output: &out)
|
||||
}
|
||||
}
|
||||
else {
|
||||
transcode(UTF16.self, encoding,
|
||||
UnsafeArray(
|
||||
start: UnsafePointer<UTF16.CodeUnit>(_baseAddress),
|
||||
length: count
|
||||
),
|
||||
output
|
||||
)
|
||||
}
|
||||
}
|
||||
else if (hasCocoaBuffer) {
|
||||
_StringCore(
|
||||
_cocoaStringToContiguous(source: cocoaBuffer!, range: 0...count,
|
||||
minimumCapacity: 0)
|
||||
).encode(encoding, output: output)
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to claim unused capacity in the String's existing
|
||||
/// native buffer, if any. Return zero and a pointer to the claimed
|
||||
/// storage if successful. Otherwise, returns a suggested new
|
||||
/// capacity and a null pointer.
|
||||
///
|
||||
/// Note: If successful, effectively appends garbage to the String
|
||||
/// until it has newSize UTF16 code units; you must immediately copy
|
||||
/// valid UTF16 into that storage.
|
||||
///
|
||||
/// Note: if unsuccessful because of insufficient space in an
|
||||
/// existing buffer, the suggested new capacity will at least double
|
||||
/// the existing buffer's storage
|
||||
mutating func _claimCapacity(newSize: Int,
|
||||
minElementWidth: Int) -> (Int, COpaquePointer) {
|
||||
if _fastPath(nativeBuffer && elementWidth >= minElementWidth) {
|
||||
var buffer = nativeBuffer!
|
||||
|
||||
// The buffer's "used" field must match this in order to be
|
||||
// grown. Otherwise, some other String is using parts of
|
||||
// the buffer beyond our last byte.
|
||||
let matchUsed = _pointerToNth(count)
|
||||
|
||||
// Attempt to claim unused capacity in the buffer
|
||||
if _fastPath(buffer.grow(
|
||||
UnsafePointer<RawByte>(matchUsed.value), newUsedCount: newSize)) {
|
||||
count = newSize
|
||||
return (0, matchUsed)
|
||||
}
|
||||
else if newSize > buffer.capacity {
|
||||
// Growth failed because of insufficient storage; double the size
|
||||
return (max(buffer.capacity * 2, newSize), .null())
|
||||
}
|
||||
}
|
||||
return (newSize, .null())
|
||||
}
|
||||
|
||||
/// Ensure that this String references a _StringBuffer having
|
||||
/// a capacity of at least newSize elements of at least the given width.
|
||||
/// Effectively appends garbage to the String until it has newSize
|
||||
/// UTF16 code units. Returns a pointer to the garbage code units;
|
||||
/// you must immediately copy valid data into that storage.
|
||||
mutating func _growBuffer(
|
||||
newSize: Int, minElementWidth: Int
|
||||
) -> COpaquePointer {
|
||||
let (newCapacity, existingStorage)
|
||||
= _claimCapacity(newSize, minElementWidth: minElementWidth)
|
||||
|
||||
if _fastPath(!existingStorage.isNull()) {
|
||||
return existingStorage
|
||||
}
|
||||
|
||||
// Allocate storage.
|
||||
let newElementWidth =
|
||||
minElementWidth >= elementWidth
|
||||
? minElementWidth
|
||||
: representableAsASCII() ? 1 : 2
|
||||
|
||||
var newStorage = _StringBuffer(capacity: newCapacity, initialSize: newSize,
|
||||
elementWidth: newElementWidth)
|
||||
|
||||
var oldCount = count
|
||||
if hasContiguousStorage {
|
||||
_StringCore._copyElements(
|
||||
_baseAddress, srcElementWidth: elementWidth,
|
||||
dstStart: COpaquePointer(newStorage.start),
|
||||
dstElementWidth: newElementWidth, count: oldCount)
|
||||
}
|
||||
else {
|
||||
// Opaque cocoa buffers might not store ASCII, so assert that
|
||||
// we've allocated for 2-byte elements.
|
||||
// FIXME: can we get Cocoa to tell us quickly that an opaque
|
||||
// string is ASCII? Do we care much about that edge case?
|
||||
assert(newStorage.elementShift == 1)
|
||||
_cocoaStringReadAll(source: cocoaBuffer!,
|
||||
destination: UnsafePointer(newStorage.start))
|
||||
}
|
||||
|
||||
self = _StringCore(newStorage)
|
||||
return _pointerToNth(oldCount)
|
||||
}
|
||||
|
||||
mutating func append(c: UnicodeScalar) {
|
||||
_invariantCheck()
|
||||
// How many bytes does it take to encode each UTF16 code unit of
|
||||
// c if ASCII storage is available?
|
||||
let minBytesPerCodeUnit = c.value <= 0x7f ? 1 : 2
|
||||
// How many UTF16 code units does it take to encode c?
|
||||
let utf16Width = c.value <= 0xFFFF ? 1 : 2
|
||||
|
||||
let destination = _growBuffer(count + utf16Width,
|
||||
minElementWidth: minBytesPerCodeUnit)
|
||||
|
||||
if _fastPath(elementWidth == 1) {
|
||||
assert(
|
||||
_pointerToNth(count)
|
||||
== COpaquePointer(UnsafePointer<RawByte>(destination) + 1))
|
||||
|
||||
UnsafePointer<UTF8.CodeUnit>(destination).set(UTF8.CodeUnit(c.value))
|
||||
}
|
||||
else {
|
||||
let destination16 = UnsafePointer<UTF16.CodeUnit>(destination.value)
|
||||
if _fastPath(utf16Width == 1) {
|
||||
assert(_pointerToNth(count) == COpaquePointer(destination16 + 1))
|
||||
destination16.set(UTF16.CodeUnit(c.value))
|
||||
}
|
||||
else {
|
||||
assert(_pointerToNth(count) == COpaquePointer(destination16 + 2))
|
||||
destination16.set(UTF16.leadSurrogate(c))
|
||||
(destination16 + 1).set(UTF16.trailSurrogate(c))
|
||||
}
|
||||
}
|
||||
_invariantCheck()
|
||||
}
|
||||
|
||||
mutating func append(rhs: _StringCore) {
|
||||
_invariantCheck()
|
||||
let minElementWidth
|
||||
= elementWidth >= rhs.elementWidth
|
||||
? elementWidth
|
||||
: rhs.representableAsASCII() ? 1 : 2
|
||||
|
||||
let destination = _growBuffer(count + rhs.count,
|
||||
minElementWidth: minElementWidth)
|
||||
if _fastPath(rhs.hasContiguousStorage) {
|
||||
_StringCore._copyElements(
|
||||
rhs._baseAddress, srcElementWidth: rhs.elementWidth,
|
||||
dstStart: destination, dstElementWidth:elementWidth, count: rhs.count)
|
||||
}
|
||||
else {
|
||||
assert(elementWidth == 2)
|
||||
_cocoaStringReadAll(source: rhs.cocoaBuffer!,
|
||||
destination: UnsafePointer(destination))
|
||||
}
|
||||
_invariantCheck()
|
||||
}
|
||||
|
||||
/// Return true iff the contents of this string can be
|
||||
/// represented as pure ASCII. O(N) in the worst case
|
||||
func representableAsASCII() -> Bool {
|
||||
if _slowPath(!hasContiguousStorage) {
|
||||
return false
|
||||
}
|
||||
if _fastPath(elementWidth == 1) {
|
||||
return true
|
||||
}
|
||||
return !contains(
|
||||
UnsafeArray(start: UnsafePointer<UTF16.CodeUnit>(_baseAddress),
|
||||
length: count)
|
||||
) { $0 > 0x7f }
|
||||
}
|
||||
}
|
||||
|
||||
extension _StringCore : Collection {
|
||||
var startIndex: Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
var endIndex: Int {
|
||||
return count
|
||||
}
|
||||
|
||||
func generate() -> IndexingGenerator<_StringCore> {
|
||||
return IndexingGenerator(self)
|
||||
}
|
||||
}
|
||||
|
||||
extension _StringCore : Sliceable {}
|
||||
|
||||
// Used to support a tighter invariant: all strings with contiguous
|
||||
// storage have a non-NULL base address.
|
||||
var _emptyStringStorage: UInt32 = 0
|
||||
|
||||
var _emptyStringBase: COpaquePointer {
|
||||
return COpaquePointer(
|
||||
UnsafePointer<UInt16>(Builtin.addressof(&_emptyStringStorage)))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
@@ -5,226 +18,162 @@ extension String {
|
||||
|
||||
init<
|
||||
Encoding: UnicodeCodec, Input: Collection
|
||||
where Input.StreamType.Element == Encoding.CodeUnit
|
||||
where Input.GeneratorType.Element == Encoding.CodeUnit
|
||||
>(
|
||||
encoding: Encoding.metatype, input: Input
|
||||
_ _encoding: Encoding.Type, input: Input
|
||||
)
|
||||
{
|
||||
self = String(StringBuffer(encoding, input))
|
||||
self = String(_StringBuffer(encoding: _encoding, input: input))
|
||||
}
|
||||
|
||||
init(str_value : StringByteData) {
|
||||
self = String(UTF8, UnsafeArray(str_value.base, str_value.length))
|
||||
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(sz: Int, c: UnicodeScalar) {
|
||||
self = String(UTF32, GenerateN<UTF32.CodeUnit>(sz, c.value))
|
||||
}
|
||||
|
||||
var str_value: StringByteData {
|
||||
var utf8 = self.asUTF8()
|
||||
return StringByteData.convertFromHeapArray(
|
||||
utf8.base.value, utf8.owner,
|
||||
utf8.count.value)
|
||||
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)]
|
||||
var result = new UTF8.CodeUnit[_encodedLength(UTF8.self)]
|
||||
var len = 0
|
||||
encode(UTF8, SinkOf<UTF8.CodeUnit>({ result[len++] = $0 }))
|
||||
_encode(UTF8.self, output: SinkOf<UTF8.CodeUnit>({ result[len++] = $0 }))
|
||||
return result
|
||||
}
|
||||
|
||||
func byteLength() -> Int {
|
||||
return encodedLength(UTF8)
|
||||
}
|
||||
|
||||
func nulTerminatedUTF8() -> StringByteData {
|
||||
var buffer = str_value
|
||||
var nul: UInt8[] = [0]
|
||||
buffer.appendBytes(nul.base, 1)
|
||||
swift_keepAlive(nul.owner)
|
||||
return buffer
|
||||
}
|
||||
|
||||
// FIXME: this typealias should die; it is only needed to satisfy
|
||||
// test/NameBinding/library.swift. That test should be updated to
|
||||
// not depend on stdlib details
|
||||
typealias CharStreamType = UTF16Scalars.StreamType
|
||||
var chars : UTF16Scalars {
|
||||
return UTF16Scalars(_contiguous())
|
||||
return _encodedLength(UTF8.self)
|
||||
}
|
||||
|
||||
var lines : String[] {
|
||||
return split('\n')
|
||||
return split("\n")
|
||||
}
|
||||
|
||||
func split(separator: UnicodeScalar) -> String[] {
|
||||
var scalarSlices = swift.split(chars, { $0 == separator })
|
||||
var scalarSlices = Swift.split(unicodeScalars, { $0 == separator })
|
||||
return scalarSlices.map { $0 as String }
|
||||
}
|
||||
|
||||
var bytes : StringByteData {
|
||||
var result = StringByteData(byteLength())
|
||||
encode(
|
||||
UTF8, SinkOf<UTF8.CodeUnit>(
|
||||
{
|
||||
var tmp = $0
|
||||
result.appendBytes(
|
||||
UnsafePointer(Builtin.addressof(&tmp)), 1)
|
||||
}
|
||||
))
|
||||
return result
|
||||
}
|
||||
|
||||
func size() -> Int {
|
||||
var count = 0
|
||||
for c in chars {
|
||||
for c in unicodeScalars {
|
||||
++count
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
var length: Int {
|
||||
return size()
|
||||
}
|
||||
|
||||
func isEmpty() -> Bool {
|
||||
switch (representation) {
|
||||
case .Opaque(var rep):
|
||||
return rep.range.isEmpty()
|
||||
case .Contiguous(var rep):
|
||||
return rep.count == 0
|
||||
}
|
||||
}
|
||||
|
||||
type func _from(utf8: StringByteData) -> String {
|
||||
return String(UTF8, UnsafeArray(utf8.base, utf8.length))
|
||||
}
|
||||
|
||||
// FIXME: for some reason, making this function an actual overload
|
||||
// of subscript breaks tests. Investigate later.
|
||||
func subscript_(rng : IntStreamType) -> String {
|
||||
return String._from(bytes[rng])
|
||||
}
|
||||
|
||||
subscript (idx : Int) -> UnicodeScalar {
|
||||
for (i, c) in swift.enumerate(chars) {
|
||||
if i == idx {
|
||||
return c
|
||||
}
|
||||
}
|
||||
alwaysTrap()
|
||||
return core.count == 0
|
||||
}
|
||||
}
|
||||
|
||||
extension String : ReplPrintable {
|
||||
func replPrint() {
|
||||
print('"')
|
||||
for c in chars {
|
||||
print("\"")
|
||||
for c in unicodeScalars {
|
||||
print(c.escape())
|
||||
}
|
||||
print('"')
|
||||
print("\"")
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
// FIXME: Locales make this interesting
|
||||
var uppercase : String {
|
||||
var str_value = self.bytes
|
||||
var len = byteLength()
|
||||
var resultArray = StringByteData.getNew(len)
|
||||
var i = 0
|
||||
while i != len {
|
||||
var u8 = str_value[i]
|
||||
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).contains(Int(u8)) {
|
||||
resultArray[i] = u8 - 32
|
||||
if 97...123 ~= u8 {
|
||||
resultArray[j++] = u8 - 32
|
||||
} else {
|
||||
resultArray[i] = u8
|
||||
resultArray[j++] = u8
|
||||
}
|
||||
i += 1
|
||||
} else if u8 < 0xE0 {
|
||||
resultArray[i] = u8
|
||||
var u8_1 = str_value[i + 1]
|
||||
if u8 == 0xC3 && (0xA0 .. 0xBF).contains(Int(u8_1)) && u8_1 != 0xB7 {
|
||||
resultArray[i+1] = u8_1 - 0x20
|
||||
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[i+1] = u8_1
|
||||
resultArray[j++] = u8_1
|
||||
}
|
||||
i += 2
|
||||
} else if u8 < 0xF0 {
|
||||
resultArray[i] = u8
|
||||
resultArray[i+1] = str_value[i+1]
|
||||
resultArray[i+2] = str_value[i+2]
|
||||
i += 3
|
||||
} else {
|
||||
resultArray[i] = u8
|
||||
resultArray[i+1] = str_value[i+1]
|
||||
resultArray[i+2] = str_value[i+2]
|
||||
resultArray[i+3] = str_value[i+3]
|
||||
i += 4
|
||||
resultArray[j++] = u8
|
||||
if u8 >= 0xF0 {
|
||||
resultArray[j++] = utf8[i++]
|
||||
}
|
||||
resultArray[j++] = utf8[i++]
|
||||
resultArray[j++] = utf8[i++]
|
||||
}
|
||||
}
|
||||
|
||||
return String._from(resultArray)
|
||||
return String(UTF8.self, input: resultArray)
|
||||
}
|
||||
|
||||
// FIXME: Locales make this interesting
|
||||
var lowercase : String {
|
||||
var str_value = self.bytes
|
||||
var len = byteLength()
|
||||
var resultArray = StringByteData.getNew(len)
|
||||
var i = 0
|
||||
while i != len {
|
||||
var u8 = str_value[i]
|
||||
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).contains(Int(u8)) {
|
||||
resultArray[i] = u8 + 32
|
||||
if 65...91 ~= u8 {
|
||||
resultArray[j++] = u8 + 32
|
||||
} else {
|
||||
resultArray[i] = u8
|
||||
resultArray[j++] = u8
|
||||
}
|
||||
i += 1
|
||||
} else if u8 < 0xE0 {
|
||||
resultArray[i] = u8
|
||||
var u8_1 = str_value[i + 1]
|
||||
if u8 == 0xC3 && (0x80 .. 0x9F).contains(Int(u8_1)) && u8_1 != 0x97 {
|
||||
resultArray[i+1] = u8_1 + 0x20
|
||||
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[i+1] = u8_1
|
||||
resultArray[j++] = u8_1
|
||||
}
|
||||
i += 2
|
||||
} else if u8 < 0xF0 {
|
||||
resultArray[i] = u8
|
||||
resultArray[i+1] = str_value[i+1]
|
||||
resultArray[i+2] = str_value[i+2]
|
||||
i += 3
|
||||
} else {
|
||||
resultArray[i] = u8
|
||||
resultArray[i+1] = str_value[i+1]
|
||||
resultArray[i+2] = str_value[i+2]
|
||||
resultArray[i+3] = str_value[i+3]
|
||||
i += 4
|
||||
resultArray[j++] = u8
|
||||
if u8 >= 0xF0 {
|
||||
resultArray[j++] = utf8[i++]
|
||||
}
|
||||
resultArray[j++] = utf8[i++]
|
||||
resultArray[j++] = utf8[i++]
|
||||
}
|
||||
}
|
||||
|
||||
return String._from(resultArray)
|
||||
return String(UTF8.self, input: resultArray)
|
||||
}
|
||||
|
||||
init(c: UnicodeScalar) {
|
||||
self = String(1, c)
|
||||
init(_ _c: UnicodeScalar) {
|
||||
self = String(count: 1, scalar: _c)
|
||||
}
|
||||
|
||||
func _isAll(predicate: (UnicodeScalar) -> Bool) -> Bool {
|
||||
for c in chars { if !predicate(c) { return false } }
|
||||
for c in unicodeScalars { if !predicate(c) { return false } }
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func startsWith(prefix: String) -> Bool {
|
||||
if prefix.size() > size() { return false }
|
||||
return Swift.startsWith(self, prefix)
|
||||
}
|
||||
|
||||
return self[0..prefix.size()] == prefix
|
||||
func endsWith(suffix: String) -> Bool {
|
||||
return Swift.startsWith(Reverse(self), Reverse(suffix))
|
||||
}
|
||||
|
||||
func isAlpha() -> Bool { return _isAll({ $0.isAlpha() }) }
|
||||
@@ -235,114 +184,125 @@ extension String {
|
||||
extension String : FormattedPrintable {
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
var toPrint = self
|
||||
if kind == 'u' { toPrint = uppercase }
|
||||
else if kind == 'l' { toPrint = lowercase }
|
||||
if kind == "u" { toPrint = uppercase }
|
||||
else if kind == "l" { toPrint = lowercase }
|
||||
return Format(layout).printToString(toPrint)
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Represent a positive integer value in the given radix,
|
||||
/// writing each UTF-16 code units into stream. The value of `ten'
|
||||
/// should be either 'A' or 'a', depending on whether you want upper-
|
||||
/// 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: (UTF16.CodeUnit)->Void )
|
||||
ten: UnicodeScalar = "a") ( stream: (UTF8.CodeUnit)->Void )
|
||||
{
|
||||
|
||||
if value == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
_formatPositiveInteger(value / radix, radix, ten)(stream)
|
||||
_formatPositiveInteger(value / radix, radix, ten: ten)(stream: stream)
|
||||
var digit = UInt32(value % radix)
|
||||
var baseCharOrd : UInt32 = digit <= 9 ? '0'.value : ten.value - 10
|
||||
stream(UTF16.CodeUnit(baseCharOrd + digit))
|
||||
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: (UTF16.CodeUnit)->Void ) {
|
||||
ten: UnicodeScalar = "a") ( stream: (UTF8.CodeUnit)->Void ) {
|
||||
|
||||
if value == 0 {
|
||||
stream (UTF16.CodeUnit('0'.value))
|
||||
stream(UTF8.CodeUnit(_asUnicodeCodePoint("0")))
|
||||
}
|
||||
else {
|
||||
if (value < 0) {
|
||||
stream(UTF16.CodeUnit('-'.value))
|
||||
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)(stream)
|
||||
_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), uppercase ? 'A' : 'a')
|
||||
var utf16Count = 0
|
||||
format { _ in ++utf16Count;() }
|
||||
var buffer = StringBuffer(utf16Count)
|
||||
var used = buffer.used
|
||||
format { used++.set($0) }
|
||||
buffer.used = used
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
init(v : UInt64, radix: Int = 10, uppercase: Bool = false) {
|
||||
var format = _formatPositiveInteger(v, UInt64(radix), uppercase ? 'A' : 'a')
|
||||
var utf16Count = v == 0 ? 1 : 0
|
||||
format { _ in ++utf16Count;() }
|
||||
var buffer = StringBuffer(utf16Count)
|
||||
var used = buffer.used
|
||||
format { used++.set($0) }
|
||||
// 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 {
|
||||
used++.set(UTF16.CodeUnit('0'.value))
|
||||
p++.set(UTF8.CodeUnit("0"))
|
||||
}
|
||||
buffer.used = used
|
||||
self = String(buffer)
|
||||
}
|
||||
|
||||
init(v : Int8, radix : Int = 10, uppercase : Bool = false) {
|
||||
self = String(Int64(v), radix, uppercase)
|
||||
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, 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, uppercase)
|
||||
init(_ v : Int32, 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, uppercase)
|
||||
init(_ v : Int, radix : Int = 10, uppercase : Bool = false) {
|
||||
self = String(Int64(v), radix: radix, uppercase: uppercase)
|
||||
}
|
||||
init(v : UInt16, radix : Int = 10, uppercase : Bool = false) {
|
||||
self = String(UInt64(v), radix, uppercase)
|
||||
init(_ v : UInt8, 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, 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) {
|
||||
var cCharBuf = Array<UInt8>(256, 0)
|
||||
var n = Int(c_print_double(cCharBuf.base.value, v))
|
||||
var buffer = StringBuffer(n)
|
||||
var used = buffer.used
|
||||
for i in 0..n {
|
||||
used++.set(UTF16.CodeUnit(cCharBuf[i]))
|
||||
init(_ v : Double) {
|
||||
var cCharBuf = UInt8[](count: 256, value: 0)
|
||||
var n = Int(c_print_double(cCharBuf.elementStorage.value, v))
|
||||
var buffer = _StringBuffer(capacity: n, initialSize: n, elementWidth: 1)
|
||||
var p = UnsafePointer<UTF8.CodeUnit>(buffer.start)
|
||||
for i in 0...n {
|
||||
p++.set(cCharBuf[i])
|
||||
}
|
||||
buffer.used = used
|
||||
self = String(buffer)
|
||||
}
|
||||
|
||||
init(v : Float) {
|
||||
init(_ v : Float) {
|
||||
self = String(Double(v))
|
||||
}
|
||||
|
||||
init(b : Bool) {
|
||||
init(_ b : Bool) {
|
||||
if b {
|
||||
self = "true"
|
||||
} else {
|
||||
@@ -356,19 +316,19 @@ extension String {
|
||||
/// \brief If the string represents an integer that fits into an Int, returns
|
||||
/// the corresponding integer.
|
||||
func toInt() -> Int? {
|
||||
var scalars = self.chars
|
||||
var scalars = self.unicodeScalars
|
||||
|
||||
var start = scalars.startIndex()
|
||||
if start == scalars.endIndex() {
|
||||
var start = scalars.startIndex
|
||||
if start == scalars.endIndex {
|
||||
return .None
|
||||
}
|
||||
|
||||
// Interpet '+' or '-' before the number.
|
||||
var negativeFactor = -1
|
||||
var firstC = scalars[start]
|
||||
if (firstC == '+') {
|
||||
if (firstC == "+") {
|
||||
++start
|
||||
} else if (firstC == '-') {
|
||||
} else if (firstC == "-") {
|
||||
++start
|
||||
negativeFactor = 1
|
||||
}
|
||||
@@ -377,7 +337,7 @@ extension String {
|
||||
// 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()] {
|
||||
for c in scalars[start...scalars.endIndex] {
|
||||
if !c.isDigit() {
|
||||
// Conversion failed if a non-digit is encountered.
|
||||
return .None
|
||||
@@ -389,7 +349,7 @@ extension String {
|
||||
}
|
||||
res = res * 10
|
||||
|
||||
var d : Int = (c - '0')
|
||||
var d : Int = (c - "0")
|
||||
// Underflow occurs if res - d < Int.min.
|
||||
if res < Int.min + d {
|
||||
return .None
|
||||
@@ -411,12 +371,12 @@ 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 = chars
|
||||
var startIndex = rng.startIndex()
|
||||
for i in 0..start {
|
||||
var rng = unicodeScalars
|
||||
var startIndex = rng.startIndex
|
||||
for i in 0...start {
|
||||
++startIndex
|
||||
}
|
||||
return rng[startIndex..rng.endIndex()]
|
||||
return rng[startIndex...rng.endIndex]
|
||||
}
|
||||
|
||||
/// \brief Split the given string at the given delimiter character, returning
|
||||
@@ -425,10 +385,10 @@ extension String {
|
||||
func splitFirst(delim: UnicodeScalar)
|
||||
-> (before: String, after: String, wasFound : Bool)
|
||||
{
|
||||
var rng = chars
|
||||
var rng = unicodeScalars
|
||||
for i in indices(rng) {
|
||||
if rng[i] == delim {
|
||||
return (rng[rng.startIndex()..i], rng[i.succ()..rng.endIndex()], true)
|
||||
return (rng[rng.startIndex...i], rng[i.succ()...rng.endIndex], true)
|
||||
}
|
||||
}
|
||||
return (self, "", false)
|
||||
@@ -441,20 +401,20 @@ extension String {
|
||||
func splitFirstIf(pred: (UnicodeScalar) -> Bool)
|
||||
-> (before: String, found: UnicodeScalar, after: String, wasFound: Bool)
|
||||
{
|
||||
var rng = chars
|
||||
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 (rng[rng.startIndex...i], rng[i], rng[i.succ()...rng.endIndex], true)
|
||||
}
|
||||
}
|
||||
return (self, '🎃', String(), false)
|
||||
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(chars, pred)
|
||||
var scalarSlices = Swift.split(unicodeScalars, pred)
|
||||
return scalarSlices.map { $0 as String }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//===--- StringUTF8.swift - A UTF8 view of StringCore ---------------------===//
|
||||
//===--- StringUTF8.swift - A UTF8 view of _StringCore ---------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
@@ -10,14 +10,14 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// StringCore currently has three representations: Native ASCII,
|
||||
// _StringCore currently has three representations: Native ASCII,
|
||||
// Native UTF16, and Opaque Cocoa. Expose each of these as UTF8 in a
|
||||
// way that will hopefully be efficient to traverse
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
extension StringCore {
|
||||
extension _StringCore {
|
||||
// An integral type that holds a chunk of UTF8, starting in its low
|
||||
// byte
|
||||
typealias UTF8Chunk = UInt64
|
||||
@@ -38,9 +38,9 @@ extension StringCore {
|
||||
var result: UTF8Chunk = ~0 // start with all bits set
|
||||
|
||||
c_memcpy(
|
||||
UnsafePointer(Builtin.addressof(&result)),
|
||||
UnsafePointer(startASCII + i),
|
||||
numericCast(utf16Count))
|
||||
dest: UnsafePointer(Builtin.addressof(&result)),
|
||||
src: UnsafePointer(startASCII + i),
|
||||
size: numericCast(utf16Count))
|
||||
|
||||
return (i + utf16Count, result)
|
||||
}
|
||||
@@ -125,17 +125,22 @@ extension StringCore {
|
||||
return (nextIndex, result)
|
||||
}
|
||||
else {
|
||||
return _cocoaStringEncodeSomeUTF8(self, i)
|
||||
return _cocoaStringEncodeSomeUTF8(target: self, position: i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
struct UTF8View : Collection {
|
||||
let _core: StringCore
|
||||
let _core: _StringCore
|
||||
|
||||
init(_ _core: _StringCore) {
|
||||
self._core = _core
|
||||
}
|
||||
|
||||
struct Index : ForwardIndex {
|
||||
init(_core: StringCore, _coreIndex: Int, _buffer: StringCore.UTF8Chunk) {
|
||||
init(_ _core: _StringCore, _ _coreIndex: Int,
|
||||
_ _buffer: _StringCore.UTF8Chunk) {
|
||||
self._core = _core
|
||||
self._coreIndex = _coreIndex
|
||||
self._buffer = _buffer
|
||||
@@ -158,9 +163,9 @@ extension String {
|
||||
return Index(_core, _coreIndex, ~0)
|
||||
}
|
||||
|
||||
let _core: StringCore
|
||||
let _core: _StringCore
|
||||
let _coreIndex: Int
|
||||
let _buffer: StringCore.UTF8Chunk
|
||||
let _buffer: _StringCore.UTF8Chunk
|
||||
}
|
||||
|
||||
var startIndex: Index {
|
||||
|
||||
@@ -1,23 +1,33 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
// Conversions between different Unicode encodings. Note that these
|
||||
// are *not* currently resilient to erroneous data.
|
||||
|
||||
import swift
|
||||
typealias UnicodeScalar = Char
|
||||
|
||||
protocol UnicodeCodec {
|
||||
typealias CodeUnit
|
||||
|
||||
static def decode(next: ()->CodeUnit?) -> UnicodeScalar?
|
||||
static def encode(input: UnicodeScalar, output: (CodeUnit)->())
|
||||
class func decode<G : Generator where G.Element == CodeUnit>(inout next:G) -> UnicodeScalar?
|
||||
class func encode<S : Sink where S.Element == CodeUnit>(input: UnicodeScalar,inout output: S)
|
||||
}
|
||||
|
||||
struct UTF8 : UnicodeCodec {
|
||||
|
||||
typealias CodeUnit = UInt8
|
||||
|
||||
static def decode(next: ()->CodeUnit?) -> UnicodeScalar? {
|
||||
static func decode<G : Generator where G.Element == CodeUnit>(inout next:G) -> UnicodeScalar? {
|
||||
|
||||
var c = next()
|
||||
var c = next.next()
|
||||
if !c {
|
||||
return .None
|
||||
}
|
||||
@@ -26,10 +36,10 @@ struct UTF8 : UnicodeCodec {
|
||||
|
||||
// one octet (7 bits)
|
||||
if c0 < 0x80 {
|
||||
return Char(UInt32(c0))
|
||||
return UnicodeScalar(UInt32(c0))
|
||||
}
|
||||
|
||||
var c1 = next()!
|
||||
var c1 = next.next()!
|
||||
|
||||
// start with octet 1 (we'll mask off high bits later)
|
||||
var result = UInt32(c0)
|
||||
@@ -37,109 +47,231 @@ struct UTF8 : UnicodeCodec {
|
||||
if c0 < 0xE0 {
|
||||
return UnicodeScalar(result & 0x000007FF) // 11 bits
|
||||
}
|
||||
c1 = next()! // prefetch octet 3
|
||||
c1 = next.next()! // prefetch octet 3
|
||||
result = (result << 6) | UInt32(c1 & 0x3F) // merge octet 3
|
||||
if c0 < 0xF0 {
|
||||
return UnicodeScalar(result & 0x0000FFFF) // 16 bits
|
||||
}
|
||||
c1 = next()! // prefetch octet 4
|
||||
c1 = next.next()! // prefetch octet 4
|
||||
result = (result << 6) | UInt32(c1 & 0x3F) // merge octet 4
|
||||
return UnicodeScalar(result & 0x001FFFFF) // 21 bits
|
||||
}
|
||||
|
||||
static def encode(input: UnicodeScalar, output: (CodeUnit)->()) {
|
||||
static func encode<S : Sink where S.Element == CodeUnit>(
|
||||
input: UnicodeScalar,inout output: S) {
|
||||
var c = UInt32(input)
|
||||
var buf3 = UInt8(c)
|
||||
var buf3 = UInt8(c & 0xFF)
|
||||
|
||||
if c >= UInt32(1<<7) {
|
||||
c >>= 6
|
||||
buf3 = (buf3 & 0x3F) | 0x80 // 10xxxxxx
|
||||
var buf2 = UInt8(c)
|
||||
var buf2 = UInt8(c & 0xFF)
|
||||
if c < UInt32(1<<5) {
|
||||
buf2 |= 0xC0 // 110xxxxx
|
||||
}
|
||||
else {
|
||||
c >>= 6
|
||||
buf2 = (buf2 & 0x3F) | 0x80 // 10xxxxxx
|
||||
var buf1 = UInt8(c)
|
||||
var buf1 = UInt8(c & 0xFF)
|
||||
if c < UInt32(1<<4) {
|
||||
buf1 |= 0xE0 // 1110xxxx
|
||||
}
|
||||
else {
|
||||
c >>= 6
|
||||
buf1 = (buf1 & 0x3F) | 0x80 // 10xxxxxx
|
||||
output(UInt8(c | 0xF0)) // 11110xxx
|
||||
output.put(UInt8(c | 0xF0)) // 11110xxx
|
||||
}
|
||||
output(buf1)
|
||||
output.put(buf1)
|
||||
}
|
||||
output(buf2)
|
||||
output.put(buf2)
|
||||
}
|
||||
output(buf3)
|
||||
output.put(buf3)
|
||||
}
|
||||
|
||||
var _value: UInt8
|
||||
var _value = UInt8()
|
||||
}
|
||||
|
||||
struct UTF16 : UnicodeCodec {
|
||||
typealias CodeUnit = UInt16
|
||||
|
||||
static def decode(next: ()->CodeUnit?) -> UnicodeScalar? {
|
||||
var first = next()
|
||||
static func decode<G : Generator where G.Element == CodeUnit>(inout input:G) -> UnicodeScalar? {
|
||||
let first = input.next()
|
||||
if !first {
|
||||
return .None
|
||||
}
|
||||
|
||||
var unit0 = UInt32(first!)
|
||||
let unit0 = UInt32(first!)
|
||||
if (unit0 >> 11) != 0x1B {
|
||||
return UnicodeScalar(unit0)
|
||||
}
|
||||
|
||||
var unit1 = UInt32(next()!)
|
||||
return UnicodeScalar(
|
||||
0x10000
|
||||
+ ((unit0 - 0xD800) << 10)
|
||||
+ (unit1 - 0xDC00))
|
||||
let unit1 = UInt32(input.next()!)
|
||||
|
||||
// FIXME: Uglified due to type checker performance issues.
|
||||
var result : UInt32 = 0x10000
|
||||
result += ((unit0 - 0xD800) << 10)
|
||||
result += (unit1 - 0xDC00)
|
||||
return UnicodeScalar(result)
|
||||
}
|
||||
|
||||
static def encode(input: UnicodeScalar, output: (UInt16)->()) {
|
||||
static func encode<S : Sink where S.Element == CodeUnit>(
|
||||
input: UnicodeScalar,inout output: S) {
|
||||
var scalarValue: UInt32 = UInt32(input)
|
||||
|
||||
if UInt32(UInt16(scalarValue)) == scalarValue {
|
||||
output(UInt16(scalarValue))
|
||||
if scalarValue <= UInt32(UInt16.max) {
|
||||
output.put(UInt16(scalarValue))
|
||||
}
|
||||
else {
|
||||
var lead_offset = UInt32(0xD800) - (0x10000 >> 10)
|
||||
output(UInt16(lead_offset + (scalarValue >> 10)))
|
||||
output(UInt16(0xDC00 + (scalarValue & 0x3FF)))
|
||||
output.put(UInt16(lead_offset + (scalarValue >> 10)))
|
||||
output.put(UInt16(0xDC00 + (scalarValue & 0x3FF)))
|
||||
}
|
||||
}
|
||||
|
||||
var _value: UInt16
|
||||
var _value = UInt16()
|
||||
}
|
||||
|
||||
struct UTF32 : UnicodeCodec {
|
||||
typealias CodeUnit = UInt32
|
||||
|
||||
static def create(value: CodeUnit) -> UTF32 {
|
||||
init(_ _value: UInt32) {
|
||||
self._value = _value
|
||||
}
|
||||
|
||||
static func create(value: CodeUnit) -> UTF32 {
|
||||
return UTF32(value)
|
||||
}
|
||||
|
||||
def value() -> CodeUnit {
|
||||
func value() -> CodeUnit {
|
||||
return self._value
|
||||
}
|
||||
|
||||
static def decode(next: ()->CodeUnit?) -> UnicodeScalar? {
|
||||
var x = next()
|
||||
static func decode<G : Generator where G.Element == CodeUnit>(
|
||||
inout input:G) -> UnicodeScalar? {
|
||||
var x = input.next()
|
||||
if x {
|
||||
return UnicodeScalar(x!)
|
||||
}
|
||||
return .None
|
||||
}
|
||||
|
||||
static def encode(input: UnicodeScalar, output: (UInt32)->()) {
|
||||
output(UInt32(input))
|
||||
static func encode<S : Sink where S.Element == CodeUnit>(
|
||||
input: UnicodeScalar,inout output: S) {
|
||||
output.put(UInt32(input))
|
||||
}
|
||||
|
||||
var _value: UInt32
|
||||
var _value = UInt32()
|
||||
}
|
||||
|
||||
func transcode<
|
||||
Input: Generator,
|
||||
Output: Sink,
|
||||
InputEncoding: UnicodeCodec,
|
||||
OutputEncoding: UnicodeCodec
|
||||
where InputEncoding.CodeUnit == Input.Element,
|
||||
OutputEncoding.CodeUnit == Output.Element> (
|
||||
inputEncoding: InputEncoding.Type, outputEncoding: OutputEncoding.Type,
|
||||
var input: Input, var output: Output
|
||||
) {
|
||||
for var scalar = InputEncoding.decode(&input);
|
||||
scalar;
|
||||
scalar = InputEncoding.decode(&input)
|
||||
{
|
||||
var s = scalar!
|
||||
OutputEncoding.encode(s, output: &output)
|
||||
}
|
||||
}
|
||||
|
||||
// Trivial transcoder; I'm hoping this will kick in for common cases
|
||||
func transcode<
|
||||
Input: Generator,
|
||||
Output: Sink,
|
||||
Encoding: UnicodeCodec
|
||||
where Encoding.CodeUnit == Input.Element, Encoding.CodeUnit == Output.Element
|
||||
> (
|
||||
inputEncoding: Encoding.Type, outputEncoding: Encoding.Type,
|
||||
var input: Input, var output: Output
|
||||
) {
|
||||
while true {
|
||||
var x = input.next()
|
||||
if !x {
|
||||
break
|
||||
}
|
||||
output.put(x!)
|
||||
}
|
||||
}
|
||||
|
||||
protocol StringElement {
|
||||
class func toUTF16CodeUnit(_: Self) -> UTF16.CodeUnit
|
||||
class func fromUTF16CodeUnit(utf16: UTF16.CodeUnit) -> Self
|
||||
}
|
||||
|
||||
extension UTF16.CodeUnit : StringElement {
|
||||
static func toUTF16CodeUnit(x: UTF16.CodeUnit) -> UTF16.CodeUnit {
|
||||
return x
|
||||
}
|
||||
static func fromUTF16CodeUnit(utf16: UTF16.CodeUnit) -> UTF16.CodeUnit {
|
||||
return utf16
|
||||
}
|
||||
}
|
||||
|
||||
extension UTF8.CodeUnit : StringElement {
|
||||
static func toUTF16CodeUnit(x: UTF8.CodeUnit) -> UTF16.CodeUnit {
|
||||
return UTF16.CodeUnit(x)
|
||||
}
|
||||
static func fromUTF16CodeUnit(utf16: UTF16.CodeUnit) -> UTF8.CodeUnit {
|
||||
return UTF8.CodeUnit(utf16)
|
||||
}
|
||||
}
|
||||
|
||||
extension UTF16 {
|
||||
static func width(x: UnicodeScalar) -> Int {
|
||||
return x.value <= 0xFFFF ? 1 : 2
|
||||
}
|
||||
|
||||
static func leadSurrogate(x: UnicodeScalar) -> UTF16.CodeUnit {
|
||||
assert(width(x) == 2)
|
||||
return (UTF16.CodeUnit(x.value - 0x1_0000) >> 10) + 0xD800
|
||||
}
|
||||
|
||||
static func trailSurrogate(x: UnicodeScalar) -> UTF16.CodeUnit {
|
||||
assert(width(x) == 2)
|
||||
return (UTF16.CodeUnit(x.value - 0x1_0000) & ((1 << 10) - 1)) + 0xDC00
|
||||
}
|
||||
|
||||
static func copy<T: StringElement, U: StringElement>(
|
||||
source: UnsafePointer<T>, destination: UnsafePointer<U>, count: Int
|
||||
) {
|
||||
if UWord(Builtin.strideof(T.self)) == UWord(Builtin.strideof(U.self)) {
|
||||
c_memcpy(
|
||||
dest: UnsafePointer(destination),
|
||||
src: UnsafePointer(source),
|
||||
size: UInt(count) * UInt(Builtin.strideof(U.self)))
|
||||
}
|
||||
else {
|
||||
for i in 0...count {
|
||||
let u16 = T.toUTF16CodeUnit((source + i).get())
|
||||
(destination + i).set(U.fromUTF16CodeUnit(u16))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func measure<Encoding: UnicodeCodec, Input: Generator where Encoding.CodeUnit == Input.Element>(
|
||||
_: Encoding.Type, var input: Input
|
||||
) -> (Int, Bool) {
|
||||
var count = 0
|
||||
var isAscii = true
|
||||
while true {
|
||||
if let x = Encoding.decode(&input) {
|
||||
if x.value > 0x7f {
|
||||
isAscii = false
|
||||
}
|
||||
count += width(x)
|
||||
}
|
||||
else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return (count, isAscii)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +1,66 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// UnicodeScalar Type
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct UnicodeScalar : BuiltinCharacterLiteralConvertible, CharacterLiteralConvertible,
|
||||
ReplPrintable {
|
||||
var _value : Builtin.Int21
|
||||
struct UnicodeScalar :
|
||||
ExtendedGraphemeClusterLiteralConvertible, ReplPrintable {
|
||||
|
||||
var value : UInt32 {
|
||||
get:
|
||||
var zextValue = Builtin.zext_Int21_Int32(_value)
|
||||
return UInt32(zextValue)
|
||||
var _value: Builtin.Int32
|
||||
|
||||
var value: UInt32 {
|
||||
get {
|
||||
return UInt32(_value)
|
||||
}
|
||||
}
|
||||
|
||||
static func _convertFromBuiltinCharacterLiteral(val: Builtin.Int21) -> UnicodeScalar {
|
||||
return UnicodeScalar(val)
|
||||
}
|
||||
|
||||
static func convertFromCharacterLiteral(value: UnicodeScalar) -> UnicodeScalar {
|
||||
return value
|
||||
static func convertFromExtendedGraphemeClusterLiteral(
|
||||
value: String) -> UnicodeScalar {
|
||||
let unicodeScalars = value.unicodeScalars
|
||||
return unicodeScalars[unicodeScalars.startIndex]
|
||||
}
|
||||
|
||||
init() {
|
||||
self._value = Builtin.trunc_Int32_Int21(Int32(0).value)
|
||||
self._value = Int32(0).value
|
||||
}
|
||||
|
||||
init(value : Builtin.Int21) {
|
||||
init(_ value : Builtin.Int32) {
|
||||
self._value = value
|
||||
}
|
||||
|
||||
init(v : UInt32) {
|
||||
init(_ v : UInt32) {
|
||||
var lowHalf = v & 0xFFFF
|
||||
// reserved in each plane
|
||||
debugTrap(lowHalf != 0xFFFE && lowHalf != 0xFFFF)
|
||||
assert(lowHalf != 0xFFFE && lowHalf != 0xFFFF)
|
||||
// UTF-16 surrogate pair values are not valid code points
|
||||
debugTrap(v < 0xD800 || v > 0xDFFF)
|
||||
assert(v < 0xD800 || v > 0xDFFF)
|
||||
// U+FDD0...U+FDEF are also reserved
|
||||
debugTrap(v < 0xFDD0 || v > 0xFDEF)
|
||||
assert(v < 0xFDD0 || v > 0xFDEF)
|
||||
// beyond what is defined to be valid
|
||||
debugTrap(v < 0x10FFFF)
|
||||
assert(v < 0x10FFFF)
|
||||
|
||||
self._value = Builtin.trunc_Int32_Int21(v.value)
|
||||
self._value = v.value
|
||||
}
|
||||
|
||||
init(_ v: UnicodeScalar) {
|
||||
// This constructor allows one to provide necessary type context to
|
||||
// disambiguate between function overloads on 'String' and 'UnicodeScalar'.
|
||||
self = v
|
||||
}
|
||||
|
||||
func replPrint() {
|
||||
print('\'')
|
||||
print("\"")
|
||||
print(escape())
|
||||
print('\'')
|
||||
print("\"")
|
||||
}
|
||||
|
||||
func escape() -> String {
|
||||
@@ -58,21 +73,21 @@ struct UnicodeScalar : BuiltinCharacterLiteralConvertible, CharacterLiteralConve
|
||||
}
|
||||
}
|
||||
|
||||
if self == '\\' {
|
||||
if self == "\\" {
|
||||
return "\\\\"
|
||||
} else if self == '"' {
|
||||
return "\\\""
|
||||
} else if self == '\'' {
|
||||
} else if self == "\'" {
|
||||
return "\\\'"
|
||||
} else if self == "\"" {
|
||||
return "\\\""
|
||||
} else if isPrint() {
|
||||
return String(self)
|
||||
} else if self == '\0' {
|
||||
} else if self == "\0" {
|
||||
return "\\0"
|
||||
} else if self == '\n' {
|
||||
} else if self == "\n" {
|
||||
return "\\n"
|
||||
} else if self == '\r' {
|
||||
} else if self == "\r" {
|
||||
return "\\r"
|
||||
} else if self == '\t' {
|
||||
} else if self == "\t" {
|
||||
return "\\t"
|
||||
} else if UInt32(self) < 128 {
|
||||
return "\\x"
|
||||
@@ -110,19 +125,19 @@ struct UnicodeScalar : BuiltinCharacterLiteralConvertible, CharacterLiteralConve
|
||||
|
||||
// FIXME: Locales make this interesting
|
||||
func isAlpha() -> Bool {
|
||||
return (self >= 'A' && self <= 'Z') || (self >= 'a' && self <= 'z')
|
||||
return (self >= "A" && self <= "Z") || (self >= "a" && self <= "z")
|
||||
}
|
||||
|
||||
// FIXME: Locales make this interesting
|
||||
func isDigit() -> Bool {
|
||||
return self >= '0' && self <= '9'
|
||||
return self >= "0" && self <= "9"
|
||||
}
|
||||
|
||||
// FIXME: Locales make this interesting
|
||||
var uppercase : UnicodeScalar {
|
||||
if self >= 'a' && self <= 'z' {
|
||||
if self >= "a" && self <= "z" {
|
||||
return UnicodeScalar(UInt32(self) - 32)
|
||||
} else if self >= 'à' && self <= 'þ' && self != '÷' {
|
||||
} else if self >= "à" && self <= "þ" && self != "÷" {
|
||||
return UnicodeScalar(UInt32(self) - 32)
|
||||
}
|
||||
return self
|
||||
@@ -130,9 +145,9 @@ struct UnicodeScalar : BuiltinCharacterLiteralConvertible, CharacterLiteralConve
|
||||
|
||||
// FIXME: Locales make this interesting
|
||||
var lowercase : UnicodeScalar {
|
||||
if self >= 'A' && self <= 'Z' {
|
||||
if self >= "A" && self <= "Z" {
|
||||
return UnicodeScalar(UInt32(self) + 32)
|
||||
} else if self >= 'À' && self <= 'Þ' && self != '×' {
|
||||
} else if self >= "À" && self <= "Þ" && self != "×" {
|
||||
return UnicodeScalar(UInt32(self) + 32)
|
||||
}
|
||||
return self
|
||||
@@ -143,43 +158,43 @@ struct UnicodeScalar : BuiltinCharacterLiteralConvertible, CharacterLiteralConve
|
||||
// FIXME: The constraint-based type checker goes painfully exponential
|
||||
// when we turn this into one large expression. Break it up for now,
|
||||
// until we can optimize the constraint solver better.
|
||||
if self == ' ' || self == '\t' { return true }
|
||||
if self == '\n' || self == '\r' { return true }
|
||||
return self == '\x0B' || self == '\x0C'
|
||||
if self == " " || self == "\t" { return true }
|
||||
if self == "\n" || self == "\r" { return true }
|
||||
return self == "\x0B" || self == "\x0C"
|
||||
}
|
||||
}
|
||||
|
||||
extension UnicodeScalar : FormattedPrintable {
|
||||
func format(kind: UnicodeScalar, layout: String) -> String {
|
||||
return String(self).format(kind, layout)
|
||||
return String(self).format(kind, layout: layout)
|
||||
}
|
||||
}
|
||||
|
||||
extension UnicodeScalar : Hashable {
|
||||
func hashValue() -> Int {
|
||||
var hashValue: Int {
|
||||
return Int(self.value)
|
||||
}
|
||||
}
|
||||
|
||||
extension UnicodeScalar {
|
||||
init(v : Int) {
|
||||
init(_ v : Int) {
|
||||
self = UnicodeScalar(UInt32(v))
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt8 {
|
||||
init(v : UnicodeScalar) {
|
||||
debugTrap(v.value <= UInt32(UInt8.max), "Code point value does not fit into UInt8")
|
||||
init(_ v : UnicodeScalar) {
|
||||
assert(v.value <= UInt32(UInt8.max), "Code point value does not fit into UInt8")
|
||||
self = UInt8(v.value)
|
||||
}
|
||||
}
|
||||
extension UInt32 {
|
||||
init(v : UnicodeScalar) {
|
||||
init(_ v : UnicodeScalar) {
|
||||
self = v.value
|
||||
}
|
||||
}
|
||||
extension UInt64 {
|
||||
init(v : UnicodeScalar) {
|
||||
init(_ v : UnicodeScalar) {
|
||||
self = UInt64(v.value)
|
||||
}
|
||||
}
|
||||
@@ -216,3 +231,19 @@ extension UnicodeScalar {
|
||||
return (self >= UnicodeScalar(0o040) && self <= UnicodeScalar(0o176))
|
||||
}
|
||||
}
|
||||
|
||||
/// Helpers to provide type context to guide type inference in code like::
|
||||
///
|
||||
/// var zero = _asUnicodeCodePoint('0')
|
||||
func _asUnicodeCodePoint(us: UnicodeScalar) -> Builtin.Int32 {
|
||||
return us._value
|
||||
}
|
||||
func _asUnicodeCodePoint(us: UnicodeScalar) -> UInt32 {
|
||||
return us.value
|
||||
}
|
||||
func _asUTF16CodeUnit(us: UnicodeScalar) -> UTF16.CodeUnit {
|
||||
var codePoint = us.value
|
||||
assert(codePoint <= UInt32(UInt16.max))
|
||||
return UTF16.CodeUnit(codePoint)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
/// When you use this type, you become partially responsible for
|
||||
/// keeping the object alive.
|
||||
struct Unmanaged<T: AnyObject> {
|
||||
@unowned(unsafe) var _value: T
|
||||
unowned(unsafe) var _value: T
|
||||
|
||||
@transparent
|
||||
init(_private: T) { _value = _private }
|
||||
@@ -85,13 +85,19 @@ struct Unmanaged<T: AnyObject> {
|
||||
|
||||
/// Get the value of this unmanaged reference as a managed
|
||||
/// reference without consuming an unbalanced retain of it.
|
||||
var unretainedValue: T {
|
||||
///
|
||||
/// This is useful when a function returns an unmanaged reference
|
||||
/// and you know that you're not responsible for releasing the result.
|
||||
func takeUnretainedValue() -> T {
|
||||
return _value
|
||||
}
|
||||
|
||||
/// Get the value of this unmanaged reference as a managed
|
||||
/// reference and consume an unbalanced retain of it.
|
||||
var retainedValue: T {
|
||||
///
|
||||
/// This is useful when a function returns an unmanaged reference
|
||||
/// and you know that you're responsible for releasing the result.
|
||||
func takeRetainedValue() -> T {
|
||||
let result = _value
|
||||
release()
|
||||
return result
|
||||
@@ -103,7 +109,7 @@ struct Unmanaged<T: AnyObject> {
|
||||
/// for ensuring that the types are actually compatible at
|
||||
/// runtime.
|
||||
func bridgeUnretainedValueTo<U: AnyObject>() -> U {
|
||||
return reinterpretCast(unretainedValue)
|
||||
return reinterpretCast(takeUnretainedValue())
|
||||
}
|
||||
|
||||
/// Get the value of this unmanaged reference as an managed
|
||||
@@ -112,7 +118,7 @@ struct Unmanaged<T: AnyObject> {
|
||||
/// for ensuring that the types are actually compatible at
|
||||
/// runtime.
|
||||
func bridgeRetainedValueTo<U: AnyObject>() -> U {
|
||||
return reinterpretCast(retainedValue)
|
||||
return reinterpretCast(takeRetainedValue())
|
||||
}
|
||||
|
||||
/// Perform an unbalanced retain of the object.
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// \brief Wrapper for a contiguous array of T. UnsafeArray is both a
|
||||
/// Wrapper for a contiguous array of T. UnsafeArray is both a
|
||||
/// Collection—which is multi-pass if you use indices or call
|
||||
/// generate() on it—and a Generator, which can only be assumed to be
|
||||
/// single-pass. It's not clear how well this combination will work
|
||||
@@ -18,10 +18,6 @@
|
||||
/// this an experiment.
|
||||
struct UnsafeArray<T> : Collection, Generator {
|
||||
|
||||
func countElements() -> Int {
|
||||
return endIndex - startIndex
|
||||
}
|
||||
|
||||
var startIndex: Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
/// \brief A wrapper around a C pointer to type T.
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// A wrapper around a C pointer to type T.
|
||||
///
|
||||
/// This wrapper stores a C pointer to an object of type T, and is
|
||||
/// intended to be used to interface with C libraries. It provides no
|
||||
@@ -8,163 +20,329 @@
|
||||
/// For C pointers for which the pointed-to type cannot be represented
|
||||
/// directly in Swift, the \c COpaquePointer will be used instead.
|
||||
struct UnsafePointer<T> : BidirectionalIndex, Comparable, Hashable {
|
||||
/// \brief The underlying raw (untyped) pointer.
|
||||
/// The underlying raw (untyped) pointer.
|
||||
var value : Builtin.RawPointer
|
||||
|
||||
/// \brief Construct a null pointer.
|
||||
constructor() {
|
||||
this.value = Builtin.inttoptr_Int64(0.value)
|
||||
/// Construct a null pointer.
|
||||
init() {
|
||||
self.value = Builtin.inttoptr_Word(0.value)
|
||||
}
|
||||
|
||||
/// \brief Construct an UnsafePointer from a builtin raw pointer.
|
||||
constructor(value : Builtin.RawPointer) {
|
||||
this.value = value
|
||||
/// Construct an UnsafePointer from a builtin raw pointer.
|
||||
init(_ value : Builtin.RawPointer) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
/// \brief Convert from an opaque C pointer to a typed C pointer.
|
||||
/// Convert from an opaque C pointer to a typed C pointer.
|
||||
///
|
||||
/// This is a fundamentally unsafe conversion.
|
||||
constructor(other : COpaquePointer) {
|
||||
init(_ other : COpaquePointer) {
|
||||
value = other.value
|
||||
}
|
||||
|
||||
/// \brief Convert from a pointer of a different type.
|
||||
/// Construct an UnsafePointer from a given address in memory.
|
||||
///
|
||||
/// This is a fundamentally unsafe conversion.
|
||||
constructor<U>(from : UnsafePointer<U>) {
|
||||
init(_ value : Int) {
|
||||
self.value = Builtin.inttoptr_Word(value.value)
|
||||
}
|
||||
|
||||
/// Convert from a pointer of a different type.
|
||||
///
|
||||
/// This is a fundamentally unsafe conversion.
|
||||
init<U>(_ from : UnsafePointer<U>) {
|
||||
value = from.value
|
||||
}
|
||||
|
||||
static func null() -> UnsafePointer<T> {
|
||||
static func null() -> UnsafePointer {
|
||||
return UnsafePointer()
|
||||
}
|
||||
|
||||
/// \brief Get the address of an lvalue.
|
||||
///
|
||||
/// This is a fundamentally unsafe operation. The validity of the address
|
||||
/// cannot be guaranteed beyond the scope of the statement containing the
|
||||
/// constructed pointer. If the lvalue is a logical property, any value
|
||||
/// written to the pointer will be written back to the property, and the
|
||||
/// pointer will be invalidated at the end of the statement.
|
||||
static func addressOf(lv : [byref] T) -> UnsafePointer<T> {
|
||||
return UnsafePointer(Builtin.addressof(&lv))
|
||||
}
|
||||
|
||||
static func alloc(num : Int) -> UnsafePointer<T> {
|
||||
static func alloc(num: Int) -> UnsafePointer {
|
||||
// Don't both with overflow checking.
|
||||
var size = Int(Builtin.strideof(T)) * num
|
||||
return UnsafePointer(Builtin.allocRaw(size.value, Builtin.alignof(T)))
|
||||
var size = Int(Builtin.strideof(T.self)) * num
|
||||
return UnsafePointer(Builtin.allocRaw(size.value, Builtin.alignof(T.self)))
|
||||
}
|
||||
|
||||
func dealloc(num : Int) {
|
||||
func dealloc(num: Int) {
|
||||
// Overflow checking is actually not required here.
|
||||
var size = Int(Builtin.strideof(T)) * num
|
||||
var size = Int(Builtin.strideof(T.self)) * num
|
||||
Builtin.deallocRaw(value, size.value)
|
||||
}
|
||||
|
||||
|
||||
/// \brief Retrieve the value the pointer points to.
|
||||
/// Retrieve the value the pointer points to.
|
||||
@transparent
|
||||
func get() -> T {
|
||||
debugTrap(!isNull())
|
||||
return Builtin.load(value)
|
||||
}
|
||||
|
||||
/// \brief Set the value the pointer points to, copying over the
|
||||
/// Set the value the pointer points to, copying over the
|
||||
/// previous value.
|
||||
func set(newvalue : T) {
|
||||
debugTrap(!isNull())
|
||||
func set(newvalue: T) {
|
||||
Builtin.assign(newvalue, value)
|
||||
}
|
||||
|
||||
/// \brief Initialize the value the pointer points to, to construct
|
||||
/// Initialize the value the pointer points to, to construct
|
||||
/// an object where there was no object previously stored.
|
||||
func init(newvalue : T) {
|
||||
debugTrap(!isNull())
|
||||
Builtin.init(newvalue, value)
|
||||
func initialize(newvalue: T) {
|
||||
Builtin.initialize(newvalue, value)
|
||||
}
|
||||
|
||||
/// \brief Retrieve the value the pointer points to, moving it away
|
||||
/// Retrieve the value the pointer points to, moving it away
|
||||
/// from the location referenced in memory.
|
||||
///
|
||||
/// The object in memory should not be used again (except perhaps to
|
||||
/// initialize or destroy it).
|
||||
/// Postcondition: The value has been destroyed and the memory must
|
||||
/// be initialized before being used again.
|
||||
func move() -> T {
|
||||
debugTrap(!isNull())
|
||||
return Builtin.move(value)
|
||||
return Builtin.take(value)
|
||||
}
|
||||
|
||||
/// \brief Destroy the object the pointer points to.
|
||||
/// Move count values beginning at source into uninitialized memory,
|
||||
/// transforming the source values into raw memory, proceeding from
|
||||
/// the last value to the first. Use this for copying ranges into
|
||||
/// later memory that may overlap with the source range.
|
||||
///
|
||||
/// Requires: either `source` precedes `self` or follows `self + count`.
|
||||
func moveInitializeBackwardFrom(source: UnsafePointer, count: Int) {
|
||||
assert(
|
||||
source <= self || source > self + count,
|
||||
"moveInitializeBackwardFrom non-preceding overlapping range; use moveInitializeFrom instead")
|
||||
var src = source + count
|
||||
var dst = self + count
|
||||
while dst != self {
|
||||
(--dst).initialize((--src).move())
|
||||
}
|
||||
}
|
||||
|
||||
/// Assign from count values beginning at source into initialized
|
||||
/// memory, transforming the source values into raw memory.
|
||||
func moveAssignFrom(source: UnsafePointer, count: Int) {
|
||||
assert(
|
||||
source > self || source < self - count,
|
||||
"moveAssignFrom non-following overlapping range")
|
||||
for i in 0...count {
|
||||
self[i] = (source + i).move()
|
||||
}
|
||||
}
|
||||
|
||||
/// Move count values beginning at source into raw memory,
|
||||
/// transforming the source values into raw memory.
|
||||
func moveInitializeFrom(source: UnsafePointer, count: Int) {
|
||||
assert(
|
||||
source >= self || source < self - count,
|
||||
"moveInitializeFrom non-following overlapping range; use moveInitializeBackwardFrom")
|
||||
for i in 0...count {
|
||||
(self + i).initialize((source + i).move())
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy count values beginning at source into raw memory.
|
||||
func initializeFrom(source: UnsafePointer, count: Int) {
|
||||
assert(
|
||||
source >= self || source < self - count,
|
||||
"initializeFrom non-following overlapping range")
|
||||
for i in 0...count {
|
||||
(self + i).initialize(source[i])
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy the elements of `C` into raw memory.
|
||||
func initializeFrom<
|
||||
C: Collection where C._Element == T
|
||||
>(
|
||||
source: C
|
||||
) {
|
||||
var p = self
|
||||
for x in source {
|
||||
p++.initialize((x as T)!)
|
||||
}
|
||||
}
|
||||
|
||||
/// Destroy the object the pointer points to.
|
||||
func destroy() {
|
||||
debugTrap(!isNull())
|
||||
Builtin.destroy(T, value)
|
||||
Builtin.destroy(T.self, value)
|
||||
}
|
||||
|
||||
/// Destroy the `count` objects the pointer points to.
|
||||
func destroy(count: Int) {
|
||||
Builtin.destroyArray(T.self, value, count.value)
|
||||
}
|
||||
|
||||
func isNull() -> Bool {
|
||||
return this == UnsafePointer.null()
|
||||
return self == UnsafePointer.null()
|
||||
}
|
||||
|
||||
subscript (i : Int) -> T {
|
||||
get:
|
||||
debugTrap(!isNull())
|
||||
return (this + i).get()
|
||||
set:
|
||||
debugTrap(!isNull())
|
||||
(this + i).set(value)
|
||||
@transparent
|
||||
get {
|
||||
return (self + i).get()
|
||||
}
|
||||
@transparent
|
||||
nonmutating set {
|
||||
(self + i).set(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Protocol conformance
|
||||
//
|
||||
func __equal__(rhs: UnsafePointer<T>) -> Bool {
|
||||
return _getBool(Builtin.cmp_eq_RawPointer(value, rhs.value))
|
||||
var hashValue: Int {
|
||||
return Int(Builtin.ptrtoint_Word(value))
|
||||
}
|
||||
func __less__(rhs: UnsafePointer<T>) -> Bool {
|
||||
return _getBool(Builtin.cmp_ult_RawPointer(value, rhs.value))
|
||||
func succ() -> UnsafePointer {
|
||||
return self + 1
|
||||
}
|
||||
func hashValue() -> Int {
|
||||
return Int(Builtin.ptrtoint_Int64(value))
|
||||
func pred() -> UnsafePointer {
|
||||
return self - 1
|
||||
}
|
||||
func succ() -> UnsafePointer<T> {
|
||||
return this + 1
|
||||
|
||||
//
|
||||
// Conversion to C argument pointers
|
||||
//
|
||||
|
||||
// FIXME: Should be in an extension, but that doesn't work yet.
|
||||
@transparent @conversion
|
||||
func __conversion() -> CMutablePointer<T> {
|
||||
return CMutablePointer(owner: _nilNativeObject, value: value)
|
||||
}
|
||||
func pred() -> UnsafePointer<T> {
|
||||
return this - 1
|
||||
func __conversion() -> CMutableVoidPointer {
|
||||
return CMutableVoidPointer(owner: _nilNativeObject, value: value)
|
||||
}
|
||||
@transparent @conversion
|
||||
func __conversion() -> CConstPointer<T> {
|
||||
return CConstPointer(_nilNativeObject, value)
|
||||
}
|
||||
@transparent @conversion
|
||||
func __conversion() -> CConstVoidPointer {
|
||||
return CConstVoidPointer(_nilNativeObject, value)
|
||||
}
|
||||
@transparent @conversion
|
||||
func __conversion() -> ObjCMutablePointer<T> {
|
||||
return ObjCMutablePointer(value)
|
||||
}
|
||||
|
||||
/// Construct from a CConstPointer.
|
||||
///
|
||||
/// This is an explicit construction because it is not always safe.
|
||||
/// It is only allowed to convert an unscoped pointer, that is, one
|
||||
/// that does not have a lifetime-guaranteeing owner reference. To use
|
||||
/// a scoped pointer as an UnsafePointer, the withUnsafePointer method
|
||||
/// must be used instead.
|
||||
init(_ cp: CConstPointer<T>) {
|
||||
assert(!cp.scoped,
|
||||
"scoped CConstPointers must be converted using withUnsafePointer")
|
||||
self.value = cp.value
|
||||
}
|
||||
|
||||
/// Construct from a CMutablePointer.
|
||||
///
|
||||
/// This is an explicit construction because it is not always safe.
|
||||
/// It is only allowed to convert an unscoped pointer, that is, one
|
||||
/// that does not have a lifetime-guaranteeing owner reference. To use
|
||||
/// a scoped pointer as an UnsafePointer, the withUnsafePointer method
|
||||
/// must be used instead.
|
||||
init(_ cm: CMutablePointer<T>) {
|
||||
assert(!cm.scoped,
|
||||
"scoped CMutablePointers must be converted using withUnsafePointer")
|
||||
self.value = cm.value
|
||||
}
|
||||
|
||||
/// Construct from an ObjCMutablePointer.
|
||||
///
|
||||
/// This is an explicit construction
|
||||
/// because it is unsafe--UnsafePointer's store operations assume that
|
||||
/// the pointed-to storage has strong ownership, whereas ObjCMutablePointers
|
||||
/// reference +0 storage. Any values stored through the resulting
|
||||
/// UnsafePointer must be autoreleased.
|
||||
init(_ op: ObjCMutablePointer<T>) {
|
||||
self.value = op.value
|
||||
}
|
||||
|
||||
/// Construct from a CConstVoidPointer.
|
||||
///
|
||||
/// This is an explicit construction because it is not always safe.
|
||||
/// It is only allowed to convert an unscoped pointer, that is, one
|
||||
/// that does not have a lifetime-guaranteeing owner reference. To use
|
||||
/// a scoped pointer as an UnsafePointer, the withUnsafePointer method
|
||||
/// must be used instead.
|
||||
init(_ cp: CConstVoidPointer) {
|
||||
assert(!cp.scoped,
|
||||
"scoped CConstPointers must be converted using withUnsafePointer")
|
||||
self.value = cp.value
|
||||
}
|
||||
|
||||
/// Construct from a CMutableVoidPointer.
|
||||
///
|
||||
/// This is an explicit construction because it is not always safe.
|
||||
/// It is only allowed to convert an unscoped pointer, that is, one
|
||||
/// that does not have a lifetime-guaranteeing owner reference. To use
|
||||
/// a scoped pointer as an UnsafePointer, the withUnsafePointer method
|
||||
/// must be used instead.
|
||||
init(_ cp: CMutableVoidPointer) {
|
||||
assert(!cp.scoped,
|
||||
"scoped CMutableVoidPointers must be converted using withUnsafePointer")
|
||||
self.value = cp.value
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Should we expose/use size_t and ptrdiff_t?
|
||||
@transparent
|
||||
func == <T> (lhs: UnsafePointer<T>, rhs: UnsafePointer<T>) -> Bool {
|
||||
return Bool(Builtin.cmp_eq_RawPointer(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
func + <T>(lhs : UnsafePointer<T>,
|
||||
rhs : Int64) -> UnsafePointer<T> {
|
||||
debugTrap(!lhs.isNull())
|
||||
@transparent
|
||||
func < <T>(lhs: UnsafePointer<T>, rhs: UnsafePointer<T>) -> Bool {
|
||||
return Bool(Builtin.cmp_ult_RawPointer(lhs.value, rhs.value))
|
||||
}
|
||||
|
||||
@transparent
|
||||
func + <T>(lhs: UnsafePointer<T>, rhs: Int) -> UnsafePointer<T> {
|
||||
return UnsafePointer(
|
||||
Builtin.gep_Int64(lhs.value,
|
||||
(rhs * Int(Builtin.strideof(T))).value))
|
||||
Builtin.gep_Word(lhs.value, (rhs * Int(Builtin.strideof(T.self))).value))
|
||||
}
|
||||
|
||||
func + <T>(lhs : Int64,
|
||||
rhs : UnsafePointer<T>) -> UnsafePointer<T> {
|
||||
@transparent
|
||||
func + <T>(lhs: Int,
|
||||
rhs: UnsafePointer<T>) -> UnsafePointer<T> {
|
||||
return rhs + lhs
|
||||
}
|
||||
|
||||
func - <T>(lhs : UnsafePointer<T>,
|
||||
rhs : Int64) -> UnsafePointer<T> {
|
||||
@transparent
|
||||
func - <T>(lhs: UnsafePointer<T>, rhs: Int) -> UnsafePointer<T> {
|
||||
return lhs + -rhs
|
||||
}
|
||||
|
||||
func - <T>(lhs : UnsafePointer<T>,
|
||||
rhs : UnsafePointer<T>) -> Int {
|
||||
debugTrap((!lhs.isNull() && !rhs.isNull()) ||
|
||||
(lhs.isNull() && rhs.isNull()),
|
||||
"subtracting unrelated pointers")
|
||||
return Int(Builtin.sub_Int64(Builtin.ptrtoint_Int64(lhs.value),
|
||||
Builtin.ptrtoint_Int64(rhs.value)))
|
||||
@transparent
|
||||
func - <T>(lhs: UnsafePointer<T>, rhs: UnsafePointer<T>) -> Int {
|
||||
return
|
||||
Int(Builtin.sub_Word(Builtin.ptrtoint_Word(lhs.value),
|
||||
Builtin.ptrtoint_Word(rhs.value)))
|
||||
/ Int(Builtin.strideof(T.self))
|
||||
}
|
||||
|
||||
func [assignment] += <T>(lhs : [byref] UnsafePointer<T>, rhs : Int64) {
|
||||
@transparent
|
||||
@assignment func += <T>(inout lhs: UnsafePointer<T>, rhs: Int) {
|
||||
lhs = lhs + rhs
|
||||
}
|
||||
|
||||
func [assignment] -= <T>(lhs : [byref] UnsafePointer<T>, rhs : Int64) {
|
||||
@transparent
|
||||
@assignment func -= <T>(inout lhs: UnsafePointer<T>, rhs: Int) {
|
||||
lhs = lhs - rhs
|
||||
}
|
||||
|
||||
/// A byte-sized thing that isn't designed to interoperate with
|
||||
/// any other types; it makes a decent parameter to UnsafePointer when
|
||||
/// you just want to do bytewise pointer arithmetic.
|
||||
struct RawByte {
|
||||
let _inaccessible: UInt8
|
||||
}
|
||||
|
||||
// Make nil work with UnsafePointer
|
||||
extension _Nil {
|
||||
@transparent
|
||||
@conversion func __conversion<T>() -> UnsafePointer<T> {
|
||||
return .null()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,33 +1,57 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
protocol CVarArg {
|
||||
func encode() -> Word[]
|
||||
}
|
||||
|
||||
#if arch(x86_64)
|
||||
let _x86_64CountGPRegisters = 6
|
||||
let _x86_64CountSSERegisters = 8
|
||||
let _x86_64SSERegisterWords = 2
|
||||
let _x86_64RegisterSaveWords = _x86_64CountGPRegisters + _x86_64CountSSERegisters * _x86_64SSERegisterWords
|
||||
#endif
|
||||
|
||||
@asmname="swift_runningOnX86_64" func swift_runningOnX86_64() -> Bool
|
||||
|
||||
func withVaList<R>(args: CVarArg[], f: (CVaList)->R) -> R {
|
||||
var argList: C_va_list = makeC_va_list()
|
||||
func withVaList<R>(args: CVarArg[], f: (CVaListPointer)->R) -> R {
|
||||
var builder = VaListBuilder()
|
||||
for a in args {
|
||||
argList.append(a)
|
||||
builder.append(a)
|
||||
}
|
||||
return f(argList)
|
||||
return withVaList(builder, f)
|
||||
}
|
||||
|
||||
func withVaList<R>(builder: VaListBuilder, f: (CVaListPointer)->R) -> R {
|
||||
let result = f(builder.va_list())
|
||||
_fixLifetime(builder)
|
||||
return result
|
||||
}
|
||||
|
||||
// FIXME: workaround for <rdar://problem/15715225>
|
||||
func sizeof(_:Word.metatype) -> Int {
|
||||
return Int(Word(Builtin.sizeof(Word)))
|
||||
func getVaList(args: CVarArg[]) -> CVaListPointer {
|
||||
var builder = VaListBuilder()
|
||||
for a in args {
|
||||
builder.append(a)
|
||||
}
|
||||
// FIXME: Use some Swift equivalent of NS_RETURNS_INNER_POINTER if we get one.
|
||||
Builtin.retain(builder)
|
||||
Builtin.autorelease(builder)
|
||||
return builder.va_list()
|
||||
}
|
||||
|
||||
func encodeBitsAsWords<T: CVarArg>(x: T) -> Word[] {
|
||||
var result = Array<Word>(
|
||||
(sizeof(T) + sizeof(Word) - 1) / sizeof(Word), 0)
|
||||
|
||||
c_memcpy(result.base, addressof(&x), UInt64(sizeof(T)))
|
||||
var result = Word[](count: (sizeof(T.self) + sizeof(Word.self) - 1) / sizeof(Word.self), value: 0)
|
||||
var tmp = x
|
||||
c_memcpy(dest: UnsafePointer(result.elementStorage),
|
||||
src: UnsafePointer(Builtin.addressof(&tmp)),
|
||||
size: UInt(sizeof(T.self)))
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -36,6 +60,12 @@ func encodeBitsAsWords<T: CVarArg>(x: T) -> Word[] {
|
||||
// encoding.
|
||||
|
||||
// Signed types
|
||||
extension Int : CVarArg {
|
||||
func encode() -> Word[] {
|
||||
return encodeBitsAsWords(self)
|
||||
}
|
||||
}
|
||||
|
||||
extension Int64 : CVarArg {
|
||||
func encode() -> Word[] {
|
||||
return encodeBitsAsWords(self)
|
||||
@@ -61,6 +91,12 @@ extension Int8 : CVarArg {
|
||||
}
|
||||
|
||||
// Unsigned types
|
||||
extension UInt : CVarArg {
|
||||
func encode() -> Word[] {
|
||||
return encodeBitsAsWords(self)
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt64 : CVarArg {
|
||||
func encode() -> Word[] {
|
||||
return encodeBitsAsWords(self)
|
||||
@@ -103,14 +139,10 @@ extension Double : CVarArg {
|
||||
}
|
||||
}
|
||||
|
||||
protocol C_va_list {
|
||||
func append(arg: CVarArg)
|
||||
#if !arch(x86_64)
|
||||
|
||||
@conversion
|
||||
func __conversion() -> COpaquePointer
|
||||
}
|
||||
|
||||
struct BasicC_va_list : C_va_list {
|
||||
@final
|
||||
class VaListBuilder {
|
||||
|
||||
func append(arg: CVarArg) {
|
||||
for x in arg.encode() {
|
||||
@@ -118,43 +150,41 @@ struct BasicC_va_list : C_va_list {
|
||||
}
|
||||
}
|
||||
|
||||
@conversion
|
||||
func __conversion() -> COpaquePointer {
|
||||
return COpaquePointer(storage.base)
|
||||
func va_list() -> CVaListPointer {
|
||||
return CVaListPointer(fromUnsafePointer: UnsafePointer<Void>(storage.elementStorage))
|
||||
}
|
||||
|
||||
var storage: Word[] = Array<Word>()
|
||||
var storage = Word[]()
|
||||
}
|
||||
|
||||
func &&<T: LogicValue>(a: T, b: @auto_closure () -> T) -> T {
|
||||
return a ? b() : a
|
||||
}
|
||||
#else
|
||||
|
||||
func ||<T: LogicValue>(a: T, b: @auto_closure () -> T) -> T {
|
||||
return a ? a : b()
|
||||
}
|
||||
|
||||
struct X86_64_va_list : C_va_list {
|
||||
@final
|
||||
class VaListBuilder {
|
||||
|
||||
struct Header {
|
||||
var gp_offset = CUnsignedInt(0)
|
||||
var fp_offset = CUnsignedInt(_x86_64CountGPRegisters * sizeof(Word))
|
||||
var fp_offset = CUnsignedInt(_x86_64CountGPRegisters * strideof(Word.self))
|
||||
var overflow_arg_area: UnsafePointer<Word> = UnsafePointer<Word>.null()
|
||||
var reg_save_area: UnsafePointer<Word> = UnsafePointer<Word>.null()
|
||||
}
|
||||
|
||||
init() {
|
||||
// prepare the register save area
|
||||
storage = Array(_x86_64RegisterSaveWords, Word(0))
|
||||
storage = Array(count: _x86_64RegisterSaveWords, value: 0)
|
||||
}
|
||||
|
||||
func append(arg: CVarArg) {
|
||||
var encoded = arg.encode()
|
||||
|
||||
if ((arg as Float) || (arg as Double)) && sseRegistersUsed < _x86_64CountSSERegisters {
|
||||
var startIndex = _x86_64CountGPRegisters + (sseRegistersUsed * _x86_64SSERegisterWords)
|
||||
var endIndex = startIndex + encoded.count
|
||||
storage[startIndex..endIndex] = encoded
|
||||
if ((arg as Float) || (arg as Double))
|
||||
&& sseRegistersUsed < _x86_64CountSSERegisters {
|
||||
var startIndex = _x86_64CountGPRegisters
|
||||
+ (sseRegistersUsed * _x86_64SSERegisterWords)
|
||||
for w in encoded {
|
||||
storage[startIndex] = w
|
||||
++startIndex
|
||||
}
|
||||
++sseRegistersUsed
|
||||
}
|
||||
else if encoded.count == 1 && gpRegistersUsed < _x86_64CountGPRegisters {
|
||||
@@ -167,24 +197,20 @@ struct X86_64_va_list : C_va_list {
|
||||
}
|
||||
}
|
||||
|
||||
@conversion
|
||||
func __conversion() -> COpaquePointer {
|
||||
header.reg_save_area = storage.base
|
||||
header.overflow_arg_area = storage.base + _x86_64RegisterSaveWords
|
||||
return COpaquePointer(addressof(&self.header))
|
||||
func va_list() -> CVaListPointer {
|
||||
header.reg_save_area = storage.elementStorage
|
||||
header.overflow_arg_area = storage.elementStorage + _x86_64RegisterSaveWords
|
||||
return CVaListPointer(
|
||||
fromUnsafePointer: UnsafePointer<Void>(
|
||||
Builtin.addressof(&self.header)))
|
||||
}
|
||||
|
||||
var gpRegistersUsed = 0
|
||||
var sseRegistersUsed = 0
|
||||
|
||||
@final // Property must be final since it is used by Builtin.addressof.
|
||||
var header = Header()
|
||||
var storage: Word[]
|
||||
}
|
||||
|
||||
func makeC_va_list() -> C_va_list {
|
||||
if swift_runningOnX86_64() {
|
||||
return X86_64_va_list()
|
||||
}
|
||||
else {
|
||||
return BasicC_va_list()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,42 +1,49 @@
|
||||
struct ZipEnumerator2<E0 : Enumerator, E1 : Enumerator> : Enumerator
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 ZipGenerator2<E0 : Generator, E1 : Generator> : Generator
|
||||
{
|
||||
typealias Element = (E0.Element,E1.Element)
|
||||
|
||||
constructor(e0: E0, e1: E1) {
|
||||
baseEnumerators.value = (e0,e1)
|
||||
init(_ e0: E0, _ e1: E1) {
|
||||
baseStreams = (e0,e1)
|
||||
}
|
||||
|
||||
func isEmpty() -> Bool {
|
||||
if baseEnumerators.value.0.isEmpty() {
|
||||
return true
|
||||
}
|
||||
return baseEnumerators.value.1.isEmpty()
|
||||
mutating func next() -> Element? {
|
||||
var e0 = baseStreams.0.next()
|
||||
if !e0 { return .None }
|
||||
var e1 = baseStreams.1.next()
|
||||
if !e1 { return .None }
|
||||
return .Some((e0!, e1!))
|
||||
}
|
||||
|
||||
func next() -> Element {
|
||||
return (
|
||||
baseEnumerators.value.0.next(),
|
||||
baseEnumerators.value.1.next())
|
||||
}
|
||||
|
||||
var baseEnumerators : GenericIVar<(E0,E1)>
|
||||
var baseStreams : (E0,E1)
|
||||
}
|
||||
|
||||
struct Zip2<S0: Enumerable, S1: Enumerable> : Enumerable
|
||||
struct Zip2<S0: Sequence, S1: Sequence> : Sequence
|
||||
{
|
||||
typealias Enumerator1 = S0.EnumeratorType
|
||||
typealias Enumerator2 = S1.EnumeratorType
|
||||
typealias EnumeratorType = ZipEnumerator2<Enumerator1, Enumerator2>
|
||||
typealias Stream1 = S0.GeneratorType
|
||||
typealias Stream2 = S1.GeneratorType
|
||||
typealias GeneratorType = ZipGenerator2<Stream1, Stream2>
|
||||
|
||||
constructor(s0: S0, s1: S1) {
|
||||
sequences.value = (s0,s1)
|
||||
init(_ s0: S0, _ s1: S1) {
|
||||
sequences = (s0,s1)
|
||||
}
|
||||
|
||||
func getEnumeratorType() -> EnumeratorType {
|
||||
return EnumeratorType(
|
||||
sequences.value.0.getEnumeratorType(),
|
||||
sequences.value.1.getEnumeratorType())
|
||||
func generate() -> GeneratorType {
|
||||
return GeneratorType(
|
||||
sequences.0.generate(),
|
||||
sequences.1.generate())
|
||||
}
|
||||
|
||||
var sequences: GenericIVar<(S0,S1)>
|
||||
var sequences: (S0,S1)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Foundation
|
||||
import AppKit
|
||||
@exported import AppKit
|
||||
|
||||
class REPLApplication : NSApplication {
|
||||
}
|
||||
@@ -8,16 +20,72 @@ class REPLApplication : NSApplication {
|
||||
func replApplicationMain() {
|
||||
assert(NSApp === nil)
|
||||
// Create a REPLApplication as the NSApp.
|
||||
var app = REPLApplication.sharedApplication() as! REPLApplication
|
||||
let app = (REPLApplication.sharedApplication() as REPLApplication)!
|
||||
|
||||
// Set the activation policy so we get a dock icon and can go foreground.
|
||||
// FIXME: enum type
|
||||
app.setActivationPolicy(
|
||||
NSApplicationActivationPolicy(NSApplicationActivationPolicyRegular))
|
||||
app.setActivationPolicy(.Regular)
|
||||
|
||||
// Run asynchronously.
|
||||
app.performSelector("run", withObject:nil, afterDelay:0.0)
|
||||
NSOperationQueue.mainQueue().addOperationWithBlock { app.run() }
|
||||
|
||||
// Quit the NSApplication when the REPL quits.
|
||||
atREPLExit({ app.terminate(nil) })
|
||||
_atREPLExit({ app.terminate(nil) })
|
||||
|
||||
}
|
||||
|
||||
struct _NSViewMirror : Mirror {
|
||||
var _v : NSView
|
||||
|
||||
init(_ v : NSView) {_v = v}
|
||||
|
||||
var value: Any { get { return _v } }
|
||||
|
||||
var valueType: Any.Type { get { return (_v as Any).dynamicType } }
|
||||
|
||||
var objectIdentifier: ObjectIdentifier? { get { return .None } }
|
||||
|
||||
var count: Int { get { return 0 } }
|
||||
|
||||
subscript(_: Int) -> (String,Mirror) { get { fatal("don't ask") } }
|
||||
|
||||
var summary: String { get { return ""} }
|
||||
|
||||
var quickLookObject: QuickLookObject? { get {
|
||||
// this code comes straight from the quicklooks
|
||||
|
||||
/*NSBitmapImageRep *b = (NSBitmapImageRep *)[%dataValueName% bitmapImageRepForCachingDisplayInRect:(NSRect)[%dataValueName% bounds]];
|
||||
(void)[%dataValueName% cacheDisplayInRect:(NSRect)[%dataValueName% bounds] toBitmapImageRep:b];
|
||||
(NSData *)[b representationUsingType:4 properties:nil];*/
|
||||
|
||||
let bounds = _v.bounds
|
||||
|
||||
// we need to do this check to avoid the @unchecked -> Any -> NSObject cast failure
|
||||
if var b = _v.bitmapImageRepForCachingDisplayInRect(bounds) {
|
||||
_v.cacheDisplayInRect(bounds, toBitmapImageRep: b)
|
||||
// don't do the last step - return the image and the encoder will translate the NSImage to a TIFF alright
|
||||
return .Some(.View(b))
|
||||
}
|
||||
return nil
|
||||
|
||||
} }
|
||||
|
||||
var disposition : MirrorDisposition { get { return .Aggregate } }
|
||||
}
|
||||
|
||||
extension NSView : Reflectable {
|
||||
func getMirror() -> Mirror {
|
||||
return _NSViewMirror(self)
|
||||
}
|
||||
}
|
||||
|
||||
// Overlays for variadics.
|
||||
|
||||
extension NSGradient {
|
||||
convenience init(colorsAndLocations objects: (AnyObject, CGFloat)...) {
|
||||
let colors : AnyObject[] = new AnyObject[objects.count] { objects[$0].0 }
|
||||
let locations = new CGFloat[objects.count] { objects[$0].1 }
|
||||
self.init(colors: asNSArray(colors), atLocations: locations.elementStorage, colorSpace: NSColorSpace.genericRGBColorSpace())
|
||||
_fixLifetime(locations)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,51 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
extension CGPoint : Equatable {
|
||||
static var zeroPoint: CGPoint { get { return CGPoint(0, 0) } }
|
||||
static var zeroPoint: CGPoint { get { return CGPoint(x: 0, y: 0) } }
|
||||
|
||||
init() {
|
||||
self.init(x: 0.0, y: 0.0)
|
||||
}
|
||||
|
||||
init(x: Int, y: Int) {
|
||||
self.init(x: CGFloat(x), y: CGFloat(y))
|
||||
}
|
||||
}
|
||||
|
||||
struct _CGPointMirror : Mirror {
|
||||
let _value : CGPoint
|
||||
|
||||
init(_ x : CGPoint) {
|
||||
_value = x
|
||||
}
|
||||
|
||||
var value: Any { return _value }
|
||||
|
||||
var valueType: Any.Type { return (_value as Any).dynamicType }
|
||||
|
||||
var objectIdentifier: ObjectIdentifier? { return .None }
|
||||
|
||||
var count: Int { return 2 }
|
||||
|
||||
subscript(i: Int) -> (String, Mirror) {
|
||||
switch i {
|
||||
case 0: return ("x",reflect(_value.x))
|
||||
case 1: return ("y",reflect(_value.y))
|
||||
default: fatal("cannot extract this child index")
|
||||
}
|
||||
}
|
||||
|
||||
var summary: String { return "(\(_value.x),\(_value.y))" }
|
||||
|
||||
var quickLookObject: QuickLookObject? { return .Some(.Point(Double(_value.x),Double(_value.y))) }
|
||||
|
||||
var disposition: MirrorDisposition { return .Aggregate }
|
||||
}
|
||||
|
||||
extension CGPoint : Reflectable {
|
||||
func getMirror() -> Mirror {
|
||||
return _CGPointMirror(self)
|
||||
}
|
||||
}
|
||||
|
||||
func == (lhs: CGPoint, rhs: CGPoint) -> Bool {
|
||||
@@ -27,7 +71,51 @@ func == (lhs: CGPoint, rhs: CGPoint) -> Bool {
|
||||
|
||||
|
||||
extension CGSize : Equatable {
|
||||
static var zeroSize: CGSize { get { return CGSize(0, 0) } }
|
||||
static var zeroSize: CGSize { return CGSize(width: 0, height: 0) }
|
||||
|
||||
init() {
|
||||
self.init(width: 0.0, height: 0.0)
|
||||
}
|
||||
|
||||
init(width: Int, height: Int) {
|
||||
self.init(width: CGFloat(width), height: CGFloat(height))
|
||||
}
|
||||
}
|
||||
|
||||
struct _CGSizeMirror : Mirror {
|
||||
let _value : CGSize
|
||||
|
||||
init(_ x : CGSize) {
|
||||
_value = x
|
||||
}
|
||||
|
||||
var value: Any { return _value }
|
||||
|
||||
var valueType: Any.Type { return (_value as Any).dynamicType }
|
||||
|
||||
var objectIdentifier: ObjectIdentifier? { return .None }
|
||||
|
||||
var count: Int { return 2 }
|
||||
|
||||
subscript(i: Int) -> (String, Mirror) {
|
||||
switch i {
|
||||
case 0: return ("x",reflect(_value.width))
|
||||
case 1: return ("y",reflect(_value.height))
|
||||
default: fatal("cannot extract this child index")
|
||||
}
|
||||
}
|
||||
|
||||
var summary: String { return "(\(_value.width),\(_value.height))" }
|
||||
|
||||
var quickLookObject: QuickLookObject? { return .Some(.Size(Double(_value.width),Double(_value.height))) }
|
||||
|
||||
var disposition: MirrorDisposition { return .Aggregate }
|
||||
}
|
||||
|
||||
extension CGSize : Reflectable {
|
||||
func getMirror() -> Mirror {
|
||||
return _CGSizeMirror(self)
|
||||
}
|
||||
}
|
||||
|
||||
func == (lhs: CGSize, rhs: CGSize) -> Bool {
|
||||
@@ -37,6 +125,14 @@ func == (lhs: CGSize, rhs: CGSize) -> Bool {
|
||||
|
||||
extension CGVector : Equatable {
|
||||
static var zeroVector: CGVector { get { return CGVector(0, 0) } }
|
||||
|
||||
init(_ dx: CGFloat, _ dy: CGFloat) {
|
||||
self.init(dx: CGFloat(dx), dy: CGFloat(dy))
|
||||
}
|
||||
|
||||
init(_ dx: Int, _ dy: Int) {
|
||||
self.init(CGFloat(dx), CGFloat(dy))
|
||||
}
|
||||
}
|
||||
|
||||
func == (lhs: CGVector, rhs: CGVector) -> Bool {
|
||||
@@ -45,12 +141,24 @@ func == (lhs: CGVector, rhs: CGVector) -> Bool {
|
||||
|
||||
|
||||
extension CGRect : Equatable {
|
||||
static var zeroRect: CGRect { get { return CGRect(0, 0, 0, 0) } }
|
||||
static var zeroRect: CGRect {
|
||||
return CGRect(x: 0, y: 0, width: 0, height: 0)
|
||||
}
|
||||
static var nullRect: CGRect { get { return CGRectNull } }
|
||||
static var infiniteRect: CGRect { get { return CGRectInfinite } }
|
||||
|
||||
init() {
|
||||
self.init(origin: CGPoint(), size: CGSize())
|
||||
}
|
||||
|
||||
init(x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat) {
|
||||
self.init(origin:CGPoint(x, y), size:CGSize(width, height))
|
||||
self.init(origin: CGPoint(x: x, y: y),
|
||||
size: CGSize(width: width, height: height))
|
||||
}
|
||||
|
||||
init(x: Int, y: Int, width: Int, height: Int) {
|
||||
self.init(origin: CGPoint(x: x, y: y),
|
||||
size: CGSize(width: width, height: height))
|
||||
}
|
||||
|
||||
var width: CGFloat { get { return CGRectGetWidth(self) } }
|
||||
@@ -72,7 +180,7 @@ extension CGRect : Equatable {
|
||||
get { return CGRectStandardize(self) }
|
||||
}
|
||||
|
||||
@mutating func standardize() {
|
||||
mutating func standardize() {
|
||||
self = self.standardizedRect
|
||||
}
|
||||
|
||||
@@ -80,26 +188,26 @@ extension CGRect : Equatable {
|
||||
get { return CGRectIntegral(self) }
|
||||
}
|
||||
|
||||
@mutating func integerize() {
|
||||
mutating func integerize() {
|
||||
self = self.integerRect
|
||||
}
|
||||
|
||||
|
||||
func rectByInsetting(dx: CGFloat, dy: CGFloat) -> CGRect {
|
||||
func rectByInsetting(`dx: CGFloat, dy: CGFloat) -> CGRect {
|
||||
return CGRectInset(self, dx, dy)
|
||||
}
|
||||
|
||||
@mutating func inset(dx: CGFloat, dy: CGFloat) {
|
||||
self = self.rectByInsetting(dx, dy)
|
||||
mutating func inset(`dx: CGFloat, dy: CGFloat) {
|
||||
self = self.rectByInsetting(dx: dx, dy: dy)
|
||||
}
|
||||
|
||||
|
||||
func rectByOffsetting(dx: CGFloat, dy: CGFloat) -> CGRect {
|
||||
func rectByOffsetting(`dx: CGFloat, dy: CGFloat) -> CGRect {
|
||||
return CGRectOffset(self, dx, dy)
|
||||
}
|
||||
|
||||
@mutating func offset(dx: CGFloat, dy: CGFloat) {
|
||||
self = self.rectByOffsetting(dx, dy)
|
||||
mutating func offset(`dx: CGFloat, dy: CGFloat) {
|
||||
self = self.rectByOffsetting(dx: dx, dy: dy)
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +215,7 @@ extension CGRect : Equatable {
|
||||
return CGRectUnion(self, withRect)
|
||||
}
|
||||
|
||||
@mutating func union(withRect: CGRect) {
|
||||
mutating func union(withRect: CGRect) {
|
||||
self = self.rectByUnion(withRect)
|
||||
}
|
||||
|
||||
@@ -115,7 +223,7 @@ extension CGRect : Equatable {
|
||||
return CGRectIntersection(self, withRect)
|
||||
}
|
||||
|
||||
@mutating func intersect(withRect: CGRect) {
|
||||
mutating func intersect(withRect: CGRect) {
|
||||
self = self.rectByIntersecting(withRect)
|
||||
}
|
||||
|
||||
@@ -143,6 +251,42 @@ extension CGRect : Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
struct _CGRectMirror : Mirror {
|
||||
let _value : CGRect
|
||||
|
||||
init(_ x : CGRect) {
|
||||
_value = x
|
||||
}
|
||||
|
||||
var value: Any { return _value }
|
||||
|
||||
var valueType: Any.Type { return (_value as Any).dynamicType }
|
||||
|
||||
var objectIdentifier: ObjectIdentifier? { return .None }
|
||||
|
||||
var count: Int { return 2 }
|
||||
|
||||
subscript(i: Int) -> (String, Mirror) {
|
||||
switch i {
|
||||
case 0: return ("x",reflect(_value.origin))
|
||||
case 1: return ("y",reflect(_value.size))
|
||||
default: fatal("cannot extract this child index")
|
||||
}
|
||||
}
|
||||
|
||||
var summary: String { return "(\(_value.origin.x),\(_value.origin.y),\(_value.size.width),\(_value.size.height))" }
|
||||
|
||||
var quickLookObject: QuickLookObject? { return .Some(.Rectangle(Double(_value.origin.x),Double(_value.origin.y),Double(_value.size.width),Double(_value.size.height))) }
|
||||
|
||||
var disposition: MirrorDisposition { return .Aggregate }
|
||||
}
|
||||
|
||||
extension CGRect : Reflectable {
|
||||
func getMirror() -> Mirror {
|
||||
return _CGRectMirror(self)
|
||||
}
|
||||
}
|
||||
|
||||
func == (lhs: CGRect, rhs: CGRect) -> Bool {
|
||||
return CGRectEqualToRect(lhs, rhs)
|
||||
}
|
||||
|
||||
@@ -20,3 +20,16 @@ var errno : Int32 {
|
||||
__error().set(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
@availability(*, unavailable, message="Please use threads or posix_spawn*()")
|
||||
func fork() -> Int32 {
|
||||
errno = ENOSYS
|
||||
return -1
|
||||
}
|
||||
|
||||
@availability(*, unavailable, message="Please use threads or posix_spawn*()")
|
||||
func vfork() -> Int32 {
|
||||
errno = ENOSYS
|
||||
return -1
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,13 @@ let DISPATCH_QUEUE_PRIORITY_HIGH = dispatch_queue_priority_t(2)
|
||||
let DISPATCH_QUEUE_PRIORITY_DEFAULT = dispatch_queue_priority_t(0)
|
||||
let DISPATCH_QUEUE_PRIORITY_LOW = dispatch_queue_priority_t(-2)
|
||||
let DISPATCH_QUEUE_PRIORITY_BACKGROUND = dispatch_queue_priority_t(-32768)
|
||||
// FIXME: DISPATCH_QUEUE_CONCURRENT
|
||||
|
||||
var DISPATCH_QUEUE_CONCURRENT : dispatch_queue_attr_t {
|
||||
get { return _swift_dispatch_queue_concurrent() }
|
||||
}
|
||||
|
||||
@asmname("_swift_dispatch_queue_concurrent")
|
||||
func _swift_dispatch_queue_concurrent() -> dispatch_queue_attr_t
|
||||
|
||||
// dispatch/source.h
|
||||
// FIXME: DISPATCH_SOURCE_TYPE_*
|
||||
@@ -52,6 +58,63 @@ let DISPATCH_VNODE_RENAME = dispatch_source_vnode_flags_t(0x20)
|
||||
let DISPATCH_VNODE_REVOKE = dispatch_source_vnode_flags_t(0x40)
|
||||
let DISPATCH_TIMER_STRICT = dispatch_source_timer_flags_t(1)
|
||||
|
||||
var DISPATCH_SOURCE_TYPE_DATA_ADD : dispatch_source_type_t {
|
||||
get { return _swift_dispatch_source_type_data_add() }
|
||||
}
|
||||
var DISPATCH_SOURCE_TYPE_DATA_OR : dispatch_source_type_t {
|
||||
get { return _swift_dispatch_source_type_data_or() }
|
||||
}
|
||||
var DISPATCH_SOURCE_TYPE_MACH_SEND : dispatch_source_type_t {
|
||||
get { return _swift_dispatch_source_type_mach_send() }
|
||||
}
|
||||
var DISPATCH_SOURCE_TYPE_MACH_RECV : dispatch_source_type_t {
|
||||
get { return _swift_dispatch_source_type_mach_recv() }
|
||||
}
|
||||
var DISPATCH_SOURCE_TYPE_MEMORYPRESSURE : dispatch_source_type_t {
|
||||
get { return _swift_dispatch_source_type_memorypressure() }
|
||||
}
|
||||
var DISPATCH_SOURCE_TYPE_READ : dispatch_source_type_t {
|
||||
get { return _swift_dispatch_source_type_read() }
|
||||
}
|
||||
var DISPATCH_SOURCE_TYPE_PROC : dispatch_source_type_t {
|
||||
get { return _swift_dispatch_source_type_proc() }
|
||||
}
|
||||
var DISPATCH_SOURCE_TYPE_SIGNAL : dispatch_source_type_t {
|
||||
get { return _swift_dispatch_source_type_signal() }
|
||||
}
|
||||
var DISPATCH_SOURCE_TYPE_TIMER : dispatch_source_type_t {
|
||||
get { return _swift_dispatch_source_type_timer() }
|
||||
}
|
||||
var DISPATCH_SOURCE_TYPE_VNODE : dispatch_source_type_t {
|
||||
get { return _swift_dispatch_source_type_vnode() }
|
||||
}
|
||||
var DISPATCH_SOURCE_TYPE_WRITE : dispatch_source_type_t {
|
||||
get { return _swift_dispatch_source_type_write() }
|
||||
}
|
||||
|
||||
@asmname("_swift_dispatch_source_type_DATA_ADD")
|
||||
func _swift_dispatch_source_type_data_add() -> dispatch_source_type_t
|
||||
@asmname("_swift_dispatch_source_type_DATA_OR")
|
||||
func _swift_dispatch_source_type_data_or() -> dispatch_source_type_t
|
||||
@asmname("_swift_dispatch_source_type_MACH_SEND")
|
||||
func _swift_dispatch_source_type_mach_send() -> dispatch_source_type_t
|
||||
@asmname("_swift_dispatch_source_type_MACH_RECV")
|
||||
func _swift_dispatch_source_type_mach_recv() -> dispatch_source_type_t
|
||||
@asmname("_swift_dispatch_source_type_MEMORYPRESSURE")
|
||||
func _swift_dispatch_source_type_memorypressure() -> dispatch_source_type_t
|
||||
@asmname("_swift_dispatch_source_type_PROC")
|
||||
func _swift_dispatch_source_type_proc() -> dispatch_source_type_t
|
||||
@asmname("_swift_dispatch_source_type_READ")
|
||||
func _swift_dispatch_source_type_read() -> dispatch_source_type_t
|
||||
@asmname("_swift_dispatch_source_type_SIGNAL")
|
||||
func _swift_dispatch_source_type_signal() -> dispatch_source_type_t
|
||||
@asmname("_swift_dispatch_source_type_TIMER")
|
||||
func _swift_dispatch_source_type_timer() -> dispatch_source_type_t
|
||||
@asmname("_swift_dispatch_source_type_VNODE")
|
||||
func _swift_dispatch_source_type_vnode() -> dispatch_source_type_t
|
||||
@asmname("_swift_dispatch_source_type_WRITE")
|
||||
func _swift_dispatch_source_type_write() -> dispatch_source_type_t
|
||||
|
||||
// dispatch/time.h
|
||||
// DISPATCH_TIME_NOW: ok
|
||||
// DISPATCH_TIME_FOREVER: ok
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,11 +23,12 @@ extension NSObject {
|
||||
forKeyPath keyPath: String!,
|
||||
kvoContext: KVOContext)
|
||||
{
|
||||
let ptr = CMutableVoidPointer(kvoContext, reinterpretCast(kvoContext))
|
||||
let ptr = CMutableVoidPointer(owner: kvoContext,
|
||||
value: reinterpretCast(kvoContext))
|
||||
self.removeObserver(observer,
|
||||
forKeyPath: keyPath,
|
||||
context: ptr)
|
||||
Unmanaged(kvoContext).release()
|
||||
Unmanaged(_private: kvoContext).release()
|
||||
}
|
||||
|
||||
func addObserver(observer: NSObject!,
|
||||
@@ -35,8 +36,9 @@ extension NSObject {
|
||||
options: NSKeyValueObservingOptions,
|
||||
kvoContext: KVOContext)
|
||||
{
|
||||
let ptr = CMutableVoidPointer(kvoContext, reinterpretCast(kvoContext))
|
||||
Unmanaged(kvoContext).retain()
|
||||
let ptr = CMutableVoidPointer(owner: kvoContext,
|
||||
value: reinterpretCast(kvoContext))
|
||||
Unmanaged(_private: kvoContext).retain()
|
||||
self.addObserver(observer,
|
||||
forKeyPath: keyPath,
|
||||
options: options,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,15 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@exported
|
||||
import ObjectiveC
|
||||
|
||||
@@ -12,6 +24,10 @@ import ObjectiveC
|
||||
struct ObjCBool : ReplPrintable {
|
||||
var value : Bool
|
||||
|
||||
init(_ value: Bool) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
/// \brief Allow use in a Boolean context.
|
||||
func getLogicValue() -> Bool {
|
||||
return value == true
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@exported
|
||||
import ObjectiveC
|
||||
|
||||
@@ -10,6 +22,10 @@ import ObjectiveC
|
||||
struct ObjCBool : ReplPrintable {
|
||||
var value : Int8
|
||||
|
||||
init(_ value: Int8) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
/// \brief Allow use in a Boolean context.
|
||||
func getLogicValue() -> Bool {
|
||||
return value != 0
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
import 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@exported
|
||||
import ObjectiveC
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -7,43 +19,6 @@ import ObjectiveC
|
||||
// FIXME: Objective-C types belong in a layer below the Objective-C support
|
||||
// libraries, not here.
|
||||
|
||||
/// \brief The Objective-C BOOL type.
|
||||
///
|
||||
/// The Objective-C BOOL type is typically a typedef of "signed char". Clang
|
||||
/// importer imports it as ObjCBool.
|
||||
///
|
||||
/// Note: When BOOL is a typedef of C's _Bool/C++'s bool, this struct goes away
|
||||
/// and simply becomes a typealias for CBool.
|
||||
///
|
||||
/// The compiler has special knowledge of this type.
|
||||
struct ObjCBool {
|
||||
var value : UInt8
|
||||
|
||||
/// \brief Allow use in a Boolean context.
|
||||
func getLogicValue() -> Bool {
|
||||
return value != 0
|
||||
}
|
||||
|
||||
/// \brief Implicit conversion from C Boolean type to Swift Boolean
|
||||
/// type.
|
||||
func [conversion] __conversion() -> Bool {
|
||||
return this.getLogicValue()
|
||||
}
|
||||
|
||||
func replPrint() {
|
||||
// Dispatch to Bool.
|
||||
this.getLogicValue().replPrint()
|
||||
}
|
||||
}
|
||||
|
||||
extension Bool {
|
||||
/// \brief Implicit conversion from Swift Boolean type to
|
||||
/// Objective-C Boolean type.
|
||||
func [conversion] __conversion() -> ObjCBool {
|
||||
return ObjCBool(this ? 1 : 0)
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief The Objective-C SEL type.
|
||||
///
|
||||
/// The Objective-C SEL type is typically an opaque pointer. Swift
|
||||
@@ -51,53 +26,91 @@ extension Bool {
|
||||
/// convert between C strings and selectors.
|
||||
///
|
||||
/// The compiler has special knowledge of this type.
|
||||
struct ObjCSel : StringLiteralConvertible {
|
||||
struct Selector : StringLiteralConvertible, ReplPrintable {
|
||||
var ptr : COpaquePointer
|
||||
|
||||
/// \brief Create a selector from a string.
|
||||
constructor(str : String) {
|
||||
var LM = LifetimeManager()
|
||||
ptr = sel_registerName(LM.getCString(str)).ptr
|
||||
LM.release()
|
||||
init(_ str : String) {
|
||||
ptr = str.withCString { sel_registerName($0).ptr }
|
||||
}
|
||||
|
||||
typealias StringLiteralType = CString
|
||||
/// \brief Construct a selector from a string literal.
|
||||
static func convertFromExtendedGraphemeClusterLiteral(
|
||||
value: CString) -> Selector {
|
||||
|
||||
return convertFromStringLiteral(value)
|
||||
}
|
||||
|
||||
/// \brief Construct a selector from a string literal.
|
||||
///
|
||||
/// FIXME: Fast-path this in the compiler, so we don't end up with
|
||||
/// the sel_registerName call at compile time.
|
||||
static func convertFromStringLiteral(str : CString) -> ObjCSel {
|
||||
return sel_registerName(str)
|
||||
static func convertFromStringLiteral(value: CString) -> Selector {
|
||||
return sel_registerName(value)
|
||||
}
|
||||
|
||||
init(_: _Nil) {
|
||||
ptr = nil
|
||||
}
|
||||
|
||||
func replPrint() {
|
||||
print(String(this))
|
||||
print(String(self))
|
||||
}
|
||||
}
|
||||
|
||||
extension ObjCSel : Equatable, Hashable {
|
||||
func __equal__ (rhs : ObjCSel) -> Bool {
|
||||
return sel_isEqual(this, rhs)
|
||||
}
|
||||
func hashValue() -> Int {
|
||||
return ptr.hashValue()
|
||||
func ==(lhs: Selector, rhs: Selector) -> Bool {
|
||||
return sel_isEqual(lhs, rhs)
|
||||
}
|
||||
|
||||
extension Selector : Equatable, Hashable {
|
||||
var hashValue: Int {
|
||||
return ptr.hashValue
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
/// \brief Construct the C string representation of an Objective-C selector.
|
||||
constructor(sel : ObjCSel) {
|
||||
init(_ sel: Selector) {
|
||||
// FIXME: This misses the ASCII optimization.
|
||||
this = String.fromCString(sel_getName(sel))
|
||||
self = String.fromCString(sel_getName(sel))
|
||||
}
|
||||
}
|
||||
|
||||
// Functions used to implicitly bridge ObjCBool types to Swift's Bool type.
|
||||
|
||||
func convertBoolToObjCBool(x:Bool) -> ObjCBool {
|
||||
func _convertBoolToObjCBool(x: Bool) -> ObjCBool {
|
||||
return x
|
||||
}
|
||||
func convertObjCBoolToBool(x:ObjCBool) -> Bool {
|
||||
func _convertObjCBoolToBool(x: ObjCBool) -> Bool {
|
||||
return x
|
||||
}
|
||||
|
||||
extension _Nil {
|
||||
@conversion func __conversion() -> Selector {
|
||||
return Selector(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func ~=(x: NSObject, y: NSObject) -> Bool {
|
||||
return x.isEqual(y)
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FIXME: @autoreleasepool substitute
|
||||
//===----------------------------------------------------------------------===//
|
||||
@asmname("objc_autoreleasePoolPush") func __pushAutoreleasePool() -> COpaquePointer
|
||||
@asmname("objc_autoreleasePoolPop") func __popAutoreleasePool(pool: COpaquePointer)
|
||||
|
||||
func autoreleasepool(code: () -> ()) {
|
||||
var pool = __pushAutoreleasePool()
|
||||
code()
|
||||
__popAutoreleasePool(pool)
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Mark YES and NO unavailable.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@availability(*, unavailable, message="Use 'Bool' value 'true' instead") var YES : ObjCBool = Bool.true
|
||||
@availability(*, unavailable, message="Use 'Bool' value 'false' instead") var NO : ObjCBool = Bool.false
|
||||
|
||||
|
||||
@@ -4,9 +4,194 @@
|
||||
|
||||
#if os(OSX)
|
||||
typealias SKColor = NSColor
|
||||
#else
|
||||
#if os(iOS)
|
||||
#elseif os(iOS)
|
||||
typealias SKColor = UIColor
|
||||
#endif
|
||||
|
||||
#if os(OSX)
|
||||
// this class only exists to allow AnyObject lookup of _copyImageData
|
||||
// since that method only exists in a private header in SpriteKit, the lookup
|
||||
// mechanism by default fails to accept it as a valid AnyObject call
|
||||
@objc class _SpriteKitMethodProvider : NSObject {
|
||||
init() { fatal("don't touch me") }
|
||||
@objc func _copyImageData() -> NSData! { return nil }
|
||||
}
|
||||
|
||||
// HACK - these four mirrors do the exact same thing, they should be one and the same
|
||||
// and use an AnyObject, or some T : NSObject as their ivar type, but that causes
|
||||
// the compiler to crash - as a result, four mirrors it is
|
||||
struct _SKShapeNodeMirror : Mirror {
|
||||
var _value : SKShapeNode
|
||||
|
||||
init(_ _v : SKShapeNode) {
|
||||
_value = _v
|
||||
}
|
||||
|
||||
var value : Any { return (_value as Any)}
|
||||
|
||||
var valueType: Any.Type { return (_value as Any).dynamicType }
|
||||
|
||||
var objectIdentifier: ObjectIdentifier? { return .None }
|
||||
|
||||
var count: Int { return 0 }
|
||||
|
||||
subscript(_: Int) -> (String,Mirror) { fatal("don't ask") }
|
||||
|
||||
var summary: String { return _value.description }
|
||||
|
||||
var quickLookObject: QuickLookObject? {
|
||||
// this code comes straight from the quicklooks
|
||||
|
||||
if let data = (_value as AnyObject)._copyImageData?() {
|
||||
// we could send a Raw, but I don't want to make a copy of the bytes for no good reason
|
||||
// make an NSImage out of them and send that
|
||||
let img = NSImage(data: data)
|
||||
return .Some(.Sprite(img))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var disposition : MirrorDisposition { get { return .Aggregate } }
|
||||
}
|
||||
|
||||
struct _SKSpriteNodeMirror : Mirror {
|
||||
var _value : SKSpriteNode
|
||||
|
||||
init(_ _v : SKSpriteNode) {
|
||||
_value = _v
|
||||
}
|
||||
|
||||
var value : Any { return (_value as Any)}
|
||||
|
||||
var valueType: Any.Type { return (_value as Any).dynamicType }
|
||||
|
||||
var objectIdentifier: ObjectIdentifier? { return .None }
|
||||
|
||||
var count: Int { return 0 }
|
||||
|
||||
subscript(_: Int) -> (String,Mirror) { fatal("don't ask") }
|
||||
|
||||
var summary: String { return _value.description }
|
||||
|
||||
var quickLookObject: QuickLookObject? {
|
||||
// this code comes straight from the quicklooks
|
||||
|
||||
if let data = (_value as AnyObject)._copyImageData?() {
|
||||
// we could send a Raw, but I don't want to make a copy of the bytes for no good reason
|
||||
// make an NSImage out of them and send that
|
||||
let img = NSImage(data: data)
|
||||
return .Some(.Sprite(img))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var disposition : MirrorDisposition { get { return .Aggregate } }
|
||||
}
|
||||
|
||||
struct _SKTextureAtlasMirror : Mirror {
|
||||
var _value : SKTextureAtlas
|
||||
|
||||
init(_ _v : SKTextureAtlas) {
|
||||
_value = _v
|
||||
}
|
||||
|
||||
var value : Any { return (_value as Any)}
|
||||
|
||||
var valueType: Any.Type { return (_value as Any).dynamicType }
|
||||
|
||||
var objectIdentifier: ObjectIdentifier? { return .None }
|
||||
|
||||
var count: Int { return 0 }
|
||||
|
||||
subscript(_: Int) -> (String,Mirror) { fatal("don't ask") }
|
||||
|
||||
var summary: String { return _value.description }
|
||||
|
||||
var quickLookObject: QuickLookObject? {
|
||||
// this code comes straight from the quicklooks
|
||||
|
||||
if let data = (_value as AnyObject)._copyImageData?() {
|
||||
// we could send a Raw, but I don't want to make a copy of the bytes for no good reason
|
||||
// make an NSImage out of them and send that
|
||||
let img = NSImage(data: data)
|
||||
return .Some(.Sprite(img))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var disposition : MirrorDisposition { get { return .Aggregate } }
|
||||
}
|
||||
|
||||
struct _SKTextureMirror : Mirror {
|
||||
var _value : SKTexture
|
||||
|
||||
init(_ _v : SKTexture) {
|
||||
_value = _v
|
||||
}
|
||||
|
||||
var value : Any { return (_value as Any)}
|
||||
|
||||
var valueType: Any.Type { return (_value as Any).dynamicType }
|
||||
|
||||
var objectIdentifier: ObjectIdentifier? { return .None }
|
||||
|
||||
var count: Int { return 0 }
|
||||
|
||||
subscript(_: Int) -> (String,Mirror) { fatal("don't ask") }
|
||||
|
||||
var summary: String { return _value.description }
|
||||
|
||||
var quickLookObject: QuickLookObject? {
|
||||
// this code comes straight from the quicklooks
|
||||
|
||||
if let data = (_value as AnyObject)._copyImageData?() {
|
||||
// we could send a Raw, but I don't want to make a copy of the bytes for no good reason
|
||||
// make an NSImage out of them and send that
|
||||
let img = NSImage(data: data)
|
||||
return .Some(.Sprite(img))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var disposition : MirrorDisposition { get { return .Aggregate } }
|
||||
}
|
||||
|
||||
extension SKShapeNode : Reflectable {
|
||||
func getMirror() -> Mirror {
|
||||
return _SKShapeNodeMirror(self)
|
||||
}
|
||||
}
|
||||
|
||||
extension SKSpriteNode : Reflectable {
|
||||
func getMirror() -> Mirror {
|
||||
return _SKSpriteNodeMirror(self)
|
||||
}
|
||||
}
|
||||
extension SKTextureAtlas : Reflectable {
|
||||
func getMirror() -> Mirror {
|
||||
return _SKTextureAtlasMirror(self)
|
||||
}
|
||||
}
|
||||
extension SKTexture : Reflectable {
|
||||
func getMirror() -> Mirror {
|
||||
return _SKTextureMirror(self)
|
||||
}
|
||||
}
|
||||
#elseif os(iOS)
|
||||
// FIXME: we want to interop nicely with SpriteKit on iOS as well
|
||||
#endif
|
||||
|
||||
extension SKNode {
|
||||
subscript (name: String) -> SKNode[] {
|
||||
var nodes = SKNode[]()
|
||||
enumerateChildNodesWithName(name) { node, stop in
|
||||
if let n = node { nodes.append(n) }
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +1,130 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Foundation
|
||||
import [exported] UIKit
|
||||
@exported import UIKit
|
||||
|
||||
// Overlay UIApplicationMain, which is declared with a non-const char *argv[]
|
||||
// argument that gets mapped to UnsafePointer<UnsafePointer<CChar>> by the
|
||||
// importer, with one that takes UnsafePointer<CString> instead, matching the
|
||||
// type of C_ARGV.
|
||||
@asmname("UIApplicationMain")
|
||||
func UIApplicationMain(argc: CInt,
|
||||
argv: UnsafePointer<CString>,
|
||||
principalClassName: NSString?,
|
||||
delegateClassName: NSString?) -> CInt
|
||||
|
||||
// These are un-imported macros in UIKit.
|
||||
|
||||
extension UIDeviceOrientation {
|
||||
var isLandscape: Bool {
|
||||
get { return self == .LandscapeLeft || self == .LandscapeRight }
|
||||
}
|
||||
|
||||
var isPortrait: Bool {
|
||||
get { return self == .Portrait || self == .PortraitUpsideDown }
|
||||
}
|
||||
|
||||
var isFlat: Bool {
|
||||
get { return self == .FaceUp || self == .FaceDown }
|
||||
}
|
||||
|
||||
var isValidInterfaceOrientation: Bool {
|
||||
get {
|
||||
switch (self) {
|
||||
case .Portrait, .PortraitUpsideDown, .LandscapeLeft, .LandscapeRight:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func UIDeviceOrientationIsLandscape(orientation: UIDeviceOrientation) -> Bool {
|
||||
return orientation.isLandscape
|
||||
}
|
||||
|
||||
func UIDeviceOrientationIsPortrait(orientation: UIDeviceOrientation) -> Bool {
|
||||
return orientation.isPortrait
|
||||
}
|
||||
|
||||
func UIDeviceOrientationIsValidInterfaceOrientation(
|
||||
orientation: UIDeviceOrientation) -> Bool
|
||||
{
|
||||
return orientation.isValidInterfaceOrientation
|
||||
}
|
||||
|
||||
|
||||
extension UIInterfaceOrientation {
|
||||
var isLandscape: Bool {
|
||||
get { return self == .LandscapeLeft || self == .LandscapeRight }
|
||||
}
|
||||
|
||||
var isPortrait: Bool {
|
||||
get { return self == .Portrait || self == .PortraitUpsideDown }
|
||||
}
|
||||
}
|
||||
|
||||
func UIInterfaceOrientationIsPortrait(orientation: UIInterfaceOrientation)
|
||||
-> Bool
|
||||
{
|
||||
return orientation.isPortrait
|
||||
}
|
||||
|
||||
func UIInterfaceOrientationIsLandscape(orientation: UIInterfaceOrientation)
|
||||
-> Bool
|
||||
{
|
||||
return orientation.isLandscape
|
||||
}
|
||||
|
||||
// Overlays for variadic initializers.
|
||||
|
||||
extension UIActionSheet {
|
||||
convenience init(title: String?,
|
||||
delegate: UIActionSheetDelegate?,
|
||||
cancelButtonTitle: String?,
|
||||
destructiveButtonTitle: String?,
|
||||
// Hack around overload ambiguity with non-variadic constructor.
|
||||
// <rdar://problem/16704770>
|
||||
otherButtonTitles firstButtonTitle: String,
|
||||
_ moreButtonTitles: String...) {
|
||||
self.init(title: title,
|
||||
delegate: delegate,
|
||||
cancelButtonTitle: cancelButtonTitle,
|
||||
destructiveButtonTitle: destructiveButtonTitle)
|
||||
self.addButtonWithTitle(firstButtonTitle)
|
||||
for buttonTitle in moreButtonTitles {
|
||||
self.addButtonWithTitle(buttonTitle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UIAlertView {
|
||||
convenience init(title: String,
|
||||
message: String,
|
||||
delegate: UIAlertViewDelegate?,
|
||||
cancelButtonTitle: String?,
|
||||
// Hack around overload ambiguity with non-variadic constructor.
|
||||
// <rdar://problem/16704770>
|
||||
otherButtonTitles firstButtonTitle: String,
|
||||
_ moreButtonTitles: String...) {
|
||||
self.init(title: title,
|
||||
message: message,
|
||||
delegate: delegate,
|
||||
cancelButtonTitle: cancelButtonTitle)
|
||||
self.addButtonWithTitle(firstButtonTitle)
|
||||
for buttonTitle in moreButtonTitles {
|
||||
self.addButtonWithTitle(buttonTitle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,30 +10,32 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import XCTest
|
||||
@exported import XCTest // Clang module
|
||||
|
||||
/// Returns the current test case, so we can use free functions instead of methods for the overlay.
|
||||
@asmname("_XCTCurrentTestCase") func _XCTCurrentTestCase() -> XCTestCase
|
||||
|
||||
/// Register the failure, expected or unexpected, of the given test.
|
||||
func _XCTRegisterFailure(test: XCTestCase, expected: Bool, condition: String, message: String, file: String, line: Int) -> Void {
|
||||
/// Register the failure, expected or unexpected, of the current test case.
|
||||
func _XCTRegisterFailure(expected: Bool, condition: String, message: String, file: String, line: Int) -> Void {
|
||||
// Call the real _XCTFailureHandler.
|
||||
let test = _XCTCurrentTestCase()
|
||||
_XCTPreformattedFailureHandler(test, expected, file, line, condition, message)
|
||||
}
|
||||
|
||||
/// Produce a failure description for the given assertion type.
|
||||
func _XCTFailureDescription(assertionType: _XCTAssertionType, formatIndex: Int, expressionStrings: CVarArg...) -> String {
|
||||
return String(withFormat: _XCTFailureFormat(assertionType, formatIndex), arguments: expressionStrings)
|
||||
return String(format: _XCTFailureFormat(assertionType, formatIndex), arguments: expressionStrings)
|
||||
}
|
||||
|
||||
extension XCTestCase {
|
||||
// --- Supported Assertions ---
|
||||
// --- Supported Assertions ---
|
||||
|
||||
func XCTFail(message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTFail(_ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_Fail
|
||||
|
||||
_XCTRegisterFailure(self, true, _XCTFailureDescription(assertionType, 0, ""), message, file, line)
|
||||
}
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, ""), message, file, line)
|
||||
}
|
||||
|
||||
func XCTAssertNil(expression: @auto_closure () -> AnyObject?, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssertNil(expression: @auto_closure () -> AnyObject?, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_Nil
|
||||
|
||||
// evaluate the expression exactly once
|
||||
@@ -41,12 +43,14 @@ extension XCTestCase {
|
||||
|
||||
// test both Optional and value to treat .None and nil as synonymous
|
||||
var passed: Bool
|
||||
var expressionValueStr: String = "nil"
|
||||
if let expressionValueUnwrapped: AnyObject = expressionValueOptional {
|
||||
// TODO: passed = (expressionValueUnwrapped === nil)
|
||||
if expressionValueUnwrapped === nil {
|
||||
passed = true
|
||||
} else {
|
||||
passed = false
|
||||
expressionValueStr = reflect(expressionValueUnwrapped).summary
|
||||
}
|
||||
} else {
|
||||
passed = true
|
||||
@@ -56,17 +60,14 @@ extension XCTestCase {
|
||||
// TODO: @auto_string expression
|
||||
let expressionStr = "expressionStr"
|
||||
|
||||
// TODO: stringify expressionValue
|
||||
let expressionValueStr = "expressionValueStr"
|
||||
|
||||
_XCTRegisterFailure(self, true, _XCTFailureDescription(assertionType, 0, expressionStr, expressionValueStr), message, file, line)
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionStr, expressionValueStr), message, file, line)
|
||||
}
|
||||
|
||||
// TODO: handle an exception for which we can get a description
|
||||
// TODO: handle an exception for which we can't get a description
|
||||
}
|
||||
}
|
||||
|
||||
func XCTAssertNotNil(expression: @auto_closure () -> AnyObject?, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssertNotNil(expression: @auto_closure () -> AnyObject?, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_NotNil
|
||||
|
||||
// evaluate the expression exactly once
|
||||
@@ -74,12 +75,14 @@ extension XCTestCase {
|
||||
|
||||
// test both Optional and value to treat .None and nil as synonymous
|
||||
var passed: Bool
|
||||
var expressionValueStr: String = "nil"
|
||||
if let expressionValueUnwrapped: AnyObject = expressionValueOptional {
|
||||
// TODO: passed = !(expressionValueUnwrapped === nil)
|
||||
if expressionValueUnwrapped === nil {
|
||||
passed = false
|
||||
} else {
|
||||
passed = true
|
||||
expressionValueStr = reflect(expressionValueUnwrapped).summary
|
||||
}
|
||||
} else {
|
||||
passed = false
|
||||
@@ -89,19 +92,19 @@ extension XCTestCase {
|
||||
// TODO: @auto_string expression
|
||||
let expressionStr = "expressionStr"
|
||||
|
||||
_XCTRegisterFailure(self, true, _XCTFailureDescription(assertionType, 0, expressionStr), message, file, line)
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionStr, expressionValueStr), message, file, line)
|
||||
}
|
||||
|
||||
// TODO: handle an exception for which we can get a description
|
||||
// TODO: handle an exception for which we can't get a description
|
||||
}
|
||||
}
|
||||
|
||||
func XCTAssert(expression: @auto_closure () -> LogicValue, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssert(expression: @auto_closure () -> LogicValue, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
// XCTAssert is just a cover for XCTAssertTrue.
|
||||
XCTAssertTrue(expression, message, file, line);
|
||||
}
|
||||
XCTAssertTrue(expression, message, file: file, line: line);
|
||||
}
|
||||
|
||||
func XCTAssertTrue(expression: @auto_closure () -> LogicValue, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssertTrue(expression: @auto_closure () -> LogicValue, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_True
|
||||
|
||||
// evaluate the expression exactly once
|
||||
@@ -109,16 +112,16 @@ extension XCTestCase {
|
||||
|
||||
if !expressionValue {
|
||||
// TODO: @auto_string expression
|
||||
let expressionStr = "expressionStr"
|
||||
let expressionStr = expressionValue ? "true" : "false"
|
||||
|
||||
_XCTRegisterFailure(self, true, _XCTFailureDescription(assertionType, 0, expressionStr), message, file, line)
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionStr), message, file, line)
|
||||
}
|
||||
|
||||
// TODO: handle an exception for which we can get a description
|
||||
// TODO: handle an exception for which we can't get a description
|
||||
}
|
||||
}
|
||||
|
||||
func XCTAssertFalse(expression: @auto_closure () -> LogicValue, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssertFalse(expression: @auto_closure () -> LogicValue, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_False
|
||||
|
||||
// evaluate the expression exactly once
|
||||
@@ -128,64 +131,105 @@ extension XCTestCase {
|
||||
// TODO: @auto_string expression
|
||||
let expressionStr = expressionValue ? "true" : "false"
|
||||
|
||||
_XCTRegisterFailure(self, true, _XCTFailureDescription(assertionType, 0, expressionStr), message, file, line)
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionStr), message, file, line)
|
||||
}
|
||||
|
||||
// TODO: handle an exception for which we can get a description
|
||||
// TODO: handle an exception for which we can't get a description
|
||||
}
|
||||
}
|
||||
|
||||
func XCTAssertEqualObjects(expression1: @auto_closure () -> NSObject, expression2: @auto_closure () -> NSObject, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssertEqualObjects(expression1: @auto_closure () -> NSObject?, expression2: @auto_closure () -> NSObject?, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_EqualObjects
|
||||
|
||||
// evaluate each expression exactly once
|
||||
let expressionValue1 = expression1()
|
||||
let expressionValue2 = expression2()
|
||||
|
||||
if (expressionValue1 == nil && expressionValue2 == nil) || !(expressionValue1.isEqual(expressionValue2)) {
|
||||
var isEqualOrBothNil: Bool = false
|
||||
var expressionValueStr1: String
|
||||
var expressionValueStr2: String
|
||||
|
||||
if let expressionValue1NonOptional: NSObject = expressionValue1 {
|
||||
expressionValueStr1 = "\(expressionValue1NonOptional.description)"
|
||||
|
||||
if let expressionValue2NonOptional: NSObject = expressionValue2 {
|
||||
expressionValueStr2 = "\(expressionValue2NonOptional.description)"
|
||||
|
||||
isEqualOrBothNil = expressionValue1NonOptional.isEqual(expressionValue2NonOptional)
|
||||
} else {
|
||||
expressionValueStr2 = "nil"
|
||||
}
|
||||
} else {
|
||||
expressionValueStr1 = "nil"
|
||||
|
||||
if let expressionValue2NonOptional: NSObject = expressionValue2 {
|
||||
expressionValueStr2 = "\(expressionValue2NonOptional.description)"
|
||||
} else {
|
||||
expressionValueStr2 = "nil"
|
||||
|
||||
// If both are nil, also consider XCTAssertEqualObjects to pass.
|
||||
isEqualOrBothNil = true
|
||||
}
|
||||
}
|
||||
|
||||
if !isEqualOrBothNil {
|
||||
// TODO: @auto_string expression1
|
||||
// TODO: @auto_string expression2
|
||||
let expressionStr1 = "expressionStr1"
|
||||
let expressionStr2 = "expressionStr2"
|
||||
|
||||
// TODO: stringify expressionValue1
|
||||
// TODO: stringify expressionValue2
|
||||
let expressionValueStr1 = "expressionValueStr1"
|
||||
let expressionValueStr2 = "expressionValueStr2"
|
||||
|
||||
_XCTRegisterFailure(self, true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, expressionValueStr1, expressionValueStr2), message, file, line)
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, expressionValueStr1, expressionValueStr2), message, file, line)
|
||||
}
|
||||
|
||||
// TODO: handle an exception for which we can get a description
|
||||
// TODO: handle an exception for which we can't get a description
|
||||
}
|
||||
}
|
||||
|
||||
func XCTAssertNotEqualObjects(expression1: @auto_closure () -> NSObject, expression2: @auto_closure () -> NSObject, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssertNotEqualObjects(expression1: @auto_closure () -> NSObject?, expression2: @auto_closure () -> NSObject?, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_NotEqualObjects
|
||||
|
||||
// evaluate each expression exactly once
|
||||
let expressionValue1 = expression1()
|
||||
let expressionValue2 = expression2()
|
||||
|
||||
if (expressionValue1 == expressionValue2) || expressionValue1.isEqual(expressionValue2) {
|
||||
var isEqualAndBothNonNil: Bool = false
|
||||
var expressionValueStr1: String
|
||||
var expressionValueStr2: String
|
||||
|
||||
if let expressionValue1NonOptional = expressionValue1 {
|
||||
expressionValueStr1 = "\(expressionValue1NonOptional.description)"
|
||||
|
||||
if let expressionValue2NonOptional = expressionValue2 {
|
||||
expressionValueStr2 = "\(expressionValue2NonOptional.description)"
|
||||
|
||||
isEqualAndBothNonNil = expressionValue1NonOptional.isEqual(expressionValue2NonOptional)
|
||||
} else {
|
||||
expressionValueStr2 = "nil"
|
||||
}
|
||||
} else {
|
||||
expressionValueStr1 = "nil"
|
||||
|
||||
if let expressionValue2NonOptional: NSObject = expressionValue2 {
|
||||
expressionValueStr2 = "\(expressionValue2NonOptional.description)"
|
||||
} else {
|
||||
expressionValueStr2 = "nil"
|
||||
}
|
||||
}
|
||||
|
||||
if isEqualAndBothNonNil || (expressionValue1 == nil && expressionValue2 == nil) {
|
||||
// TODO: @auto_string expression1
|
||||
// TODO: @auto_string expression2
|
||||
let expressionStr1 = "expressionStr1"
|
||||
let expressionStr2 = "expressionStr2"
|
||||
|
||||
// TODO: stringify expressionValue1
|
||||
// TODO: stringify expressionValue2
|
||||
let expressionValueStr1 = "expressionValueStr1"
|
||||
let expressionValueStr2 = "expressionValueStr2"
|
||||
|
||||
_XCTRegisterFailure(self, true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, expressionValueStr1, expressionValueStr2), message, file, line)
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, expressionValueStr1, expressionValueStr2), message, file, line)
|
||||
}
|
||||
|
||||
// TODO: handle an exception for which we can get a description
|
||||
// TODO: handle an exception for which we can't get a description
|
||||
}
|
||||
}
|
||||
|
||||
func XCTAssertEqual<T: Equatable>(expression1: @auto_closure () -> T, expression2: @auto_closure () -> T, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssertEqual<T: Equatable>(expression1: @auto_closure () -> T, expression2: @auto_closure () -> T, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_Equal
|
||||
|
||||
// evaluate each expression exactly once
|
||||
@@ -198,19 +242,17 @@ extension XCTestCase {
|
||||
let expressionStr1 = "expressionStr1"
|
||||
let expressionStr2 = "expressionStr2"
|
||||
|
||||
// TODO: stringify expressionValue1
|
||||
// TODO: stringify expressionValue2
|
||||
let expressionValueStr1 = "expressionValueStr1"
|
||||
let expressionValueStr2 = "expressionValueStr2"
|
||||
var expressionValueStr1 = reflect(expressionValue1).summary
|
||||
let expressionValueStr2 = reflect(expressionValue2).summary
|
||||
|
||||
_XCTRegisterFailure(self, true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, expressionValueStr1, expressionValueStr2), message, file, line)
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, expressionValueStr1, expressionValueStr2), message, file, line)
|
||||
}
|
||||
|
||||
// TODO: handle an exception for which we can get a description
|
||||
// TODO: handle an exception for which we can't get a description
|
||||
}
|
||||
}
|
||||
|
||||
func XCTAssertNotEqual<T: Equatable>(expression1: @auto_closure () -> T, expression2: @auto_closure () -> T, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssertNotEqual<T: Equatable>(expression1: @auto_closure () -> T, expression2: @auto_closure () -> T, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_NotEqual
|
||||
|
||||
// evaluate each expression exactly once
|
||||
@@ -223,116 +265,242 @@ extension XCTestCase {
|
||||
let expressionStr1 = "expressionStr1"
|
||||
let expressionStr2 = "expressionStr2"
|
||||
|
||||
// TODO: stringify expressionValue1
|
||||
// TODO: stringify expressionValue2
|
||||
let expressionValueStr1 = "expressionValueStr1"
|
||||
let expressionValueStr2 = "expressionValueStr2"
|
||||
var expressionValueStr1 = reflect(expressionValue1).summary
|
||||
let expressionValueStr2 = reflect(expressionValue2).summary
|
||||
|
||||
_XCTRegisterFailure(self, true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, expressionValueStr1, expressionValueStr2), message, file, line)
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, expressionValueStr1, expressionValueStr2), message, file, line)
|
||||
}
|
||||
|
||||
// TODO: handle an exception for which we can get a description
|
||||
// TODO: handle an exception for which we can't get a description
|
||||
}
|
||||
}
|
||||
|
||||
#if XCTEST_ENABLE_EQUAL_WITH_ACCURACY_ASSERTIONS
|
||||
func XCTAssertEqualWithAccuracy<T: FloatingPointNumber>(expression1: @auto_closure () -> T, expression2: @auto_closure () -> T, accuracy: T, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func _XCTCheckEqualWithAccuracy_Double(value1: Double, value2: Double, accuracy: Double) -> Bool {
|
||||
return (!value1.isNaN() && !value2.isNaN())
|
||||
&& (abs(value1 - value2) <= accuracy)
|
||||
}
|
||||
|
||||
func _XCTCheckEqualWithAccuracy_Float(value1: Float, value2: Float, accuracy: Float) -> Bool {
|
||||
return (!value1.isNaN() && !value2.isNaN())
|
||||
&& (abs(value1 - value2) <= accuracy)
|
||||
}
|
||||
|
||||
func XCTAssertEqualWithAccuracy<T: FloatingPointNumber>(expression1: @auto_closure () -> T, expression2: @auto_closure () -> T, accuracy: T, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_EqualWithAccuracy
|
||||
|
||||
// evaluate each expression exactly once
|
||||
let expressionValue1: FloatingPointNumber = expression1()
|
||||
let expressionValue2: FloatingPointNumber = expression2()
|
||||
let expressionValue1 = expression1()
|
||||
let expressionValue2 = expression2()
|
||||
|
||||
if expressionValue1.isNaN() || expressionValue2.isNaN()
|
||||
|| ((max(expressionValue1, expressionValue2)
|
||||
- min(expressionValue1, expressionValue2)) > accuracy) {
|
||||
var equalWithAccuracy: Bool = false
|
||||
|
||||
switch (expressionValue1, expressionValue2, accuracy) {
|
||||
case let (expressionValue1Double as Double, expressionValue2Double as Double, accuracyDouble as Double):
|
||||
equalWithAccuracy = _XCTCheckEqualWithAccuracy_Double(expressionValue1Double, expressionValue2Double, accuracyDouble)
|
||||
|
||||
case let (expressionValue1Float as Float, expressionValue2Float as Float, accuracyFloat as Float):
|
||||
equalWithAccuracy = _XCTCheckEqualWithAccuracy_Float(expressionValue1Float, expressionValue2Float, accuracyFloat)
|
||||
|
||||
default:
|
||||
// unknown type, fail with prejudice
|
||||
fatal("unsupported floating-point type passed to XCTAssertEqualWithAccuracy")
|
||||
}
|
||||
|
||||
if !equalWithAccuracy {
|
||||
// TODO: @auto_string expression1
|
||||
// TODO: @auto_string expression2
|
||||
let expressionStr1 = "expressionStr1"
|
||||
let expressionStr2 = "expressionStr2"
|
||||
|
||||
// TODO: stringify expressionValue1
|
||||
// TODO: stringify expressionValue2
|
||||
// TODO: stringify accuracy
|
||||
let expressionValueStr1 = "expressionValueStr1"
|
||||
let expressionValueStr2 = "expressionValueStr2"
|
||||
let accuracyStr = "accuracyStr"
|
||||
var expressionValueStr1 = reflect(expressionValue1).summary
|
||||
let expressionValueStr2 = reflect(expressionValue2).summary
|
||||
var accuracyStr = reflect(accuracy).summary
|
||||
|
||||
_XCTRegisterFailure(self, true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, accuracyStr, expressionValueStr1, expressionValueStr2, accuracyStr), message, file, line)
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, accuracyStr, expressionValueStr1, expressionValueStr2, accuracyStr), message, file, line)
|
||||
}
|
||||
|
||||
// TODO: handle an exception for which we can get a description
|
||||
// TODO: handle an exception for which we can't get a description
|
||||
}
|
||||
}
|
||||
|
||||
func XCTAssertNotEqualWithAccuracy<T: FloatingPointNumber>(expression1: @auto_closure () -> T, expression2: @auto_closure () -> T, accuracy: T, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func _XCTCheckNotEqualWithAccuracy_Double(value1: Double, value2: Double, accuracy: Double) -> Bool {
|
||||
return (value1.isNaN() || value2.isNaN())
|
||||
|| (abs(value1 - value2) > accuracy)
|
||||
}
|
||||
|
||||
func _XCTCheckNotEqualWithAccuracy_Float(value1: Float, value2: Float, accuracy: Float) -> Bool {
|
||||
return (value1.isNaN() || value2.isNaN())
|
||||
|| (abs(value1 - value2) > accuracy)
|
||||
}
|
||||
|
||||
func XCTAssertNotEqualWithAccuracy<T: FloatingPointNumber>(expression1: @auto_closure () -> T, expression2: @auto_closure () -> T, accuracy: T, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_NotEqualWithAccuracy
|
||||
|
||||
// evaluate each expression exactly once
|
||||
let expressionValue1: FloatingPointNumber = expression1()
|
||||
let expressionValue2: FloatingPointNumber = expression2()
|
||||
let expressionValue1 = expression1()
|
||||
let expressionValue2 = expression2()
|
||||
|
||||
if !expressionValue1.isNaN() && !expressionValue2.isNaN()
|
||||
&& ((max(expressionValue1, expressionValue2)
|
||||
- min(expressionValue1, expressionValue2)) <= accuracy) {
|
||||
var notEqualWithAccuracy: Bool = false
|
||||
|
||||
switch (expressionValue1, expressionValue2, accuracy) {
|
||||
case let (expressionValue1Double as Double, expressionValue2Double as Double, accuracyDouble as Double):
|
||||
notEqualWithAccuracy = _XCTCheckNotEqualWithAccuracy_Double(expressionValue1Double, expressionValue2Double, accuracyDouble)
|
||||
|
||||
case let (expressionValue1Float as Float, expressionValue2Float as Float, accuracyFloat as Float):
|
||||
notEqualWithAccuracy = _XCTCheckNotEqualWithAccuracy_Float(expressionValue1Float, expressionValue2Float, accuracyFloat)
|
||||
|
||||
default:
|
||||
// unknown type, fail with prejudice
|
||||
fatal("unsupported floating-point type passed to XCTAssertNotEqualWithAccuracy")
|
||||
}
|
||||
|
||||
if !notEqualWithAccuracy {
|
||||
// TODO: @auto_string expression1
|
||||
// TODO: @auto_string expression2
|
||||
// TODO: @auto_string accuracy
|
||||
let expressionStr1 = "expressionStr1"
|
||||
let expressionStr2 = "expressionStr2"
|
||||
|
||||
// TODO: stringify expressionValue1
|
||||
// TODO: stringify expressionValue2
|
||||
// TODO: stringify accuracy
|
||||
let expressionValueStr1 = "expressionValueStr1"
|
||||
let expressionValueStr2 = "expressionValueStr2"
|
||||
let accuracyStr = "accuracyStr"
|
||||
var expressionValueStr1 = reflect(expressionValue1).summary
|
||||
let expressionValueStr2 = reflect(expressionValue2).summary
|
||||
var accuracyStr = reflect(accuracy).summary
|
||||
|
||||
_XCTRegisterFailure(self, true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, accuracyStr, expressionValueStr1, expressionValueStr2, accuracyStr), message, file, line)
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, accuracyStr, expressionValueStr1, expressionValueStr2, accuracyStr), message, file, line)
|
||||
}
|
||||
|
||||
// TODO: handle an exception for which we can get a description
|
||||
// TODO: handle an exception for which we can't get a description
|
||||
}
|
||||
|
||||
func XCTAssertGreaterThan<T: Comparable>(expression1: @auto_closure () -> T, expression2: @auto_closure () -> T, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_GreaterThan
|
||||
|
||||
// evaluate each expression exactly once
|
||||
let expressionValue1 = expression1()
|
||||
let expressionValue2 = expression2()
|
||||
|
||||
if !(expressionValue1 > expressionValue2) {
|
||||
// TODO: @auto_string expression1
|
||||
// TODO: @auto_string expression2
|
||||
let expressionStr1 = "expressionStr1"
|
||||
let expressionStr2 = "expressionStr2"
|
||||
|
||||
var expressionValueStr1 = reflect(expressionValue1).summary
|
||||
let expressionValueStr2 = reflect(expressionValue2).summary
|
||||
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, expressionValueStr1, expressionValueStr2), message, file, line)
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: handle an exception for which we can get a description
|
||||
// TODO: handle an exception for which we can't get a description
|
||||
}
|
||||
|
||||
func XCTAssertGreaterThanOrEqual<T: Comparable>(expression1: @auto_closure () -> T, expression2: @auto_closure () -> T, _ message: String = "", file: String = __FILE__, line: Int = __LINE__)
|
||||
{
|
||||
let assertionType = _XCTAssertionType.Assertion_GreaterThanOrEqual
|
||||
|
||||
// evaluate each expression exactly once
|
||||
let expressionValue1 = expression1()
|
||||
let expressionValue2 = expression2()
|
||||
|
||||
if !(expressionValue1 >= expressionValue2) {
|
||||
// TODO: @auto_string expression1
|
||||
// TODO: @auto_string expression2
|
||||
let expressionStr1 = "expressionStr1"
|
||||
let expressionStr2 = "expressionStr2"
|
||||
|
||||
var expressionValueStr1 = reflect(expressionValue1).summary
|
||||
let expressionValueStr2 = reflect(expressionValue2).summary
|
||||
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, expressionValueStr1, expressionValueStr2), message, file, line)
|
||||
}
|
||||
|
||||
// TODO: handle an exception for which we can get a description
|
||||
// TODO: handle an exception for which we can't get a description
|
||||
}
|
||||
|
||||
func XCTAssertLessThan<T: Comparable>(expression1: @auto_closure () -> T, expression2: @auto_closure () -> T, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_LessThan
|
||||
|
||||
// evaluate each expression exactly once
|
||||
let expressionValue1 = expression1()
|
||||
let expressionValue2 = expression2()
|
||||
|
||||
if !(expressionValue1 < expressionValue2) {
|
||||
// TODO: @auto_string expression1
|
||||
// TODO: @auto_string expression2
|
||||
let expressionStr1 = "expressionStr1"
|
||||
let expressionStr2 = "expressionStr2"
|
||||
|
||||
var expressionValueStr1 = reflect(expressionValue1).summary
|
||||
let expressionValueStr2 = reflect(expressionValue2).summary
|
||||
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, expressionValueStr1, expressionValueStr2), message, file, line)
|
||||
}
|
||||
|
||||
// TODO: handle an exception for which we can get a description
|
||||
// TODO: handle an exception for which we can't get a description
|
||||
}
|
||||
|
||||
func XCTAssertLessThanOrEqual<T: Comparable>(expression1: @auto_closure () -> T, expression2: @auto_closure () -> T, _ message: String = "", file: String = __FILE__, line: Int = __LINE__)
|
||||
{
|
||||
let assertionType = _XCTAssertionType.Assertion_LessThanOrEqual
|
||||
|
||||
// evaluate each expression exactly once
|
||||
let expressionValue1 = expression1()
|
||||
let expressionValue2 = expression2()
|
||||
|
||||
if !(expressionValue1 <= expressionValue2) {
|
||||
// TODO: @auto_string expression1
|
||||
// TODO: @auto_string expression2
|
||||
let expressionStr1 = "expressionStr1"
|
||||
let expressionStr2 = "expressionStr2"
|
||||
|
||||
var expressionValueStr1 = reflect(expressionValue1).summary
|
||||
let expressionValueStr2 = reflect(expressionValue2).summary
|
||||
|
||||
_XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionStr1, expressionStr2, expressionValueStr1, expressionValueStr2), message, file, line)
|
||||
}
|
||||
|
||||
// TODO: handle an exception for which we can get a description
|
||||
// TODO: handle an exception for which we can't get a description
|
||||
}
|
||||
|
||||
#if XCTEST_ENABLE_EXCEPTION_ASSERTIONS
|
||||
// --- Currently-Unsupported Assertions ---
|
||||
// --- Currently-Unsupported Assertions ---
|
||||
|
||||
func XCTAssertThrows(expression: @auto_closure () -> Any?, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssertThrows(expression: @auto_closure () -> Any?, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_Throws
|
||||
|
||||
// FIXME: Unsupported
|
||||
}
|
||||
}
|
||||
|
||||
func XCTAssertThrowsSpecific(expression: @auto_closure () -> Any?, exception: Any, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssertThrowsSpecific(expression: @auto_closure () -> Any?, exception: Any, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_ThrowsSpecific
|
||||
|
||||
// FIXME: Unsupported
|
||||
}
|
||||
}
|
||||
|
||||
func XCTAssertThrowsSpecificNamed(expression: @auto_closure () -> Any?, exception: Any, name: String, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssertThrowsSpecificNamed(expression: @auto_closure () -> Any?, exception: Any, name: String, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_ThrowsSpecificNamed
|
||||
|
||||
// FIXME: Unsupported
|
||||
}
|
||||
}
|
||||
|
||||
func XCTAssertNoThrow(expression: @auto_closure () -> Any?, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssertNoThrow(expression: @auto_closure () -> Any?, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_NoThrow
|
||||
|
||||
// FIXME: Unsupported
|
||||
}
|
||||
}
|
||||
|
||||
func XCTAssertNoThrowSpecific(expression: @auto_closure () -> Any?, exception: Any, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssertNoThrowSpecific(expression: @auto_closure () -> Any?, exception: Any, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_NoThrowSpecific
|
||||
|
||||
// FIXME: Unsupported
|
||||
}
|
||||
}
|
||||
|
||||
func XCTAssertNoThrowSpecificNamed(expression: @auto_closure () -> Any?, exception: Any, name: String, message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
func XCTAssertNoThrowSpecificNamed(expression: @auto_closure () -> Any?, exception: Any, name: String, _ message: String = "", file: String = __FILE__, line: Int = __LINE__) -> Void {
|
||||
let assertionType = _XCTAssertionType.Assertion_NoThrowSpecificNamed
|
||||
|
||||
// FIXME: Unsupported
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
%# -*- mode: swift -*-
|
||||
//===--- NSSwiftXXXBase.mm.gyb - Cocoa bases for Swift container buffers --===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
@@ -43,7 +44,7 @@ extern "C" id _objc_rootAutorelease(id);
|
||||
|
||||
using namespace swift;
|
||||
|
||||
% for Class in ('Array','Dictionary'):
|
||||
% for Class in ('Array','Dictionary','Enumerator'):
|
||||
@interface NSSwift${Class}Base : NS${Class}
|
||||
{
|
||||
SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
|
||||
@@ -54,9 +55,10 @@ using namespace swift;
|
||||
+ (void)load {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
class_setSuperclass(
|
||||
objc_getClass("NSSwift${Class}"),
|
||||
[NSSwift${Class}Base class]);
|
||||
char buffer[64];
|
||||
snprintf(buffer, 64, "_TtCSs%d%s", (int)strlen("NSSwift${Class}"),
|
||||
"NSSwift${Class}");
|
||||
class_setSuperclass(objc_getClass(buffer), [NSSwift${Class}Base class]);
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
|
||||
@@ -15,17 +15,36 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <Block.h>
|
||||
#include <objc/NSObject.h>
|
||||
#include <objc/runtime.h>
|
||||
#include <objc/message.h>
|
||||
#if __has_include(<objc/objc-internal.h>)
|
||||
#include <objc/objc-abi.h>
|
||||
#include <objc/objc-internal.h>
|
||||
#else
|
||||
extern "C" id _objc_rootAutorelease(id);
|
||||
#endif
|
||||
#include "swift/Runtime/Alloc.h"
|
||||
#include "swift/Runtime/Heap.h"
|
||||
#include "swift/Runtime/HeapObject.h"
|
||||
#include "swift/Runtime/Metadata.h"
|
||||
#include "swift/Runtime/ObjCBridge.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "Private.h"
|
||||
#include "Debug.h"
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <mutex>
|
||||
#include "../shims/shims.h"
|
||||
|
||||
// Redeclare these just we check them.
|
||||
extern "C" id objc_retain(id);
|
||||
extern "C" void objc_release(id);
|
||||
extern "C" id _objc_rootAutorelease(id);
|
||||
extern "C" void objc_moveWeak(id*, id*);
|
||||
extern "C" void objc_copyWeak(id*, id*);
|
||||
extern "C" id objc_initWeak(id*, id);
|
||||
extern "C" id objc_storeWeak(id*, id);
|
||||
extern "C" void objc_destroyWeak(id*);
|
||||
extern "C" id objc_loadWeakRetained(id*);
|
||||
|
||||
using namespace swift;
|
||||
|
||||
@@ -37,38 +56,133 @@ struct SwiftObject_s {
|
||||
#if __has_attribute(objc_root_class)
|
||||
__attribute__((objc_root_class))
|
||||
#endif
|
||||
@interface SwiftObject
|
||||
{
|
||||
@interface SwiftObject<NSObject> {
|
||||
SwiftObject_s magic;
|
||||
}
|
||||
- (id)retain;
|
||||
- (void)release;
|
||||
- (id)autorelease;
|
||||
- (void)dealloc;
|
||||
|
||||
- (BOOL)isEqual:(id)object;
|
||||
- (NSUInteger)hash;
|
||||
|
||||
- (Class)superclass;
|
||||
- (Class)class;
|
||||
- (instancetype)self;
|
||||
- (struct _NSZone *)zone;
|
||||
|
||||
- (id)performSelector:(SEL)aSelector;
|
||||
- (id)performSelector:(SEL)aSelector withObject:(id)object;
|
||||
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
|
||||
|
||||
- (BOOL)isProxy;
|
||||
|
||||
+ (BOOL)isSubclassOfClass:(Class)aClass;
|
||||
- (BOOL)isKindOfClass:(Class)aClass;
|
||||
- (BOOL)isMemberOfClass:(Class)aClass;
|
||||
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;
|
||||
|
||||
- (BOOL)respondsToSelector:(SEL)aSelector;
|
||||
|
||||
- (instancetype)retain;
|
||||
- (oneway void)release;
|
||||
- (instancetype)autorelease;
|
||||
- (NSUInteger)retainCount;
|
||||
|
||||
- (NSString *)description;
|
||||
- (NSString *)debugDescription;
|
||||
@end
|
||||
|
||||
void reportUnrecognizedSelector(Class cls, SEL sel) {
|
||||
printf("class '%s' does not recognize %s selector '%s', aborting\n",
|
||||
class_getName(cls),
|
||||
class_isMetaClass(cls) ? "class" : "instance",
|
||||
sel_getName(sel));
|
||||
abort();
|
||||
static SwiftObject *_allocHelper(Class cls) {
|
||||
// XXX FIXME
|
||||
// When we have layout information, do precise alignment rounding
|
||||
// For now, assume someone is using hardware vector types
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
const size_t mask = 32 - 1;
|
||||
#else
|
||||
const size_t mask = 16 - 1;
|
||||
#endif
|
||||
return reinterpret_cast<SwiftObject *>(swift::swift_allocObject(
|
||||
reinterpret_cast<HeapMetadata const *>(cls),
|
||||
class_getInstanceSize(cls), mask));
|
||||
}
|
||||
|
||||
// Helper from the standard library for stringizing an arbitrary object.
|
||||
namespace {
|
||||
struct String { void *x, *y, *z; };
|
||||
}
|
||||
|
||||
extern "C" void swift_getSummary(String *out, OpaqueValue *value,
|
||||
const Metadata *T);
|
||||
|
||||
static NSString *_getDescription(SwiftObject *obj) {
|
||||
// Cached lookup of swift_convertStringToNSString, which is in Foundation.
|
||||
static NSString *(*convertStringToNSString)(void *sx, void *sy, void *sz)
|
||||
= nullptr;
|
||||
|
||||
if (!convertStringToNSString) {
|
||||
convertStringToNSString = (decltype(convertStringToNSString))(uintptr_t)
|
||||
dlsym(RTLD_DEFAULT, "swift_convertStringToNSString");
|
||||
// If Foundation hasn't loaded yet, fall back to returning the static string
|
||||
// "SwiftObject". The likelihood of someone invoking -description without
|
||||
// ObjC interop is low.
|
||||
if (!convertStringToNSString)
|
||||
return @"SwiftObject";
|
||||
}
|
||||
|
||||
String tmp;
|
||||
swift_retain((HeapObject*)obj);
|
||||
swift_getSummary(&tmp, (OpaqueValue*)&obj,
|
||||
(const Metadata*)object_getClass(obj));
|
||||
return [convertStringToNSString(tmp.x, tmp.y, tmp.z) autorelease];
|
||||
}
|
||||
|
||||
@implementation SwiftObject
|
||||
+ (void)load {}
|
||||
+ (void)initialize {}
|
||||
|
||||
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
|
||||
assert(zone == nullptr);
|
||||
return _allocHelper(self);
|
||||
}
|
||||
|
||||
+ (instancetype)alloc {
|
||||
// we do not support "placement new" or zones,
|
||||
// so there is no need to call allocWithZone
|
||||
return _allocHelper(self);
|
||||
}
|
||||
|
||||
+ (Class)class {
|
||||
return self;
|
||||
}
|
||||
- (id)class {
|
||||
return object_getClass(self);
|
||||
}
|
||||
+ (Class)superclass {
|
||||
return class_getSuperclass(self);
|
||||
}
|
||||
- (Class)superclass {
|
||||
return class_getSuperclass([self class]);
|
||||
}
|
||||
|
||||
+ (BOOL)isMemberOfClass:(Class)cls {
|
||||
return object_getClass((id)self) == cls;
|
||||
}
|
||||
|
||||
- (BOOL)isMemberOfClass:(Class)cls {
|
||||
return [self class] == cls;
|
||||
}
|
||||
|
||||
- (instancetype)self {
|
||||
return self;
|
||||
}
|
||||
- (BOOL)isProxy {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (struct _NSZone *)zone {
|
||||
return (struct _NSZone *)&swift::zoneShims;
|
||||
}
|
||||
|
||||
- (void)doesNotRecognizeSelector: (SEL) sel {
|
||||
reportUnrecognizedSelector(object_getClass(self), sel);
|
||||
swift::crash("Unrecognized selector");
|
||||
}
|
||||
|
||||
- (id)retain {
|
||||
@@ -83,6 +197,9 @@ void reportUnrecognizedSelector(Class cls, SEL sel) {
|
||||
- (id)autorelease {
|
||||
return _objc_rootAutorelease(self);
|
||||
}
|
||||
- (NSUInteger)retainCount {
|
||||
return swift::swift_retainCount(reinterpret_cast<HeapObject *>(self));
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
auto SELF = reinterpret_cast<HeapObject *>(self);
|
||||
@@ -97,8 +214,292 @@ void reportUnrecognizedSelector(Class cls, SEL sel) {
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (BOOL)isSubclassOfClass:(Class)someClass {
|
||||
for (Class isa = self; isa != Nil; isa = class_getSuperclass(isa))
|
||||
if (isa == someClass)
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (BOOL)respondsToSelector:(SEL)sel {
|
||||
if (!sel) return NO;
|
||||
return class_respondsToSelector(object_getClass((id)self), sel);
|
||||
}
|
||||
|
||||
- (BOOL)respondsToSelector:(SEL)sel {
|
||||
if (!sel) return NO;
|
||||
return class_respondsToSelector([self class], sel);
|
||||
}
|
||||
|
||||
- (BOOL)conformsToProtocol:(Protocol*)proto {
|
||||
if (!proto) return NO;
|
||||
return class_conformsToProtocol([self class], proto);
|
||||
}
|
||||
|
||||
- (bool) __usesNativeSwiftReferenceCounting {
|
||||
return true;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
return (NSUInteger)self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
return self == object;
|
||||
}
|
||||
|
||||
- (id)performSelector:(SEL)aSelector {
|
||||
return ((id(*)(id, SEL))objc_msgSend)(self, aSelector);
|
||||
}
|
||||
|
||||
- (id)performSelector:(SEL)aSelector withObject:(id)object {
|
||||
return ((id(*)(id, SEL, id))objc_msgSend)(self, aSelector, object);
|
||||
}
|
||||
|
||||
- (id)performSelector:(SEL)aSelector withObject:(id)object1
|
||||
withObject:(id)object2 {
|
||||
return ((id(*)(id, SEL, id, id))objc_msgSend)(self, aSelector, object1,
|
||||
object2);
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return _getDescription(self);
|
||||
}
|
||||
- (NSString *)debugDescription {
|
||||
return _getDescription(self);
|
||||
}
|
||||
@end
|
||||
|
||||
// FIXME: there can be no exhaustive list of ObjC root classes; this
|
||||
// really needs to be done by the runtime.
|
||||
@implementation NSObject (__UsesNativeSwiftReferenceCounting)
|
||||
- (bool) __usesNativeSwiftReferenceCounting {
|
||||
return false;
|
||||
}
|
||||
@end
|
||||
// FIXME: NSProxy?
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************** WEAK REFERENCES ******************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/// A side-table of shared weak references for use by the unowned entry.
|
||||
///
|
||||
/// FIXME: this needs to be integrated with the ObjC runtime so that
|
||||
/// entries will actually get collected. Also, that would make this just
|
||||
/// a simple manipulation of the internal structures there.
|
||||
namespace {
|
||||
struct UnownedRefEntry {
|
||||
id Value;
|
||||
size_t Count;
|
||||
};
|
||||
}
|
||||
static llvm::DenseMap<const void*, UnownedRefEntry> UnownedRefs;
|
||||
static std::mutex UnownedRefsMutex;
|
||||
|
||||
static void objc_rootRetainUnowned(id object) {
|
||||
std::lock_guard<std::mutex> lock(UnownedRefsMutex);
|
||||
auto it = UnownedRefs.find((const void*) object);
|
||||
assert(it != UnownedRefs.end());
|
||||
assert(it->second.Count > 0);
|
||||
|
||||
// Do an unbalanced retain.
|
||||
id result = objc_loadWeakRetained(&it->second.Value);
|
||||
|
||||
// If that yielded null, abort.
|
||||
if (!result) _swift_abortRetainUnowned((const void*) object);
|
||||
}
|
||||
|
||||
static void objc_rootWeakRetain(id object) {
|
||||
std::lock_guard<std::mutex> lock(UnownedRefsMutex);
|
||||
auto ins = UnownedRefs.insert({ (const void*) object, UnownedRefEntry() });
|
||||
if (ins.second) {
|
||||
ins.first->second.Count++;
|
||||
} else {
|
||||
objc_initWeak(&ins.first->second.Value, object);
|
||||
ins.first->second.Count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void objc_rootWeakRelease(id object) {
|
||||
std::lock_guard<std::mutex> lock(UnownedRefsMutex);
|
||||
auto it = UnownedRefs.find((const void*) object);
|
||||
assert(it != UnownedRefs.end());
|
||||
assert(it->second.Count > 0);
|
||||
if (--it->second.Count == 0) {
|
||||
objc_destroyWeak(&it->second.Value);
|
||||
UnownedRefs.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
/// Decide dynamically whether the given object uses native Swift
|
||||
/// reference-counting.
|
||||
static bool usesNativeSwiftReferenceCounting(void *object) {
|
||||
// This could be *much* faster if it were integrated into the ObjC runtime.
|
||||
assert(object);
|
||||
return [(id) object __usesNativeSwiftReferenceCounting];
|
||||
}
|
||||
|
||||
void *swift::swift_unknownRetain(void *object) {
|
||||
if (object == nullptr) return nullptr;
|
||||
if (usesNativeSwiftReferenceCounting(object))
|
||||
return swift_retain((HeapObject*) object);
|
||||
return objc_retain((id) object);
|
||||
}
|
||||
|
||||
void swift::swift_unknownRelease(void *object) {
|
||||
if (object == nullptr) return;
|
||||
if (usesNativeSwiftReferenceCounting(object))
|
||||
return swift_release((HeapObject*) object);
|
||||
return objc_release((id) object);
|
||||
}
|
||||
|
||||
void swift::swift_unknownRetainUnowned(void *object) {
|
||||
if (object == nullptr) return;
|
||||
if (usesNativeSwiftReferenceCounting(object))
|
||||
return swift_retainUnowned((HeapObject*) object);
|
||||
objc_rootRetainUnowned((id) object);
|
||||
}
|
||||
|
||||
void swift::swift_unknownWeakRetain(void *object) {
|
||||
if (object == nullptr) return;
|
||||
if (usesNativeSwiftReferenceCounting(object))
|
||||
return swift_weakRetain((HeapObject*) object);
|
||||
objc_rootWeakRetain((id) object);
|
||||
}
|
||||
void swift::swift_unknownWeakRelease(void *object) {
|
||||
if (object == nullptr) return;
|
||||
if (usesNativeSwiftReferenceCounting(object))
|
||||
return swift_weakRelease((HeapObject*) object);
|
||||
objc_rootWeakRelease((id) object);
|
||||
}
|
||||
|
||||
// FIXME: these are not really valid implementations; they assume too
|
||||
// much about the implementation of ObjC weak references, and the
|
||||
// loads from ->Value can race with clears by the runtime.
|
||||
|
||||
static void doWeakInit(WeakReference *addr, void *value, bool valueIsNative) {
|
||||
assert(value != nullptr);
|
||||
if (valueIsNative) {
|
||||
swift_weakInit(addr, (HeapObject*) value);
|
||||
} else {
|
||||
objc_initWeak((id*) &addr->Value, (id) value);
|
||||
}
|
||||
}
|
||||
|
||||
static void doWeakDestroy(WeakReference *addr, bool valueIsNative) {
|
||||
if (valueIsNative) {
|
||||
swift_weakDestroy(addr);
|
||||
} else {
|
||||
objc_destroyWeak((id*) &addr->Value);
|
||||
}
|
||||
}
|
||||
|
||||
void swift::swift_unknownWeakInit(WeakReference *addr, void *value) {
|
||||
if (value == nullptr) {
|
||||
addr->Value = nullptr;
|
||||
return;
|
||||
}
|
||||
doWeakInit(addr, value, usesNativeSwiftReferenceCounting(value));
|
||||
}
|
||||
|
||||
void swift::swift_unknownWeakAssign(WeakReference *addr, void *newValue) {
|
||||
// If the incoming value is null, this is just a destroy and
|
||||
// re-initialize.
|
||||
if (newValue == nullptr) {
|
||||
swift_unknownWeakDestroy(addr);
|
||||
addr->Value = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
bool newIsNative = usesNativeSwiftReferenceCounting(newValue);
|
||||
|
||||
// If the existing value is null, this is just an initialize.
|
||||
void *oldValue = addr->Value;
|
||||
if (oldValue == nullptr)
|
||||
return doWeakInit(addr, newValue, newIsNative);
|
||||
|
||||
bool oldIsNative = usesNativeSwiftReferenceCounting(oldValue);
|
||||
|
||||
// If they're both native, we can use the native function.
|
||||
if (oldIsNative && newIsNative)
|
||||
return swift_weakAssign(addr, (HeapObject*) newValue);
|
||||
|
||||
// If neither is native, we can use the ObjC function.
|
||||
if (!oldIsNative && !newIsNative)
|
||||
return (void) objc_storeWeak((id*) &addr->Value, (id) newValue);
|
||||
|
||||
// Otherwise, destroy according to one set of semantics and
|
||||
// re-initialize with the other.
|
||||
doWeakDestroy(addr, oldIsNative);
|
||||
doWeakInit(addr, newValue, newIsNative);
|
||||
}
|
||||
|
||||
void *swift::swift_unknownWeakLoadStrong(WeakReference *addr) {
|
||||
void *value = addr->Value;
|
||||
if (value == nullptr) return nullptr;
|
||||
|
||||
if (usesNativeSwiftReferenceCounting(value)) {
|
||||
return swift_weakLoadStrong(addr);
|
||||
} else {
|
||||
return (void*) objc_loadWeakRetained((id*) &addr->Value);
|
||||
}
|
||||
}
|
||||
|
||||
void *swift::swift_unknownWeakTakeStrong(WeakReference *addr) {
|
||||
void *value = addr->Value;
|
||||
if (value == nullptr) return nullptr;
|
||||
|
||||
if (usesNativeSwiftReferenceCounting(value)) {
|
||||
return swift_weakTakeStrong(addr);
|
||||
} else {
|
||||
void *result = (void*) objc_loadWeakRetained((id*) &addr->Value);
|
||||
objc_destroyWeak((id*) &addr->Value);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void swift::swift_unknownWeakDestroy(WeakReference *addr) {
|
||||
id object = (id) addr->Value;
|
||||
if (object == nullptr) return;
|
||||
doWeakDestroy(addr, usesNativeSwiftReferenceCounting(object));
|
||||
}
|
||||
void swift::swift_unknownWeakCopyInit(WeakReference *dest, WeakReference *src) {
|
||||
id object = (id) src->Value;
|
||||
if (object == nullptr) {
|
||||
dest->Value = nullptr;
|
||||
return;
|
||||
}
|
||||
if (usesNativeSwiftReferenceCounting(object))
|
||||
return swift_weakCopyInit(dest, src);
|
||||
objc_copyWeak((id*) &dest->Value, (id*) src);
|
||||
}
|
||||
void swift::swift_unknownWeakTakeInit(WeakReference *dest, WeakReference *src) {
|
||||
id object = (id) src->Value;
|
||||
if (object == nullptr) {
|
||||
dest->Value = nullptr;
|
||||
return;
|
||||
}
|
||||
if (usesNativeSwiftReferenceCounting(object))
|
||||
return swift_weakTakeInit(dest, src);
|
||||
objc_moveWeak((id*) &dest->Value, (id*) &src->Value);
|
||||
}
|
||||
void swift::swift_unknownWeakCopyAssign(WeakReference *dest, WeakReference *src) {
|
||||
if (dest == src) return;
|
||||
swift_unknownWeakDestroy(dest);
|
||||
swift_unknownWeakCopyInit(dest, src);
|
||||
}
|
||||
void swift::swift_unknownWeakTakeAssign(WeakReference *dest, WeakReference *src) {
|
||||
if (dest == src) return;
|
||||
swift_unknownWeakDestroy(dest);
|
||||
swift_unknownWeakTakeInit(dest, src);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/******************************* DYNAMIC CASTS *******************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
const void *
|
||||
swift::swift_dynamicCastObjCClass(const void *object,
|
||||
@@ -106,9 +507,11 @@ swift::swift_dynamicCastObjCClass(const void *object,
|
||||
// FIXME: We need to decide if this is really how we want to treat 'nil'.
|
||||
if (object == nullptr)
|
||||
return nullptr;
|
||||
// FIXME: -isKindOfClass: is not a core part of the Objective-C language.
|
||||
if ([(id)object isKindOfClass:(Class)targetType])
|
||||
|
||||
if ([(id)object isKindOfClass:(Class)targetType]) {
|
||||
return object;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -118,67 +521,200 @@ swift::swift_dynamicCastObjCClassUnconditional(const void *object,
|
||||
// FIXME: We need to decide if this is really how we want to treat 'nil'.
|
||||
if (object == nullptr)
|
||||
return nullptr;
|
||||
// FIXME: -isKindOfClass: is not a core part of the Objective-C language.
|
||||
if ([(id)object isKindOfClass:(Class)targetType])
|
||||
|
||||
if ([(id)object isKindOfClass:(Class)targetType]) {
|
||||
return object;
|
||||
}
|
||||
|
||||
swift::crash("Swift dynamic cast failed");
|
||||
}
|
||||
|
||||
|
||||
/// \brief Fetch the type metadata associated with the formal dynamic
|
||||
/// type of the given (possibly Objective-C) object. The formal
|
||||
/// dynamic type ignores dynamic subclasses such as those introduced
|
||||
/// by KVO.
|
||||
///
|
||||
/// The object pointer may be a tagged pointer, but cannot be null.
|
||||
const Metadata *swift::swift_getObjectType(id object) {
|
||||
auto theClass = object_getClass(object);
|
||||
auto classAsMetadata = reinterpret_cast<ClassMetadata*>(theClass);
|
||||
if (classAsMetadata->isTypeMetadata()) return classAsMetadata;
|
||||
|
||||
return swift_getObjCClassMetadata(classAsMetadata);
|
||||
}
|
||||
|
||||
extern "C" bool swift_objcRespondsToSelector(id object, SEL selector) {
|
||||
return [object respondsToSelector:selector];
|
||||
}
|
||||
|
||||
extern "C" id swift_dynamicCastObjCProtocolUnconditional(id object,
|
||||
size_t numProtocols,
|
||||
Protocol * const *protocols) {
|
||||
for (size_t i = 0; i < numProtocols; ++i) {
|
||||
// FIXME: More informative failure message
|
||||
if (![object conformsToProtocol:protocols[i]]) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char *swift_getClassName(HeapMetadata *s) {
|
||||
// FIXME: The class name should be available in a more Swiftish way.
|
||||
// FIXME: Generic parameters of generic class instances.
|
||||
return class_getName(reinterpret_cast<Class>(s));
|
||||
extern "C" id swift_dynamicCastObjCProtocolConditional(id object,
|
||||
size_t numProtocols,
|
||||
Protocol * const *protocols) {
|
||||
for (size_t i = 0; i < numProtocols; ++i) {
|
||||
if (![object conformsToProtocol:protocols[i]]) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
//
|
||||
// Temporary block conversion shims
|
||||
//
|
||||
extern "C" void swift_instantiateObjCClass(Class c) {
|
||||
static const objc_image_info ImageInfo = {0, 0};
|
||||
|
||||
// Register the class.
|
||||
Class registered = objc_readClassPair(c, &ImageInfo);
|
||||
assert(registered == c
|
||||
&& "objc_readClassPair failed to instantiate the class in-place");
|
||||
(void)registered;
|
||||
|
||||
// objc_readClassPair does not preserve the "is Swift" bit in the rodata, so
|
||||
// set it back.
|
||||
((ClassMetadata*)c)->Data |= 1;
|
||||
}
|
||||
|
||||
namespace {
|
||||
template<typename T> struct block_shim;
|
||||
|
||||
template<typename R, typename...A>
|
||||
struct block_shim<R(A...)> {
|
||||
using block_type = R (^)(A...);
|
||||
using code_type = R (*)(A..., HeapObject *);
|
||||
// protocol _BridgedToObjectiveC {
|
||||
struct _BridgedToObjectiveCWitnessTable {
|
||||
// typealias ObjectiveCType: class
|
||||
const Metadata *ObjectiveCType;
|
||||
// func bridgeToObjectiveC() -> ObjectiveCType
|
||||
HeapObject *(*bridgeToObjectiveC)(OpaqueValue *self, const Metadata *Self);
|
||||
};
|
||||
// }
|
||||
|
||||
template<typename...U>
|
||||
static void pass(U &&...) {}
|
||||
// protocol _ConditionallyBridgedToObjectiveC {
|
||||
struct _ConditionallyBridgedToObjectiveCWitnessTable {
|
||||
// My untrained eye can't find this offset in the generated LLVM IR,
|
||||
// but I do see it being applied in x86 assembly. It disappears
|
||||
// when inheritance from _BridgedToObjectiveC is removed. If it
|
||||
// presents any portability problems we can drop that inheritance
|
||||
// relationship.
|
||||
const void* const probablyPointsAtBridgedToObjectiveCWitnessTable;
|
||||
|
||||
template<typename U>
|
||||
static void retain_if_id(U const &x) {}
|
||||
static void retain_if_id(id x) { [x retain]; }
|
||||
// class func isBridgedToObjectiveC() -> bool
|
||||
bool (*isBridgedToObjectiveC)(const Metadata* value, const Metadata *T);
|
||||
};
|
||||
// }
|
||||
|
||||
extern "C" const ProtocolDescriptor _TMpSs20_BridgedToObjectiveC;
|
||||
extern "C" const ProtocolDescriptor _TMpSs33_ConditionallyBridgedToObjectiveC;
|
||||
|
||||
static block_type shim(code_type code, HeapObject *context) {
|
||||
// Manage non-class Swift memory in a way that blocks can understand.
|
||||
SwiftRAII contextRAII{context, /*AlreadyRetained=*/true};
|
||||
return Block_copy(^R (A...args) {
|
||||
// Adjust the context and any id arguments to +1 retain count.
|
||||
pass((retain_if_id(args), 0)...);
|
||||
return code(args..., swift_retain(*contextRAII));
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// MAKE_BLOCK_SHIM(_Tmangled_name, return_type(arg_types...));
|
||||
#define MAKE_BLOCK_SHIM(MANGLED_NAME, ...) \
|
||||
extern "C" block_shim<__VA_ARGS__>::block_type \
|
||||
MANGLED_NAME(block_shim<__VA_ARGS__>::code_type code, HeapObject *context) { \
|
||||
return block_shim<__VA_ARGS__>::shim(code, context); \
|
||||
static const _BridgedToObjectiveCWitnessTable*
|
||||
findBridgeWitness(const Metadata *T) {
|
||||
auto w = swift_conformsToProtocol(T, &_TMpSs20_BridgedToObjectiveC, nullptr);
|
||||
return reinterpret_cast<const _BridgedToObjectiveCWitnessTable*>(w);
|
||||
}
|
||||
|
||||
static const _ConditionallyBridgedToObjectiveCWitnessTable*
|
||||
findConditionalBridgeWitness(const Metadata *T) {
|
||||
auto w = swift_conformsToProtocol(
|
||||
T, &_TMpSs33_ConditionallyBridgedToObjectiveC, nullptr);
|
||||
|
||||
return reinterpret_cast<
|
||||
const _ConditionallyBridgedToObjectiveCWitnessTable*
|
||||
>(w);
|
||||
}
|
||||
|
||||
static inline bool swift_isClassOrObjCExistentialImpl(const Metadata *T) {
|
||||
auto kind = T->getKind();
|
||||
return kind == MetadataKind::Class ||
|
||||
kind == MetadataKind::ObjCClassWrapper ||
|
||||
(kind == MetadataKind::Existential &&
|
||||
static_cast<const ExistentialTypeMetadata *>(T)->isObjC());
|
||||
}
|
||||
|
||||
// func bridgeToObjectiveC<T>(x: T) -> AnyObject?
|
||||
extern "C" HeapObject *
|
||||
swift_bridgeToObjectiveC(OpaqueValue *value, const Metadata *T) {
|
||||
auto const bridgeWitness = findBridgeWitness(T);
|
||||
|
||||
if (bridgeWitness) {
|
||||
if (auto conditionalWitness = findConditionalBridgeWitness(T)) {
|
||||
if (!conditionalWitness->isBridgedToObjectiveC(T, T))
|
||||
return nullptr;
|
||||
}
|
||||
auto result = bridgeWitness->bridgeToObjectiveC(value, T);
|
||||
// Witnesses take 'self' at +0, so we still need to consume the +1 argument.
|
||||
T->vw_destroy(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
@class NSString;
|
||||
if (swift_isClassOrObjCExistentialImpl(T))
|
||||
return *reinterpret_cast<HeapObject**>(value);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// () -> ()
|
||||
MAKE_BLOCK_SHIM(_TTbbT_T_, void(void));
|
||||
/// (NSString, UnsafePointer<BOOL>) -> ()
|
||||
MAKE_BLOCK_SHIM(_TTbbTCSo8NSStringGVSs13UnsafePointerV10ObjectiveC8ObjCBool__T_,
|
||||
void(id, BOOL *));
|
||||
/// (int64_t) -> ()
|
||||
MAKE_BLOCK_SHIM(_TTbbSiT_,
|
||||
void(int64_t));
|
||||
// (NSObject, NSObject) -> NSComparisonResult aka NSComparator
|
||||
MAKE_BLOCK_SHIM(_TTbbTCSo8NSObjectS__V10Foundation18NSComparisonResult,
|
||||
long(id, id));
|
||||
// func isBridgedToObjectiveC<T>(x: T.Type) -> Bool
|
||||
extern "C" bool
|
||||
swift_isBridgedToObjectiveC(const Metadata *value, const Metadata *T) {
|
||||
auto bridgeWitness = findBridgeWitness(T);
|
||||
|
||||
if (bridgeWitness) {
|
||||
auto conditionalWitness = findConditionalBridgeWitness(T);
|
||||
return !conditionalWitness
|
||||
|| conditionalWitness->isBridgedToObjectiveC(value, T);
|
||||
}
|
||||
return swift_isClassOrObjCExistentialImpl(T);
|
||||
}
|
||||
|
||||
// func isBridgedVerbatimToObjectiveC<T>(x: T.Type) -> Bool
|
||||
extern "C" bool
|
||||
swift_isBridgedVerbatimToObjectiveC(const Metadata *value, const Metadata *T) {
|
||||
if (findBridgeWitness(T))
|
||||
return false;
|
||||
return swift_isClassOrObjCExistentialImpl(T);
|
||||
}
|
||||
|
||||
// func _swift_isClassOrObjCExistential<T>(x: T.Type) -> Bool
|
||||
extern "C" bool
|
||||
swift_isClassOrObjCExistential(const Metadata *value, const Metadata *T) {
|
||||
return swift_isClassOrObjCExistentialImpl(T);
|
||||
}
|
||||
|
||||
const ClassMetadata *
|
||||
swift::swift_dynamicCastObjCClassMetatype(const ClassMetadata *source,
|
||||
const ClassMetadata *dest) {
|
||||
if ([(Class)source isSubclassOfClass:(Class)dest])
|
||||
return source;
|
||||
return nil;
|
||||
}
|
||||
|
||||
const ClassMetadata *
|
||||
swift::swift_dynamicCastObjCClassMetatypeUnconditional(
|
||||
const ClassMetadata *source,
|
||||
const ClassMetadata *dest) {
|
||||
if ([(Class)source isSubclassOfClass:(Class)dest])
|
||||
return source;
|
||||
swift::crash("Swift dynamic cast failed");
|
||||
}
|
||||
|
||||
extern "C" const char *swift_getGenericClassObjCName(const ClassMetadata *clas,
|
||||
const char *basename) {
|
||||
// FIXME: We should use a runtime mangler to form the real mangled name of the
|
||||
// generic instance. Since we don't have a runtime mangler yet, just tack the
|
||||
// address of the class onto the basename, which is totally lame but at least
|
||||
// gives a unique name to the ObjC runtime.
|
||||
size_t baseLen = strlen(basename);
|
||||
auto fullName = (char*)swift_slowAlloc(baseLen + 17, 0);
|
||||
snprintf(fullName, baseLen + 17, "%s%016llX", basename,
|
||||
(unsigned long long)clas);
|
||||
return fullName;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// RUN: %swift -parse %s -verify -D FOO -D BAR -target arm64-apple-ios7.0 -D FOO
|
||||
|
||||
#if arch(ARM64) && os(iOS)
|
||||
#if arch(arm64) && os(iOS)
|
||||
class C {}
|
||||
var x = C()
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// RUN: %swift -parse %s -verify -D FOO -D BAR -target arm-apple-ios7.0 -D FOO
|
||||
|
||||
#if arch(ARM) && os(iOS)
|
||||
#if arch(arm) && os(iOS)
|
||||
class C {}
|
||||
var x = C()
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// RUN: %swift -parse %s -verify -D FOO -D BAR
|
||||
// REQUIRES: X86
|
||||
// RUN: %swift -parse %s -verify -D FOO -D BAR -target x86_64-apple-darwin11.3.0
|
||||
|
||||
class A {}
|
||||
|
||||
@@ -63,3 +62,21 @@ class P : P1 {
|
||||
func fFOO() -> Int { return 0; }
|
||||
func fBAR() -> Int { return 0; }
|
||||
}
|
||||
|
||||
func constants1() -> Int {
|
||||
#if true
|
||||
return 1
|
||||
#else
|
||||
return "1" // should not result in an error
|
||||
#endif
|
||||
}
|
||||
|
||||
func constants2() -> Int {
|
||||
#if false
|
||||
return "1" // should not result in an error
|
||||
#elseif ((false || false))
|
||||
return "1" // should not result in an error
|
||||
#else
|
||||
return 1
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// RUN: %swift -parse %s -verify -D FOO -D BAZ
|
||||
// REQUIRES: X86
|
||||
// RUN: %swift -parse %s -verify -D FOO -D BAZ -target x86_64-apple-darwin11.3.0
|
||||
|
||||
#if FOO
|
||||
var a = 0
|
||||
@@ -31,22 +30,22 @@ var k = 0
|
||||
#endif
|
||||
var l = k
|
||||
|
||||
#if arch(X64)
|
||||
#if arch(x86_64)
|
||||
var m = 0
|
||||
#endif
|
||||
var n = m
|
||||
|
||||
#if FOO && !BAR && BAZ && os(OSX) && arch(X64)
|
||||
#if FOO && !BAR && BAZ && os(OSX) && arch(x86_64)
|
||||
var o = 0
|
||||
#endif
|
||||
var p = o
|
||||
|
||||
#if FOO && (!BAR && BAZ && os(OSX) && arch(X64))
|
||||
#if FOO && (!BAR && BAZ && os(OSX) && arch(x86_64))
|
||||
var q = 0
|
||||
#endif
|
||||
var r = q
|
||||
|
||||
#if FOO && !(!BAZ && BAZ && os(OSX) && arch(X64))
|
||||
#if FOO && !(!BAZ && BAZ && os(OSX) && arch(x86_64))
|
||||
var s = 0
|
||||
#endif
|
||||
var t = s
|
||||
|
||||
@@ -1,15 +1,58 @@
|
||||
// RUN: %swift -parse %s -verify -D FOO -D BAZ
|
||||
// REQUIRES: X86
|
||||
// RUN: %swift -parse %s -verify -D FOO -D BAZ -target x86_64-apple-darwin11.3.0
|
||||
|
||||
#if FOO == BAZ // expected-error{{expected '&&' or '||' expression}}
|
||||
var x = 0
|
||||
#endif
|
||||
|
||||
#if ^FOO // expected-error{{expected unary '!' expression}}
|
||||
#if ^FOO // expected-error {{expected unary '!' expression}}
|
||||
var y = 0
|
||||
#endif
|
||||
|
||||
#if swift(FOO) // expected-error{{unexpected target configuration expression (expected 'os' or 'arch')}}
|
||||
#if swift(FOO) // expected-error {{unexpected target configuration expression (expected 'os' or 'arch')}}
|
||||
var z = 0
|
||||
#endif
|
||||
|
||||
#if FOO || !FOO
|
||||
func f() {}
|
||||
#endif ; f() // expected-error {{extra tokens at the end of the build configuration directive}}
|
||||
|
||||
#if FOO || !FOO
|
||||
func g() {}
|
||||
#else g() // expected-error {{extra tokens at the end of the build configuration directive}}
|
||||
#endif
|
||||
|
||||
|
||||
#if FOO || !FOO
|
||||
func h() {}
|
||||
#else /* aaa */
|
||||
#endif /* bbb */
|
||||
|
||||
#if foo.bar()
|
||||
.baz() // expected-error {{unexpected target configuration expression argument type}}
|
||||
|
||||
#endif
|
||||
|
||||
struct S {
|
||||
#if FOO
|
||||
#else
|
||||
#else // expected-error {{further conditions after #else are unreachable}}
|
||||
#endif
|
||||
|
||||
#if FOO
|
||||
#elseif BAR
|
||||
#elseif BAZ
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FOO
|
||||
#else
|
||||
#else // expected-error {{further conditions after #else are unreachable}}
|
||||
#endif
|
||||
|
||||
#if FOO
|
||||
#elseif BAR
|
||||
#elseif BAZ
|
||||
#else
|
||||
#endif
|
||||
|
||||
|
||||
@@ -8,6 +8,6 @@ class C {
|
||||
#else
|
||||
func bar() {}
|
||||
func baz() {}
|
||||
} // expected-error{{expected declaration}}
|
||||
} // expected-error{{expected #else or #endif at end of configuration block}} expected-error {{expected declaration}}
|
||||
#endif
|
||||
// expected-error@+1{{expected declaration}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// RUN: %swift -parse %s -verify -D FOO -D BAR -target i386-apple-ios7.0 -D FOO
|
||||
|
||||
#if arch(I386) && os(iOS)
|
||||
#if arch(i386) && os(iOS)
|
||||
class C {}
|
||||
var x = C()
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// RUN: %swift -parse %s -verify
|
||||
|
||||
// With a space next to the '#if'
|
||||
#if
|
||||
class C {} // expected-error{{expected #else or #endif at end of configuration block}}
|
||||
#endif
|
||||
|
||||
#if // expected-error {{expected a build configuration expression to follow the #if clause}}
|
||||
class C {} //expected-error {{expected #else or #endif at end of configuration block}}
|
||||
#endif // expected-error {{unexpected configuration block terminator}}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// No space next to the '#if'
|
||||
|
||||
// expected-error@+1{{expected expression, var, or let in 'if' condition}}
|
||||
#if// expected-error 2{{invalid character in source file}}
|
||||
class D {}
|
||||
#if // expected-error {{expected a build configuration expression to follow the #if clause}}
|
||||
class D {} // expected-error {{expected #else or #endif at end of configuration block}}
|
||||
#endif
|
||||
// expected-error @-1{{unexpected configuration block terminator}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// RUN: %swift -parse %s -verify -D FOO -D BAZ -target x86_64-apple-darwin11.3.0
|
||||
|
||||
#if arch(X64) && os(OSX)
|
||||
#if arch(x86_64) && os(OSX)
|
||||
println("Mac") // This should not be parsed as a trailing closure
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// RUN: %swift -parse %s -verify -D FOO -D BAR -target x86_64-apple-ios7.0 -D FOO
|
||||
|
||||
#if arch(X64) && os(iOS)
|
||||
#if arch(x86_64) && os(iOS)
|
||||
class C {}
|
||||
var x = C()
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
// RUN: %target-swift-frontend %s -verify
|
||||
|
||||
import Darwin
|
||||
import ObjectiveC
|
||||
|
||||
errno = 0
|
||||
assert(errno == 0)
|
||||
|
||||
fork() // expected-error{{'fork' is unavailable}}
|
||||
vfork() // expected-error{{'vfork' is unavailable}}
|
||||
|
||||
|
||||
// Test YES and NO.
|
||||
let x_YES = YES // expected-error {{'YES' is unavailable: Use 'Bool' value 'true' instead}}
|
||||
let x_NO = NO // expected-error {{'NO' is unavailable: Use 'Bool' value 'false' instead}}
|
||||
|
||||
func test_shadow(flag: Bool) -> Bool {
|
||||
let YES = true
|
||||
let NO = false
|
||||
return flag ? YES : NO
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@exported import ProtoWithInitializer
|
||||
|
||||
class Impl : InitProto {
|
||||
init withInt(i: CInt) {}
|
||||
init(int i: CInt) {}
|
||||
}
|
||||
|
||||
@@ -1 +1,34 @@
|
||||
// empty (for now)
|
||||
@objc class ForwardClass : NSObject {
|
||||
}
|
||||
|
||||
@objc protocol ForwardProto : NSObjectProtocol {
|
||||
}
|
||||
@objc class ForwardProtoAdopter : NSObject, ForwardProto {
|
||||
}
|
||||
|
||||
@objc class PartialBaseClass {
|
||||
}
|
||||
@objc class PartialSubClass : NSObject {
|
||||
}
|
||||
|
||||
class ProtoConformer : ForwardClassUser {
|
||||
func consumeForwardClass(arg: ForwardClass) {}
|
||||
|
||||
var forward = ForwardClass()
|
||||
}
|
||||
|
||||
func testProtocolWrapper(conformer: ForwardClassUser) {
|
||||
conformer.consumeForwardClass(conformer.forward)
|
||||
}
|
||||
|
||||
func testStruct(p: Point) -> Point {
|
||||
var result = p
|
||||
result.y += 5
|
||||
return result
|
||||
}
|
||||
|
||||
class Derived : Base {
|
||||
override func safeOverride(arg: NSObject) -> ForwardClass {
|
||||
return ForwardClass()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,3 +10,12 @@ func testReexportedClangModules(foo : FooProto) {
|
||||
let _: CInt = foo.bar
|
||||
let _: CInt = ExternIntX.x
|
||||
}
|
||||
|
||||
func testCrossReferences(derived: Derived) {
|
||||
let obj: Base = derived
|
||||
let _: NSObject = obj.safeOverride(ForwardClass())
|
||||
let _: NSObject = obj.safeOverrideProto(ForwardProtoAdopter())
|
||||
|
||||
testProtocolWrapper(ProtoConformer())
|
||||
testStruct(Point(x: 2,y: 3))
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@ import AppKit
|
||||
|
||||
let encoding: UInt = NSUTF8StringEncoding
|
||||
|
||||
let point: Redeclaration.NSPoint = AppKit.NSPoint(0, 0)
|
||||
let point: Redeclaration.NSPoint = AppKit.NSPoint(x: 0, y: 0)
|
||||
Redeclaration.NSStringToNSString(AppKit.NSStringToNSString("abc"))
|
||||
|
||||
@@ -1,13 +1,31 @@
|
||||
// RUN: %swift -sdk=%S/Inputs -I=%S/Inputs/custom-modules %s -emit-llvm -o - | FileCheck %s
|
||||
// RUN: rm -rf %t
|
||||
// RUN: mkdir -p %t
|
||||
// RUN: %swift %s -target x86_64-apple-darwin13 -sdk %S/Inputs -I=%S/Inputs/custom-modules -module-cache-path %t/clang-module-cache -emit-ir -o %t/without-adapter.ll
|
||||
// RUN: FileCheck %s < %t/without-adapter.ll
|
||||
|
||||
// RUN: %swift -emit-module %S/Inputs/adapter.swift -sdk %S/Inputs -module-link-name SwiftAdapter -module-name ClangModuleWithAdapter -I=%S/Inputs/custom-modules -o %t
|
||||
// RUN: %swift %s -target x86_64-apple-darwin13 -sdk %S/Inputs -I=%S/Inputs/custom-modules -I %t -module-cache-path %t/clang-module-cache -emit-ir -o %t/with-adapter.ll
|
||||
// RUN: FileCheck %s < %t/with-adapter.ll
|
||||
// RUN: FileCheck --check-prefix=CHECK-WITH-SWIFT %s < %t/with-adapter.ll
|
||||
|
||||
import LinkMusket
|
||||
import LinkFramework
|
||||
import ClangModuleUser
|
||||
import IndirectFrameworkImporter
|
||||
import UsesSubmodule
|
||||
|
||||
var _ = LinkFramework.IComeFromLinkFramework
|
||||
UsesSubmodule.useSomethingFromSubmodule()
|
||||
|
||||
// CHECK: !{{[0-9]+}} = metadata !{i32 6, metadata !"Linker Options", metadata ![[LINK_LIST:[0-9]+]]}
|
||||
// CHECK: ![[LINK_LIST]] = metadata !{
|
||||
|
||||
// CHECK-DAG: !{{[0-9]+}} = metadata !{metadata !"-lLock"}
|
||||
// CHECK-DAG: !{{[0-9]+}} = metadata !{metadata !"-lStock"}
|
||||
// CHECK-DAG: !{{[0-9]+}} = metadata !{metadata !"-framework", metadata !"Barrel"}
|
||||
// CHECK-DAG: !{{[0-9]+}} = metadata !{metadata !"-framework", metadata !"LinkFramework"}
|
||||
// CHECK-DAG: !{{[0-9]+}} = metadata !{metadata !"-lUnderlyingClangLibrary"}
|
||||
// CHECK-DAG: !{{[0-9]+}} = metadata !{metadata !"-framework", metadata !"Indirect"}
|
||||
// CHECK-DAG: !{{[0-9]+}} = metadata !{metadata !"-framework", metadata !"HasSubmodule"}
|
||||
|
||||
// CHECK-WITH-SWIFT: !{{[0-9]+}} = metadata !{metadata !"-lSwiftAdapter"}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// RUN: %swift %clang-importer-sdk -parse -verify -module-cache-path %t/clang-module-cache -target x86_64-apple-darwin13 %s
|
||||
|
||||
import Foundation
|
||||
import stdio
|
||||
|
||||
// Test if an instance method marked __attribute__((unavailable)) on
|
||||
// the *class* NSObject can be used.
|
||||
@@ -9,7 +10,24 @@ func test_unavailable_instance_method(x : NSObject) -> Bool {
|
||||
return x.allowsWeakReference() // expected-error {{'allowsWeakReference' is unavailable}}
|
||||
}
|
||||
|
||||
func test_unavailable_method_in_protocol(x : NSObjectProtocol) {
|
||||
x.retain() // expected-error {{'retain' is unavailable}}
|
||||
}
|
||||
func test_unavailable_method_in_protocol_use_class_instance(x : NSObject) {
|
||||
x.retain() // expected-error {{'retain' is unavailable}}
|
||||
}
|
||||
|
||||
func test_unavailable_func(x : NSObject) {
|
||||
NSDeallocateObject(x) // expected-error {{'NSDeallocateObject' is unavailable}}
|
||||
}
|
||||
|
||||
func test_deprecated_imported_as_unavailable(s:CMutablePointer<CChar>) {
|
||||
let x = tmpnam(s) // expected-error {{'tmpnam' is unavailable: Due to security concerns inherent in the design of tmpnam(3), it is highly recommended that you use mkstemp(3) instead.}}
|
||||
}
|
||||
|
||||
func test_NSInvocation(x:NSInvocation) {} // expected-error {{'NSInvocation' is unavailable}}
|
||||
|
||||
func test_class_avail(x:NSObject) {
|
||||
x.`class`() // expected-error {{'class' is unavailable: use 'dynamicType' instead}}
|
||||
NSObject.`class`() // expected-error {{'class' is unavailable: use 'self' instead}}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
// RUN: rm -rf %t/clang-module-cache
|
||||
// RUN: %swift -constraint-checker -parse -verify -module-cache-path=%t/clang-module-cache -sdk=%S/Inputs %s
|
||||
// RUN: ls -lR %t/clang-module-cache | grep blocks.pcm
|
||||
// RUN: %swift %clang-importer-sdk -parse -verify -module-cache-path %t/clang-module-cache -target x86_64-apple-darwin13 %s
|
||||
// RUN: ls -lR %t/clang-module-cache | FileCheck %s
|
||||
// CHECK: blocks{{.*}}.pcm
|
||||
|
||||
import blocks
|
||||
import Foundation
|
||||
|
||||
var someNSString : NSString
|
||||
func useNSString(s:NSString) {}
|
||||
func useString(s: String) {}
|
||||
|
||||
dispatch_async(dispatch_get_current_queue()) { }
|
||||
someNSString.enumerateLinesUsingBlock {(s:String?) in }
|
||||
someNSString.enumerateLinesUsingBlock {s in }
|
||||
someNSString.enumerateLinesUsingBlock({ useString($0) })
|
||||
|
||||
dispatch_async(dispatch_get_current_queue(), /*not a block=*/()) // expected-error{{'()' is not convertible to 'dispatch_block_t'}}
|
||||
|
||||
dispatch_async(dispatch_get_current_queue(), func() { })
|
||||
someNSString.enumerateLinesUsingBlock(func(s:NSString) { })
|
||||
someNSString.enumerateLinesUsingBlock(func(s) { })
|
||||
someNSString.enumerateLinesUsingBlock({ useNSString($0) })
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
|
||||
import CoreCooling
|
||||
|
||||
func assertUnmanaged<T:AnyObject>(t: Unmanaged<T>) {}
|
||||
func assertUnmanaged<T: AnyObject>(t: Unmanaged<T>) {}
|
||||
func assertManaged<T: AnyObject>(t: T) {}
|
||||
|
||||
func test0(fridge: CCRefrigeratorRef) {
|
||||
assertUnmanaged(fridge)
|
||||
assertManaged(fridge)
|
||||
}
|
||||
|
||||
func test1(power: CCPowerSupplyRef) {
|
||||
func test1(power: Unmanaged<CCPowerSupplyRef>) {
|
||||
assertUnmanaged(power)
|
||||
let fridge = CCRefrigeratorCreate(power)
|
||||
let fridge = CCRefrigeratorCreate(power) // expected-error {{'Unmanaged<CCPowerSupplyRef>' is not convertible to 'CCPowerSupply'}}
|
||||
assertUnmanaged(fridge)
|
||||
}
|
||||
|
||||
@@ -20,3 +21,46 @@ func test2() {
|
||||
assertUnmanaged(fridge)
|
||||
}
|
||||
|
||||
func test3(fridge: CCRefrigerator) {
|
||||
assertManaged(fridge)
|
||||
}
|
||||
|
||||
func test4() {
|
||||
// FIXME: this should not require a type annotation
|
||||
let power: CCPowerSupply = kCCPowerStandard
|
||||
assertManaged(power)
|
||||
let fridge = CCRefrigeratorCreate(power)
|
||||
assertUnmanaged(fridge)
|
||||
}
|
||||
|
||||
func test5() {
|
||||
let power: Unmanaged<CCPowerSupply> = .passUnretained(kCCPowerStandard)
|
||||
assertUnmanaged(power)
|
||||
let fridge = CCRefrigeratorCreate(power.takeUnretainedValue())
|
||||
}
|
||||
|
||||
func test6() {
|
||||
let fridge = CCRefrigeratorCreate(nil)
|
||||
fridge?.release()
|
||||
}
|
||||
|
||||
func test7() {
|
||||
let value = CFBottom()
|
||||
assertUnmanaged(value)
|
||||
}
|
||||
|
||||
func test8(f: CCRefrigerator) {
|
||||
let v1: CFTypeRef = f
|
||||
let v2: AnyObject = f
|
||||
}
|
||||
|
||||
func test9() {
|
||||
let fridge = CCRefrigeratorCreateMutable(kCCPowerStandard).takeRetainedValue()
|
||||
let constFridge: CCRefrigerator = fridge
|
||||
CCRefrigeratorOpen(fridge)
|
||||
let item = CCRefrigeratorGet(fridge, 0).takeUnretainedValue()
|
||||
CCRefrigeratorInsert(item, fridge) // expected-error {{'CCItem' is not convertible to 'CCMutableRefrigerator'}}
|
||||
CCRefrigeratorInsert(constFridge, item) // expected-error {{'CCRefrigerator' is not convertible to 'CCMutableRefrigerator'}}
|
||||
CCRefrigeratorInsert(fridge, item)
|
||||
CCRefrigeratorClose(fridge)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
// RUN: rm -rf %t/clang-module-cache
|
||||
// RUN: %swift -module-cache-path=%t/clang-module-cache -sdk=%S/Inputs %s -emit-llvm -o - | FileCheck %s
|
||||
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -target x86_64-apple-darwin13 %s -emit-ir -o - | FileCheck %s
|
||||
|
||||
import cfuncs
|
||||
|
||||
// CHECK: call void @cfunc1
|
||||
cfunc1()
|
||||
|
||||
// CHECK: call double @pow(double 3.141590e+00, double 2.718280e+00)
|
||||
var d = pow(3.14159, 2.71828)
|
||||
|
||||
// CHECK: call i32 @"\01_something_else"(i32 17)
|
||||
renamed(17)
|
||||
|
||||
// CHECK: call void @exit(i32 17)
|
||||
exit(17)
|
||||
|
||||
|
||||
@@ -1,22 +1,121 @@
|
||||
// RUN: rm -rf %t/clang-module-cache
|
||||
// RUN: %swift -parse -verify -module-cache-path=%t/clang-module-cache -sdk=%S/Inputs %s
|
||||
// RUN: ls -lR %t/clang-module-cache | grep cfuncs.pcm
|
||||
// RUN: rm -rf %t
|
||||
// RUN: mkdir -p %t
|
||||
// RUN: %swift %clang-importer-sdk -parse -verify -module-cache-path %t/clang-module-cache -target x86_64-apple-darwin13 -I %S/Inputs %s
|
||||
// RUN: ls -lR %t/clang-module-cache | FileCheck %s
|
||||
// CHECK: cfuncs{{.*}}.pcm
|
||||
|
||||
import cfuncs
|
||||
|
||||
func test_cfunc1(i : Int) {
|
||||
func test_cfunc1(i: Int) {
|
||||
cfunc1() // okay
|
||||
cfunc1(i) // expected-error{{invalid conversion from type 'Int' to '()'}} expected-note{{while converting}}
|
||||
cfunc1(i) // expected-error{{cannot convert the expression's type '$T2' to type '() -> Void'}}
|
||||
}
|
||||
|
||||
func test_cfunc2(i : Int) {
|
||||
func test_cfunc2(i: Int) {
|
||||
var f = cfunc2(i, 17)
|
||||
var f2 : Float = f
|
||||
cfunc2(b=17, a=i)
|
||||
cfunc2(b:17, a:i) // expected-error{{cannot convert the expression's type '$T3' to type 'CLong'}}
|
||||
}
|
||||
|
||||
func test_cfunc3() {
|
||||
// FIXME: Breaks with an explicit closure, but I'm not sure why.
|
||||
var b = cfunc3( func(a : Double, b : Double) -> Double { return a + b } )
|
||||
func test_cfunc3_a() {
|
||||
var b = cfunc3( { (a : Double, b : Double) -> Double in a + b } )
|
||||
var d : Double = b(1.5, 2.5)
|
||||
var d1 : Double = b // expected-error{{invalid conversion from type 'double_bin_op_block' to 'Double'}} expected-note{{while converting}}
|
||||
var d1 : Double = b // expected-error{{'double_bin_op_block' is not convertible to 'Double'}}
|
||||
}
|
||||
|
||||
func test_cfunc3_b() {
|
||||
var b = cfunc3( { a, b in a + b } )
|
||||
var d : Double = b(1.5, 2.5)
|
||||
var d1 : Double = b // expected-error{{'double_bin_op_block' is not convertible to 'Double'}}
|
||||
}
|
||||
|
||||
func test_cfunc3_c() {
|
||||
var b = cfunc3({ $0 + $1 })
|
||||
var d : Double = b(1.5, 2.5)
|
||||
var d1 : Double = b // expected-error{{'double_bin_op_block' is not convertible to 'Double'}}
|
||||
}
|
||||
|
||||
func test_cfunc3_d() {
|
||||
var x: Double = 0
|
||||
var y: Double = 0
|
||||
var z: Double? = cfunc3(nil)?(x, y)
|
||||
var w: Double = cfunc3(nil)!(x, y)
|
||||
}
|
||||
|
||||
func test_cfunc4() {
|
||||
// Okay: has no prototype, so assume no parameters.
|
||||
cfunc4()
|
||||
}
|
||||
|
||||
func test_pow() {
|
||||
pow(1.5, 2.5)
|
||||
}
|
||||
|
||||
func test_puts(s: String) {
|
||||
var i = s.withCString { puts($0) + 32 };
|
||||
}
|
||||
|
||||
func test_fopen(filename: String) -> CInt {
|
||||
var file = filename.withCString { fopen($0, "r") }
|
||||
return file.get().inode
|
||||
}
|
||||
|
||||
func test_cfunc_in_swift() -> Int {
|
||||
return cfunc_in_swift(5)
|
||||
}
|
||||
|
||||
func test_inline_available() {
|
||||
createSomething()
|
||||
}
|
||||
|
||||
func test_pointer() {
|
||||
var i: CInt = 0
|
||||
var ia: CInt[] = [1, 2, 3]
|
||||
var f: CFloat = 0
|
||||
var fa: CFloat[] = [1, 2, 3]
|
||||
|
||||
param_pointer(UnsafePointer<CInt>())
|
||||
param_pointer(&i)
|
||||
param_pointer(&ia)
|
||||
|
||||
param_const_pointer(UnsafePointer<CInt>())
|
||||
param_const_pointer(&i)
|
||||
param_const_pointer(ia)
|
||||
param_const_pointer([1, 2, 3])
|
||||
|
||||
param_void_pointer(COpaquePointer())
|
||||
param_void_pointer(UnsafePointer<CInt>())
|
||||
param_void_pointer(UnsafePointer<CFloat>())
|
||||
param_void_pointer(&i)
|
||||
param_void_pointer(&ia)
|
||||
param_void_pointer(&f)
|
||||
param_void_pointer(&fa)
|
||||
|
||||
param_const_void_pointer(COpaquePointer())
|
||||
param_const_void_pointer(UnsafePointer<CInt>())
|
||||
param_const_void_pointer(UnsafePointer<CFloat>())
|
||||
param_const_void_pointer(&i)
|
||||
param_const_void_pointer(ia)
|
||||
param_const_void_pointer([1, 2, 3])
|
||||
param_const_void_pointer(&f)
|
||||
param_const_void_pointer(fa)
|
||||
param_const_void_pointer([1.0, 2.0, 3.0])
|
||||
}
|
||||
|
||||
func test_decay() {
|
||||
decay_param_array(UnsafePointer<CInt>())
|
||||
var i: CInt = 0
|
||||
var a: CInt[] = [1, 2, 3]
|
||||
decay_param_array(&i)
|
||||
decay_param_array(&a)
|
||||
decay_param_const_array(UnsafePointer<CInt>())
|
||||
decay_param_const_array(&i)
|
||||
decay_param_const_array(a)
|
||||
decay_param_const_array([1, 2, 3])
|
||||
}
|
||||
|
||||
func exit(_: Float) {} // expected-note {{found this candidate}}
|
||||
func test_ambiguous() {
|
||||
exit(5) // expected-error {{ambiguous use of 'exit'}}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user