@@ -493,6 +493,116 @@ extension String {
493493 self = String . _fromNonContiguousUnsafeBitcastUTF8Repairing ( codeUnits) . 0
494494 }
495495
496+ /// Creates a new string by copying and validating the sequence of
497+ /// code units passed in, according to the specified encoding.
498+ ///
499+ /// This initializer does not try to repair ill-formed code unit sequences.
500+ /// If any are found, the result of the initializer is `nil`.
501+ ///
502+ /// The following example calls this initializer with the contents of two
503+ /// different arrays---first with a well-formed UTF-8 code unit sequence and
504+ /// then with an ill-formed UTF-16 code unit sequence.
505+ ///
506+ /// let validUTF8: [UInt8] = [67, 97, 0, 102, 195, 169]
507+ /// let valid = String(validating: validUTF8, as: UTF8.self)
508+ /// print(valid ?? "nil")
509+ /// // Prints "Café"
510+ ///
511+ /// let invalidUTF16: [UInt16] = [0x41, 0x42, 0xd801]
512+ /// let invalid = String(validating: invalidUTF16, as: UTF16.self)
513+ /// print(invalid ?? "nil")
514+ /// // Prints "nil"
515+ ///
516+ /// - Parameters:
517+ /// - codeUnits: A sequence of code units that encode a `String`
518+ /// - encoding: A conformer to `Unicode.Encoding` to be used
519+ /// to decode `codeUnits`.
520+ @inlinable
521+ @available ( SwiftStdlib 5 . 11 , * )
522+ public init ? < Encoding: Unicode . Encoding > (
523+ validating codeUnits: some Sequence < Encoding . CodeUnit > ,
524+ as encoding: Encoding . Type
525+ ) {
526+ let contiguousResult = codeUnits. withContiguousStorageIfAvailable {
527+ String . _validate ( $0, as: Encoding . self)
528+ }
529+ if let validationResult = contiguousResult {
530+ guard let validatedString = validationResult else {
531+ return nil
532+ }
533+ self = validatedString
534+ return
535+ }
536+
537+ // slow-path
538+ var transcoded : [ UTF8 . CodeUnit ] = [ ]
539+ transcoded. reserveCapacity ( codeUnits. underestimatedCount)
540+ var isASCII = true
541+ let error = transcode (
542+ codeUnits. makeIterator ( ) ,
543+ from: Encoding . self,
544+ to: UTF8 . self,
545+ stoppingOnError: true ,
546+ into: {
547+ uint8 in
548+ transcoded. append ( uint8)
549+ if isASCII && ( uint8 & 0x80 ) == 0x80 { isASCII = false }
550+ }
551+ )
552+ if error { return nil }
553+ self = transcoded. withUnsafeBufferPointer {
554+ String . _uncheckedFromUTF8 ( $0, asciiPreScanResult: isASCII)
555+ }
556+ }
557+
558+ /// Creates a new string by copying and validating the sequence of
559+ /// code units passed in, according to the specified encoding.
560+ ///
561+ /// This initializer does not try to repair ill-formed code unit sequences.
562+ /// If any are found, the result of the initializer is `nil`.
563+ ///
564+ /// The following example calls this initializer with the contents of two
565+ /// different arrays---first with a well-formed UTF-8 code unit sequence and
566+ /// then with an ill-formed ASCII code unit sequence.
567+ ///
568+ /// let validUTF8: [Int8] = [67, 97, 0, 102, -61, -87]
569+ /// let valid = String(validating: validUTF8, as: UTF8.self)
570+ /// print(valid ?? "nil")
571+ /// // Prints "Café"
572+ ///
573+ /// let invalidASCII: [Int8] = [67, 97, -5]
574+ /// let invalid = String(validating: invalidASCII, as: Unicode.ASCII.self)
575+ /// print(invalid ?? "nil")
576+ /// // Prints "nil"
577+ ///
578+ /// - Parameters:
579+ /// - codeUnits: A sequence of code units that encode a `String`
580+ /// - encoding: A conformer to `Unicode.Encoding` that can decode
581+ /// `codeUnits` as `UInt8`
582+ @inlinable
583+ @available ( SwiftStdlib 5 . 11 , * )
584+ public init ? < Encoding> (
585+ validating codeUnits: some Sequence < Int8 > ,
586+ as encoding: Encoding . Type
587+ ) where Encoding: Unicode . Encoding , Encoding. CodeUnit == UInt8 {
588+ let contiguousResult = codeUnits. withContiguousStorageIfAvailable {
589+ $0. withMemoryRebound ( to: UInt8 . self) {
590+ String . _validate ( $0, as: Encoding . self)
591+ }
592+ }
593+ if let validationResult = contiguousResult {
594+ guard let validatedString = validationResult else {
595+ return nil
596+ }
597+ self = validatedString
598+ return
599+ }
600+
601+ // slow-path
602+ let uint8s = codeUnits. lazy. map ( UInt8 . init ( bitPattern: ) )
603+ self . init ( validating: uint8s, as: Encoding . self)
604+ }
605+
496606 /// Creates a new string with the specified capacity in UTF-8 code units, and
497607 /// then calls the given closure with a buffer covering the string's
498608 /// uninitialized memory.
0 commit comments