| File: InterningReadTranslator.cs | Web Access |
| Project: src\msbuild\src\Framework\Microsoft.Build.Framework.csproj (Microsoft.Build.Framework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; namespace Microsoft.Build.BackEnd { /// <summary> /// Reads strings form a translator which contains interned packets. /// </summary> /// <remarks> /// This maintains a reusable lookup table to deserialize packets interned by <see cref="InterningWriteTranslator"/>. /// On Translate, the intern header (aka the array of strings indexed by ID) is deserialized. /// The caller can then forward reads to deserialize any interned values in the packet body. /// </remarks> internal sealed class InterningReadTranslator : ITranslatable { private readonly ITranslator _translator; private List<string> _strings = []; private Dictionary<InternPathIds, string> _pathIdsToString = []; internal InterningReadTranslator(ITranslator translator) { if (translator.Mode != TranslationDirection.ReadFromStream) { throw new InvalidOperationException( $"{nameof(InterningReadTranslator)} can only be used with {nameof(TranslationDirection.ReadFromStream)}."); } _translator = translator; } internal string? Read() { int key = -1; _translator.Translate(ref key); return _strings[key]; } internal string? ReadPath() { // If the writer set a null marker, read this as a single string. if (!_translator.TranslateNullable(string.Empty)) { return Read(); } int directoryKey = -1; int fileNameKey = -1; _translator.Translate(ref directoryKey); _translator.Translate(ref fileNameKey); InternPathIds pathIds = new(directoryKey, fileNameKey); // Only concatenate paths the first time we encounter a pair. if (_pathIdsToString.TryGetValue(pathIds, out string? path)) { return path; } string directory = _strings[pathIds.DirectoryId]; string fileName = _strings[pathIds.FileNameId]; string str = string.Concat(directory, fileName); _pathIdsToString.Add(pathIds, str); return str; } public void Translate(ITranslator translator) { // Only deserialize the intern header since the caller will be reading directly from the stream. _translator.Translate(ref _strings); #if NET _pathIdsToString.Clear(); _pathIdsToString.EnsureCapacity(_strings.Count); #else _pathIdsToString = new(_strings.Count); #endif } } }