Skip to content

Commit

Permalink
Merge pull request #1363 from EvilBeaver/feature/buffer-split
Browse files Browse the repository at this point in the history
БуферДвоичныхДанных.Разделить() Для 1.8
  • Loading branch information
EvilBeaver authored Oct 21, 2023
2 parents 37d377c + 9a8ed3d commit 6a775b4
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 16 deletions.
122 changes: 106 additions & 16 deletions src/ScriptEngine.HostedScript/Library/Binary/BinaryDataBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,7 @@ public override void SetIndexedValue(IValue index, IValue val)
/// </summary>
/// <value>Булево (Boolean)</value>
[ContextProperty("ТолькоЧтение", "ReadOnly")]
public bool ReadOnly
{
get { return _readOnly; }

}
public bool ReadOnly => _readOnly;

/// <summary>
///
Expand Down Expand Up @@ -521,27 +517,121 @@ public ulong ReadInt64(int position, IValue byteOrder = null)


/// <summary>
/// Разделить буфер на части по заданному разделителю.
///
/// НЕ РЕАЛИЗОВАН
/// Разделить буфер на части по заданному разделителю или массиву разделителей.
/// </summary>
///
/// <remarks>
///
/// По двоичному буферу
/// </remarks>
///
/// <param name="separator">
/// Разделитель. </param>
///
/// <returns name="Array"/>
/// <returns name="Array">Массив из буферов двоичных данных</returns>
///
[ContextMethod("Разделить", "Split")]
public IValue Split(IValue separator)
public ArrayImpl Split(IValue separator)
{
throw new NotImplementedException();
var buffers = ParseParam(separator);

// Функция поиска требует, чтобы буферы были в порядке убывания размера
buffers.Sort((a, b) => b._buffer.LongLength.CompareTo(a._buffer.LongLength));
return SplitBuffer(buffers.ToArray());
}

private static List<BinaryDataBuffer> ParseParam(IValue separator)
{
var rawSeparator = separator?.GetRawValue();
switch (rawSeparator)
{
case BinaryDataBuffer buffer:
return new List<BinaryDataBuffer> { CheckedBuffer(buffer) };

case ArrayImpl array:
{
var buffers = new List<BinaryDataBuffer>();

foreach (var element in array)
{
buffers.AddRange(ParseParam(element));
}

return buffers;
}

default:
throw RuntimeException.InvalidArgumentType();
}
}

private static BinaryDataBuffer CheckedBuffer(BinaryDataBuffer buffer)
{
if (buffer.Size == 0)
{
throw RuntimeException.InvalidArgumentValue();
}

return buffer;
}

private ArrayImpl SplitBuffer(BinaryDataBuffer[] splitter)
{
var result = new List<BinaryDataBuffer>();
long start = 0;
var foundPosition = FindFirst(splitter, start);
while (foundPosition.pos != -1)
{
var length = foundPosition.pos - start;
result.Add(new BinaryDataBuffer(Copy(start, length), ByteOrder));
start = foundPosition.pos + foundPosition.buffer.Size;
foundPosition = FindFirst(splitter, start);
}

// хвостовой элемент
result.Add(new BinaryDataBuffer(Copy(start, _buffer.LongLength - start)));
return new ArrayImpl(result);
}

/// <summary>
/// Ищет ближайшее вхождение любого из буферов. Если на одной позиции находятся два и более буфера, берется бОльший.
/// </summary>
/// <param name="buffers">Массив искомых буферов</param>
/// <param name="start">Начальная позиция поиска</param>
/// <returns>Буфер и позиция или null, если нет вхождений</returns>
private (BinaryDataBuffer buffer, long pos) FindFirst(BinaryDataBuffer[] buffers, long start)
{
var maxI = Size - buffers[buffers.Length - 1].Size;
for (var i = start; i < maxI; i++)
{
foreach (var expectedBuffer in buffers)
{
if (SubsequenceEquals(_buffer, i, expectedBuffer._buffer))
{
return (expectedBuffer, i);
}
}
}

return (null, -1);
}

private byte[] Copy(long start, long length)
{
if (length == 0) return Array.Empty<byte>();
var partition = new byte[length];
Array.Copy(_buffer, start, partition, 0, length);
return partition;
}

private static bool SubsequenceEquals(byte[] sequence, long start, byte[] subsequence)
{
for (long j = 0; j < subsequence.LongLength; j++)
{
if (subsequence[j] != sequence[start + j])
{
return false;
}
}

return true;
}

/// <summary>
///
/// Создает копию массива.
Expand Down
58 changes: 58 additions & 0 deletions tests/binary-objects.os
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
ВсеТесты = Новый Массив;

ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоСоздаетсяБуферДвоичныхДанных");
ВсеТесты.Добавить("ТестДолжен_ПроверитьРазделениеБуфераДвоичныхДанныхНесколькимиБуферами");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоМожноЗаписатьБайты");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоМожноПрочитатьБайты");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоМожноЗаписатьПрочитатьЦелое16");
Expand All @@ -30,6 +31,8 @@
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоМетодОткрытьПотокДляЧтенияВозвращаетПотокТолькоДляЧтения");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоХешированиеРаботаетСПотоком");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоХешированиеРаботаетСДвоичнымиДанными");

ВсеТесты.Добавить("ТестДолжен_ПроверитьРазделениеБуфераДвоичныхДанныхОднимБуфером");

Возврат ВсеТесты;

Expand Down Expand Up @@ -351,3 +354,58 @@
НРег(ПолучитьHexСтрокуИзДвоичныхДанных(Хеширование.ХешСумма)));

КонецПроцедуры

Процедура ТестДолжен_ПроверитьРазделениеБуфераДвоичныхДанныхОднимБуфером() Экспорт

Подстроки = Новый Массив;
Подстроки.Добавить("Часть1");
Подстроки.Добавить("Часть2");
Подстроки.Добавить("Часть3");
РазделительТекстом = "123";

ТестовыйБуфер = ПолучитьБуферДвоичныхДанныхИзСтроки(СтрСоединить(Подстроки, РазделительТекстом));
Разделитель = ПолучитьБуферДвоичныхДанныхИзСтроки(РазделительТекстом);

РазделенныеДанные = ТестовыйБуфер.Разделить(Разделитель);

юТест.ПроверитьРавенство(РазделенныеДанные.Количество(), 3, "два разделителя - три элемента");

Для Инд = 0 По Подстроки.ВГраница() Цикл

СтрокаИзБуфера = ПолучитьСтрокуИзБуфераДвоичныхДанных(РазделенныеДанные[Инд]);
юТест.ПроверитьРавенство(СтрокаИзБуфера, Подстроки[Инд], "сравнение строк после разделения буфера");

КонецЦикла;

КонецПроцедуры

Процедура ТестДолжен_ПроверитьРазделениеБуфераДвоичныхДанныхНесколькимиБуферами() Экспорт

Подстроки = Новый Массив;
Подстроки.Добавить("Часть1");
Подстроки.Добавить("Часть2");
Подстроки.Добавить("Часть3");
Подстроки.Добавить("Часть4");
Подстроки.Добавить("Часть5");

ТестоваяСтрока = "Часть1\R\R\NЧасть2\R\NЧасть3\NЧасть4\RЧасть5";

ТестовыйБуфер = ПолучитьБуферДвоичныхДанныхИзСтроки(ТестоваяСтрока);
Разделители = Новый Массив;
Разделители.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("\N"));
Разделители.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("\R\N"));
Разделители.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("\R"));
Разделители.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("\R\R\N"));

РазделенныеДанные = ТестовыйБуфер.Разделить(Разделители);

юТест.ПроверитьРавенство(РазделенныеДанные.Количество(), 5);

Для Инд = 0 По РазделенныеДанные.ВГраница() Цикл

СтрокаИзБуфера = ПолучитьСтрокуИзБуфераДвоичныхДанных(РазделенныеДанные[Инд]);
юТест.ПроверитьРавенство(СтрокаИзБуфера, Подстроки[Инд], "сравнение строк после разделения буфера");

КонецЦикла;

КонецПроцедуры

0 comments on commit 6a775b4

Please sign in to comment.