diff --git a/src/OneScript.StandardLibrary/Collections/ArrayImpl.cs b/src/OneScript.StandardLibrary/Collections/ArrayImpl.cs
index 388125736..b3f3945bc 100644
--- a/src/OneScript.StandardLibrary/Collections/ArrayImpl.cs
+++ b/src/OneScript.StandardLibrary/Collections/ArrayImpl.cs
@@ -5,16 +5,21 @@ This Source Code Form is subject to the terms of the
at http://mozilla.org/MPL/2.0/.
----------------------------------------------------------*/
-using System.Collections.Generic;
using OneScript.Contexts;
using OneScript.Exceptions;
using OneScript.Types;
using OneScript.Values;
using ScriptEngine.Machine;
using ScriptEngine.Machine.Contexts;
+using System.Collections.Generic;
namespace OneScript.StandardLibrary.Collections
{
+ ///
+ /// Коллекция элементов произвольного типа.
+ /// Возможно обращение к значениям элементов по числовому индексу (нумерация начинается с 0).
+ /// Доступен обход в цикле Для Каждого Из.
+ ///
[ContextClass("Массив", "Array")]
public class ArrayImpl : AutoCollectionContext, IValueArray
{
@@ -24,6 +29,11 @@ public ArrayImpl()
{
_values = new List();
}
+
+ public ArrayImpl(int capacity)
+ {
+ _values = new List(capacity);
+ }
public ArrayImpl(IEnumerable values)
{
@@ -56,16 +66,23 @@ public override void SetIndexedValue(IValue index, IValue val)
Set((int)index.AsNumber(), val);
else
base.SetIndexedValue(index, val);
- }
-
+ }
+
#region ICollectionContext Members
-
+
+ ///
+ /// Получает количество элементов в массиве
+ ///
+ /// Количество элементов массива
[ContextMethod("Количество", "Count")]
public override int Count()
{
return _values.Count;
- }
-
+ }
+
+ ///
+ /// Удаляет все элементы из массива
+ ///
[ContextMethod("Очистить", "Clear")]
public void Clear()
{
@@ -82,19 +99,27 @@ public override IEnumerator GetEnumerator()
{
yield return item;
}
- }
-
+ }
+
#endregion
-
+
+ ///
+ /// Добавляет элемент в конец массива
+ ///
+ /// Произвольный: Добавляемое значение. Если не указано, то добавляется Неопределено
[ContextMethod("Добавить", "Add")]
public void Add(IValue value = null)
{
- if (value == null)
- _values.Add(ValueFactory.Create());
- else
- _values.Add(value);
- }
-
+ _values.Add(value ?? ValueFactory.Create());
+ }
+
+ ///
+ /// Вставляет значение в массив по указанному индексу
+ ///
+ /// Число: Индекс вставляемого значения.
+ /// Если индекс превышает размер массива, то массив дополняется элементами Неопределено до указанного индекса.
+ /// Если индекс отрицательный, то выбрасывается исключение
+ /// Произвольный: Вставляемое значение. Если не указано, то вставляется Неопределено
[ContextMethod("Вставить", "Insert")]
public void Insert(int index, IValue value = null)
{
@@ -104,26 +129,27 @@ public void Insert(int index, IValue value = null)
if (index > _values.Count)
Extend(index - _values.Count);
- if (value == null)
- _values.Insert(index, ValueFactory.Create());
- else
- _values.Insert(index, value);
+ _values.Insert(index, value ?? ValueFactory.Create());
}
+ ///
+ /// Выполняет поиск элемента в массиве
+ ///
+ /// Произвольный: Искомое значение
+ /// Если элемент найден, возвращается его индекс, иначе Неопределено
[ContextMethod("Найти", "Find")]
public IValue Find(IValue what)
{
var idx = _values.FindIndex(x => x.StrictEquals(what));
- if(idx < 0)
- {
- return ValueFactory.Create();
- }
- else
- {
- return ValueFactory.Create(idx);
- }
- }
-
+ return idx>=0 ? ValueFactory.Create(idx) : ValueFactory.Create();
+ }
+
+ ///
+ /// Удаляет значение из массива
+ ///
+ /// Число: Индекс удаляемого элемента.
+ /// Если индекс находится за границами массива, то выбрасывается исключение
+ ///
[ContextMethod("Удалить", "Delete")]
public void Remove(int index)
{
@@ -133,12 +159,23 @@ public void Remove(int index)
_values.RemoveAt(index);
}
+ ///
+ /// Получает наибольший индекс элемента массива
+ ///
+ /// Наибольший индекс в массиве. Если количество элементов массива равно 0, возвращает -1
[ContextMethod("ВГраница", "UBound")]
public int UpperBound()
{
return _values.Count - 1;
- }
-
+ }
+
+ ///
+ /// Получает значение из массива по индексу
+ ///
+ /// Число: Индекс элемента.
+ /// Если индекс находится за границами массива, то выбрасывается исключение
+ ///
+ /// Значение элемента массива
[ContextMethod("Получить", "Get")]
public IValue Get(int index)
{
@@ -146,8 +183,15 @@ public IValue Get(int index)
throw RuntimeException.IndexOutOfRange();
return _values[index];
- }
-
+ }
+
+ ///
+ /// Устанавливает значение в массиве по индексу
+ ///
+ /// Число: Индекс элемента.
+ /// Если индекс находится за границами массива, то выбрасывается исключение
+ ///
+ /// Произвольный: Устанавливаемое значение
[ContextMethod("Установить", "Set")]
public void Set(int index, IValue value)
{
@@ -165,20 +209,22 @@ private void Extend(int count)
}
}
- private static void FillArray(ArrayImpl currentArray, int bound)
+ private static ArrayImpl CreateArray(int bound)
{
+ var array = new ArrayImpl(bound);
for (int i = 0; i < bound; i++)
{
- currentArray._values.Add(ValueFactory.Create());
+ array._values.Add(ValueFactory.Create());
}
+ return array;
}
- private static IValue CloneArray(ArrayImpl cloneable)
+ private static ArrayImpl CloneArray(ArrayImpl cloneable)
{
- ArrayImpl clone = new ArrayImpl();
+ ArrayImpl clone = new ArrayImpl(cloneable._values.Count);
foreach (var item in cloneable._values)
{
- clone._values.Add(item ?? ValueFactory.Create());
+ clone._values.Add(item is ArrayImpl arr ? CloneArray(arr) : item );
}
return clone;
}
@@ -198,35 +244,37 @@ public static ArrayImpl Constructor()
public static ArrayImpl Constructor(IValue[] dimensions)
{
if (dimensions.Length == 1 && dimensions[0] is FixedArrayImpl fa)
- {
- return Constructor(fa);
+ {
+ return Constructor(fa);
}
-
- ArrayImpl cloneable = null;
- for (int dim = dimensions.Length - 1; dim >= 0; dim--)
+
+ // fail fast
+ int size = 0;
+ for (int dim = 0; dim < dimensions.Length; dim++)
{
if (dimensions[dim] == null)
- throw RuntimeException.InvalidNthArgumentType(dim + 1);
-
- int bound = (int)dimensions[dim].AsNumber();
- if (bound <= 0)
+ throw RuntimeException.InvalidNthArgumentType(dim + 1);
+
+ size = (int)dimensions[dim].AsNumber();
+ if (size <= 0)
throw RuntimeException.InvalidNthArgumentValue(dim + 1);
-
- var newInst = new ArrayImpl();
- FillArray(newInst, bound);
- if(cloneable != null)
- {
- for (int i = 0; i < bound; i++)
- {
- newInst._values[i] = CloneArray(cloneable);
- }
- }
- cloneable = newInst;
-
+ }
+
+ var newInst = CreateArray(size); // длина по последней размерности
+
+ for (int dim = dimensions.Length - 2; dim >= 0; dim--) // если размерность >= 2
+ {
+ ArrayImpl nested = newInst;
+ int bound = (int)dimensions[dim].AsNumber();
+
+ newInst = new ArrayImpl(bound);
+ for (int i = 0; i < bound; i++)
+ {
+ newInst._values.Add(CloneArray(nested));
+ }
}
- return cloneable;
-
+ return newInst;
}
[ScriptConstructor(Name = "На основании фиксированного массива")]
diff --git a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTable.cs b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTable.cs
index 3fdbff358..f3cfcd92d 100644
--- a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTable.cs
+++ b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTable.cs
@@ -149,7 +149,7 @@ public void LoadColumn(IValue values, IValue columnIndex)
[ContextMethod("ВыгрузитьКолонку", "UnloadColumn")]
public ArrayImpl UnloadColumn(IValue column)
{
- var result = new ArrayImpl();
+ var result = new ArrayImpl(_rows.Count);
foreach (var row in _rows)
{
diff --git a/src/OneScript.StandardLibrary/Collections/ValueTree/ValueTreeRowCollection.cs b/src/OneScript.StandardLibrary/Collections/ValueTree/ValueTreeRowCollection.cs
index 10a1c8259..077de1ae2 100644
--- a/src/OneScript.StandardLibrary/Collections/ValueTree/ValueTreeRowCollection.cs
+++ b/src/OneScript.StandardLibrary/Collections/ValueTree/ValueTreeRowCollection.cs
@@ -146,7 +146,7 @@ public void LoadColumn(ArrayImpl values, IValue columnIndex)
[ContextMethod("ВыгрузитьКолонку", "UnloadColumn")]
public ArrayImpl UnloadColumn(IValue column)
{
- ArrayImpl result = new ArrayImpl();
+ ArrayImpl result = new ArrayImpl(_rows.Count);
foreach (ValueTreeRow row in _rows)
{
diff --git a/src/OneScript.StandardLibrary/SystemEnvironmentContext.cs b/src/OneScript.StandardLibrary/SystemEnvironmentContext.cs
index 57b74b6b2..57a3f4c81 100644
--- a/src/OneScript.StandardLibrary/SystemEnvironmentContext.cs
+++ b/src/OneScript.StandardLibrary/SystemEnvironmentContext.cs
@@ -172,8 +172,8 @@ public FixedArrayImpl GetLogicalDrives
{
get
{
- var arr = new ArrayImpl();
var data = Environment.GetLogicalDrives();
+ var arr = new ArrayImpl(data.Length);
foreach (var itm in data)
{
arr.Add(ValueFactory.Create(itm));
diff --git a/src/OneScript.StandardLibrary/Tasks/BackgroundTasksManager.cs b/src/OneScript.StandardLibrary/Tasks/BackgroundTasksManager.cs
index 9999dd86c..98aec99f1 100644
--- a/src/OneScript.StandardLibrary/Tasks/BackgroundTasksManager.cs
+++ b/src/OneScript.StandardLibrary/Tasks/BackgroundTasksManager.cs
@@ -135,7 +135,7 @@ public void WaitCompletionOfTasks()
public ArrayImpl GetBackgroundJobs(StructureImpl filter = default)
{
if(filter == default)
- return new ArrayImpl(_tasks.ToArray());
+ return new ArrayImpl(_tasks);
var arr = new ArrayImpl();
foreach (var task in _tasks)
diff --git a/tests/array.os b/tests/array.os
new file mode 100644
index 000000000..6d2bd49a2
--- /dev/null
+++ b/tests/array.os
@@ -0,0 +1,91 @@
+#Использовать asserts
+
+///////////////////////////////////////////////////////////////////////
+// Тест класса Массив
+///////////////////////////////////////////////////////////////////////
+
+Перем юТест;
+
+////////////////////////////////////////////////////////////////////
+// Программный интерфейс
+
+Функция ПолучитьСписокТестов(ЮнитТестирование) Экспорт
+
+ юТест = ЮнитТестирование;
+
+ ВсеТесты = Новый Массив;
+
+ ВсеТесты.Добавить("ТестДолжен_ПроверитьПоискВМассиве");
+ ВсеТесты.Добавить("ТестДолжен_СоздатьМногомерныйМассив");
+ ВсеТесты.Добавить("ТестДолжен_ПроверитьЗаписьВМногомерныйМассив"); // issue #1663
+ ВсеТесты.Добавить("ТестДолжен_ПроверитьОшибкуРазмерности");
+
+ Возврат ВсеТесты;
+
+КонецФункции
+
+Процедура ТестДолжен_ПроверитьПоискВМассиве() Экспорт
+
+ Массив = Новый Массив();
+ Массив.Добавить("1");
+ Массив.Добавить("2");
+ Массив.Добавить("3");
+
+ Если Массив.Найти("1") <> Неопределено Тогда
+ НашлиЗначение1 = Истина;
+ Иначе
+ НашлиЗначение1 = Ложь;
+ КонецЕсли;
+
+ Если Массив.Найти("9") <> Неопределено Тогда
+ НашлиЗначение9 = Истина;
+ Иначе
+ НашлиЗначение9 = Ложь;
+ КонецЕсли;
+
+ юТест.ПроверитьРавенство(НашлиЗначение1, Истина, "Нашли 1");
+ юТест.ПроверитьРавенство(НашлиЗначение9, Ложь, "Не нашли 9");
+ юТест.ПроверитьРавенство(Массив.Найти("2"), 1, "Индекс элемента по значению");
+
+КонецПроцедуры
+
+Процедура ТестДолжен_СоздатьМногомерныйМассив() Экспорт
+
+ Массив = Новый Массив(2,4,6,8);
+
+ Ожидаем.Что(Массив.Количество(), "1-я размерность").Равно(2);
+ Ожидаем.Что(Массив[0].Количество(), "2-я размерность").Равно(4);
+ Ожидаем.Что(Массив[1][1].Количество(), "3-я размерность").Равно(6);
+ Ожидаем.Что(Массив[1][1][2].Количество(), "4-я размерность").Равно(8);
+
+КонецПроцедуры
+
+Процедура ТестДолжен_ПроверитьЗаписьВМногомерныйМассив() Экспорт
+
+ Массив = Новый Массив(3,3,3);
+ Массив[0][0][0] = "Привет";
+ Массив[1][0][0] = "Привет.";
+ Массив[1][1][0] = "Привет!";
+ Массив[2][0][0] = "Привет!!!";
+
+ Ожидаем.Что(Массив[0][0][0]).Равно("Привет");
+ Ожидаем.Что(Массив[1][0][0]).Равно("Привет.");
+ Ожидаем.Что(Массив[1][1][0]).Равно("Привет!");
+ Ожидаем.Что(Массив[2][0][0]).Равно("Привет!!!");
+ Ожидаем.Что(Массив[2][1][0]).Равно(Неопределено);
+
+КонецПроцедуры
+
+Процедура ТестДолжен_ПроверитьОшибкуРазмерности() Экспорт
+
+ Попытка
+ Массив = Новый Массив(-1,-2,-3);
+ Исключение
+ Ошибка = ИнформацияОбОшибке().Описание;
+ юТест.ПроверитьНеРавенство(Найти(Ошибка,"Неверное значение аргумента номер 1"), 0, "Неверный вид ошибки: "+Ошибка); // не "номер 3"!
+ Возврат;
+ КонецПопытки;
+
+ ВызватьИсключение "Должно было быть выдано исключение, но его не было";
+
+КонецПроцедуры
\ No newline at end of file