File tree Expand file tree Collapse file tree 3 files changed +44
-2
lines changed
Expand file tree Collapse file tree 3 files changed +44
-2
lines changed Original file line number Diff line number Diff line change @@ -81,6 +81,10 @@ extension Character {
8181 internal func _invariantCheck( ) {
8282 _internalInvariant ( _str. count == 1 )
8383 _internalInvariant ( _str. _guts. isFastUTF8)
84+
85+ // TODO(@eject): Switch to a helper property on StringObject/StringGuts.
86+ _internalInvariant (
87+ _str. _guts. isSmall || _str. _guts. _object. _countAndFlags. isTailAllocated)
8488 }
8589 #endif // INTERNAL_CHECKS_ENABLED
8690}
@@ -173,7 +177,17 @@ extension Character :
173177 " Can't form a Character from an empty String " )
174178 _debugPrecondition ( s. index ( after: s. startIndex) == s. endIndex,
175179 " Can't form a Character from a String containing more than one extended grapheme cluster " )
176- self . init ( unchecked: s)
180+
181+ // TODO(@eject): Switch to a helper property on StringObject/StringGuts.
182+ if _fastPath (
183+ s. _guts. isSmall || s. _guts. _object. _countAndFlags. isTailAllocated
184+ ) {
185+ self . init ( unchecked: s)
186+ return
187+ }
188+
189+ // TODO(@eject): Outline this
190+ self . init ( unchecked: s. _withUTF8 { String . _uncheckedFromUTF8 ( $0) } )
177191 }
178192}
179193
Original file line number Diff line number Diff line change @@ -617,9 +617,10 @@ extension _StringObject {
617617 isNativelyStored: set for native stored strings
618618 - `largeAddressBits` holds an instance of `_StringStorage`.
619619 - I.e. the start of the code units is at the stored address + `nativeBias`
620- isTailAllocated: start of the code units is at the stored address + `nativeBias`
620+ isTailAllocated: contiguous UTF-8 code units starts at address + `nativeBias`
621621 - `isNativelyStored` always implies `isTailAllocated`, but not vice versa
622622 (e.g. literals)
623+ - `isTailAllocated` always implies `isFastUTF8`
623624 TBD: Reserved for future usage
624625 - Setting a TBD bit to 1 must be semantically equivalent to 0
625626 - I.e. it can only be used to "cache" fast-path information in the future
@@ -1073,6 +1074,9 @@ extension _StringObject {
10731074 } else {
10741075 _internalInvariant ( isLarge)
10751076 _internalInvariant ( largeCount == count)
1077+ if _countAndFlags. isTailAllocated {
1078+ _internalInvariant ( providesFastUTF8)
1079+ }
10761080 if providesFastUTF8 && largeFastIsTailAllocated {
10771081 _internalInvariant ( !isSmall)
10781082 _internalInvariant ( !largeIsCocoa)
Original file line number Diff line number Diff line change @@ -75,5 +75,29 @@ StringBridgeTests.test("Tagged NSString") {
7575#endif // not 32bit
7676}
7777
78+ func returnOne< T> ( _ t: T ) -> Int { return 1 }
79+ StringBridgeTests . test ( " Character from NSString " ) {
80+ // NOTE: Using hard-coded literals to directly construct NSStrings
81+ let ns1 = " A " as NSString
82+ let ns2 = " A \u{301} " as NSString
83+ let ns3 = " 𓁹͇͈͉͍͎͊͋͌ͧͨͩͪͫͬͭͮ͏̛͓͔͕͖͙͚̗̘̙̜̹̺̻̼͐͑͒͗͛ͣͤͥͦ̽̾̿̀́͂̓̈́͆ͧͨͩͪͫͬͭͮ͘̚͜͟͢͝͞͠͡ͅ " as NSString
84+
85+ let c1 = Character ( ns1 as String )
86+ let c2 = Character ( ns2 as String )
87+ let c3 = Character ( ns3 as String )
88+
89+ expectEqual ( " A " , String ( c1) )
90+ expectNotNil ( String ( c1) . utf8. withContiguousStorageIfAvailable ( returnOne) )
91+
92+ expectEqual ( " A \u{301} " , String ( c2) )
93+ expectNotNil ( String ( c2) . utf8. withContiguousStorageIfAvailable ( returnOne) )
94+ expectNil ( ( ns2 as String ) . utf8. withContiguousStorageIfAvailable ( returnOne) )
95+
96+ expectEqual ( " 𓁹͇͈͉͍͎͊͋͌ͧͨͩͪͫͬͭͮ͏̛͓͔͕͖͙͚̗̘̙̜̹̺̻̼͐͑͒͗͛ͣͤͥͦ̽̾̿̀́͂̓̈́͆ͧͨͩͪͫͬͭͮ͘̚͜͟͢͝͞͠͡ͅ " , String ( c3) )
97+ expectNotNil ( String ( c3) . utf8. withContiguousStorageIfAvailable ( returnOne) )
98+ expectNil ( ( ns3 as String ) . utf8. withContiguousStorageIfAvailable ( returnOne) )
99+ }
100+
101+
78102runAllTests ( )
79103
You can’t perform that action at this time.
0 commit comments