// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using EpicGames.Core; namespace UnrealBuildTool { /// /// Identifier for a config file key, including information about the hierarchy used to read it /// [DebuggerDisplay("{Name}")] class ConfigDependencyKey : IEquatable { /// /// The config hierarchy type /// public ConfigHierarchyType Type; /// /// Project directory to read config files from /// public DirectoryReference? ProjectDir; /// /// The platform being built /// public UnrealTargetPlatform Platform; /// /// The section name /// public string SectionName; /// /// The key name /// public string KeyName; /// /// Constructor /// /// The config hierarchy type /// Project directory to read config files from /// The platform being built /// The section name /// The key name public ConfigDependencyKey(ConfigHierarchyType Type, DirectoryReference? ProjectDir, UnrealTargetPlatform Platform, string SectionName, string KeyName) { this.Type = Type; this.ProjectDir = ProjectDir; this.Platform = Platform; this.SectionName = SectionName; this.KeyName = KeyName; } /// /// Construct a key from an archive /// /// Archive to read from public ConfigDependencyKey(BinaryArchiveReader Reader) { Type = (ConfigHierarchyType)Reader.ReadInt(); ProjectDir = Reader.ReadDirectoryReference(); Platform = Reader.ReadUnrealTargetPlatform(); SectionName = Reader.ReadString()!; KeyName = Reader.ReadString()!; } /// /// Writes this key to an archive /// /// Archive to write to public void Write(BinaryArchiveWriter Writer) { Writer.WriteInt((int)Type); Writer.WriteDirectoryReference(ProjectDir); Writer.WriteUnrealTargetPlatform(Platform); Writer.WriteString(SectionName); Writer.WriteString(KeyName); } /// /// Tests whether this key is equal to another object /// /// The object to compare to /// True if the keys are equal, false otherwise public override bool Equals(object? Other) { return (Other is ConfigDependencyKey key) && Equals(key); } /// /// Tests whether this key is equal to another key /// /// The key to compare to /// True if the keys are equal, false otherwise public bool Equals(ConfigDependencyKey? Other) { return Other is not null && Type == Other.Type && ProjectDir == Other.ProjectDir && Platform == Other.Platform && SectionName == Other.SectionName && KeyName == Other.KeyName; } /// /// Gets a hash code for this object /// /// Hash code for the object public override int GetHashCode() { int Hash = 17; Hash = (Hash * 31) + Type.GetHashCode(); Hash = (Hash * 31) + ((ProjectDir == null) ? 0 : ProjectDir.GetHashCode()); Hash = (Hash * 31) + Platform.GetHashCode(); Hash = (Hash * 31) + SectionName.GetHashCode(); Hash = (Hash * 31) + KeyName.GetHashCode(); return Hash; } } /// /// Stores a list of config key/value pairs that have been read /// class ConfigValueTracker { /// /// The dependencies list /// readonly IReadOnlyDictionary?> Dependencies; /// /// Constructor /// public ConfigValueTracker(IReadOnlyDictionary?> ConfigValues) { Dependencies = new Dictionary?>(ConfigValues); } /// /// Construct an object from an archive on disk /// /// Archive to read from public ConfigValueTracker(BinaryArchiveReader Reader) { Dependencies = Reader.ReadDictionary(() => new ConfigDependencyKey(Reader), () => (IReadOnlyList?)Reader.ReadList(() => Reader.ReadString()))!; } /// /// Write the dependencies object to disk /// /// Archive to write to public void Write(BinaryArchiveWriter Writer) { Writer.WriteDictionary(Dependencies, Key => Key.Write(Writer), Value => Writer.WriteList(Value, x => Writer.WriteString(x))); } /// /// Checks whether the list of dependencies is still valid /// /// public bool IsValid() { foreach (KeyValuePair?> Pair in Dependencies) { // Read the appropriate hierarchy ConfigHierarchy Hierarchy = ConfigCache.ReadHierarchy(Pair.Key.Type, Pair.Key.ProjectDir, Pair.Key.Platform); // Get the value(s) associated with this key IReadOnlyList? NewValues; Hierarchy.TryGetValues(Pair.Key.SectionName, Pair.Key.KeyName, out NewValues); // Check if they're different if (Pair.Value == null) { if (NewValues != null) { return false; } } else { if (NewValues == null || !Enumerable.SequenceEqual(Pair.Value, NewValues, StringComparer.Ordinal)) { return false; } } } return true; } } }