csharp/Abc-Arbitrage/ZeroLog/src/ZeroLog/LogEvent.cs

LogEvent.cs
using System;
using System.Diagnostics;
using System.Diagnostics.Codeastysis;
using System.Runtime.CompilerServices;
using System.Text.Formatting;
using System.Threading;
using InlineIL;
using ZeroLog.Appenders;
using ZeroLog.Utils;
using static InlineIL.IL.Emit;

namespace ZeroLog
{
    internal unsafe partial clast LogEvent : IInternalLogEvent
    {
        private const int _maxArgCapacity = byte.MaxValue;
        private string[] _strings;
        private IntPtr[] _argPointers;
        private Log _log;
        private LogEventArgumentExhaustionStrategy _argumentExhaustionStrategy;

        protected readonly byte* _startOfBuffer;
        protected readonly byte* _endOfBuffer;
        protected byte* _dataPointer;
        private byte _argCount;
        private bool _isTruncated;

        public LogEvent(BufferSegment bufferSegment, int argCapacity)
        {
            argCapacity = Math.Min(argCapacity, _maxArgCapacity);
            _argPointers = new IntPtr[argCapacity];
            _strings = new string[argCapacity];

            _startOfBuffer = bufferSegment.Data;
            _dataPointer = bufferSegment.Data;
            _endOfBuffer = bufferSegment.Data + bufferSegment.Length;
            _log = default!;
        }

        public Level Level { get; private set; }
        public DateTime Timestamp { get; private set; }
        public Thread? Thread { get; private set; }
        public string Name => _log.Name;
        public IAppender[] Appenders => _log.Appenders;
        public virtual bool IsPooled => true;

        public void Initialize(Level level, Log log, LogEventArgumentExhaustionStrategy argumentExhaustionStrategy)
        {
            Timestamp = SystemDateTime.UtcNow;
            Level = level;
            _log = log;
            _argCount = 0;
            _dataPointer = _startOfBuffer;
            _isTruncated = false;
            _argumentExhaustionStrategy = argumentExhaustionStrategy;
            Thread = Thread.CurrentThread;
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        private void AppendGenericSlow(T arg)
        {
            if (TypeUtilSlow.IsNullableEnum)
                AppendNullableEnumInternal(arg);
            else if (TypeUtilSlow.IsUnmanaged)
                AppendUnmanagedInternal(arg);
            else
                throw new NotSupportedException($"Type {typeof(T)} is not supported ");
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void AppendFormat(string format)
        {
            if (!PrepareAppend(sizeof(ArgumentType) + sizeof(byte) + sizeof(byte), 1))
                return;

            AppendArgumentType(ArgumentType.FormatString);
            AppendString(format);
            AppendByte(_argCount);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public ILogEvent Append(string? s)
        {
            if (!PrepareAppend(sizeof(ArgumentType) + sizeof(byte), 1))
                return this;

            if (s == null)
            {
                AppendArgumentType(ArgumentType.Null);
                return this;
            }

            AppendArgumentType(ArgumentType.String);
            AppendString(s);
            return this;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public ILogEvent AppendKeyValue(string key, string? value)
        {
            if (!PrepareAppend(sizeof(ArgumentType) + sizeof(byte) + sizeof(ArgumentType) + sizeof(byte), 2))
                return this;

            AppendArgumentType(ArgumentType.KeyString);
            AppendString(key);

            if (value == null)
            {
                AppendArgumentType(ArgumentType.Null);
                return this;
            }

            AppendArgumentType(ArgumentType.String);
            AppendString(value);
            return this;
        }

        public ILogEvent AppendKeyValue(string key, T value)
            where T : struct, Enum
        {
            if (!PrepareAppend(sizeof(ArgumentType) + sizeof(byte) + sizeof(ArgumentType) + sizeof(EnumArg), 2))
                return this;

            AppendArgumentType(ArgumentType.KeyString);
            AppendString(key);

            AppendArgumentType(ArgumentType.Enum);
            *(EnumArg*)_dataPointer = new EnumArg(TypeUtil.TypeHandle, EnumCache.ToUInt64(value));
            _dataPointer += sizeof(EnumArg);
            return this;
        }

        public ILogEvent AppendKeyValue(string key, T? value)
            where T : struct, Enum
        {
            if (!PrepareAppend(sizeof(ArgumentType) + sizeof(byte) + sizeof(ArgumentType) + sizeof(EnumArg), 2))
                return this;

            AppendArgumentType(ArgumentType.KeyString);
            AppendString(key);

            if (value == null)
            {
                AppendArgumentType(ArgumentType.Null);
                return this;
            }

            AppendArgumentType(ArgumentType.Enum);
            *(EnumArg*)_dataPointer = new EnumArg(TypeUtil.TypeHandle, EnumCache.ToUInt64(value.GetValueOrDefault()));
            _dataPointer += sizeof(EnumArg);
            return this;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public ILogEvent AppendKeyValueAscii(string key, byte[]? bytes, int length)
        {
            if (length < 0 || !PrepareAppend(sizeof(ArgumentType) + sizeof(byte) + sizeof(ArgumentType) + sizeof(int) + length, 2))
                return this;

            AppendArgumentType(ArgumentType.KeyString);
            AppendString(key);

            if (bytes is null)
            {
                AppendArgumentType(ArgumentType.Null);
                return this;
            }

            AppendArgumentType(ArgumentType.AsciiString);
            AppendInt32(length);

            if (length != 0)
                AppendBytes(bytes, length);

            return this;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public ILogEvent AppendKeyValueAscii(string key, byte* bytes, int length)
        {
            if (length < 0 || !PrepareAppend(sizeof(ArgumentType) + sizeof(byte) + sizeof(ArgumentType) + sizeof(int) + length, 2))
                return this;

            AppendArgumentType(ArgumentType.KeyString);
            AppendString(key);

            if (bytes == null)
            {
                AppendArgumentType(ArgumentType.Null);
                return this;
            }

            AppendArgumentType(ArgumentType.AsciiString);
            AppendInt32(length);
            AppendBytes(bytes, length);
            return this;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public ILogEvent AppendKeyValueAscii(string key, ReadOnlySpan bytes)
        {
            var length = bytes.Length;
            if (!PrepareAppend(sizeof(ArgumentType) + sizeof(byte) + sizeof(ArgumentType) + sizeof(int) + length, 2))
                return this;

            AppendArgumentType(ArgumentType.KeyString);
            AppendString(key);

            AppendArgumentType(ArgumentType.AsciiString);
            AppendInt32(length);
            AppendBytes(bytes);
            return this;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public ILogEvent AppendKeyValueAscii(string key, ReadOnlySpan chars)
        {
            var length = chars.Length;
            if (!PrepareAppend(sizeof(ArgumentType) + sizeof(byte) + sizeof(ArgumentType) + sizeof(int) + length, 2))
                return this;

            AppendArgumentType(ArgumentType.KeyString);
            AppendString(key);

            AppendArgumentType(ArgumentType.AsciiString);
            AppendInt32(length);

            foreach (var c in chars)
                *_dataPointer++ = (byte)c;

            return this;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public ILogEvent AppendAsciiString(byte[]? bytes, int length)
        {
            if (bytes == null)
            {
                if (PrepareAppend(sizeof(ArgumentType), 1))
                    AppendArgumentType(ArgumentType.Null);

                return this;
            }

            var remainingBytes = (int)(_endOfBuffer - _dataPointer);
            remainingBytes -= sizeof(ArgumentType) + sizeof(int);

            if (length > remainingBytes)
            {
                _isTruncated = true;
                length = remainingBytes;
            }

            if (length  remainingBytes)
            {
                _isTruncated = true;
                length = remainingBytes;
            }

            if (length  remainingBytes)
            {
                _isTruncated = true;
                length = remainingBytes;
            }

            if (length  remainingBytes)
            {
                _isTruncated = true;
                length = remainingBytes;
            }

            if (length