Skip to content

Commit 6a775b4

Browse files
authored
Merge pull request #1363 from EvilBeaver/feature/buffer-split
БуферДвоичныхДанных.Разделить() Для 1.8
2 parents 37d377c + 9a8ed3d commit 6a775b4

File tree

2 files changed

+164
-16
lines changed

2 files changed

+164
-16
lines changed

src/ScriptEngine.HostedScript/Library/Binary/BinaryDataBuffer.cs

Lines changed: 106 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,7 @@ public override void SetIndexedValue(IValue index, IValue val)
9797
/// </summary>
9898
/// <value>Булево (Boolean)</value>
9999
[ContextProperty("ТолькоЧтение", "ReadOnly")]
100-
public bool ReadOnly
101-
{
102-
get { return _readOnly; }
103-
104-
}
100+
public bool ReadOnly => _readOnly;
105101

106102
/// <summary>
107103
///
@@ -521,27 +517,121 @@ public ulong ReadInt64(int position, IValue byteOrder = null)
521517

522518

523519
/// <summary>
524-
/// Разделить буфер на части по заданному разделителю.
525-
///
526-
/// НЕ РЕАЛИЗОВАН
520+
/// Разделить буфер на части по заданному разделителю или массиву разделителей.
527521
/// </summary>
528522
///
529-
/// <remarks>
530-
///
531-
/// По двоичному буферу
532-
/// </remarks>
533-
///
534523
/// <param name="separator">
535524
/// Разделитель. </param>
536525
///
537-
/// <returns name="Array"/>
526+
/// <returns name="Array">Массив из буферов двоичных данных</returns>
538527
///
539528
[ContextMethod("Разделить", "Split")]
540-
public IValue Split(IValue separator)
529+
public ArrayImpl Split(IValue separator)
541530
{
542-
throw new NotImplementedException();
531+
var buffers = ParseParam(separator);
532+
533+
// Функция поиска требует, чтобы буферы были в порядке убывания размера
534+
buffers.Sort((a, b) => b._buffer.LongLength.CompareTo(a._buffer.LongLength));
535+
return SplitBuffer(buffers.ToArray());
536+
}
537+
538+
private static List<BinaryDataBuffer> ParseParam(IValue separator)
539+
{
540+
var rawSeparator = separator?.GetRawValue();
541+
switch (rawSeparator)
542+
{
543+
case BinaryDataBuffer buffer:
544+
return new List<BinaryDataBuffer> { CheckedBuffer(buffer) };
545+
546+
case ArrayImpl array:
547+
{
548+
var buffers = new List<BinaryDataBuffer>();
549+
550+
foreach (var element in array)
551+
{
552+
buffers.AddRange(ParseParam(element));
553+
}
554+
555+
return buffers;
556+
}
557+
558+
default:
559+
throw RuntimeException.InvalidArgumentType();
560+
}
561+
}
562+
563+
private static BinaryDataBuffer CheckedBuffer(BinaryDataBuffer buffer)
564+
{
565+
if (buffer.Size == 0)
566+
{
567+
throw RuntimeException.InvalidArgumentValue();
568+
}
569+
570+
return buffer;
571+
}
572+
573+
private ArrayImpl SplitBuffer(BinaryDataBuffer[] splitter)
574+
{
575+
var result = new List<BinaryDataBuffer>();
576+
long start = 0;
577+
var foundPosition = FindFirst(splitter, start);
578+
while (foundPosition.pos != -1)
579+
{
580+
var length = foundPosition.pos - start;
581+
result.Add(new BinaryDataBuffer(Copy(start, length), ByteOrder));
582+
start = foundPosition.pos + foundPosition.buffer.Size;
583+
foundPosition = FindFirst(splitter, start);
584+
}
585+
586+
// хвостовой элемент
587+
result.Add(new BinaryDataBuffer(Copy(start, _buffer.LongLength - start)));
588+
return new ArrayImpl(result);
589+
}
590+
591+
/// <summary>
592+
/// Ищет ближайшее вхождение любого из буферов. Если на одной позиции находятся два и более буфера, берется бОльший.
593+
/// </summary>
594+
/// <param name="buffers">Массив искомых буферов</param>
595+
/// <param name="start">Начальная позиция поиска</param>
596+
/// <returns>Буфер и позиция или null, если нет вхождений</returns>
597+
private (BinaryDataBuffer buffer, long pos) FindFirst(BinaryDataBuffer[] buffers, long start)
598+
{
599+
var maxI = Size - buffers[buffers.Length - 1].Size;
600+
for (var i = start; i < maxI; i++)
601+
{
602+
foreach (var expectedBuffer in buffers)
603+
{
604+
if (SubsequenceEquals(_buffer, i, expectedBuffer._buffer))
605+
{
606+
return (expectedBuffer, i);
607+
}
608+
}
609+
}
610+
611+
return (null, -1);
612+
}
613+
614+
private byte[] Copy(long start, long length)
615+
{
616+
if (length == 0) return Array.Empty<byte>();
617+
var partition = new byte[length];
618+
Array.Copy(_buffer, start, partition, 0, length);
619+
return partition;
543620
}
544621

622+
private static bool SubsequenceEquals(byte[] sequence, long start, byte[] subsequence)
623+
{
624+
for (long j = 0; j < subsequence.LongLength; j++)
625+
{
626+
if (subsequence[j] != sequence[start + j])
627+
{
628+
return false;
629+
}
630+
}
631+
632+
return true;
633+
}
634+
545635
/// <summary>
546636
///
547637
/// Создает копию массива.

tests/binary-objects.os

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
ВсеТесты = Новый Массив;
1212

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

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

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

353356
КонецПроцедуры
357+
358+
Процедура ТестДолжен_ПроверитьРазделениеБуфераДвоичныхДанныхОднимБуфером() Экспорт
359+
360+
Подстроки = Новый Массив;
361+
Подстроки.Добавить("Часть1");
362+
Подстроки.Добавить("Часть2");
363+
Подстроки.Добавить("Часть3");
364+
РазделительТекстом = "123";
365+
366+
ТестовыйБуфер = ПолучитьБуферДвоичныхДанныхИзСтроки(СтрСоединить(Подстроки, РазделительТекстом));
367+
Разделитель = ПолучитьБуферДвоичныхДанныхИзСтроки(РазделительТекстом);
368+
369+
РазделенныеДанные = ТестовыйБуфер.Разделить(Разделитель);
370+
371+
юТест.ПроверитьРавенство(РазделенныеДанные.Количество(), 3, "два разделителя - три элемента");
372+
373+
Для Инд = 0 По Подстроки.ВГраница() Цикл
374+
375+
СтрокаИзБуфера = ПолучитьСтрокуИзБуфераДвоичныхДанных(РазделенныеДанные[Инд]);
376+
юТест.ПроверитьРавенство(СтрокаИзБуфера, Подстроки[Инд], "сравнение строк после разделения буфера");
377+
378+
КонецЦикла;
379+
380+
КонецПроцедуры
381+
382+
Процедура ТестДолжен_ПроверитьРазделениеБуфераДвоичныхДанныхНесколькимиБуферами() Экспорт
383+
384+
Подстроки = Новый Массив;
385+
Подстроки.Добавить("Часть1");
386+
Подстроки.Добавить("Часть2");
387+
Подстроки.Добавить("Часть3");
388+
Подстроки.Добавить("Часть4");
389+
Подстроки.Добавить("Часть5");
390+
391+
ТестоваяСтрока = "Часть1\R\R\NЧасть2\R\NЧасть3\NЧасть4\RЧасть5";
392+
393+
ТестовыйБуфер = ПолучитьБуферДвоичныхДанныхИзСтроки(ТестоваяСтрока);
394+
Разделители = Новый Массив;
395+
Разделители.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("\N"));
396+
Разделители.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("\R\N"));
397+
Разделители.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("\R"));
398+
Разделители.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("\R\R\N"));
399+
400+
РазделенныеДанные = ТестовыйБуфер.Разделить(Разделители);
401+
402+
юТест.ПроверитьРавенство(РазделенныеДанные.Количество(), 5);
403+
404+
Для Инд = 0 По РазделенныеДанные.ВГраница() Цикл
405+
406+
СтрокаИзБуфера = ПолучитьСтрокуИзБуфераДвоичныхДанных(РазделенныеДанные[Инд]);
407+
юТест.ПроверитьРавенство(СтрокаИзБуфера, Подстроки[Инд], "сравнение строк после разделения буфера");
408+
409+
КонецЦикла;
410+
411+
КонецПроцедуры

0 commit comments

Comments
 (0)