//===----------------------------------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // TODO: describe // // HACK HACK HACK: For whatever reason, having this directly on String instead // of _StringGuts avoids a cascade of ARC. Also note, we can have a global // function that forwards, but that function **must not be on _StringGuts**, // else ARC. // extension String { @inlinable @inline(__always) func _visit( range: (Range, performBoundsCheck: Bool)? = nil, ascii: /*@convention(thin)*/ (_UnmanagedString) -> Result, utf16: /*@convention(thin)*/ (_UnmanagedString) -> Result, opaque: /*@convention(thin)*/ (_UnmanagedOpaqueString) -> Result ) -> Result { if _slowPath(_guts._isOpaque) { return self._visitOpaque( range: range, ascii: ascii, utf16: utf16, opaque: opaque) } defer { _fixLifetime(self) } if _guts.isASCII { var view = _guts._unmanagedASCIIView if let (range, boundsCheck) = range { if boundsCheck { view._boundsCheck(offsetRange: range) } view = view[range] } return ascii(view) } else { var view = _guts._unmanagedUTF16View if let (range, boundsCheck) = range { if boundsCheck { view._boundsCheck(offsetRange: range) } view = view[range] } return utf16(view) } } @usableFromInline @effects(readonly) @inline(never) // @_outlined func _visitOpaque( range: (Range, performBoundsCheck: Bool)? = nil, ascii: /*@convention(thin)*/ (_UnmanagedString) -> Result, utf16: /*@convention(thin)*/ (_UnmanagedString) -> Result, opaque: /*@convention(thin)*/ (_UnmanagedOpaqueString) -> Result ) -> Result { _sanityCheck(_guts._isOpaque) if _guts._isSmall { _sanityCheck(_guts._object._isSmallUTF8, "no other small forms yet") let small = _guts._smallUTF8String if small.isASCII { return small.withUnmanagedASCII { view in var view = view if let (range, boundsCheck) = range { if boundsCheck { view._boundsCheck(offsetRange: range) } view = view[range] } return ascii(view) } } return small.withUnmanagedUTF16 { view in var view = view if let (range, boundsCheck) = range { if boundsCheck { view._boundsCheck(offsetRange: range) } view = view[range] } return utf16(view) } } // TODO: But can it provide a pointer+length representation? defer { _fixLifetime(self) } var view = _guts._asOpaque() if let (range, boundsCheck) = range { if boundsCheck { view._boundsCheck(offsetRange: range) } view = view[range] } return opaque(view) } @inlinable @inline(__always) func _visit( range: (Range, performBoundsCheck: Bool)?, args x: T, ascii: /*@convention(thin)*/ (_UnmanagedString, T) -> Result, utf16: /*@convention(thin)*/ (_UnmanagedString, T) -> Result, opaque: /*@convention(thin)*/ (_UnmanagedOpaqueString, T) -> Result ) -> Result { if _slowPath(_guts._isOpaque) { return self._visitOpaque( range: range, args: x, ascii: ascii, utf16: utf16, opaque: opaque) } defer { _fixLifetime(self) } if _guts.isASCII { var view = _guts._unmanagedASCIIView if let (range, boundsCheck) = range { if boundsCheck { view._boundsCheck(offsetRange: range) } view = view[range] } return ascii(view, x) } else { var view = _guts._unmanagedUTF16View if let (range, boundsCheck) = range { if boundsCheck { view._boundsCheck(offsetRange: range) } view = view[range] } return utf16(view, x) } } @usableFromInline // @opaque @effects(readonly) @inline(never) func _visitOpaque( range: (Range, performBoundsCheck: Bool)?, args x: T, ascii: /*@convention(thin)*/ (_UnmanagedString, T) -> Result, utf16: /*@convention(thin)*/ (_UnmanagedString, T) -> Result, opaque: /*@convention(thin)*/ (_UnmanagedOpaqueString, T) -> Result ) -> Result { _sanityCheck(_guts._isOpaque) if _fastPath(_guts._isSmall) { _sanityCheck(_guts._object._isSmallUTF8, "no other small forms yet") let small = _guts._smallUTF8String if small.isASCII { return small.withUnmanagedASCII { view in var view = view if let (range, boundsCheck) = range { if boundsCheck { view._boundsCheck(offsetRange: range) } view = view[range] } return ascii(view, x) } } return small.withUnmanagedUTF16 { view in var view = view if let (range, boundsCheck) = range { if boundsCheck { view._boundsCheck(offsetRange: range) } view = view[range] } return utf16(view, x) } } // TODO: But can it provide a pointer+length representation? defer { _fixLifetime(self) } var view = _guts._asOpaque() if let (range, boundsCheck) = range { if boundsCheck { view._boundsCheck(offsetRange: range) } view = view[range] } return opaque(view, x) } } @inlinable @inline(__always) internal func _visitGuts( _ guts: _StringGuts, range: (Range, performBoundsCheck: Bool)? = nil, ascii: /*@convention(thin)*/ (_UnmanagedString) -> Result, utf16: /*@convention(thin)*/ (_UnmanagedString) -> Result, opaque: /*@convention(thin)*/ (_UnmanagedOpaqueString) -> Result ) -> Result { return String(guts)._visit( range: range, ascii: ascii, utf16: utf16, opaque: opaque) } @inlinable @inline(__always) internal func _visitGuts( _ guts: _StringGuts, range: (Range, performBoundsCheck: Bool)? = nil, args x: T, ascii: /*@convention(thin)*/ (_UnmanagedString, T) -> Result, utf16: /*@convention(thin)*/ (_UnmanagedString, T) -> Result, opaque: /*@convention(thin)*/ (_UnmanagedOpaqueString, T) -> Result ) -> Result { return String(guts)._visit( range: range, args: x, ascii: ascii, utf16: utf16, opaque: opaque) }