CharacterSet
is available, actually.にソースコードcontains
のソースは次のとおりです。
fileprivate func contains(_ member: Unicode.Scalar) -> Bool {
switch _backing {
case .immutable(let cs):
return CFCharacterSetIsLongCharacterMember(cs, member.value)
case .mutable(let cs):
return CFCharacterSetIsLongCharacterMember(cs, member.value)
}
}
だから、基本的にはCFCharacterSetIsLongCharacterMember
に通じ呼び出します。そのis also available, although only for Yosemiteのソースコード(El CapとSierraの両方のバージョンは「Coming Soon」と呼ばれています)。しかし、ヨセミテのコードは、私がシエラの分解で見ていたものと一致するように見えました。とにかく、そのコードは次のようになります:
Boolean CFCharacterSetIsLongCharacterMember(CFCharacterSetRef theSet, UTF32Char theChar) {
CFIndex length;
UInt32 plane = (theChar >> 16);
Boolean isAnnexInverted = false;
Boolean isInverted;
Boolean result = false;
CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, Boolean, (NSCharacterSet *)theSet, longCharacterIsMember:(UTF32Char)theChar);
__CFGenericValidateType(theSet, __kCFCharacterSetTypeID);
if (plane) {
CFCharacterSetRef annexPlane;
if (__CFCSetIsBuiltin(theSet)) {
isInverted = __CFCSetIsInverted(theSet);
return (CFUniCharIsMemberOf(theChar, __CFCSetBuiltinType(theSet)) ? !isInverted : isInverted);
}
isAnnexInverted = __CFCSetAnnexIsInverted(theSet);
if ((annexPlane = __CFCSetGetAnnexPlaneCharacterSetNoAlloc(theSet, plane)) == NULL) {
if (!__CFCSetHasNonBMPPlane(theSet) && __CFCSetIsRange(theSet)) {
isInverted = __CFCSetIsInverted(theSet);
length = __CFCSetRangeLength(theSet);
return (length && __CFCSetRangeFirstChar(theSet) <= theChar && theChar < __CFCSetRangeFirstChar(theSet) + length ? !isInverted : isInverted);
} else {
return (isAnnexInverted ? true : false);
}
} else {
theSet = annexPlane;
theChar &= 0xFFFF;
}
}
isInverted = __CFCSetIsInverted(theSet);
switch (__CFCSetClassType(theSet)) {
case __kCFCharSetClassBuiltin:
result = (CFUniCharIsMemberOf(theChar, __CFCSetBuiltinType(theSet)) ? !isInverted : isInverted);
break;
case __kCFCharSetClassRange:
length = __CFCSetRangeLength(theSet);
result = (length && __CFCSetRangeFirstChar(theSet) <= theChar && theChar < __CFCSetRangeFirstChar(theSet) + length ? !isInverted : isInverted);
break;
case __kCFCharSetClassString:
result = ((length = __CFCSetStringLength(theSet)) ? (__CFCSetBsearchUniChar(__CFCSetStringBuffer(theSet), length, theChar) ? !isInverted : isInverted) : isInverted);
break;
case __kCFCharSetClassBitmap:
result = (__CFCSetCompactBitmapBits(theSet) ? (__CFCSetIsMemberBitmap(__CFCSetBitmapBits(theSet), theChar) ? true : false) : isInverted);
break;
case __kCFCharSetClassCompactBitmap:
result = (__CFCSetCompactBitmapBits(theSet) ? (__CFCSetIsMemberInCompactBitmap(__CFCSetCompactBitmapBits(theSet), theChar) ? true : false) : isInverted);
break;
default:
CFAssert1(0, __kCFLogAssertion, "%s: Internal inconsistency error: unknown character set type", __PRETTY_FUNCTION__); // We should never come here
return false; // To make compiler happy
}
return (result ? !isAnnexInverted : isAnnexInverted);
}
私たちはそれに続いて何が起こっているか把握しています。残念ながら、私たちはx86_64組立スキルを破棄しなければなりません。しかし、恐れてはいません。私はあなたのためにこれをしています。なぜなら、これは金曜日の夜、私が楽しいためにやっていることです。
struct __CFCharacterSet {
CFRuntimeBase _base;
CFHashCode _hashValue;
union {
struct {
CFIndex _type;
} _builtin;
struct {
UInt32 _firstChar;
CFIndex _length;
} _range;
struct {
UniChar *_buffer;
CFIndex _length;
} _string;
struct {
uint8_t *_bits;
} _bitmap;
struct {
uint8_t *_cBits;
} _compactBitmap;
} _variants;
CFCharSetAnnexStruct *_annex;
};
私たちは、いったいCFRuntimeBase
が何であるかを知っておく必要があります、あまりにも::
typedef struct __CFRuntimeBase {
uintptr_t _cfisa;
uint8_t _cfinfo[4];
#if __LP64__
uint32_t _rc;
#endif
} CFRuntimeBase;
そして、何を推測
ておくと便利なことは、データ構造です!必要な定数もいくつかあります。私たちは、その後、CFCharacterSetIsLongCharacterMember
でブレークし、構造を記録することができ
enum {
__kCFCharSetClassTypeMask = 0x0070,
__kCFCharSetClassBuiltin = 0x0000,
__kCFCharSetClassRange = 0x0010,
__kCFCharSetClassString = 0x0020,
__kCFCharSetClassBitmap = 0x0030,
__kCFCharSetClassSet = 0x0040,
__kCFCharSetClassCompactBitmap = 0x0040,
// irrelevant stuff redacted
};
:
上記の構造体に基づいて
supersetA.contains(UnicodeScalar(128518)!)
(lldb) po [NSData dataWithBytes:$rdi length:48]
<21b3d2ad ffff1d00 90190000 02000000 00000000 00000000 06f60100 00000000 01000000 00000000 00000000 00000000>
、我々はこの文字セットがで作られているかを把握することができます。この場合、関連する部分は、CFRuntimeBase
からのcfinfo
の最初のバイトとなり、バイト9-12です。これの最初のバイト、0x90
には、文字セットのタイプ情報が含まれています。 AND
を__kCFCharSetClassTypeMask
とすると、0x10
という__kCFCharSetClassRange
となります。この回線の
:
supersetB.contains(UnicodeScalar(128518)!)
構造は以下の通りである:
(lldb) po [NSData dataWithBytes:$rdi length:48]
<21b3d2ad ffff1d00 a0190000 02000000 00000000 00000000 9066f000 01000000 02000000 00000000 00000000 00000000>
今回バイト9は、マスクとAND
EDは0x20
、__kCFCharSetClassString
ある、0xa0
あります。
この時点で、Monty Pythonのキャストは「Get On With It!」と叫んでいるので、CFCharacterSetIsLongCharacterMember
のソースを見て、何が起こっているのかを見てみましょう。すべてCF_OBJC_FUNCDISPATCHV
がらくたを過ぎてスキップ
が、我々はこの行を取得:
if (plane) {
これは明らかに両方のケースでtrueに評価されます。次のテスト:
if (__CFCSetIsBuiltin(theSet)) {
どちらのタイプが__kCFCharSetClassBuiltin
だったので、これは、両方のケースではfalseと評価され、私たちは、そのブロックをスキップします。両方の場合において
isAnnexInverted = __CFCSetAnnexIsInverted(theSet);
、_annex
ポインタは、(構造体の終わりにすべてゼロを参照)ヌルであった、これはfalse
あります。
このテストは、同じ理由でtrue
次のようになります。
if ((annexPlane = __CFCSetGetAnnexPlaneCharacterSetNoAlloc(theSet, plane)) == NULL) {
はに私たちを取る:
if (!__CFCSetHasNonBMPPlane(theSet) && __CFCSetIsRange(theSet)) {
__CFCSetHasNonBMPPlane
マクロチェック_annex
、それは偽ですので。もちろん、絵文字はBMPプレーンにはないので、実際にはの場合は両方ともの場合、正しい結果を返すものであっても間違っているようです。
__CFCSetIsRange
は、タイプが__kCFCharSetClassRange
であるかどうかを確認します。これは初めての場合のみです。だから、これは発散のポイントです。間違った結果を生成し、この第二の呼び出しは、次の行に返されます。
return (isAnnexInverted ? true : false);
と別館がisAnnexInverted
が偽であることを引き起こして、NULL
であることから、これはfalseを返します。
それを修正する方法は...まあ、できません。しかし今、私たちはそれがなぜ起こったのか知っています。私が知ることから、主な問題は、キャラクタセットが作成されたときに_annex
フィールドが埋まっていないことです。また、別館が非BMPプレーンのキャラクタを追跡するために使用されているように見えます。両方の文字セットに存在する必要があります。ちなみに、この情報はおそらくfile oneに決定したら、バグレポートに役立ちます(実際の問題があるので、CoreFoundationに対して提出します)。
Foundation(またはSwift Standard Library)のバグのようです。 'supersetD'の場合はXcode 9で' true'を返すので、 'union(_ :)'のバグは最新のSDKで修正されているようです。回避策: 'CharacterSet(charactersIn:" ")).union(CharacterSet(charactersIn:" A "))'。 – OOPer
そしてそれはより奇妙になります:https://pastebin.com/zCrM1XUL。私はいくつかの掘り下げを行い、 'CFCharacterSet.c'の中の' _CFCharacterSetIsLongCharacterMember'を見たいと思うかもしれません。それはcontainsメソッドがしていることです(そして私はそれを理解していません)。 https://github.com/apple/swift-corelibs-foundation/blob/d95964015bed377baa99c3612281afa11bf06990/CoreFoundation/String.subproj/CFCharacterSet.c#L1716 – nyg
@nygそれはすべてのことを考え出す時間を費やしました。好奇心が強い、以下の私の答えを見てください。 –