From 81a1a29a045d3a1cf2a86f2ba53aedb13051c13e Mon Sep 17 00:00:00 2001 From: Leonid Date: Thu, 16 Jun 2022 23:01:39 -0700 Subject: [PATCH] Correct usage of enumerators and yield statements --- ISOv4Plugin/Mappers/MultiFileTimeLogMapper.cs | 110 +++++++++++------- 1 file changed, 66 insertions(+), 44 deletions(-) diff --git a/ISOv4Plugin/Mappers/MultiFileTimeLogMapper.cs b/ISOv4Plugin/Mappers/MultiFileTimeLogMapper.cs index 590316b..448b910 100644 --- a/ISOv4Plugin/Mappers/MultiFileTimeLogMapper.cs +++ b/ISOv4Plugin/Mappers/MultiFileTimeLogMapper.cs @@ -45,75 +45,97 @@ public override IEnumerable ImportTimeLogs(ISOTask loggedTask, IE protected override IEnumerable ReadTimeLog(ISOTimeLog _timeLog, string _dataPath) { List readers = new List(); + try { - // Obtain binary readers for each time log - foreach (var timeLog in _timeLogs) + readers = CreateBinaryReaders(); + + // Below alogrithm is using queues for each binary file and matching records on TimeStart/Position. + // At start of each iteration a single record is read from binary file into queue. + // Records with earliest TimeStart are merged together and removed from each file queue. + while (true) { - var reader = base.ReadTimeLog(timeLog, TaskDataPath); - if (reader != null) + // Read next record from each time log + var readersWithData = ReadNextRecords(readers); + + if (readersWithData.Count == 0) { - readers.Add(new BinaryReaderHelper - { - Enumerator = reader.GetEnumerator() - }); + // No more records in each file. Stop processing. + break; } - } - return ReadFromBinaryReaders(readers); + // Group records by TimeStart and East/North position, and then grab ones with earliest TimeStart. + // This leads to processing earliest records from any file first and keeping other records untouched. + // They will be processed in the next loop iteration along with any records read from already processed files. + var candidates = readersWithData.GroupBy(x => new { x.CurrentRecord.TimeStart, x.CurrentRecord.EastPosition, x.CurrentRecord.NorthPosition }) + .OrderBy(x => x.Key.TimeStart) + .First().ToList(); + + // Merge data from all candidates + ISOSpatialRow result = MergeRecords(candidates); + + yield return result; + } } finally { // Clean up readers - foreach (var reader in readers) - { - reader.Enumerator?.Dispose(); - } + DisposeBinaryReaders(readers); } } - private IEnumerable ReadFromBinaryReaders(List readers) + private List CreateBinaryReaders() { - // Below alogrithm is using queues for each binary file and matching records on TimeStart/Position. - // At start of each iteration a single record is read from binary file into queue. - // Records with earliest TimeStart are merged together and removed from each file queue. - while (true) + List readers = new List(); + // Obtain binary readers for each time log + foreach (var timeLog in _timeLogs) { - // Read next record from each time log - foreach (var reader in readers) + var reader = base.ReadTimeLog(timeLog, TaskDataPath); + if (reader != null) { - if (reader.CurrentRecord == null) + readers.Add(new BinaryReaderHelper { - reader.CurrentRecord = reader.Enumerator.MoveNext() ? reader.Enumerator.Current : null; - } + Enumerator = reader.GetEnumerator() + }); } + } - // Only get readers which still have records; - var readersWithData = readers.Where(x => x.CurrentRecord != null).ToList(); - if (readersWithData.Count == 0) - { - // No more records in each file. Stop processing. - break; - } + return readers; + } - // Group records by TimeStart and East/North position, and then grab ones with earliest TimeStart. - // This leads to processing earliest records from any file first and keeping other records untouched. - // They will be processed in the next loop iteration along with any records read from already processed files. - var candidates = readersWithData.GroupBy(x => new { x.CurrentRecord.TimeStart, x.CurrentRecord.EastPosition, x.CurrentRecord.NorthPosition }) - .OrderBy(x => x.Key.TimeStart) - .First().ToList(); + private void DisposeBinaryReaders(List readers) + { + foreach (var reader in readers) + { + reader.Enumerator?.Dispose(); + } + } - // Merge data from all candidates into first record - ISOSpatialRow result = null; - foreach (var candidate in candidates) + private List ReadNextRecords(List readers) + { + foreach (var reader in readers) + { + if (reader.CurrentRecord == null) { - result = result == null ? candidate.CurrentRecord : result.Merge(candidate.CurrentRecord); - // Clear current record to force reading next one - candidate.CurrentRecord = null; + reader.CurrentRecord = reader.Enumerator.MoveNext() ? reader.Enumerator.Current : null; } + } + + // Only return readers which still have records + return readers.Where(x => x.CurrentRecord != null).ToList(); + } - yield return result; + private ISOSpatialRow MergeRecords(List candidates) + { + // Merge data from all candidates into first record + ISOSpatialRow result = null; + foreach (var candidate in candidates) + { + result = result == null ? candidate.CurrentRecord : result.Merge(candidate.CurrentRecord); + // Clear current record to force reading next one + candidate.CurrentRecord = null; } + return result; } protected override ISOTime GetTimeElementFromTimeLog(ISOTimeLog isoTimeLog)