在.Net 7源碼中bool代碼優化
作者:秋風技術
代碼總是從簡單到復雜,從易讀到晦澀,有的是業務邏輯復雜導致代碼也復雜,有的是為了性能優化,導致代碼不那么易讀易懂了.這里主要是看到最近.Net
bool類型源碼變化。
起因
代碼總是從簡單到復雜,從易讀到晦澀,有的是業務邏輯復雜導致代碼也復雜,有的是為了性能優化,導致代碼不那么易讀易懂了.這里主要是看到最近.Net bool類型源碼變化.
- Streamline bool.TryParse/Format (#64782)
- Fix bool.TryParse/Format on big-endian systems (#65078)
在.Net 6中TryParse
public static bool TryParse(ReadOnlySpan<char> value, out bool result)
{
if (IsTrueStringIgnoreCase(value)) //關注IsTrueStringIgnoreCase
{
result = true;
return true;
}
if (IsFalseStringIgnoreCase(value)) //關注和IsFalseStringIgnoreCase
{
result = false;
return true;
}
value = TrimWhiteSpaceAndNull(value);
if (IsTrueStringIgnoreCase(value))
{
result = true;
return true;
}
if (IsFalseStringIgnoreCase(value))
{
result = false;
return true;
}
result = false;
return false;
}
在TryParse中,調用IsTrueStringIgnoreCase和IsFalseStringIgnoreCase這兩個函數這時候是易讀易懂.
在.Net 7中TryParse(優化)
//只保留IsTrueStringIgnoreCase和IsFalseStringIgnoreCase
internal static bool IsTrueStringIgnoreCase(ReadOnlySpan<char> value)
{
// "true" as a ulong, each char |'d with 0x0020 for case-insensitivity
// 先判斷cpu支持大小端模式, 采用無符號long類型存儲4個字符的ASCII碼值 小端:: 65→e 75→u 72→r 74→t
// 將value轉為byte數組,讀取為ulong類型,然后或運算, 0x20為十六進制 是十進制32 或運算:: A | 32 = a 這樣就不用區分大小寫
// 0x0020002000200020為4個0x20,因為值一樣,不區分大小端
ulong true_val = BitConverter.IsLittleEndian ? 0x65007500720074ul : 0x74007200750065ul;
return value.Length == 4 &&
(MemoryMarshal.Read<ulong>(MemoryMarshal.AsBytes(value)) | 0x0020002000200020) == true_val;
}
internal static bool IsFalseStringIgnoreCase(ReadOnlySpan<char> value)
{
// "fals" as a ulong, each char |'d with 0x0020 for case-insensitivity
// ulong類型只能存4個字符,所以存儲 "fals"這4個字符 73→s 6c→l 61→a 66→f
// 最后1個字符進行與0x20進行或運算,得到小寫字符和'e'進行判斷
ulong fals_val = BitConverter.IsLittleEndian ? 0x73006C00610066ul : 0x660061006C0073ul;
return value.Length == 5 &&
(((MemoryMarshal.Read<ulong>(MemoryMarshal.AsBytes(value)) | 0x0020002000200020) == fals_val) &
((value[4] | 0x20) == 'e'));
}
在.Net 6中TryFormat
public bool TryFormat(Span<char> destination, out int charsWritten)
{
if (m_value) //為真
{
if ((uint)destination.Length > 3u)
{
//進行4次賦值操作
destination[0] = 'T';
destination[1] = 'r';
destination[2] = 'u';
destination[3] = 'e';
charsWritten = 4;
return true;
}
}
else if ((uint)destination.Length > 4u) //不為真
{
//進行5次賦值操作
destination[0] = 'F';
destination[1] = 'a';
destination[2] = 'l';
destination[3] = 's';
destination[4] = 'e';
charsWritten = 5;
return true;
}
charsWritten = 0;
return false;
}
在.Net 7中TryFormat(優化)
public bool TryFormat(Span<char> destination, out int charsWritten)
{
if (m_value)
{
if ((uint)destination.Length > 3) // uint cast, per https://github.com/dotnet/runtime/issues/10596
{
//先判斷cpu支持大小端模式, 采用無符號long類型存儲4個字符的ASCII碼值 小端:: 65→e 75→u 72→r 74→t
//將Span<char>轉為byte數組,將true_val寫入,減少賦值的次數,與.Net 6中4次賦值操作,這里只有1次
ulong true_val = BitConverter.IsLittleEndian ? 0x65007500720054ul : 0x54007200750065ul; // "True"
MemoryMarshal.Write<ulong>(MemoryMarshal.AsBytes(destination), ref true_val);
charsWritten = 4;
return true;
}
}
else
{
if ((uint)destination.Length > 4)
{
//不為真時,進行2次賦值操作 第1次 ulong 只能存4個字符, 第2次通過下標賦值為'e'
ulong fals_val = BitConverter.IsLittleEndian ? 0x73006C00610046ul : 0x460061006C0073ul; // "Fals"
MemoryMarshal.Write<ulong>(MemoryMarshal.AsBytes(destination), ref fals_val);
destination[4] = 'e';
charsWritten = 5;
return true;
}
}
charsWritten = 0;
return false;
}
在.Net 7中對bool的改進,就是減少賦值操作,將4個字符轉為ulong,實現了一次將4個字符賦值.還有通過位或操作巧妙的實現將大寫字母進行轉換.這種實現不是第一次看到,曾在wrk(壓力工具,使用c語言編寫)看到:
#define LOWER(c) (unsigned char)(c | 0x20)
責任編輯:未麗燕
來源:
今日頭條