<commit_before>using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Semmle.Extraction
{
    /// <summary>
    /// A `TextWriter` object that wraps another `TextWriter` object, and which
    /// HTML escapes the characters `&`, `{`, `}`, `"`, `@`, and `#`, before
    /// writing to the underlying object.
    /// </summary>
    public class EscapingTextWriter : TextWriter
    {
        private readonly TextWriter wrapped;
        private readonly bool disposeUnderlying;

        public EscapingTextWriter(TextWriter wrapped, bool disposeUnderlying = false)
        {
            this.wrapped = wrapped;
            this.disposeUnderlying = disposeUnderlying;
        }

        /// <summary>
        /// Creates a new instance with a new underlying `StringWriter` object. The
        /// underlying object is disposed of when this object is.
        /// </summary>
        public EscapingTextWriter() : this(new StringWriter(), true) { }

        public EscapingTextWriter(IFormatProvider? formatProvider) : base(formatProvider)
            => throw new NotImplementedException();

        private void WriteEscaped(char c)
        {
            switch (c)
            {
                case '&':
                    wrapped.Write("&amp;");
                    break;
                case '{':
                    wrapped.Write("&lbrace;");
                    break;
                case '}':
                    wrapped.Write("&rbrace;");
                    break;
                case '"':
                    wrapped.Write("&quot;");
                    break;
                case '@':
                    wrapped.Write("&commat;");
                    break;
                case '#':
                    wrapped.Write("&num;");
                    break;
                default:
                    wrapped.Write(c);
                    break;
            };
        }

        public void WriteSubId(IEntity entity)
        {
            if (entity is null)
            {
                wrapped.Write("<null>");
                return;
            }

            WriteUnescaped('{');
            wrapped.WriteLabel(entity);
            WriteUnescaped('}');
        }

        public void WriteUnescaped(char c)
            => wrapped.Write(c);

        public void WriteUnescaped(string s)
            => wrapped.Write(s);

        #region overrides

        public override Encoding Encoding => wrapped.Encoding;

        public override IFormatProvider FormatProvider => wrapped.FormatProvider;

        public override string NewLine { get => wrapped.NewLine; }

        public override void Close()
            => throw new NotImplementedException();

        public override ValueTask DisposeAsync()
            => throw new NotImplementedException();

        public override bool Equals(object? obj)
            => wrapped.Equals(obj);

        public override void Flush()
            => wrapped.Flush();

        public override Task FlushAsync()
            => wrapped.FlushAsync();

        public override int GetHashCode()
            => wrapped.GetHashCode();

        public override string ToString()
            => wrapped.ToString() ?? "";

        public override void Write(bool value)
            => wrapped.Write(value);

        public override void Write(char value)
            => WriteEscaped(value);

        public override void Write(char[]? buffer)
        {
            if (buffer is null)
                return;
            Write(buffer, 0, buffer.Length);
        }

        public override void Write(char[] buffer, int index, int count)
        {
            for (var i = index; i < buffer.Length && i < index + count; i++)
            {
                WriteEscaped(buffer[i]);
            }
        }


        public override void Write(decimal value)
            => wrapped.Write(value);<commit_msg>C#: Fix `GetHashCode/Equals` on `EscapingTextWriter`<commit_after>using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Semmle.Extraction
{
    /// <summary>
    /// A `TextWriter` object that wraps another `TextWriter` object, and which
    /// HTML escapes the characters `&`, `{`, `}`, `"`, `@`, and `#`, before
    /// writing to the underlying object.
    /// </summary>
    public sealed class EscapingTextWriter : TextWriter
    {
        private readonly TextWriter wrapped;
        private readonly bool disposeUnderlying;

        public EscapingTextWriter(TextWriter wrapped, bool disposeUnderlying = false)
        {
            this.wrapped = wrapped;
            this.disposeUnderlying = disposeUnderlying;
        }

        /// <summary>
        /// Creates a new instance with a new underlying `StringWriter` object. The
        /// underlying object is disposed of when this object is.
        /// </summary>
        public EscapingTextWriter() : this(new StringWriter(), true) { }

        public EscapingTextWriter(IFormatProvider? formatProvider) : base(formatProvider)
            => throw new NotImplementedException();

        private void WriteEscaped(char c)
        {
            switch (c)
            {
                case '&':
                    wrapped.Write("&amp;");
                    break;
                case '{':
                    wrapped.Write("&lbrace;");
                    break;
                case '}':
                    wrapped.Write("&rbrace;");
                    break;
                case '"':
                    wrapped.Write("&quot;");
                    break;
                case '@':
                    wrapped.Write("&commat;");
                    break;
                case '#':
                    wrapped.Write("&num;");
                    break;
                default:
                    wrapped.Write(c);
                    break;
            };
        }

        public void WriteSubId(IEntity entity)
        {
            if (entity is null)
            {
                wrapped.Write("<null>");
                return;
            }

            WriteUnescaped('{');
            wrapped.WriteLabel(entity);
            WriteUnescaped('}');
        }

        public void WriteUnescaped(char c)
            => wrapped.Write(c);

        public void WriteUnescaped(string s)
            => wrapped.Write(s);

        #region overrides

        public override Encoding Encoding => wrapped.Encoding;

        public override IFormatProvider FormatProvider => wrapped.FormatProvider;

        public override string NewLine { get => wrapped.NewLine; }

        public override void Close()
            => throw new NotImplementedException();

        public override ValueTask DisposeAsync()
            => throw new NotImplementedException();

        public override bool Equals(object? obj)
            => wrapped.Equals(obj) && obj is EscapingTextWriter other && disposeUnderlying == other.disposeUnderlying;

        public override void Flush()
            => wrapped.Flush();

        public override Task FlushAsync()
            => wrapped.FlushAsync();

        public override int GetHashCode()
            => HashCode.Combine(wrapped, disposeUnderlying);

        public override string ToString()
            => wrapped.ToString() ?? "";

        public override void Write(bool value)
            => wrapped.Write(value);

        public override void Write(char value)
            => WriteEscaped(value);

        public override void Write(char[]? buffer)
        {
            if (buffer is null)
                return;
            Write(buffer, 0, buffer.Length);
        }

        public override void Write(char[] buffer, int index, int count)
        {
            for (var i = index; i < buffer.Length && i < index + count; i++)
            {
                WriteEscaped(buffer[i]);
            }
        }


        public override void Write(decimal value)
            => wrapped.Write(value);
{'fraction_non_alphanumeric': 0.10360811826609873, 'fraction_numerical': 0.00025056376847907793, 'mean_word_length': 1.553742802303263, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7484083', 'n_tokens_mistral': 1987, 'n_tokens_neox': 1872, 'n_words': 511}