1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
6 using System.Diagnostics;
7 using System.Collections;
8 using System.Collections.Generic;
10 namespace System.Runtime.InteropServices.WindowsRuntime
13 /// This is a constant map aimed to efficiently support a Split operation (map decomposition).
14 /// A Split operation returns two non-overlapping, non-empty views of the existing map (or both
15 /// values are set to NULL). The two views returned should contain roughly the same number of elements.
16 /// This map is backed by a sorted array. Thus, split operations are O(1) and enumerations are fast;
17 /// however, look-up in the map are O(log n).
19 /// <typeparam name="TKey">Type of objects that act as keys.</typeparam>
20 /// <typeparam name="TValue">Type of objects that act as entries / values.</typeparam>
21 [DebuggerDisplay("Count = {Count}")]
22 internal sealed class ConstantSplittableMap<TKey, TValue> : IMapView<TKey, TValue>
24 private class KeyValuePairComparator : IComparer<KeyValuePair<TKey, TValue>>
26 private static readonly IComparer<TKey> keyComparator = Comparer<TKey>.Default;
28 public int Compare(KeyValuePair<TKey, TValue> x, KeyValuePair<TKey, TValue> y)
30 return keyComparator.Compare(x.Key, y.Key);
32 } // private class KeyValuePairComparator
35 private static readonly KeyValuePairComparator keyValuePairComparator = new KeyValuePairComparator();
37 private readonly KeyValuePair<TKey, TValue>[] items;
38 private readonly int firstItemIndex;
39 private readonly int lastItemIndex;
41 internal ConstantSplittableMap(IReadOnlyDictionary<TKey, TValue> data)
44 throw new ArgumentNullException(nameof(data));
47 lastItemIndex = data.Count - 1;
48 items = CreateKeyValueArray(data.Count, data.GetEnumerator());
52 private ConstantSplittableMap(KeyValuePair<TKey, TValue>[] items, int firstItemIndex, int lastItemIndex)
55 this.firstItemIndex = firstItemIndex;
56 this.lastItemIndex = lastItemIndex;
60 private KeyValuePair<TKey, TValue>[] CreateKeyValueArray(int count, IEnumerator<KeyValuePair<TKey, TValue>> data)
62 KeyValuePair<TKey, TValue>[] kvArray = new KeyValuePair<TKey, TValue>[count];
65 while (data.MoveNext())
66 kvArray[i++] = data.Current;
68 Array.Sort(kvArray, keyValuePairComparator);
78 return lastItemIndex - firstItemIndex + 1;
83 // [CLSCompliant(false)]
88 return (uint)(lastItemIndex - firstItemIndex + 1);
93 public TValue Lookup(TKey key)
96 bool found = TryGetValue(key, out value);
100 Debug.Assert(key != null);
101 Exception e = new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key.ToString()));
102 e.HResult = HResults.E_BOUNDS;
110 public bool HasKey(TKey key)
113 bool hasKey = TryGetValue(key, out value);
117 IEnumerator IEnumerable.GetEnumerator()
119 return ((IEnumerable<IKeyValuePair<TKey, TValue>>)this).GetEnumerator();
122 public IIterator<IKeyValuePair<TKey, TValue>> First()
124 return new EnumeratorToIteratorAdapter<IKeyValuePair<TKey, TValue>>(GetEnumerator());
127 public IEnumerator<IKeyValuePair<TKey, TValue>> GetEnumerator()
129 return new IKeyValuePairEnumerator(items, firstItemIndex, lastItemIndex);
132 public void Split(out IMapView<TKey, TValue>? firstPartition, out IMapView<TKey, TValue>? secondPartition)
136 firstPartition = null;
137 secondPartition = null;
141 int pivot = (int)(((long)firstItemIndex + (long)lastItemIndex) / (long)2);
143 firstPartition = new ConstantSplittableMap<TKey, TValue>(items, firstItemIndex, pivot);
144 secondPartition = new ConstantSplittableMap<TKey, TValue>(items, pivot + 1, lastItemIndex);
147 #region IReadOnlyDictionary members
149 public bool TryGetValue(TKey key, out TValue value)
151 KeyValuePair<TKey, TValue> searchKey = new KeyValuePair<TKey, TValue>(key, default!); // TODO-NULLABLE-GENERIC
152 int index = Array.BinarySearch(items, firstItemIndex, Count, searchKey, keyValuePairComparator);
156 value = default!; // TODO-NULLABLE-GENERIC
160 value = items[index].Value;
164 #endregion IReadOnlyDictionary members
166 #region IKeyValuePair Enumerator
168 internal struct IKeyValuePairEnumerator : IEnumerator<IKeyValuePair<TKey, TValue>>
170 private KeyValuePair<TKey, TValue>[] _array;
173 private int _current;
175 internal IKeyValuePairEnumerator(KeyValuePair<TKey, TValue>[] items, int first, int end)
177 Debug.Assert(items != null);
178 Debug.Assert(first >= 0);
179 Debug.Assert(end >= 0);
180 Debug.Assert(first < items.Length);
181 Debug.Assert(end < items.Length);
186 _current = _start - 1;
189 public bool MoveNext()
199 public IKeyValuePair<TKey, TValue> Current
203 if (_current < _start) throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted);
204 if (_current > _end) throw new InvalidOperationException(SR.InvalidOperation_EnumEnded);
205 return new CLRIKeyValuePairImpl<TKey, TValue>(ref _array[_current]);
209 object? IEnumerator.Current // TODO-NULLABLE:
217 void IEnumerator.Reset()
219 _current = _start - 1;
222 public void Dispose()
227 #endregion IKeyValuePair Enumerator
228 } // internal ConstantSplittableMap<TKey, TValue>
229 } // namespace System.Runtime.InteropServices.WindowsRuntime