private static void SimpleMapTest() { var map = new FastMap <string>(); Assert.IsTrue(map.IsEmpty); Assert.AreEqual(0, map.Count); Assert.IsFalse(map.Find(5).Next(out _)); Assert.IsFalse(map.Find(6).Next(out _)); Assert.IsFalse(map.Find(7).Next(out _)); int indexA5 = map.Insert(5, "a"); Assert.IsFalse(map.IsEmpty); Assert.AreEqual(1, map.Count); Assert.IsTrue(map.Find(5).Next(out var index)); Assert.AreEqual(indexA5, index); Assert.IsFalse(map.Find(6).Next(out _)); Assert.IsFalse(map.Find(7).Next(out _)); int indexB6 = map.Insert(6, "b"); int indexA5Two = map.Insert(5, "a"); int indexB5 = map.Insert(5, "b"); Assert.IsTrue(indexA5 != indexA5Two); Assert.IsTrue(indexA5 != indexB5); Assert.IsTrue(indexA5Two != indexB5); Assert.IsFalse(map.IsEmpty); Assert.AreEqual(4, map.Count); var traverser = map.Find(5); Assert.IsTrue(traverser.Next(out index)); Assert.AreEqual(indexB5, index); Assert.IsTrue(traverser.Next(out index)); Assert.AreEqual(indexA5Two, index); Assert.IsTrue(traverser.Next(out index)); Assert.AreEqual(indexA5, index); Assert.IsFalse(traverser.Next(out _)); traverser = map.Find(6); Assert.IsTrue(traverser.Next(out index)); Assert.AreEqual(indexB6, index); Assert.IsFalse(traverser.Next(out _)); Assert.IsFalse(map.Find(7).Next(out _)); map.Remove(indexA5); Assert.IsFalse(map.IsEmpty); Assert.AreEqual(3, map.Count); traverser = map.Find(5); Assert.IsTrue(traverser.Next(out index)); Assert.AreEqual(indexB5, index); Assert.IsTrue(traverser.Next(out index)); Assert.AreEqual(indexA5Two, index); Assert.IsFalse(traverser.Next(out _)); traverser = map.Find(6); Assert.IsTrue(traverser.Next(out index)); Assert.AreEqual(indexB6, index); Assert.IsFalse(traverser.Next(out _)); Assert.IsFalse(map.Find(7).Next(out _)); map.Remove(indexA5Two); map.Remove(indexB6); Assert.IsFalse(map.IsEmpty); Assert.AreEqual(1, map.Count); traverser = map.Find(5); Assert.IsTrue(traverser.Next(out index)); Assert.AreEqual(indexB5, index); Assert.IsFalse(traverser.Next(out _)); Assert.IsFalse(map.Find(6).Next(out _)); Assert.IsFalse(map.Find(7).Next(out _)); map.Remove(indexB5); Assert.IsTrue(map.IsEmpty); Assert.AreEqual(0, map.Count); Assert.IsFalse(map.Find(5).Next(out _)); Assert.IsFalse(map.Find(6).Next(out _)); Assert.IsFalse(map.Find(7).Next(out _)); }
private static void ReuseTest() { var map = new FastMap <string>(5); Assert.AreEqual(1, map.Insert(5, "0")); Assert.AreEqual(2, map.Insert(5, "1")); Assert.AreEqual(3, map.Insert(5, "2")); Assert.AreEqual(4, map.Insert(5, "3")); Assert.AreEqual(5, map.Insert(5, "4")); map.Remove(3); Assert.AreEqual(3, map.Insert(5, "5")); map.Remove(2); map.Remove(1); map.Remove(5); map.Remove(3); map.Remove(4); Assert.AreEqual(4, map.Insert(5, "6")); Assert.AreEqual(3, map.Insert(5, "7")); Assert.AreEqual(5, map.Insert(5, "8")); Assert.AreEqual(1, map.Insert(5, "9")); Assert.AreEqual(2, map.Insert(5, "10")); Assert.AreEqual(6, map.Insert(5, "11")); }
private static void LargerTest() { var map = new FastMap <string>(1); const int Size = 100; for (int i = 0; i < Size; i++) { map.Insert(i, "one" + i); map.Insert(i, "two" + i); } for (int i = 0; i < Size; i++) { map.Insert(i, "three" + i); } Assert.AreEqual(Size * 3, map.Count); for (int i = 0; i < Size; i++) { var traverse = map.Find(i); bool hasOne = false; bool hasTwo = false; bool hasThree = false; for (int j = 0; j < 3; j++) { Assert.IsTrue(traverse.Next(out var index)); if (map.Values[index] == "one" + i) { hasOne = true; } else if (map.Values[index] == "two" + i) { hasTwo = true; } else if (map.Values[index] == "three" + i) { hasThree = true; } else { Assert.Fail(); } } Assert.IsFalse(traverse.Next(out _)); Assert.IsTrue(hasOne); Assert.IsTrue(hasTwo); Assert.IsTrue(hasThree); } for (int i = 0; i < Size; i++) { var traverse = map.Find(i); while (traverse.Next(out int index)) { if (map.Values[index] == "two" + i) { map.Remove(index); break; } } } Assert.AreEqual(Size * 2, map.Count); for (int i = 0; i < Size; i++) { var traverse = map.Find(i); bool hasOne = false; bool hasThree = false; for (int j = 0; j < 2; j++) { Assert.IsTrue(traverse.Next(out var index)); if (map.Values[index] == "one" + i) { hasOne = true; } else if (map.Values[index] == "three" + i) { hasThree = true; } else { Assert.Fail(); } } Assert.IsFalse(traverse.Next(out _)); Assert.IsTrue(hasOne); Assert.IsTrue(hasThree); } for (int i = 0; i < Size; i++) { var traverse = map.Find(i); while (traverse.Next(out int index)) { if (map.Values[index] == "one" + i) { map.Remove(index); break; } } } Assert.AreEqual(Size, map.Count); for (int i = 0; i < Size; i++) { var traverse = map.Find(i); Assert.IsTrue(traverse.Next(out int index)); Assert.AreEqual("three" + i, map.Values[index]); Assert.IsFalse(traverse.Next(out _)); } for (int i = 0; i < Size; i++) { var traverse = map.Find(i); while (traverse.Next(out int index)) { if (map.Values[index] == "three" + i) { map.Remove(index); break; } } } Assert.IsTrue(map.IsEmpty); }
private void ProcessPendingEntries() { foreach (var pKey in this.processQueue) { PooledElasticCircularBuffer <LEntry> leftWorking = null; PooledElasticCircularBuffer <REntry> rightWorking = null; this.leftQueue.Lookup(pKey, out int index); leftWorking = this.leftQueue.entries[index].value; rightWorking = this.rightQueue.entries[index].value; FastMap <ActiveEvent <TLeft> > leftEdgeMapForPartition = null; FastMap <ActiveEvent <TRight> > rightEdgeMapForPartition = null; this.partitionData.Lookup(pKey, out index); var partition = this.partitionData.entries[index].value; leftEdgeMapForPartition = partition.leftEdgeMap; rightEdgeMapForPartition = partition.rightEdgeMap; while (true) { bool hasLeftBatch = leftWorking.TryPeekFirst(out LEntry leftEntry); bool hasRightBatch = rightWorking.TryPeekFirst(out REntry rightEntry); FastMap <ActiveEvent <TRight> > .FindTraverser rightEdges = default; FastMap <ActiveEvent <TLeft> > .FindTraverser leftEdges = default; if (hasLeftBatch && hasRightBatch) { UpdateNextLeftTime(partition, leftEntry.Sync); UpdateNextRightTime(partition, rightEntry.Sync); if (partition.nextLeftTime <= partition.nextRightTime) { if (leftEntry.Other != long.MinValue) { TKey key = leftEntry.Key; var hash = leftEntry.Hash; if (rightEdgeMapForPartition.Find(hash, ref rightEdges)) { while (rightEdges.Next(out int rightIndex)) { if (this.keyComparer(key, rightEdgeMapForPartition.Values[rightIndex].Key)) { OutputStartEdge(partition.nextLeftTime, ref key, ref leftEntry.Payload, ref rightEdgeMapForPartition.Values[rightIndex].Payload, hash); } } } if (!partition.isRightComplete) { int newIndex = leftEdgeMapForPartition.Insert(hash); leftEdgeMapForPartition.Values[newIndex].Populate(ref key, ref leftEntry.Payload); } UpdateNextLeftTime(partition, leftEntry.Sync); } else { OutputPunctuation(leftEntry.Sync, ref leftEntry.Key, leftEntry.Hash); } } else { if (rightEntry.Other != long.MinValue) { TKey key = rightEntry.Key; var hash = rightEntry.Hash; if (leftEdgeMapForPartition.Find(hash, ref leftEdges)) { while (leftEdges.Next(out int leftIndex)) { if (this.keyComparer(key, leftEdgeMapForPartition.Values[leftIndex].Key)) { OutputStartEdge(partition.nextRightTime, ref key, ref leftEdgeMapForPartition.Values[leftIndex].Payload, ref rightEntry.Payload, hash); } } } if (!partition.isLeftComplete) { int newIndex = rightEdgeMapForPartition.Insert(hash); rightEdgeMapForPartition.Values[newIndex].Populate(ref key, ref rightEntry.Payload); } UpdateNextRightTime(partition, rightEntry.Sync); } else { OutputPunctuation(rightEntry.Sync, ref rightEntry.Key, rightEntry.Hash); } } } else if (hasLeftBatch) { UpdateNextLeftTime(partition, leftEntry.Sync); if (leftEntry.Other != long.MinValue) { TKey key = leftEntry.Key; var hash = leftEntry.Hash; if (rightEdgeMapForPartition.Find(hash, ref rightEdges)) { while (rightEdges.Next(out int rightIndex)) { if (this.keyComparer(key, rightEdgeMapForPartition.Values[rightIndex].Key)) { OutputStartEdge(partition.nextLeftTime, ref key, ref leftEntry.Payload, ref rightEdgeMapForPartition.Values[rightIndex].Payload, hash); } } } if (!partition.isRightComplete) { int newIndex = leftEdgeMapForPartition.Insert(hash); leftEdgeMapForPartition.Values[newIndex].Populate(ref key, ref leftEntry.Payload); } UpdateNextLeftTime(partition, leftEntry.Sync); } else { OutputPunctuation(leftEntry.Sync, ref leftEntry.Key, leftEntry.Hash); return; } } else if (hasRightBatch) { UpdateNextRightTime(partition, rightEntry.Sync); if (rightEntry.Other != long.MinValue) { TKey key = rightEntry.Key; var hash = rightEntry.Hash; if (leftEdgeMapForPartition.Find(hash, ref leftEdges)) { while (leftEdges.Next(out int leftIndex)) { if (this.keyComparer(key, leftEdgeMapForPartition.Values[leftIndex].Key)) { OutputStartEdge(partition.nextRightTime, ref key, ref leftEdgeMapForPartition.Values[leftIndex].Payload, ref rightEntry.Payload, hash); } } } if (!partition.isLeftComplete) { int newIndex = rightEdgeMapForPartition.Insert(hash); rightEdgeMapForPartition.Values[newIndex].Populate(ref key, ref rightEntry.Payload); } UpdateNextRightTime(partition, rightEntry.Sync); } else { OutputPunctuation(rightEntry.Sync, ref rightEntry.Key, rightEntry.Hash); } } else { if (partition.nextLeftTime < this.lastLeftCTI) { UpdateNextLeftTime(partition, this.lastLeftCTI); } if (partition.nextRightTime < this.lastRightCTI) { UpdateNextRightTime(partition, this.lastRightCTI); } this.cleanKeys.Add(pKey); break; } } } if (this.emitCTI) { var earliest = Math.Min(this.lastLeftCTI, this.lastRightCTI); AddLowWatermarkToBatch(earliest); this.emitCTI = false; foreach (var p in this.cleanKeys) { this.leftQueue.Lookup(p, out int index); var l = this.leftQueue.entries[index]; var r = this.rightQueue.entries[index]; if (l.value.Count == 0 && r.value.Count == 0) { this.seenKeys.Remove(p); l.value.Dispose(); this.leftQueue.Remove(p); r.value.Dispose(); this.rightQueue.Remove(p); } } this.cleanKeys.Clear(); } this.processQueue.Clear(); }