Use BitOperations in more places (#76933)
authorStephen Toub <stoub@microsoft.com>
Fri, 14 Oct 2022 03:41:28 +0000 (23:41 -0400)
committerGitHub <noreply@github.com>
Fri, 14 Oct 2022 03:41:28 +0000 (23:41 -0400)
13 files changed:
src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueueSegment.cs
src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs
src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XHashtable.cs
src/libraries/System.Private.Xml/src/System.Private.Xml.csproj
src/libraries/System.Private.Xml/src/System/Xml/Bits.cs [deleted file]
src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdDateTime.cs
src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/XmlIlVisitor.cs
src/libraries/System.Private.Xml/src/System/Xml/Xsl/XmlQueryTypeFactory.cs
src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/CompilerScopeManager.cs
src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/MatcherBuilder.cs
src/libraries/System.Text.RegularExpressions/gen/Stubs.cs
src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs

index 958f9ff..5e32c78 100644 (file)
@@ -3,6 +3,7 @@
 
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
+using System.Numerics;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Threading;
@@ -45,7 +46,7 @@ namespace System.Collections.Concurrent
         {
             // Validate the length
             Debug.Assert(boundedLength >= 2, $"Must be >= 2, got {boundedLength}");
-            Debug.Assert((boundedLength & (boundedLength - 1)) == 0, $"Must be a power of 2, got {boundedLength}");
+            Debug.Assert(BitOperations.IsPow2(boundedLength), $"Must be a power of 2, got {boundedLength}");
 
             // Initialize the slots and the mask.  The mask is used as a way of quickly doing "% _slots.Length",
             // instead letting us do "& _slotsMask".
index e716950..fc8c2a8 100644 (file)
@@ -5214,20 +5214,20 @@ namespace System.Diagnostics.Tracing
 
         public void AddKeyword(string name, ulong value)
         {
-            if ((value & (value - 1)) != 0)   // Is it a power of 2?
+            if ((value & (value - 1)) != 0) // Must be zero or a power of 2
             {
-                ManifestError(SR.Format(SR.EventSource_KeywordNeedPowerOfTwo, "0x" + value.ToString("x", CultureInfo.CurrentCulture), name), true);
+                ManifestError(SR.Format(SR.EventSource_KeywordNeedPowerOfTwo, $"0x{value:x}", name), true);
             }
             if ((flags & EventManifestOptions.Strict) != 0)
             {
                 if (value >= 0x0000100000000000UL && !name.StartsWith("Session", StringComparison.Ordinal))
                 {
-                    ManifestError(SR.Format(SR.EventSource_IllegalKeywordsValue, name, "0x" + value.ToString("x", CultureInfo.CurrentCulture)));
+                    ManifestError(SR.Format(SR.EventSource_IllegalKeywordsValue, name, $"0x{value:x}"));
                 }
 
                 if (keywordTab != null && keywordTab.TryGetValue(value, out string? prevName) && !name.Equals(prevName, StringComparison.Ordinal))
                 {
-                    ManifestError(SR.Format(SR.EventSource_KeywordCollision, name, prevName, "0x" + value.ToString("x", CultureInfo.CurrentCulture)));
+                    ManifestError(SR.Format(SR.EventSource_KeywordCollision, name, prevName, $"0x{value:x}"));
                 }
             }
 
@@ -5590,7 +5590,7 @@ namespace System.Diagnostics.Tracing
 
                             // ETW requires all bitmap values to be powers of 2.  Skip the ones that are not.
                             // TODO: Warn people about the dropping of values.
-                            if (isbitmap && ((hexValue & (hexValue - 1)) != 0 || hexValue == 0))
+                            if (isbitmap && !BitOperations.IsPow2(hexValue))
                                 continue;
 
                             hexValue.TryFormat(ulongHexScratch, out int charsWritten, "x");
index 1336f00..4233c29 100644 (file)
@@ -5,7 +5,7 @@ using System.Collections;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
-using System.Runtime.CompilerServices;
+using System.Numerics;
 using System.Threading;
 
 namespace System.Runtime.CompilerServices
@@ -403,8 +403,6 @@ namespace System.Runtime.CompilerServices
             c.CreateEntryNoResize(key, value);
         }
 
-        private static bool IsPowerOfTwo(int value) => (value > 0) && ((value & (value - 1)) == 0);
-
         //--------------------------------------------------------------------------------------------
         // Entry can be in one of four states:
         //
@@ -462,7 +460,7 @@ namespace System.Runtime.CompilerServices
             internal Container(ConditionalWeakTable<TKey, TValue> parent)
             {
                 Debug.Assert(parent != null);
-                Debug.Assert(IsPowerOfTwo(InitialCapacity));
+                Debug.Assert(BitOperations.IsPow2(InitialCapacity));
 
                 const int Size = InitialCapacity;
                 _buckets = new int[Size];
@@ -485,7 +483,7 @@ namespace System.Runtime.CompilerServices
                 Debug.Assert(buckets != null);
                 Debug.Assert(entries != null);
                 Debug.Assert(buckets.Length == entries.Length);
-                Debug.Assert(IsPowerOfTwo(buckets.Length));
+                Debug.Assert(BitOperations.IsPow2(buckets.Length));
 
                 _parent = parent;
                 _buckets = buckets;
@@ -678,7 +676,7 @@ namespace System.Runtime.CompilerServices
             internal Container Resize(int newSize)
             {
                 Debug.Assert(newSize >= _buckets.Length);
-                Debug.Assert(IsPowerOfTwo(newSize));
+                Debug.Assert(BitOperations.IsPow2(newSize));
 
                 // Reallocate both buckets and entries and rebuild the bucket and entries from scratch.
                 // This serves both to scrub entries with expired keys and to put the new entries in the proper bucket.
index a5bade7..d4f4489 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Diagnostics.CodeAnalysis;
+using System.Numerics;
 using System.Threading;
 using Debug = System.Diagnostics.Debug;
 using Interlocked = System.Threading.Interlocked;
@@ -143,7 +144,7 @@ namespace System.Xml.Linq
             /// </summary>
             public XHashtableState(ExtractKeyDelegate extractKey, int capacity)
             {
-                Debug.Assert((capacity & (capacity - 1)) == 0, "capacity must be a power of 2");
+                Debug.Assert(BitOperations.IsPow2(capacity), "capacity must be a power of 2");
                 Debug.Assert(extractKey != null, "extractKey may not be null");
 
                 // Initialize hash table data structures, with specified maximum capacity
index 405e637..74006bd 100644 (file)
@@ -19,7 +19,6 @@
     <Compile Include="System\Xml\BinHexDecoder.cs" />
     <Compile Include="System\Xml\BinHexEncoder.cs" />
     <Compile Include="System\Xml\BinHexEncoderAsync.cs" />
-    <Compile Include="System\Xml\Bits.cs" />
     <Compile Include="System\Xml\BitStack.cs" />
     <Compile Include="System\Xml\ByteStack.cs" />
     <Compile Include="System\Xml\Core\HtmlEncodedRawTextWriter.cs">
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Bits.cs b/src/libraries/System.Private.Xml/src/System/Xml/Bits.cs
deleted file mode 100644 (file)
index 9105407..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.Diagnostics;
-
-namespace System.Xml
-{
-    /// <summary>
-    /// Contains static utility methods used to manipulate bits in a word.
-    /// </summary>
-    internal static class Bits
-    {
-        private const uint MASK_0101010101010101 = 0x55555555;
-        private const uint MASK_0011001100110011 = 0x33333333;
-        private const uint MASK_0000111100001111 = 0x0f0f0f0f;
-        private const uint MASK_0000000011111111 = 0x00ff00ff;
-        private const uint MASK_1111111111111111 = 0x0000ffff;
-
-        /// <summary>
-        /// Returns the number of 1 bits in an unsigned integer.  Counts bits by divide-and-conquer method,
-        /// first computing 16 2-bit counts, then 8 4-bit counts, then 4 8-bit counts, then 2 16-bit counts,
-        /// and finally 1 32-bit count.
-        /// </summary>
-        public static int Count(uint num)
-        {
-            num = (num & MASK_0101010101010101) + ((num >> 1) & MASK_0101010101010101);
-            num = (num & MASK_0011001100110011) + ((num >> 2) & MASK_0011001100110011);
-            num = (num & MASK_0000111100001111) + ((num >> 4) & MASK_0000111100001111);
-            num = (num & MASK_0000000011111111) + ((num >> 8) & MASK_0000000011111111);
-            num = (num & MASK_1111111111111111) + (num >> 16);
-
-            return (int)num;
-        }
-
-        /// <summary>
-        /// Returns true if the unsigned integer has exactly one bit set.
-        /// </summary>
-        public static bool ExactlyOne(uint num)
-        {
-            return num != 0 && (num & (num - 1)) == 0;
-        }
-
-        /// <summary>
-        /// Clear the least significant bit that is set and return the result.
-        /// </summary>
-        public static uint ClearLeast(uint num)
-        {
-            return num & (num - 1);
-        }
-
-        /// <summary>
-        /// Compute the 1-based position of the least significant bit that is set, and return it (return 0 if no bits are set).
-        /// (e.g. 0x1001100 will return 3, since the 3rd bit is set).
-        /// </summary>
-        public static int LeastPosition(uint num)
-        {
-            if (num == 0) return 0;
-            return Count(num ^ (num - 1));
-        }
-    }
-}
index 05adf65..c811032 100644 (file)
@@ -2,9 +2,10 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System;
-using System.Xml;
 using System.Diagnostics;
+using System.Numerics;
 using System.Text;
+using System.Xml;
 
 namespace System.Xml.Schema
 {
@@ -176,10 +177,10 @@ namespace System.Xml.Schema
         /// </summary>
         public XsdDateTime(DateTime dateTime, XsdDateTimeFlags kinds)
         {
-            Debug.Assert(Bits.ExactlyOne((uint)kinds), "Only one DateTime type code can be set.");
+            Debug.Assert(BitOperations.IsPow2((uint)kinds), "One and only one DateTime type code can be set.");
             _dt = dateTime;
 
-            DateTimeTypeCode code = (DateTimeTypeCode)(Bits.LeastPosition((uint)kinds) - 1);
+            DateTimeTypeCode code = (DateTimeTypeCode)BitOperations.TrailingZeroCount((uint)kinds);
             int zoneHour = 0;
             int zoneMinute = 0;
             XsdDateTimeKind kind;
@@ -220,12 +221,12 @@ namespace System.Xml.Schema
 
         public XsdDateTime(DateTimeOffset dateTimeOffset, XsdDateTimeFlags kinds)
         {
-            Debug.Assert(Bits.ExactlyOne((uint)kinds), "Only one DateTime type code can be set.");
+            Debug.Assert(BitOperations.IsPow2((uint)kinds), "Only one DateTime type code can be set.");
 
             _dt = dateTimeOffset.DateTime;
 
             TimeSpan zoneOffset = dateTimeOffset.Offset;
-            DateTimeTypeCode code = (DateTimeTypeCode)(Bits.LeastPosition((uint)kinds) - 1);
+            DateTimeTypeCode code = (DateTimeTypeCode)BitOperations.TrailingZeroCount((uint)kinds);
             XsdDateTimeKind kind;
             if (zoneOffset.TotalMinutes < 0)
             {
index a76423d..557213c 100644 (file)
@@ -2,19 +2,20 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System;
-using System.Xml;
-using System.Xml.XPath;
-using System.Xml.Schema;
-using System.Globalization;
 using System.Collections;
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Numerics;
 using System.Reflection;
 using System.Reflection.Emit;
+using System.Xml;
+using System.Xml.Schema;
+using System.Xml.XPath;
 using System.Xml.Xsl;
 using System.Xml.Xsl.Qil;
 using System.Xml.Xsl.Runtime;
-using System.Diagnostics.CodeAnalysis;
 using TypeFactory = System.Xml.Xsl.XmlQueryTypeFactory;
 
 namespace System.Xml.Xsl.IlGen
@@ -3263,7 +3264,7 @@ namespace System.Xml.Xsl.IlGen
             kinds = typDerived.NodeKinds & kinds;
 
             // Attempt to allow or disallow exactly one kind
-            if (!Bits.ExactlyOne((uint)kinds))
+            if (!BitOperations.IsPow2((uint)kinds))
             {
                 // Not possible to allow one kind, so try to disallow one kind
                 kinds = ~kinds & XmlNodeKindFlags.Any;
index beb8580..1768ec9 100644 (file)
@@ -5,6 +5,7 @@ using System.Collections.Generic;
 using System.Diagnostics;
 using System.Globalization;
 using System.IO;
+using System.Numerics;
 using System.Xml.Schema;
 using System.Xml.XPath;
 using TF = System.Xml.Xsl.XmlQueryTypeFactory;
@@ -699,17 +700,20 @@ namespace System.Xml.Xsl
             public static XmlQueryType Create(XmlNodeKindFlags nodeKinds)
             {
                 List<XmlQueryType> members;
+                uint kinds = (uint)nodeKinds;
 
                 // If exactly one kind is set, then create singleton ItemType
-                if (Bits.ExactlyOne((uint)nodeKinds))
-                    return ItemType.Create(s_nodeKindToTypeCode[Bits.LeastPosition((uint)nodeKinds)], false);
+                if (BitOperations.IsPow2(kinds))
+                {
+                    return ItemType.Create(s_nodeKindToTypeCode[BitOperations.TrailingZeroCount(kinds) + 1], false);
+                }
 
                 members = new List<XmlQueryType>();
-                while (nodeKinds != XmlNodeKindFlags.None)
+                while (kinds != 0)
                 {
-                    members.Add(ItemType.Create(s_nodeKindToTypeCode[Bits.LeastPosition((uint)nodeKinds)], false));
+                    members.Add(ItemType.Create(s_nodeKindToTypeCode[BitOperations.TrailingZeroCount(kinds) + 1], false));
 
-                    nodeKinds = (XmlNodeKindFlags)Bits.ClearLeast((uint)nodeKinds);
+                    kinds &= kinds - 1;
                 }
 
                 return Create(members);
index a1774a6..96d8e58 100644 (file)
@@ -3,6 +3,7 @@
 
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
+using System.Numerics;
 using QilName = System.Xml.Xsl.Qil.QilName;
 
 namespace System.Xml.Xsl.Xslt
@@ -145,7 +146,7 @@ namespace System.Xml.Xsl.Xslt
 
         private void AddRecord(ScopeFlags flag, string? ncName, string? uri, [AllowNull] V value)
         {
-            Debug.Assert(flag == (flag & ScopeFlags.ExclusiveFlags) && (flag & (flag - 1)) == 0 && flag != 0, "One exclusive flag");
+            Debug.Assert(flag == (flag & ScopeFlags.ExclusiveFlags) && BitOperations.IsPow2((uint)flag), "One exclusive flag");
             Debug.Assert(uri != null || ncName == null, "null, null means exclude '#all'");
 
             ScopeFlags flags = _records[_lastRecord].flags;
@@ -164,7 +165,7 @@ namespace System.Xml.Xsl.Xslt
 
         private void SetFlag(ScopeFlags flag, bool value)
         {
-            Debug.Assert(flag == (flag & ScopeFlags.InheritedFlags) && (flag & (flag - 1)) == 0 && flag != 0, "one inherited flag");
+            Debug.Assert(flag == (flag & ScopeFlags.InheritedFlags) && BitOperations.IsPow2((uint)flag), "one inherited flag");
             ScopeFlags flags = _records[_lastRecord].flags;
             if (((flags & flag) != 0) != value)
             {
index b1efa9b..75304c1 100644 (file)
@@ -4,6 +4,7 @@
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
+using System.Numerics;
 using System.Xml.Xsl.Qil;
 using System.Xml.Xsl.XPath;
 using T = System.Xml.Xsl.XmlQueryTypeFactory;
@@ -179,7 +180,7 @@ namespace System.Xml.Xsl.Xslt
             }
 
             XmlNodeKindFlags nodeKinds = isType.Right.XmlType!.NodeKinds;
-            if (!Bits.ExactlyOne((uint)nodeKinds))
+            if (!BitOperations.IsPow2((uint)nodeKinds))
             {
                 return;
             }
index 8db1a1a..cb372a6 100644 (file)
@@ -65,6 +65,14 @@ namespace System.Buffers
     internal delegate void SpanAction<T, in TArg>(Span<T> span, TArg arg);
 }
 
+namespace System.Numerics
+{
+    internal static class BitOperations
+    {
+        public static bool IsPow2(int value) => (value & (value - 1)) == 0 && value > 0;
+    }
+}
+
 namespace System.Threading
 {
     internal static class InterlockedExtensions
index 393ca38..abb9de4 100644 (file)
@@ -3,8 +3,8 @@
 
 using System.Collections.Generic;
 using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
 using System.Globalization;
+using System.Numerics;
 using System.Runtime.CompilerServices;
 using System.Threading;
 
@@ -1196,7 +1196,7 @@ namespace System.Text.RegularExpressions
         public static bool DifferByOneBit(char a, char b, out int mask)
         {
             mask = a ^ b;
-            return mask != 0 && (mask & (mask - 1)) == 0;
+            return BitOperations.IsPow2(mask);
         }
 
         /// <summary>Determines a character's membership in a character class (via the string representation of the class).</summary>