You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

102 lines
3.3 KiB

  1. // Copyright (c) 2017 Daniel Grunwald
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System;
  19. using System.Collections;
  20. using System.Collections.Generic;
  21. namespace ICSharpCode.Decompiler.Util
  22. {
  23. static class LongDict
  24. {
  25. public static LongDict<T> Create<T>(IEnumerable<(LongSet, T)> entries)
  26. {
  27. return new LongDict<T>(entries);
  28. }
  29. internal static readonly KeyComparer<LongInterval, long> StartComparer = KeyComparer.Create((LongInterval i) => i.Start);
  30. }
  31. /// <summary>
  32. /// An immutable mapping from keys of type long to values of type T.
  33. /// </summary>
  34. struct LongDict<T> : IEnumerable<KeyValuePair<LongInterval, T>>
  35. {
  36. readonly LongInterval[] keys;
  37. readonly T[] values;
  38. /// <summary>
  39. /// Creates a new LongDict from the given entries.
  40. /// If there are multiple entries for the same long key,
  41. /// the resulting LongDict will store the value from the first entry.
  42. /// </summary>
  43. public LongDict(IEnumerable<(LongSet, T)> entries)
  44. {
  45. LongSet available = LongSet.Universe;
  46. var keys = new List<LongInterval>();
  47. var values = new List<T>();
  48. foreach (var (key, val) in entries)
  49. {
  50. foreach (var interval in key.IntersectWith(available).Intervals)
  51. {
  52. keys.Add(interval);
  53. values.Add(val);
  54. }
  55. available = available.ExceptWith(key);
  56. }
  57. this.keys = keys.ToArray();
  58. this.values = values.ToArray();
  59. Array.Sort(this.keys, this.values, LongDict.StartComparer);
  60. }
  61. public bool TryGetValue(long key, out T value)
  62. {
  63. int pos = Array.BinarySearch(this.keys, new LongInterval(key, key), LongDict.StartComparer);
  64. // If the element isn't found, BinarySearch returns the complement of "insertion position".
  65. // We use this to find the previous element (if there wasn't any exact match).
  66. if (pos < 0)
  67. pos = ~pos - 1;
  68. if (pos >= 0 && this.keys[pos].Contains(key))
  69. {
  70. value = this.values[pos];
  71. return true;
  72. }
  73. value = default(T);
  74. return false;
  75. }
  76. public T GetOrDefault(long key)
  77. {
  78. TryGetValue(key, out T val);
  79. return val;
  80. }
  81. public IEnumerator<KeyValuePair<LongInterval, T>> GetEnumerator()
  82. {
  83. for (int i = 0; i < this.keys.Length; ++i)
  84. {
  85. yield return new KeyValuePair<LongInterval, T>(this.keys[i], this.values[i]);
  86. }
  87. }
  88. IEnumerator IEnumerable.GetEnumerator()
  89. {
  90. return GetEnumerator();
  91. }
  92. }
  93. }