|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.ObjectModel;
using System.Diagnostics;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
internal static class DynamicFlagsCustomTypeInfo
{
internal static ReadOnlyCollection<byte>? ToBytes(ArrayBuilder<bool> dynamicFlags, int startIndex = 0)
{
RoslynDebug.AssertNotNull(dynamicFlags);
Debug.Assert(startIndex >= 0);
int numFlags = dynamicFlags.Count - startIndex;
if (numFlags == 0)
{
return null;
}
int numBytes = (numFlags + 7) / 8;
byte[] bytes = new byte[numBytes];
bool seenTrue = false;
for (int b = 0; b < numBytes; b++)
{
for (int i = 0; i < 8; i++)
{
var f = b * 8 + i;
if (f >= numFlags)
{
Debug.Assert(f == numFlags);
goto ALL_FLAGS_READ;
}
if (dynamicFlags[startIndex + f])
{
seenTrue = true;
bytes[b] |= (byte)(1 << i);
}
}
}
ALL_FLAGS_READ:
return seenTrue ? new ReadOnlyCollection<byte>(bytes) : null;
}
internal static bool GetFlag(ReadOnlyCollection<byte>? bytes, int index)
{
Debug.Assert(index >= 0);
if (bytes == null)
{
return false;
}
var b = index / 8;
return b < bytes.Count &&
(bytes[b] & (1 << (index % 8))) != 0;
}
/// <remarks>
/// Not guaranteed to add the same number of flags as would
/// appear in a System.Runtime.CompilerServices.DynamicAttribute.
/// It may have more (for padding) or fewer (for compactness) falses.
/// It is, however, guaranteed to include the last true.
/// </remarks>
internal static void CopyTo(ReadOnlyCollection<byte>? bytes, ArrayBuilder<bool> builder)
{
if (bytes == null)
{
return;
}
foreach (byte b in bytes)
{
for (int i = 0; i < 8; i++)
{
builder.Add((b & (1 << i)) != 0);
}
}
}
internal static ReadOnlyCollection<byte>? SkipOne(ReadOnlyCollection<byte> bytes)
{
if (bytes == null)
{
return bytes;
}
var builder = ArrayBuilder<bool>.GetInstance();
CopyTo(bytes, builder);
var result = ToBytes(builder, startIndex: 1);
builder.Free();
return result;
}
}
}
|