//--------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Diagnostics; using System.Collections.Generic; using System.Globalization; namespace System.Data.Entity.Design.Common { /// /// Service making names within a scope unique. Initialize a new instance /// for every scope. /// /// internal sealed class UniqueIdentifierService { internal UniqueIdentifierService(bool caseSensitive) { _knownIdentifiers = new Dictionary(caseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase); _identifierToAdjustedIdentifier = new Dictionary(); _transform = s => s; } internal UniqueIdentifierService(bool caseSensitive, Func transform) { Debug.Assert(transform != null, "use the other constructor if you don't want any transform"); _knownIdentifiers = new Dictionary(caseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase); _identifierToAdjustedIdentifier = new Dictionary(); _transform = transform; } private readonly Dictionary _knownIdentifiers; private readonly Dictionary _identifierToAdjustedIdentifier; private readonly Func _transform; /// /// This method can be used in when you have an /// identifier that you know can't be used, but you don't want /// an adjusted version of it /// /// internal void RegisterUsedIdentifier(string identifier) { Debug.Assert(!_knownIdentifiers.ContainsKey(identifier), "don't register identifiers that already exist"); _knownIdentifiers.Add(identifier, true); } /// /// Given an identifier, makes it unique within the scope by adding /// a suffix (1, 2, 3, ...), and returns the adjusted identifier. /// /// Identifier. Must not be null or empty. /// Object associated with this identifier in case it is required to /// retrieve the adjusted identifier. If not null, must not exist in the current scope already. /// Identifier adjusted to be unique within the scope. internal string AdjustIdentifier(string identifier, object value) { Debug.Assert(!string.IsNullOrEmpty(identifier), "identifier is null or empty"); // find a unique name by adding suffix as necessary int numberOfConflicts = 0; string adjustedIdentifier = _transform(identifier); while (_knownIdentifiers.ContainsKey(adjustedIdentifier)) { ++numberOfConflicts; adjustedIdentifier = _transform(identifier) + numberOfConflicts.ToString(CultureInfo.InvariantCulture); } // remember the identifier in this scope Debug.Assert(!_knownIdentifiers.ContainsKey(adjustedIdentifier), "we just made it unique"); _knownIdentifiers.Add(adjustedIdentifier, true); if (null != value) { Debug.Assert(!_identifierToAdjustedIdentifier.ContainsKey(value), "should never register one value twice"); _identifierToAdjustedIdentifier.Add(value, adjustedIdentifier); } return adjustedIdentifier; } /// /// Simple overload when you don't need to track back to an object /// /// /// internal string AdjustIdentifier(string identifier) { return AdjustIdentifier(identifier, null); } /// /// Determines the adjusted name for an identifier if it has been registered in this scope. /// internal bool TryGetAdjustedName(object value, out string adjustedIdentifier) { return _identifierToAdjustedIdentifier.TryGetValue(value, out adjustedIdentifier); } } }