diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueueSegment.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueueSegment.cs index 958f9ffffce61..5e32c7872225e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueueSegment.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueueSegment.cs @@ -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 @@ internal ConcurrentQueueSegment(int boundedLength) { // 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". diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index e716950341476..fc8c2a8226cdd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -5214,20 +5214,20 @@ public void AddTask(string name, int value) 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 @@ static FieldInfo[] GetEnumFields(Type localEnumType) // 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"); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs index 1336f00a523fe..4233c291010e5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs @@ -5,7 +5,7 @@ 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 @@ private void CreateEntry(TKey key, TValue value) 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 @@ private sealed class Container internal Container(ConditionalWeakTable 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 @@ private Container(ConditionalWeakTable parent, int[] buckets, Entr 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 @@ internal Container Resize() 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. diff --git a/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XHashtable.cs b/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XHashtable.cs index a5bade7824418..d4f448976cc10 100644 --- a/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XHashtable.cs +++ b/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XHashtable.cs @@ -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 @@ private sealed class XHashtableState /// 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 diff --git a/src/libraries/System.Private.Xml/src/System.Private.Xml.csproj b/src/libraries/System.Private.Xml/src/System.Private.Xml.csproj index 405e6375a9f6b..74006bda8d133 100644 --- a/src/libraries/System.Private.Xml/src/System.Private.Xml.csproj +++ b/src/libraries/System.Private.Xml/src/System.Private.Xml.csproj @@ -19,7 +19,6 @@ - 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 index 9105407f6f33b..0000000000000 --- a/src/libraries/System.Private.Xml/src/System/Xml/Bits.cs +++ /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 -{ - /// - /// Contains static utility methods used to manipulate bits in a word. - /// - 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; - - /// - /// 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. - /// - 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; - } - - /// - /// Returns true if the unsigned integer has exactly one bit set. - /// - public static bool ExactlyOne(uint num) - { - return num != 0 && (num & (num - 1)) == 0; - } - - /// - /// Clear the least significant bit that is set and return the result. - /// - public static uint ClearLeast(uint num) - { - return num & (num - 1); - } - - /// - /// 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). - /// - public static int LeastPosition(uint num) - { - if (num == 0) return 0; - return Count(num ^ (num - 1)); - } - } -} diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdDateTime.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdDateTime.cs index 05adf65c48717..c8110320f5189 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdDateTime.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdDateTime.cs @@ -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 @@ internal static bool TryParse(string text, XsdDateTimeFlags kinds, out XsdDateTi /// 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 @@ public XsdDateTime(DateTimeOffset dateTimeOffset) : this(dateTimeOffset, XsdDate 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) { diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/XmlIlVisitor.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/XmlIlVisitor.cs index a76423d760236..557213c67f818 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/XmlIlVisitor.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/XmlIlVisitor.cs @@ -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 @@ private bool MatchesNodeKinds(QilTargetType ndIsType, XmlQueryType typDerived, X 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; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XmlQueryTypeFactory.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XmlQueryTypeFactory.cs index beb8580e31378..1768ec9be2a04 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XmlQueryTypeFactory.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XmlQueryTypeFactory.cs @@ -5,6 +5,7 @@ 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 @@ private sealed class ChoiceType : XmlQueryType public static XmlQueryType Create(XmlNodeKindFlags nodeKinds) { List 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(); - 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); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/CompilerScopeManager.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/CompilerScopeManager.cs index a1774a67be255..96d8e5843d8a8 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/CompilerScopeManager.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/CompilerScopeManager.cs @@ -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 @@ private void AddRecord() 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 @@ private void AddRecord(ScopeFlags flag, string? ncName, string? uri, [AllowNull] 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) { diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/MatcherBuilder.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/MatcherBuilder.cs index b1efa9b34e45e..75304c195d039 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/MatcherBuilder.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/MatcherBuilder.cs @@ -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 @@ private void NipOffTypeNameCheck() } XmlNodeKindFlags nodeKinds = isType.Right.XmlType!.NodeKinds; - if (!Bits.ExactlyOne((uint)nodeKinds)) + if (!BitOperations.IsPow2((uint)nodeKinds)) { return; } diff --git a/src/libraries/System.Text.RegularExpressions/gen/Stubs.cs b/src/libraries/System.Text.RegularExpressions/gen/Stubs.cs index 8db1a1a618dee..cb372a63fef21 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/Stubs.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/Stubs.cs @@ -65,6 +65,14 @@ namespace System.Buffers internal delegate void SpanAction(Span 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 diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs index 393ca384c1fe6..abb9de4dd7b18 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs @@ -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 @@ public static bool IsBoundaryWordChar(char ch) 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); } /// Determines a character's membership in a character class (via the string representation of the class).