File: src\Workspaces\SharedUtilitiesAndExtensions\Compiler\Core\Log\LogMessage.cs
Web Access
Project: src\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces)
// 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;
using Microsoft.CodeAnalysis.PooledObjects;
 
namespace Microsoft.CodeAnalysis.Internal.Log;
 
/// <summary>
/// log message that can generate string lazily
/// </summary>
internal abstract class LogMessage
{
    public LogLevel LogLevel { get; protected set; } = LogLevel.Debug;
 
    public static LogMessage Create(string message, LogLevel logLevel)
        => StaticLogMessage.Construct(message, logLevel);
 
    public static LogMessage Create(Func<string> messageGetter, LogLevel logLevel)
        => LazyLogMessage.Construct(messageGetter, logLevel);
 
    public static LogMessage Create<TArg>(Func<TArg, string> messageGetter, TArg arg, LogLevel logLevel)
        => LazyLogMessage<TArg>.Construct(messageGetter, arg, logLevel);
 
    public static LogMessage Create<TArg0, TArg1>(Func<TArg0, TArg1, string> messageGetter, TArg0 arg0, TArg1 arg1, LogLevel logLevel)
        => LazyLogMessage<TArg0, TArg1>.Construct(messageGetter, arg0, arg1, logLevel);
 
    public static LogMessage Create<TArg0, TArg1, TArg2>(Func<TArg0, TArg1, TArg2, string> messageGetter, TArg0 arg0, TArg1 arg1, TArg2 arg2, LogLevel logLevel)
        => LazyLogMessage<TArg0, TArg1, TArg2>.Construct(messageGetter, arg0, arg1, arg2, logLevel);
 
    public static LogMessage Create<TArg0, TArg1, TArg2, TArg3>(Func<TArg0, TArg1, TArg2, TArg3, string> messageGetter, TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, LogLevel logLevel)
        => LazyLogMessage<TArg0, TArg1, TArg2, TArg3>.Construct(messageGetter, arg0, arg1, arg2, arg3, logLevel);
 
    // message will be either initially set or lazily set by caller
    private string? _message;
 
    protected abstract string CreateMessage();
 
    /// <summary>
    /// Logger will call this to return LogMessage to its pool
    /// </summary>
    protected abstract void FreeCore();
 
    public string GetMessage()
    {
        _message ??= CreateMessage();
 
        return _message;
    }
 
    public void Free()
    {
        _message = null;
 
        FreeCore();
    }
 
    private sealed class StaticLogMessage : LogMessage
    {
        private static readonly ObjectPool<StaticLogMessage> s_pool = SharedPools.Default<StaticLogMessage>();
 
        public static LogMessage Construct(string message, LogLevel logLevel)
        {
            var logMessage = s_pool.Allocate();
            logMessage._message = message;
            logMessage.LogLevel = logLevel;
 
            return logMessage;
        }
 
        protected override string CreateMessage()
            => _message!;
 
        protected override void FreeCore()
        {
            if (_message == null)
            {
                return;
            }
 
            _message = null;
            s_pool.Free(this);
        }
    }
 
    private sealed class LazyLogMessage : LogMessage
    {
        private static readonly ObjectPool<LazyLogMessage> s_pool = SharedPools.Default<LazyLogMessage>();
 
        private Func<string>? _messageGetter;
 
        public static LogMessage Construct(Func<string> messageGetter, LogLevel logLevel)
        {
            var logMessage = s_pool.Allocate();
            logMessage._messageGetter = messageGetter;
            logMessage.LogLevel = logLevel;
 
            return logMessage;
        }
 
        protected override string CreateMessage()
            => _messageGetter!();
 
        protected override void FreeCore()
        {
            if (_messageGetter == null)
            {
                return;
            }
 
            _messageGetter = null;
            s_pool.Free(this);
        }
    }
 
    private sealed class LazyLogMessage<TArg0> : LogMessage
    {
        private static readonly ObjectPool<LazyLogMessage<TArg0>> s_pool = SharedPools.Default<LazyLogMessage<TArg0>>();
 
        private Func<TArg0, string>? _messageGetter;
        private TArg0? _arg;
 
        public static LogMessage Construct(Func<TArg0, string> messageGetter, TArg0 arg, LogLevel logLevel)
        {
            var logMessage = s_pool.Allocate();
            logMessage._messageGetter = messageGetter;
            logMessage._arg = arg;
            logMessage.LogLevel = logLevel;
 
            return logMessage;
        }
 
        protected override string CreateMessage()
            => _messageGetter!(_arg!);
 
        protected override void FreeCore()
        {
            if (_messageGetter == null)
            {
                return;
            }
 
            _messageGetter = null;
            _arg = default;
            s_pool.Free(this);
        }
    }
 
    private sealed class LazyLogMessage<TArg0, TArg1> : LogMessage
    {
        private static readonly ObjectPool<LazyLogMessage<TArg0, TArg1>> s_pool = SharedPools.Default<LazyLogMessage<TArg0, TArg1>>();
 
        private Func<TArg0, TArg1, string>? _messageGetter;
        private TArg0? _arg0;
        private TArg1? _arg1;
 
        internal static LogMessage Construct(Func<TArg0, TArg1, string> messageGetter, TArg0 arg0, TArg1 arg1, LogLevel logLevel)
        {
            var logMessage = s_pool.Allocate();
            logMessage._messageGetter = messageGetter;
            logMessage._arg0 = arg0;
            logMessage._arg1 = arg1;
            logMessage.LogLevel = logLevel;
 
            return logMessage;
        }
 
        protected override string CreateMessage()
            => _messageGetter!(_arg0!, _arg1!);
 
        protected override void FreeCore()
        {
            if (_messageGetter == null)
            {
                return;
            }
 
            _messageGetter = null;
            _arg0 = default;
            _arg1 = default;
            s_pool.Free(this);
        }
    }
 
    private sealed class LazyLogMessage<TArg0, TArg1, TArg2> : LogMessage
    {
        private static readonly ObjectPool<LazyLogMessage<TArg0, TArg1, TArg2>> s_pool = SharedPools.Default<LazyLogMessage<TArg0, TArg1, TArg2>>();
 
        private Func<TArg0, TArg1, TArg2, string>? _messageGetter;
        private TArg0? _arg0;
        private TArg1? _arg1;
        private TArg2? _arg2;
 
        public static LogMessage Construct(Func<TArg0, TArg1, TArg2, string> messageGetter, TArg0 arg0, TArg1 arg1, TArg2 arg2, LogLevel logLevel)
        {
            var logMessage = s_pool.Allocate();
            logMessage._messageGetter = messageGetter;
            logMessage._arg0 = arg0;
            logMessage._arg1 = arg1;
            logMessage._arg2 = arg2;
            logMessage.LogLevel = logLevel;
 
            return logMessage;
        }
 
        protected override string CreateMessage()
            => _messageGetter!(_arg0!, _arg1!, _arg2!);
 
        protected override void FreeCore()
        {
            if (_messageGetter == null)
            {
                return;
            }
 
            _messageGetter = null;
            _arg0 = default;
            _arg1 = default;
            _arg2 = default;
            s_pool.Free(this);
        }
    }
 
    private sealed class LazyLogMessage<TArg0, TArg1, TArg2, TArg3> : LogMessage
    {
        private static readonly ObjectPool<LazyLogMessage<TArg0, TArg1, TArg2, TArg3>> s_pool = SharedPools.Default<LazyLogMessage<TArg0, TArg1, TArg2, TArg3>>();
 
        private Func<TArg0, TArg1, TArg2, TArg3, string>? _messageGetter;
        private TArg0? _arg0;
        private TArg1? _arg1;
        private TArg2? _arg2;
        private TArg3? _arg3;
 
        public static LogMessage Construct(Func<TArg0, TArg1, TArg2, TArg3, string> messageGetter, TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3, LogLevel logLevel)
        {
            var logMessage = s_pool.Allocate();
            logMessage._messageGetter = messageGetter;
            logMessage._arg0 = arg0;
            logMessage._arg1 = arg1;
            logMessage._arg2 = arg2;
            logMessage._arg3 = arg3;
            logMessage.LogLevel = logLevel;
 
            return logMessage;
        }
 
        protected override string CreateMessage()
            => _messageGetter!(_arg0!, _arg1!, _arg2!, _arg3!);
 
        protected override void FreeCore()
        {
            if (_messageGetter == null)
            {
                return;
            }
 
            _messageGetter = null;
            _arg0 = default;
            _arg1 = default;
            _arg2 = default;
            _arg3 = default;
            s_pool.Free(this);
        }
    }
}