Пример #1
0
        private static string InternalFlagsFormat(RuntimeType eT, ulong result)
        {
            // These values are sorted by value. Don't change this
            TypeValuesAndNames entry = GetCachedValuesAndNames(eT, true);

            return(InternalFlagsFormat(eT, entry, result));
        }
Пример #2
0
        private static string InternalFormat(RuntimeType eT, ulong value)
        {
            Debug.Assert(eT != null);

            // These values are sorted by value. Don't change this
            TypeValuesAndNames entry = GetCachedValuesAndNames(eT, true);

            if (!entry.IsFlag) // Not marked with Flags attribute
            {
                return(Enum.GetEnumName(eT, value));
            }
            else // These are flags OR'ed together (We treat everything as unsigned types)
            {
                return(InternalFlagsFormat(eT, entry, value));
            }
        }
Пример #3
0
        static TypeValuesAndNames GetCachedValuesAndNames(RuntimeType enumType, bool getNames)
        {
            var entry = enumType.GenericCache as TypeValuesAndNames;

            if (entry == null || (getNames && entry.Names == null))
            {
                ulong[]  values = null;
                String[] names  = null;

                if (!GetEnumValuesAndNames(enumType, out values, out names))
                {
                    Array.Sort(values, names, System.Collections.Generic.Comparer <ulong> .Default);
                }

                bool isFlags = enumType.IsDefined(typeof(FlagsAttribute), inherit: false);
                entry = new TypeValuesAndNames(isFlags, values, names);
                enumType.GenericCache = entry;
            }

            return(entry);
        }
Пример #4
0
        private static TypeValuesAndNames GetCachedValuesAndNames(RuntimeType enumType, bool getNames)
        {
            TypeValuesAndNames entry = enumType.GenericCache as TypeValuesAndNames;

            if (entry == null || (getNames && entry.Names == null))
            {
                ulong[]  values = null;
                string[] names  = null;
                GetEnumValuesAndNames(
                    enumType.GetTypeHandleInternal(),
                    JitHelpers.GetObjectHandleOnStack(ref values),
                    JitHelpers.GetObjectHandleOnStack(ref names),
                    getNames);
                bool isFlags = enumType.IsDefined(typeof(FlagsAttribute), inherit: false);

                entry = new TypeValuesAndNames(isFlags, values, names);
                enumType.GenericCache = entry;
            }

            return(entry);
        }
Пример #5
0
        private static bool TryParseEnum(Type enumType, string value, bool ignoreCase, ref EnumResult parseResult)
        {
            if (enumType == null)
            {
                throw new ArgumentNullException(nameof(enumType));
            }

            RuntimeType rtType = enumType as RuntimeType;

            if (rtType == null)
            {
                throw new ArgumentException(SR.Arg_MustBeType, nameof(enumType));
            }

            if (!enumType.IsEnum)
            {
                throw new ArgumentException(SR.Arg_MustBeEnum, nameof(enumType));
            }

            if (value == null)
            {
                parseResult.SetFailure(ParseFailureKind.ArgumentNull, nameof(value));
                return(false);
            }

            int firstNonWhitespaceIndex = -1;

            for (int i = 0; i < value.Length; i++)
            {
                if (!char.IsWhiteSpace(value[i]))
                {
                    firstNonWhitespaceIndex = i;
                    break;
                }
            }
            if (firstNonWhitespaceIndex == -1)
            {
                parseResult.SetFailure(ParseFailureKind.Argument, nameof(SR.Arg_MustContainEnumInfo), null);
                return(false);
            }

            // We have 2 code paths here. One if they are values else if they are Strings.
            // values will have the first character as as number or a sign.
            ulong result = 0;

            char firstNonWhitespaceChar = value[firstNonWhitespaceIndex];

            if (char.IsDigit(firstNonWhitespaceChar) || firstNonWhitespaceChar == '-' || firstNonWhitespaceChar == '+')
            {
                Type   underlyingType = GetUnderlyingType(enumType);
                object temp;

                try
                {
                    value = value.Trim();
                    temp  = Convert.ChangeType(value, underlyingType, CultureInfo.InvariantCulture);
                    parseResult.parsedEnum = ToObject(enumType, temp);
                    return(true);
                }
                catch (FormatException)
                { // We need to Parse this as a String instead. There are cases
                  // when you tlbimp enums that can have values of the form "3D".
                  // Don't fix this code.
                }
                catch (Exception ex)
                {
                    if (parseResult.canThrow)
                    {
                        throw;
                    }
                    else
                    {
                        parseResult.SetFailure(ex);
                        return(false);
                    }
                }
            }

            // Find the field. Let's assume that these are always static classes
            // because the class is an enum.
            TypeValuesAndNames entry = GetCachedValuesAndNames(rtType, true);

            string[] enumNames  = entry.Names;
            ulong[]  enumValues = entry.Values;

            StringComparison comparison = ignoreCase ?
                                          StringComparison.OrdinalIgnoreCase :
                                          StringComparison.Ordinal;

            int valueIndex = firstNonWhitespaceIndex;

            while (valueIndex <= value.Length) // '=' is to handle invalid case of an ending comma
            {
                // Find the next separator, if there is one, otherwise the end of the string.
                int endIndex = value.IndexOf(enumSeparatorChar, valueIndex);
                if (endIndex == -1)
                {
                    endIndex = value.Length;
                }

                // Shift the starting and ending indices to eliminate whitespace
                int endIndexNoWhitespace = endIndex;
                while (valueIndex < endIndex && char.IsWhiteSpace(value[valueIndex]))
                {
                    valueIndex++;
                }
                while (endIndexNoWhitespace > valueIndex && char.IsWhiteSpace(value[endIndexNoWhitespace - 1]))
                {
                    endIndexNoWhitespace--;
                }
                int valueSubstringLength = endIndexNoWhitespace - valueIndex;

                // Try to match this substring against each enum name
                bool success = false;
                for (int i = 0; i < enumNames.Length; i++)
                {
                    if (enumNames[i].Length == valueSubstringLength &&
                        string.Compare(enumNames[i], 0, value, valueIndex, valueSubstringLength, comparison) == 0)
                    {
                        result |= enumValues[i];
                        success = true;
                        break;
                    }
                }

                // If we couldn't find a match, throw an argument exception.
                if (!success)
                {
                    // Not found, throw an argument exception.
                    parseResult.SetFailure(ParseFailureKind.ArgumentWithParameter, nameof(SR.Arg_EnumValueNotFound), value);
                    return(false);
                }

                // Move our pointer to the ending index to go again.
                valueIndex = endIndex + 1;
            }

            try
            {
                parseResult.parsedEnum = ToObject(enumType, result);
                return(true);
            }
            catch (Exception ex)
            {
                if (parseResult.canThrow)
                {
                    throw;
                }
                else
                {
                    parseResult.SetFailure(ex);
                    return(false);
                }
            }
        }
Пример #6
0
        private static string InternalFlagsFormat(RuntimeType eT, TypeValuesAndNames entry, ulong result)
        {
            Debug.Assert(eT != null);

            string[] names  = entry.Names;
            ulong[]  values = entry.Values;
            Debug.Assert(names.Length == values.Length);

            int           index      = values.Length - 1;
            StringBuilder sb         = StringBuilderCache.Acquire();
            bool          firstTime  = true;
            ulong         saveResult = result;

            // We will not optimize this code further to keep it maintainable. There are some boundary checks that can be applied
            // to minimize the comparsions required. This code works the same for the best/worst case. In general the number of
            // items in an enum are sufficiently small and not worth the optimization.
            while (index >= 0)
            {
                if ((index == 0) && (values[index] == 0))
                {
                    break;
                }

                if ((result & values[index]) == values[index])
                {
                    result -= values[index];
                    if (!firstTime)
                    {
                        sb.Insert(0, enumSeparatorString);
                    }

                    sb.Insert(0, names[index]);
                    firstTime = false;
                }

                index--;
            }

            string returnString;

            if (result != 0)
            {
                // We were unable to represent this number as a bitwise or of valid flags
                returnString = null; // return null so the caller knows to .ToString() the input
            }
            else if (saveResult == 0)
            {
                // For the cases when we have zero
                if (values.Length > 0 && values[0] == 0)
                {
                    returnString = names[0]; // Zero was one of the enum values.
                }
                else
                {
                    returnString = "0";
                }
            }
            else
            {
                returnString = sb.ToString(); // Return the string representation
            }

            StringBuilderCache.Release(sb);
            return(returnString);
        }
Пример #7
0
        private static string InternalFlagsFormat(RuntimeType eT, TypeValuesAndNames entry, ulong resultValue)
        {
            Debug.Assert(eT != null);

            string[] names  = entry.Names;
            ulong[]  values = entry.Values;
            Debug.Assert(names.Length == values.Length);

            // Values are sorted, so if the incoming value is 0, we can check to see whether
            // the first entry matches it, in which case we can return its name; otherwise,
            // we can just return "0".
            if (resultValue == 0)
            {
                return(values.Length > 0 && values[0] == 0 ?
                       names[0] :
                       "0");
            }

            // With a ulong result value, regardless of the enum's base type, the maximum
            // possible number of consistent name/values we could have is 64, since every
            // value is made up of one or more bits, and when we see values and incorporate
            // their names, we effectively switch off those bits.
            Span <int> foundItems = stackalloc int[64];

            // Walk from largest to smallest. It's common to have a flags enum with a single
            // value that matches a single entry, in which case we can just return the existing
            // name string.
            int index = values.Length - 1;

            while (index >= 0)
            {
                if (values[index] == resultValue)
                {
                    return(names[index]);
                }

                if (values[index] < resultValue)
                {
                    break;
                }

                index--;
            }

            // Now look for multiple matches, storing the indices of the values
            // into our span.
            int resultLength = 0, foundItemsCount = 0;

            while (index >= 0)
            {
                ulong currentValue = values[index];
                if (index == 0 && currentValue == 0)
                {
                    break;
                }

                if ((resultValue & currentValue) == currentValue)
                {
                    resultValue -= currentValue;
                    foundItems[foundItemsCount++] = index;
                    resultLength = checked (resultLength + names[index].Length);
                }

                index--;
            }

            // If we exhausted looking through all the values and we still have
            // a non-zero result, we couldn't match the result to only named values.
            // In that case, we return null and let the call site just generate
            // a string for the integral value.
            if (resultValue != 0)
            {
                return(null);
            }

            // We know what strings to concatenate.  Do so.

            Debug.Assert(foundItemsCount > 0);
            const int SeparatorStringLength = 2; // ", "
            string    result = string.FastAllocateString(checked (resultLength + (SeparatorStringLength * (foundItemsCount - 1))));

            Span <char> resultSpan = MemoryMarshal.CreateSpan(ref result.GetRawStringData(), result.Length);
            string      name       = names[foundItems[--foundItemsCount]];

            name.AsSpan().CopyTo(resultSpan);
            resultSpan = resultSpan.Slice(name.Length);
            while (--foundItemsCount >= 0)
            {
                resultSpan[0] = ',';
                resultSpan[1] = ' ';
                resultSpan    = resultSpan.Slice(2);

                name = names[foundItems[foundItemsCount]];
                name.AsSpan().CopyTo(resultSpan);
                resultSpan = resultSpan.Slice(name.Length);
            }
            Debug.Assert(resultSpan.IsEmpty);

            return(result);
        }