Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

БуферДвоичныхДанных.Разделить() Для 1.8 #1363

Merged
merged 4 commits into from
Oct 21, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 107 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,122 @@ 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 != null)
{
var length = foundPosition.Item2 - start;
result.Add(new BinaryDataBuffer(Copy(start, length), ByteOrder));
start = foundPosition.Item2 + foundPosition.Item1.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 Tuple<BinaryDataBuffer, long> FindFirst(BinaryDataBuffer[] buffers, long start)
dmpas marked this conversation as resolved.
Show resolved Hide resolved
{
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))
{
var result = new Tuple<BinaryDataBuffer, long>(expectedBuffer, i);
dmpas marked this conversation as resolved.
Show resolved Hide resolved
return result;
}
}
}

return null;
}

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 По РазделенныеДанные.ВГраница() Цикл

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

КонецЦикла;

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