33
44namespace MathCore ;
55
6+ /// <summary>
7+ /// Статический класс-помощник для создания и работы с указателями на массивы ArrayPtr<T>
8+ /// </summary>
69public 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<T> является 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>
1586public 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<T> для подмассива между индексами</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<T> для подмассива со смещением</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<T> для подмассива</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