Skip to content

Commit cc254f3

Browse files
committed
Расширение ArrayPtr: новые методы и документация
Добавлен статический класс ArrayPtr с методами создания указателей на массивы и подмассивы. Тип ArrayPtr<T> получил расширенную XML-документацию, поддержку отрицательных индексов, методы для срезов, разложения, копирования, а также операторы сравнения и преобразования. Все методы снабжены подробными комментариями и примерами, что улучшает удобство и самодокументируемость API.
1 parent 4ca07b4 commit cc254f3

1 file changed

Lines changed: 197 additions & 0 deletions

File tree

MathCore/ArrayPtr.cs

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,210 @@
33

44
namespace MathCore;
55

6+
/// <summary>
7+
/// Статический класс-помощник для создания и работы с указателями на массивы ArrayPtr&lt;T&gt;
8+
/// </summary>
69
public static class ArrayPtr
710
{
11+
/// <summary>
12+
/// Создаёт указатель на весь массив
13+
/// </summary>
14+
/// <param name="array">Исходный массив</param>
15+
/// <returns>Указатель на весь массив с нулевым смещением</returns>
16+
/// <example>
17+
/// <![CDATA[
18+
/// var array = new[] { 1, 2, 3, 4, 5 };
19+
/// var ptr = ArrayPtr.Create(array);
20+
/// // ptr указывает на весь массив
21+
/// ]]>
22+
/// </example>
823
public static ArrayPtr<T> Create<T>(T[] array) => new(array);
924

25+
/// <summary>
26+
/// Преобразует массив в указатель на весь массив
27+
/// </summary>
28+
/// <param name="array">Исходный массив</param>
29+
/// <returns>Указатель на весь массив</returns>
1030
public static ArrayPtr<T> ToArrayPtr<T>(this T[] array) => new(array);
31+
32+
/// <summary>
33+
/// Преобразует массив в указатель с указанным смещением
34+
/// </summary>
35+
/// <param name="array">Исходный массив</param>
36+
/// <param name="Offset">Начальное смещение в массиве</param>
37+
/// <returns>Указатель на массив со смещением</returns>
38+
/// <example>
39+
/// <![CDATA[
40+
/// var array = new[] { 1, 2, 3, 4, 5 };
41+
/// var ptr = array.ToArrayPtr(2);
42+
/// // ptr указывает на элементы начиная с индекса 2
43+
/// ]]>
44+
/// </example>
1145
public static ArrayPtr<T> ToArrayPtr<T>(this T[] array, int Offset) => new(array, Offset);
46+
47+
/// <summary>
48+
/// Преобразует массив в указатель с указанным смещением и длиной
49+
/// </summary>
50+
/// <param name="array">Исходный массив</param>
51+
/// <param name="Offset">Начальное смещение в массиве</param>
52+
/// <param name="Length">Количество элементов для доступа</param>
53+
/// <returns>Указатель на подмассив с заданным смещением и длиной</returns>
54+
/// <example>
55+
/// <![CDATA[
56+
/// var array = new[] { 1, 2, 3, 4, 5 };
57+
/// var ptr = array.ToArrayPtr(1, 3);
58+
/// // ptr указывает на элементы [2, 3, 4]
59+
/// ]]>
60+
/// </example>
1261
public static ArrayPtr<T> ToArrayPtr<T>(this T[] array, int Offset, int Length) => new(array, Offset, Length);
1362
}
1463

64+
/// <summary>
65+
/// Изменяемый ссылочный тип для работы с подмассивами без выделения дополнительной памяти
66+
/// </summary>
67+
/// <remarks>
68+
/// ArrayPtr&lt;T&gt; является ref struct, что означает, что он может использоваться только на стеке
69+
/// и не может быть боксирован, использован в async методах или храниться в полях класса.
70+
/// Поддерживает отрицательные индексы (как Python): -1 указывает на последний элемент.
71+
/// </remarks>
72+
/// <example>
73+
/// <![CDATA[
74+
/// var array = new[] { 10, 20, 30, 40, 50 };
75+
/// var ptr = new ArrayPtr<int>(array, 1, 3); // указывает на [20, 30, 40]
76+
///
77+
/// // Обращение по индексу
78+
/// var first = ptr[0]; // 20
79+
/// var last = ptr[-1]; // 40
80+
///
81+
/// // Разложение на голову и хвост
82+
/// var (head, tail) = ptr;
83+
/// // head = 20, tail указывает на [30, 40]
84+
/// ]]>
85+
/// </example>
1586
public readonly ref struct ArrayPtr<T>(T[] array, int Offset = 0, int Length = -1)
1687
{
88+
/// <summary>
89+
/// Конструктор с кортежем позиции (смещение и длина)
90+
/// </summary>
91+
/// <param name="array">Исходный массив</param>
92+
/// <param name="Position">Кортеж с полями Offset и Length</param>
1793
public ArrayPtr(T[] array, (int Offset, int Length) Position) : this(array, Position.Offset, Position.Length) { }
1894

1995
private readonly T[] _Array = array;
2096

2197
private readonly int _Offset = Offset < 0 ? (Length < 0 ? array.Length : Math.Max(array.Length, Length)) + Offset : Offset;
2298

99+
/// <summary>
100+
/// Получает количество доступных элементов в подмассиве
101+
/// </summary>
23102
public int Length { get; } = Length < 0 ? array.Length : Math.Min(Length, array.Length);
24103

104+
/// <summary>
105+
/// Получает или устанавливает элемент по индексу с поддержкой отрицательных индексов
106+
/// </summary>
107+
/// <param name="index">Индекс элемента. Отрицательные значения отсчитываются с конца</param>
108+
/// <returns>Ссылка на элемент массива</returns>
109+
/// <remarks>
110+
/// Индекс -1 указывает на последний элемент, -2 на предпоследний и так далее
111+
/// </remarks>
112+
/// <example>
113+
/// <![CDATA[
114+
/// var ptr = new ArrayPtr<int>(new[] { 10, 20, 30 });
115+
/// var first = ptr[0]; // 10
116+
/// var last = ptr[-1]; // 30
117+
/// ptr[1] = 25; // изменение элемента
118+
/// ]]>
119+
/// </example>
25120
public ref T this[int index] => ref _Array[_Offset + (index < 0 ? Length + index : index)];
26121

27122
private int GetIndex(int index) => _Offset + (index < 0 ? Length + index : index);
28123

124+
/// <summary>
125+
/// Получает срез между двумя индексами (в том числе отрицательными)
126+
/// </summary>
127+
/// <param name="Start">Начальный индекс</param>
128+
/// <param name="End">Конечный индекс</param>
129+
/// <returns>Новый ArrayPtr&lt;T&gt; для подмассива между индексами</returns>
130+
/// <example>
131+
/// <![CDATA[
132+
/// var ptr = new ArrayPtr<int>(new[] { 10, 20, 30, 40, 50 });
133+
/// var slice = ptr[1, 4]; // новый указатель на элементы [20, 30, 40]
134+
/// ]]>
135+
/// </example>
29136
public ArrayPtr<T> this[int Start, int End] => new(_Array, (GetIndex(Start), GetIndex(End)).MinMaxToMinLength());
30137

138+
/// <summary>
139+
/// Создаёт срез начиная с указанного смещения до конца
140+
/// </summary>
141+
/// <param name="Offset">Смещение относительно начала текущего подмассива</param>
142+
/// <returns>Новый ArrayPtr&lt;T&gt; для подмассива со смещением</returns>
143+
/// <example>
144+
/// <![CDATA[
145+
/// var ptr = new ArrayPtr<int>(new[] { 10, 20, 30, 40 });
146+
/// var slice = ptr.Slice(2); // новый указатель на [30, 40]
147+
/// ]]>
148+
/// </example>
31149
public ArrayPtr<T> Slice(int Offset) => new(_Array, _Offset + Offset, Length - Offset);
32150

151+
/// <summary>
152+
/// Создаёт срез с указанным смещением и длиной
153+
/// </summary>
154+
/// <param name="Offset">Смещение относительно начала текущего подмассива</param>
155+
/// <param name="Length">Максимальное количество элементов в срезе</param>
156+
/// <returns>Новый ArrayPtr&lt;T&gt; для подмассива</returns>
157+
/// <example>
158+
/// <![CDATA[
159+
/// var ptr = new ArrayPtr<int>(new[] { 10, 20, 30, 40, 50 });
160+
/// var slice = ptr.Slice(1, 2); // новый указатель на [20, 30]
161+
/// ]]>
162+
/// </example>
33163
public ArrayPtr<T> Slice(int Offset, int Length) => new(_Array, _Offset + Offset, Math.Min(this.Length - Offset, Length));
34164

165+
/// <summary>
166+
/// Разложение на первый элемент (голову) и оставшиеся элементы (хвост)
167+
/// </summary>
168+
/// <param name="head">Первый элемент подмассива</param>
169+
/// <param name="tail">Новый указатель на оставшиеся элементы начиная со второго</param>
170+
/// <remarks>
171+
/// Полезна для рекурсивной обработки элементов массива
172+
/// </remarks>
173+
/// <example>
174+
/// <![CDATA[
175+
/// var ptr = new ArrayPtr<int>(new[] { 1, 2, 3 });
176+
/// var (head, tail) = ptr;
177+
/// // head = 1, tail указывает на [2, 3]
178+
/// ]]>
179+
/// </example>
35180
public void Deconstruct(out T head, out ArrayPtr<T> tail)
36181
{
37182
head = this[0];
38183
tail = Slice(1);
39184
}
40185

186+
/// <summary>
187+
/// Копирует элементы подмассива в новый отдельный массив
188+
/// </summary>
189+
/// <returns>Новый массив, содержащий копию элементов подмассива</returns>
190+
/// <example>
191+
/// <![CDATA[
192+
/// var ptr = new ArrayPtr<int>(new[] { 10, 20, 30, 40 }, 1, 2);
193+
/// var copy = ptr.ToArray(); // [20, 30]
194+
/// ]]>
195+
/// </example>
41196
public T[] ToArray()
42197
{
43198
var result = new T[Length];
44199
Array.Copy(_Array, _Offset, result, 0, Length);
45200
return result;
46201
}
47202

203+
/// <summary>
204+
/// Возвращает строковое представление указателя с типом, смещением, длиной и элементами
205+
/// </summary>
206+
/// <remarks>
207+
/// Если элементов больше 10, выводится только информация о типе, смещении и длине с маркером *.
208+
/// В противном случае выводятся все элементы
209+
/// </remarks>
48210
public override string ToString()
49211
{
50212
var result = new StringBuilder(100).Append(typeof(T).Name);
@@ -63,21 +225,56 @@ public override string ToString()
63225
return result.ToString();
64226
}
65227

228+
/// <summary>
229+
/// Получает хеш-код для указателя
230+
/// </summary>
231+
/// <returns>Хеш-код, основанный на массиве, смещении и длине</returns>
66232
public override int GetHashCode() => HashBuilder.New(_Array).Append(_Offset).Append(Length);
67233

234+
/// <summary>
235+
/// Сравнение объектов по равенству не поддерживается
236+
/// </summary>
237+
/// <exception cref="NotSupportedException">Всегда выбрасывает исключение</exception>
68238
[EditorBrowsable(EditorBrowsableState.Never)]
69239
public override bool Equals(object? obj) => throw new NotSupportedException();
70240

241+
/// <summary>
242+
/// Проверяет равенство двух указателей
243+
/// </summary>
244+
/// <param name="other">Другой указатель для сравнения</param>
245+
/// <returns>true, если оба указателя ссылаются на один и тот же массив с одинаковым смещением и длиной</returns>
71246
public bool Equals(ArrayPtr<T> other) =>
72247
ReferenceEquals(_Array, other._Array)
73248
&& _Offset == other._Offset
74249
&& Length == other.Length;
75250

251+
/// <summary>
252+
/// Оператор проверки равенства двух указателей
253+
/// </summary>
76254
public static bool operator ==(ArrayPtr<T> a, ArrayPtr<T> b) => a.Equals(b);
255+
256+
/// <summary>
257+
/// Оператор проверки неравенства двух указателей
258+
/// </summary>
77259
public static bool operator !=(ArrayPtr<T> a, ArrayPtr<T> b) => !a.Equals(b);
78260

261+
/// <summary>
262+
/// Неявное преобразование массива в указатель на весь массив
263+
/// </summary>
264+
/// <param name="array">Исходный массив</param>
79265
public static implicit operator ArrayPtr<T>(T[] array) => new(array);
80266

267+
/// <summary>
268+
/// Явное преобразование указателя в массив
269+
/// </summary>
270+
/// <param name="ptr">Исходный указатель</param>
271+
/// <returns>
272+
/// Если указатель ссылается на весь исходный массив, возвращает исходный массив.
273+
/// В противном случае создаёт и возвращает копию элементов подмассива
274+
/// </returns>
275+
/// <remarks>
276+
/// Используйте явное приведение, если нужна гарантия работы с отдельным массивом
277+
/// </remarks>
81278
public static explicit operator T[](ArrayPtr<T> ptr) =>
82279
ptr._Offset == 0 && ptr.Length == ptr._Array.Length
83280
? ptr._Array

0 commit comments

Comments
 (0)