aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcsharptest <roger@csharptest.net>2015-02-07 15:33:24 -0600
committerrogerk <devnull@localhost>2015-02-07 15:33:24 -0600
commit1e29e701a73d3fa1466d6999b765aaddf12f1b59 (patch)
treef1350c507286e87b02550f5c3ddd6987142ffbac
parente234691b67fb62057dfa0d71196e508f230bfb5f (diff)
downloadprotobuf-1e29e701a73d3fa1466d6999b765aaddf12f1b59.tar.gz
protobuf-1e29e701a73d3fa1466d6999b765aaddf12f1b59.tar.bz2
protobuf-1e29e701a73d3fa1466d6999b765aaddf12f1b59.zip
Fix build error for missing method Enum.GetValues() on some platforms
-rw-r--r--src/ProtocolBuffers.Serialization/AbstractReader.cs28
-rw-r--r--src/ProtocolBuffers/CodedInputStream.cs81
-rw-r--r--src/ProtocolBuffers/EnumLite.cs126
3 files changed, 128 insertions, 107 deletions
diff --git a/src/ProtocolBuffers.Serialization/AbstractReader.cs b/src/ProtocolBuffers.Serialization/AbstractReader.cs
index c8dfd2b4..e198d0b0 100644
--- a/src/ProtocolBuffers.Serialization/AbstractReader.cs
+++ b/src/ProtocolBuffers.Serialization/AbstractReader.cs
@@ -469,23 +469,12 @@ namespace Google.ProtocolBuffers.Serialization
rawValue = null;
if (ReadEnum(ref rawValue))
{
- if (Enum.IsDefined(typeof(T), rawValue))
+ if (!EnumParser<T>.TryConvert(rawValue, ref value))
{
- if (rawValue is int)
- {
- value = (T) rawValue;
- }
- else if (rawValue is string)
- {
- value = (T) Enum.Parse(typeof(T), (string) rawValue, false);
- }
- else
- {
- value = default(T);
- return false;
- }
- return true;
+ value = default(T);
+ return false;
}
+ return true;
}
return false;
}
@@ -560,13 +549,10 @@ namespace Google.ProtocolBuffers.Serialization
{
foreach (object rawValue in array)
{
- if (rawValue is int)
- {
- list.Add((T) rawValue);
- }
- else if (rawValue is string)
+ T val = default(T);
+ if (EnumParser<T>.TryConvert(rawValue, ref val))
{
- list.Add((T) Enum.Parse(typeof(T), (string) rawValue, false));
+ list.Add(val);
}
else
{
diff --git a/src/ProtocolBuffers/CodedInputStream.cs b/src/ProtocolBuffers/CodedInputStream.cs
index 4f3dfb2d..773e8c18 100644
--- a/src/ProtocolBuffers/CodedInputStream.cs
+++ b/src/ProtocolBuffers/CodedInputStream.cs
@@ -482,7 +482,7 @@ namespace Google.ProtocolBuffers
where T : struct, IComparable, IFormattable
{
int number = (int) ReadRawVarint32();
- if (EnumHelper<T>.TryConvert(number, ref value))
+ if (EnumParser<T>.TryConvert(number, ref value))
{
unknown = null;
return true;
@@ -1860,84 +1860,5 @@ namespace Google.ProtocolBuffers
}
#endregion
-
- /// <summary>
- /// Helper class to make parsing enums faster.
- /// </summary>
- private static class EnumHelper<T> where T : struct
- {
- /// <summary>
- /// We use the array form if all values are in the range [0, LimitForArray),
- /// otherwise we build a dictionary.
- /// </summary>
- private const int LimitForArray = 32;
- // Only one of these will be populated.
- private static readonly Dictionary<int, T> dictionary;
- private static readonly T?[] values;
-
- static EnumHelper()
- {
- // It will actually be a T[], but the CLR will let us convert.
- int[] array = (int[]) Enum.GetValues(typeof (T));
- if (array.Length == 0)
- {
- // Empty enum; model with an empty values array.
- values = new T?[0];
- return;
- }
- int min = int.MaxValue;
- int max = int.MinValue;
- foreach (int number in array)
- {
- min = Math.Min(number, min);
- max = Math.Max(number, max);
- }
- if (min >= 0 && max < LimitForArray)
- {
- values = new T?[max + 1];
- foreach (int number in array)
- {
- values[number] = (T)(object)number;
- }
- }
- else
- {
- dictionary = new Dictionary<int, T>();
- foreach (int number in array)
- {
- dictionary[number] = (T)(object)number;
- }
- }
- }
-
- /// <summary>
- /// Tries to convert an integer to its enum representation. This would take an out parameter,
- /// but the caller uses ref, so this approach is simpler.
- /// </summary>
- internal static bool TryConvert(int number, ref T value)
- {
- if (values != null)
- {
- if (number < 0 || number >= values.Length)
- {
- return false;
- }
- T? maybeValue = values[number];
- if (maybeValue != null)
- {
- value = maybeValue.Value;
- return true;
- }
- return false;
- }
- T converted;
- if (dictionary.TryGetValue(number, out converted))
- {
- value = converted;
- return true;
- }
- return false;
- }
- }
}
} \ No newline at end of file
diff --git a/src/ProtocolBuffers/EnumLite.cs b/src/ProtocolBuffers/EnumLite.cs
index 978f4e51..1301ec2a 100644
--- a/src/ProtocolBuffers/EnumLite.cs
+++ b/src/ProtocolBuffers/EnumLite.cs
@@ -95,26 +95,140 @@ namespace Google.ProtocolBuffers
public IEnumLite FindValueByNumber(int number)
{
- if (Enum.IsDefined(typeof(TEnum), number))
+ TEnum val = default(TEnum);
+ if (EnumParser<TEnum>.TryConvert(number, ref val))
{
- return new EnumValue((TEnum)(object)number);
+ return new EnumValue(val);
}
return null;
}
public IEnumLite FindValueByName(string name)
{
- if (Enum.IsDefined(typeof(TEnum), name))
+ TEnum val = default(TEnum);
+ if (EnumParser<TEnum>.TryConvert(name, ref val))
{
- object evalue = Enum.Parse(typeof(TEnum), name, false);
- return new EnumValue((TEnum)evalue);
+ return new EnumValue(val);
}
return null;
}
public bool IsValidValue(IEnumLite value)
{
- return Enum.IsDefined(typeof(TEnum), value.Number);
+ TEnum val = default(TEnum);
+ return EnumParser<TEnum>.TryConvert(value.Number, ref val);
+ }
+ }
+
+ public static class EnumParser<T> where T : struct, IComparable, IFormattable
+ {
+ private static readonly Dictionary<int, T> _byNumber;
+ private static Dictionary<string, T> _byName;
+
+ static EnumParser()
+ {
+ int[] array;
+ try
+ {
+#if CLIENTPROFILE
+ // It will actually be a T[], but the CLR will let us convert.
+ array = (int[])Enum.GetValues(typeof(T));
+#else
+ var temp = new List<T>();
+ foreach (var fld in typeof (T).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static))
+ {
+ if (fld.IsLiteral && fld.FieldType == typeof(T))
+ {
+ temp.Add((T)fld.GetValue(null));
+ }
+ }
+ array = (int[])(object)temp.ToArray();
+#endif
+ }
+ catch
+ {
+ _byNumber = null;
+ return;
+ }
+
+ _byNumber = new Dictionary<int, T>(array.Length);
+ foreach (int i in array)
+ {
+ _byNumber[i] = (T)(object)i;
+ }
+ }
+
+ public static bool TryConvert(object input, ref T value)
+ {
+ if (input is int || input is T)
+ {
+ return TryConvert((int)input, ref value);
+ }
+ if (input is string)
+ {
+ return TryConvert((string)input, ref value);
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Tries to convert an integer to its enum representation. This would take an out parameter,
+ /// but the caller uses ref, so this approach is simpler.
+ /// </summary>
+ public static bool TryConvert(int number, ref T value)
+ {
+ // null indicates an exception at construction, use native IsDefined.
+ if (_byNumber == null)
+ {
+ return Enum.IsDefined(typeof(T), number);
+ }
+ T converted;
+ if (_byNumber != null && _byNumber.TryGetValue(number, out converted))
+ {
+ value = converted;
+ return true;
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Tries to convert a string to its enum representation. This would take an out parameter,
+ /// but the caller uses ref, so this approach is simpler.
+ /// </summary>
+ public static bool TryConvert(string name, ref T value)
+ {
+ // null indicates an exception at construction, use native IsDefined/Parse.
+ if (_byNumber == null)
+ {
+ if (Enum.IsDefined(typeof(T), name))
+ {
+ value = (T)Enum.Parse(typeof(T), name, false);
+ return true;
+ }
+ return false;
+ }
+
+ // known race, possible multiple threads each build their own copy; however, last writer will win
+ var map = _byName;
+ if (map == null)
+ {
+ map = new Dictionary<string, T>(StringComparer.Ordinal);
+ foreach (var possible in _byNumber.Values)
+ {
+ map[possible.ToString()] = possible;
+ }
+ _byName = map;
+ }
+
+ T converted;
+ if (map.TryGetValue(name, out converted))
+ {
+ value = converted;
+ return true;
+ }
+
+ return false;
}
}
} \ No newline at end of file