<commit_before>﻿
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using ScriptEngine.HostedScript.Library.Binary;
using ScriptEngine.Machine;
using ScriptEngine.Machine.Contexts;



/// <summary>
/// 
/// Коллекция байтов фиксированного размера с возможностью произвольного доступа и изменения по месту.
/// Размер буфера формально не ограничен, но поскольку все данные буфера полностью находятся в оперативной памяти, при попытке создать буфер слишком большого размера доступной памяти может оказаться недостаточно, в результате чего будет вызвано исключение. Поэтому при работе с буферами двоичных данных необходимо соотносить их размер с доступным объемом оперативной памяти.
/// При создании буфера можно указать порядок байтов, который будет использован для операций с целыми числами. При этом если буфер не создан явно, а получен с помощью вызова метода другого объекта, то порядок байтов в полученном буфере будет унаследован от порядка байтов, заданного для того объекта, метод которого вызывается.
/// Например, если буфер получен с помощью вызова метода ПрочитатьВБуферДвоичныхДанных, то порядок байтов в полученном буфере будет равен значению свойства ПорядокБайтов.
/// Возможен также более сложный случай наследования порядка байтов. Если буфер получен с помощью вызова метода ПолучитьБуферДвоичныхДанных, то порядок байтов у полученного буфера будет выбираться из объекта ЧтениеДанных, из которого был получен объект РезультатЧтенияДанных. 
/// Порядок байтов, заданный для объекта ЧтениеДанных, будет использован во всех объектах, полученных на его основании.
/// </summary>
[ContextClass("БуферДвоичныхДанных", "BinaryDataBuffer")]
public class BinaryDataBuffer : AutoContext<BinaryDataBuffer>, ICollectionContext
{
    private bool _readOnly;
    private Stream _readWriteStream;

    private readonly byte[] _buffer;

    public BinaryDataBuffer(byte[] buffer, ByteOrderEnum byteOrder = ByteOrderEnum.LittleEndian)
    {
        _buffer = buffer;
        ByteOrder = byteOrder;
        Converter = new EndianBitConverter();
        Converter.IsLittleEndian = byteOrder == ByteOrderEnum.LittleEndian;
    }

    private EndianBitConverter Converter { get; set; }

    /// <param name="size">
    /// Размер буфера в байтах. </param>
    /// <param name="byteOrder">
    /// Порядок байтов.
    /// Значение по умолчанию: LittleEndian. </param>
    ///
    [ScriptConstructor]
    public static BinaryDataBuffer Constructor(long size, ByteOrderEnum byteOrder = ByteOrderEnum.LittleEndian)
    {
        return new BinaryDataBuffer(new byte[size], byteOrder);
    }

    public override IValue GetIndexedValue(IValue index)
    {
        return ValueFactory.Create(Get((int) index.AsNumber()));
    }

    public override void SetIndexedValue(IValue index, IValue val)
    {
        if (_readOnly)
            throw new RuntimeException("Буфер находится в режиме \"Только чтение\"");

        var idx = (int)index.AsNumber();
        _buffer[idx] = (byte)val.AsNumber();
    }

    /// <summary>
    /// 
    /// Текущий порядок байтов. Влияет на операции чтения и записи целых чисел в буфер.
    /// </summary>
    /// <value>ПорядокБайтов (ByteOrder)</value>
    [ContextProperty("ПорядокБайтов", "ByteOrder")]
    public ByteOrderEnum ByteOrder { get; set; }

    /// <summary>
    /// 
    /// Размер буфера в байтах.
    /// </summary>
    /// <value>Число (Number)</value>
    [ContextProperty("Размер", "Size")]
    public long Size => _buffer.LongLength;

    /// <summary>
    /// 
    /// Значение Истина указывает, что данный буфер предназначен только для чтения.
    /// </summary>
    /// <value>Булево (Boolean)</value>
    [ContextProperty("ТолькоЧтение", "ReadOnly")]
    public bool ReadOnly
    {
        get { return _readOnly; }

    }

    /// <summary>
    /// 
    /// Заменить значения, начиная с заданной позиции, значениями из заданного буфера.
    /// </summary>
    ///
    /// <param name="position">
    /// Позиция, начиная с которой требуется записать содержимое буфера. </param>
    /// <param name="bytes">
    /// Байты, которыми нужно заполнить часть буфера. </param>
    /// <param name="number">
    /// Количество байт, которые требуется заменить. </param>
    ///
    [ContextMethod("Записать", "Write")]
    public void Write(long position, BinaryDataBuffer bytes, long number = 0)
    {
        Array.Copy(bytes._buffer, _buffer, number);
    }

    private byte[] GetBytes<T>(Converter<T, byte[]> converterOverload, T value, IValue byteOrder = null)
    {
        byte[] bytes;
        if (byteOrder == null)
            bytes = converterOverload(value);
        else
        {
            try
            {
                var order = (ByteOrderEnum)(object)byteOrder.GetRawValue();
                Converter.IsLittleEndian = order == ByteOrderEnum.LittleEndian;
                bytes = converterOverload(value);
            }
            catch (InvalidCastException)
            {
                throw RuntimeException.InvalidArgumentType();
            }
        }

        return bytes;
    }

    private void CopyBytes(int position, byte[] bytes)
    {
        for (int i = 0; i < bytes.Length; i++)
        {
            _buffer[position + i] = bytes[i];
        }
    }

    /// <summary>
    /// 
    /// Записать целое 16-битное положительное число в заданную позицию.
    /// </summary>
    ///
    /// <param name="position">
    /// Позиция, на которой требуется записать число. </param>
    /// <param name="value">
    /// Число, которое требуется записать.
    /// Если значение не помещается в 16 бит, будет вызвано исключение. </param>
    /// <param name="byteOrder">
    /// Порядок байтов, который будет использован для кодировки числа при записи в буфер. Если не установлен, то будет использован порядок байтов, заданный для текущего экземпляра БуферДвоичныхДанных.
    /// Значение по умолчанию: Неопределено. </param>
    ///
    ///
    [ContextMethod("ЗаписатьЦелое16", "WriteInt16")]
    public void WriteInt16(int position, short value, IValue byteOrder = null)
    {
        var bytes = GetBytes(Converter.GetBytes, value, byteOrder);
        CopyBytes(position, bytes);
    }

    /// <summary>
    /// 
    /// Записать целое 32-битное положительное число в заданную позицию.
    /// </summary>
    ///
    /// <param name="position">
    /// Позиция, на которой требуется записать число. </param>
    /// <param name="value">
    /// Число, которое требуется записать.
    /// Если значение не помещается в 32 бита, будет вызван исключение. </param>
    /// <param name="byteOrder">
    /// Порядок байтов, который будет использован для кодировки числа при записи в буфер. Если не установлен, то будет использован порядок байтов, заданный для текущего экземпляра БуферДвоичныхДанных.
    /// Значение по умолчанию: Неопределено. </param>
    [ContextMethod("ЗаписатьЦелое32", "WriteInt32")]
    public void WriteInt32(int position, int value, IValue byteOrder = null)
    {
        var bytes = GetBytes(Converter.GetBytes, value, byteOrder);
        CopyBytes(position, bytes);
    }


    /// <summary>
    /// 
    /// Записать целое 64-битное положительное число в заданную позицию.
    /// </summary>
    ///
    /// <param name="position">
    /// Позиция, на которой требуется записать число. </param>
    /// <param name="value">
    /// Число, которое требуется записать.
    /// Если значение не помещается в 64 бита, будет вызвано исключение. </param>
    /// <param name="byteOrder">
    /// Порядок байтов, который будет использован для кодировки числа при записи в буфер. Если не установлен, то используется порядок байтов, заданный для текущего экземпляра БуферДвоичныхДанных.
    /// Значение по умолчанию: Неопределено. </param>

    ///

    ///
    [ContextMethod("ЗаписатьЦелое64", "WriteInt64")]
    public void WriteInt64(int position, long value, IValue byteOrder = null)
    {
        var bytes = GetBytes(Converter.GetBytes, value, byteOrder);
        CopyBytes(position, bytes);
    }


    /// <summary>
    /// 
    /// Создает новый буфер, содержащий элементы текущего буфера в противоположном порядке.
    /// </summary>
    ///
    ///
    /// <returns name="BinaryDataBuffer">
    /// Коллекция байтов фиксированного размера с возможностью произвольного доступа и изменения по месту.
    /// Размер буфера формально не ограничен, но поскольку все данные буфера полностью находятся в оперативной памяти, при попытке создать буфер слишком большого размера доступной памяти может оказаться недостаточно, в результате чего будет вызвано исключение. Поэтому при работе с буферами двоичных данных необходимо соотносить их размер с доступным объемом оперативной памяти.
    /// При создании буфера можно указать порядок байтов, который будет использован для операций с целыми числами. При этом если буфер не создан явно, а получен с помощью вызова метода другого объекта, то порядок байтов в полученном буфере будет унаследован от порядка байтов, заданного для того объекта, метод которого вызывается.
    /// Например, если буфер получен с помощью вызова метода ПрочитатьВБуферДвоичныхДанных, то порядок байтов в полученном буфере будет равен значению свойства ПорядокБайтов.
    /// Возможен также более сложный случай наследования порядка байтов. Если буфер получен с помощью вызова метода ПолучитьБуферДвоичныхДанных, то порядок байтов у полученного буфера будет выбираться из объекта ЧтениеДанных, из которого был получен объект РезультатЧтенияДанных. 
    /// Порядок байтов, заданный для объекта ЧтениеДанных, будет использован во всех объектах, полученных на его основании.</returns>

    ///
    [ContextMethod("Перевернуть", "Reverse")]
    public BinaryDataBuffer Reverse()<commit_msg>Правки методов Буфера<commit_after>﻿
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using ScriptEngine.HostedScript.Library.Binary;
using ScriptEngine.Machine;
using ScriptEngine.Machine.Contexts;



/// <summary>
/// 
/// Коллекция байтов фиксированного размера с возможностью произвольного доступа и изменения по месту.
/// Размер буфера формально не ограничен, но поскольку все данные буфера полностью находятся в оперативной памяти, при попытке создать буфер слишком большого размера доступной памяти может оказаться недостаточно, в результате чего будет вызвано исключение. Поэтому при работе с буферами двоичных данных необходимо соотносить их размер с доступным объемом оперативной памяти.
/// При создании буфера можно указать порядок байтов, который будет использован для операций с целыми числами. При этом если буфер не создан явно, а получен с помощью вызова метода другого объекта, то порядок байтов в полученном буфере будет унаследован от порядка байтов, заданного для того объекта, метод которого вызывается.
/// Например, если буфер получен с помощью вызова метода ПрочитатьВБуферДвоичныхДанных, то порядок байтов в полученном буфере будет равен значению свойства ПорядокБайтов.
/// Возможен также более сложный случай наследования порядка байтов. Если буфер получен с помощью вызова метода ПолучитьБуферДвоичныхДанных, то порядок байтов у полученного буфера будет выбираться из объекта ЧтениеДанных, из которого был получен объект РезультатЧтенияДанных. 
/// Порядок байтов, заданный для объекта ЧтениеДанных, будет использован во всех объектах, полученных на его основании.
/// </summary>
[ContextClass("БуферДвоичныхДанных", "BinaryDataBuffer")]
public class BinaryDataBuffer : AutoContext<BinaryDataBuffer>, ICollectionContext
{
    private bool _readOnly;
    private Stream _readWriteStream;

    private readonly byte[] _buffer;

    public BinaryDataBuffer(byte[] buffer, ByteOrderEnum byteOrder = ByteOrderEnum.LittleEndian)
    {
        _buffer = buffer;
        ByteOrder = byteOrder;
        Converter = new EndianBitConverter();
        Converter.IsLittleEndian = byteOrder == ByteOrderEnum.LittleEndian;
    }

    private EndianBitConverter Converter { get; set; }

    /// <param name="size">
    /// Размер буфера в байтах. </param>
    /// <param name="byteOrder">
    /// Порядок байтов.
    /// Значение по умолчанию: LittleEndian. </param>
    ///
    [ScriptConstructor]
    public static BinaryDataBuffer Constructor(long size, ByteOrderEnum byteOrder = ByteOrderEnum.LittleEndian)
    {
        return new BinaryDataBuffer(new byte[size], byteOrder);
    }

    public override IValue GetIndexedValue(IValue index)
    {
        return ValueFactory.Create(Get((int) index.AsNumber()));
    }

    public override void SetIndexedValue(IValue index, IValue val)
    {
        if (_readOnly)
            throw new RuntimeException("Буфер находится в режиме \"Только чтение\"");

        int value = (int)val.AsNumber();
        if (value < byte.MinValue || value > byte.MaxValue)
            throw RuntimeException.InvalidArgumentValue();

        var idx = (int)index.AsNumber();
        _buffer[idx] = (byte) value;
    }

    /// <summary>
    /// 
    /// Текущий порядок байтов. Влияет на операции чтения и записи целых чисел в буфер.
    /// </summary>
    /// <value>ПорядокБайтов (ByteOrder)</value>
    [ContextProperty("ПорядокБайтов", "ByteOrder")]
    public ByteOrderEnum ByteOrder { get; set; }

    /// <summary>
    /// 
    /// Размер буфера в байтах.
    /// </summary>
    /// <value>Число (Number)</value>
    [ContextProperty("Размер", "Size")]
    public long Size => _buffer.LongLength;

    /// <summary>
    /// 
    /// Значение Истина указывает, что данный буфер предназначен только для чтения.
    /// </summary>
    /// <value>Булево (Boolean)</value>
    [ContextProperty("ТолькоЧтение", "ReadOnly")]
    public bool ReadOnly
    {
        get { return _readOnly; }

    }

    /// <summary>
    /// 
    /// Заменить значения, начиная с заданной позиции, значениями из заданного буфера.
    /// </summary>
    ///
    /// <param name="position">
    /// Позиция, начиная с которой требуется записать содержимое буфера. </param>
    /// <param name="bytes">
    /// Байты, которыми нужно заполнить часть буфера. </param>
    /// <param name="number">
    /// Количество байт, которые требуется заменить. </param>
    ///
    [ContextMethod("Записать", "Write")]
    public void Write(long position, BinaryDataBuffer bytes, long number = 0)
    {
        if (_readOnly)
            throw new RuntimeException("Буфер находится в режиме \"Только чтение\"");

        Array.Copy(bytes._buffer, _buffer, number);
    }

    private byte[] GetBytes<T>(Converter<T, byte[]> converterOverload, T value, IValue byteOrder = null)
    {
        byte[] bytes;
        if (byteOrder == null)
            bytes = converterOverload(value);
        else
        {
            try
            {
                var order = (ByteOrderEnum)(object)byteOrder.GetRawValue();
                Converter.IsLittleEndian = order == ByteOrderEnum.LittleEndian;
                bytes = converterOverload(value);
            }
            catch (InvalidCastException)
            {
                throw RuntimeException.InvalidArgumentType();
            }
        }

        return bytes;
    }

    private void CopyBytes(int position, byte[] bytes)
    {
        for (int i = 0; i < bytes.Length; i++)
        {
            _buffer[position + i] = bytes[i];
        }
    }

    /// <summary>
    /// 
    /// Записать целое 16-битное положительное число в заданную позицию.
    /// </summary>
    ///
    /// <param name="position">
    /// Позиция, на которой требуется записать число. </param>
    /// <param name="value">
    /// Число, которое требуется записать.
    /// Если значение не помещается в 16 бит, будет вызвано исключение. </param>
    /// <param name="byteOrder">
    /// Порядок байтов, который будет использован для кодировки числа при записи в буфер. Если не установлен, то будет использован порядок байтов, заданный для текущего экземпляра БуферДвоичныхДанных.
    /// Значение по умолчанию: Неопределено. </param>
    ///
    ///
    [ContextMethod("ЗаписатьЦелое16", "WriteInt16")]
    public void WriteInt16(int position, short value, IValue byteOrder = null)
    {
        if (_readOnly)
            throw new RuntimeException("Буфер находится в режиме \"Только чтение\"");

        var bytes = GetBytes(Converter.GetBytes, value, byteOrder);
        CopyBytes(position, bytes);
    }

    /// <summary>
    /// 
    /// Записать целое 32-битное положительное число в заданную позицию.
    /// </summary>
    ///
    /// <param name="position">
    /// Позиция, на которой требуется записать число. </param>
    /// <param name="value">
    /// Число, которое требуется записать.
    /// Если значение не помещается в 32 бита, будет вызван исключение. </param>
    /// <param name="byteOrder">
    /// Порядок байтов, который будет использован для кодировки числа при записи в буфер. Если не установлен, то будет использован порядок байтов, заданный для текущего экземпляра БуферДвоичныхДанных.
    /// Значение по умолчанию: Неопределено. </param>
    [ContextMethod("ЗаписатьЦелое32", "WriteInt32")]
    public void WriteInt32(int position, int value, IValue byteOrder = null)
    {
        if (_readOnly)
            throw new RuntimeException("Буфер находится в режиме \"Только чтение\"");

        var bytes = GetBytes(Converter.GetBytes, value, byteOrder);
        CopyBytes(position, bytes);
    }


    /// <summary>
    /// 
    /// Записать целое 64-битное положительное число в заданную позицию.
    /// </summary>
    ///
    /// <param name="position">
    /// Позиция, на которой требуется записать число. </param>
    /// <param name="value">
    /// Число, которое требуется записать.
    /// Если значение не помещается в 64 бита, будет вызвано исключение. </param>
    /// <param name="byteOrder">
    /// Порядок байтов, который будет использован для кодировки числа при записи в буфер. Если не установлен, то используется порядок байтов, заданный для текущего экземпляра БуферДвоичныхДанных.
    /// Значение по умолчанию: Неопределено. </param>

    ///

    ///
    [ContextMethod("ЗаписатьЦелое64", "WriteInt64")]
    public void WriteInt64(int position, long value, IValue byteOrder = null)
    {
        if (_readOnly)
            throw new RuntimeException("Буфер находится в режиме \"Только чтение\"");

        var bytes = GetBytes(Converter.GetBytes, value, byteOrder);
        CopyBytes(position, bytes);
    }


    /// <summary>
    /// 
    /// Создает новый буфер, содержащий элементы текущего буфера в противоположном порядке.
    /// </summary>
    ///
    ///
    /// <returns name="BinaryDataBuffer">
    /// Коллекция байтов фиксированного размера с возможностью произвольного доступа и изменения по месту.
    /// Размер буфера формально не ограничен, но поскольку все данные буфера полностью находятся в оперативной памяти, при попытке создать буфер слишком большого размера доступной памяти может оказаться недостаточно, в результате чего будет вызвано исключение. Поэтому при работе с буферами двоичных данных необходимо соотносить их размер с доступным объемом оперативной памяти.
    /// При создании буфера можно указать порядок байтов, который будет использован для операций с целыми числами. При этом если буфер не создан явно, а получен с помощью вызова метода другого объекта, то порядок байтов в полученном буфере будет унаследован от порядка байтов, заданного для того объекта, метод которого вызывается.
    /// Например, если буфер получен с помощью вызова метода ПрочитатьВБуферДвоичныхДанных, то порядок байтов в полученном буфере будет равен значению свойства ПорядокБайтов.
    /// Возможен также более сложный случай наследования порядка байтов. Если буфер получен с помощью вызова метода ПолучитьБуферДвоичныхДанных, то порядок байтов у полученного буфера будет выбираться из объекта ЧтениеДанных, из которого был получен объект РезультатЧтенияДанных. 
    /// Порядок байтов, заданный для объекта ЧтениеДанных, будет использован во всех объектах, полученных на его основании.</returns>

    ///
    [ContextMethod("Перевернуть", "Reverse")]
    public BinaryDataBuffer Reverse()
{'fraction_non_alphanumeric': 0.09893008210997761, 'fraction_numerical': 0.0031848718586713113, 'mean_word_length': 2.9450333725952103, 'pattern_counts': {'":': 0, '<': 120, '<?xml version=': 0, '>': 120, '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': '5395573', 'n_tokens_mistral': 6962, 'n_tokens_neox': 7803, 'n_words': 1868}