﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Diagnostics;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.PooledObjects;

namespace Microsoft.CodeAnalysis.CodeGen
{
    /// <summary>
    /// Dispenser of unique ordinals for synthesized variable names that have the same kind and syntax offset.
    /// </summary>
    internal sealed class SynthesizedLocalOrdinalsDispenser
    {
        // The key is (local.SyntaxOffset << 8) | local.SynthesizedKind.
        private PooledDictionary<long, int>? _lazyMap;

        private static long MakeKey(SynthesizedLocalKind localKind, int syntaxOffset)
        {
            return (long)syntaxOffset << 8 | (long)localKind;
        }

        public void Free()
        {
            if (_lazyMap != null)
            {
                _lazyMap.Free();
                _lazyMap = null;
            }
        }

        public int AssignLocalOrdinal(SynthesizedLocalKind localKind, int syntaxOffset)
        {
#if !DEBUG
            // Optimization (avoid growing the dictionary below): 
            // User-defined locals have to have a distinct syntax offset, thus ordinal is always 0.
            if (localKind == SynthesizedLocalKind.UserDefined)
            {
                return 0;
            }
#endif
            int ordinal;
            long key = MakeKey(localKind, syntaxOffset);

            // Group by syntax offset and kind.
            // Variables associated with the same syntax and kind will be assigned different ordinals.
            if (_lazyMap == null)
            {
                _lazyMap = PooledDictionary<long, int>.GetInstance();
                ordinal = 0;
            }
            else if (!_lazyMap.TryGetValue(key, out ordinal))
            {
                ordinal = 0;
            }

            _lazyMap[key] = ordinal + 1;
            Debug.Assert(ordinal == 0 || localKind != SynthesizedLocalKind.UserDefined);
            return ordinal;
        }
    }
}
