Optimize the initialization of the OrdinalCasing::s_sCasingTable table. (#46061)
authorZoltan Varga <vargaz@gmail.com>
Thu, 17 Dec 2020 23:02:51 +0000 (18:02 -0500)
committerGitHub <noreply@github.com>
Thu, 17 Dec 2020 23:02:51 +0000 (15:02 -0800)
src/libraries/System.Private.CoreLib/src/System/Globalization/OrdinalCasing.Icu.cs

index a10c39d..71da4dc 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Diagnostics;
+using System.Threading;
 using System.Runtime.InteropServices;
 using System.Runtime.CompilerServices;
 using Internal.Runtime.CompilerServices;
@@ -40,40 +41,84 @@ namespace System.Globalization
         // s_casingTable is covering the Unicode BMP plane only. Surrogate casing is handled separately.
         // Every cell in the table is covering the casing of 256 characters in the BMP.
         // Every cell is array of 512 character for uppercasing mapping.
-        private static ushort []?[] s_casingTable =
+        private static ushort []?[] s_casingTable = InitCasingTable();
+
+        /*
+         The table is initialized to:
         {
-            /* 0000-07FF */       s_basicLatin,            null,            null,            null,            null,            null,            null,            null,
-            /* 0800-0FFF */               null,            null,            null,            null,            null,            null,            null,            null,
-            /* 1000-17FF */               null,  s_noCasingPage,            null,            null,  s_noCasingPage,  s_noCasingPage,            null,            null,
-            /* 1800-1FFF */               null,            null,            null,            null,            null,            null,            null,            null,
-            /* 2000-27FF */               null,            null,  s_noCasingPage,  s_noCasingPage,            null,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* 2800-2FFF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,            null,            null,            null,            null,            null,
-            /* 3000-37FF */               null,            null,            null,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* 3800-3FFF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* 4000-47FF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* 4800-4FFF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* 5000-57FF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* 5800-5FFF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* 6000-67FF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* 6800-6FFF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* 7000-77FF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* 7800-7FFF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* 8000-87FF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* 8800-8FFF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* 9000-97FF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* 9800-9FFF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,            null,
-            /* A000-A7FF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,            null,  s_noCasingPage,            null,            null,
-            /* A800-AFFF */               null,            null,            null,            null,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* B000-B7FF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* B800-BFFF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* C000-C7FF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* C800-CFFF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* D000-D7FF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,            null,
-            /* D800-DFFF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* E000-E7FF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* E800-EFFF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* F000-F7FF */     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
-            /* F800-FFFF */     s_noCasingPage,  s_noCasingPage,            null,            null,  s_noCasingPage,            null,            null,            null,
+            // 0000-07FF //       s_basicLatin,            null,            null,            null,            null,            null,            null,            null,
+            // 0800-0FFF //               null,            null,            null,            null,            null,            null,            null,            null,
+            // 1000-17FF //               null,  s_noCasingPage,            null,            null,  s_noCasingPage,  s_noCasingPage,            null,            null,
+            // 1800-1FFF //               null,            null,            null,            null,            null,            null,            null,            null,
+            // 2000-27FF //               null,            null,  s_noCasingPage,  s_noCasingPage,            null,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // 2800-2FFF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,            null,            null,            null,            null,            null,
+            // 3000-37FF //               null,            null,            null,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // 3800-3FFF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // 4000-47FF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // 4800-4FFF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // 5000-57FF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // 5800-5FFF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // 6000-67FF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // 6800-6FFF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // 7000-77FF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // 7800-7FFF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // 8000-87FF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // 8800-8FFF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // 9000-97FF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // 9800-9FFF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,            null,
+            // A000-A7FF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,            null,  s_noCasingPage,            null,            null,
+            // A800-AFFF //               null,            null,            null,            null,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // B000-B7FF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // B800-BFFF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // C000-C7FF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // C800-CFFF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // D000-D7FF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,            null,
+            // D800-DFFF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // E000-E7FF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // E800-EFFF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // F000-F7FF //     s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,  s_noCasingPage,
+            // F800-FFFF //     s_noCasingPage,  s_noCasingPage,            null,            null,  s_noCasingPage,            null,            null,            null,
+        };
+*/
+
+        // 0 - null
+        // 1 - s_noCasingPage
+        // The bits are in reverse order for readability, i.e. the highest order bit refers to
+        // the lowest index.
+        private static ReadOnlySpan<byte> s_casingTableInit => new byte[32]
+        {
+            /* 0000-07FF */    0b00000000,
+            /* 0800-0FFF */    0b00000000,
+            /* 1000-17FF */    0b01001100,
+            /* 1800-1FFF */    0b00000000,
+            /* 2000-27FF */    0b00110111,
+            /* 2800-2FFF */    0b11100000,
+            /* 3000-37FF */    0b00011111,
+            /* 3800-3FFF */    0b11111111,
+            /* 4000-47FF */    0b11111111,
+            /* 4800-4FFF */    0b11111111,
+            /* 5000-57FF */    0b11111111,
+            /* 5800-5FFF */    0b11111111,
+            /* 6000-67FF */    0b11111111,
+            /* 6800-6FFF */    0b11111111,
+            /* 7000-77FF */    0b11111111,
+            /* 7800-7FFF */    0b11111111,
+            /* 8000-87FF */    0b11111111,
+            /* 8800-8FFF */    0b11111111,
+            /* 9000-97FF */    0b11111111,
+            /* 9800-9FFF */    0b11111110,
+            /* A000-A7FF */    0b11110100,
+            /* A800-AFFF */    0b00001111,
+            /* B000-B7FF */    0b11111111,
+            /* B800-BFFF */    0b11111111,
+            /* C000-C7FF */    0b11111111,
+            /* C800-CFFF */    0b11111111,
+            /* D000-D7FF */    0b11111110,
+            /* D800-DFFF */    0b11111111,
+            /* E000-E7FF */    0b11111111,
+            /* E800-EFFF */    0b11111111,
+            /* F000-F7FF */    0b11111111,
+            /* F800-FFFF */    0b11001000,
         };
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -427,17 +472,31 @@ namespace System.Globalization
             }
         }
 
+        private static ushort[]?[] InitCasingTable()
+        {
+            ushort[]?[] table = new ushort[]?[s_casingTableInit.Length * 8];
+            for (int i = 0; i < s_casingTableInit.Length * 8; ++i)
+            {
+                // The bits are in reverse order
+                byte val = (byte)(s_casingTableInit[i / 8] >> (7 - (i % 8)));
+                if ((val & 1) == 1)
+                    table[i] = s_noCasingPage;
+            }
+            table[0] = s_basicLatin;
+            return table;
+        }
+
         private static unsafe ushort [] InitOrdinalCasingPage(int pageNumber)
         {
             Debug.Assert(pageNumber >= 0 && pageNumber < 256);
 
-            ushort [] casingTable = new ushort[256];
+            ushort[] casingTable = new ushort[256];
             fixed (ushort* table = casingTable)
             {
                 char* pTable = (char*)table;
                 Interop.Globalization.InitOrdinalCasingPage(pageNumber, pTable);
             }
-            s_casingTable[pageNumber] = casingTable;
+            Volatile.Write(ref s_casingTable[pageNumber], casingTable);
             return casingTable;
         }
     }