1
- using System . Collections . Generic ;
1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Diagnostics ;
2
4
using System . Text ;
3
5
4
6
namespace QRCoder
@@ -8,21 +10,142 @@ public partial class QRCodeGenerator
8
10
/// <summary>
9
11
/// Represents a polynomial, which is a sum of polynomial terms.
10
12
/// </summary>
11
- private struct Polynom
13
+ private struct Polynom : IDisposable
12
14
{
15
+ private PolynomItem [ ] _polyItems ;
16
+ private int _length ;
17
+
13
18
/// <summary>
14
19
/// Initializes a new instance of the <see cref="Polynom"/> struct with a specified number of initial capacity for polynomial terms.
15
20
/// </summary>
16
21
/// <param name="count">The initial capacity of the polynomial items list.</param>
17
22
public Polynom ( int count )
18
23
{
19
- this . PolyItems = new List < PolynomItem > ( count ) ;
24
+ _length = 0 ;
25
+ _polyItems = RentArray ( count ) ;
26
+ }
27
+
28
+ /// <summary>
29
+ /// Adds a polynomial term to the polynomial.
30
+ /// </summary>
31
+ public void Add ( PolynomItem item )
32
+ {
33
+ AssertCapacity ( _length + 1 ) ;
34
+ _polyItems [ _length ++ ] = item ;
35
+ }
36
+
37
+ /// <summary>
38
+ /// Removes the polynomial term at the specified index.
39
+ /// </summary>
40
+ public void RemoveAt ( int index )
41
+ {
42
+ if ( ( uint ) index >= ( uint ) _length )
43
+ throw new IndexOutOfRangeException ( ) ;
44
+
45
+ if ( index < _length - 1 )
46
+ Array . Copy ( _polyItems , index + 1 , _polyItems , index , _length - index - 1 ) ;
47
+
48
+ _length -- ;
49
+ }
50
+
51
+ /// <summary>
52
+ /// Gets or sets a polynomial term at the specified index.
53
+ /// </summary>
54
+ public PolynomItem this [ int index ]
55
+ {
56
+ get {
57
+ if ( ( uint ) index >= _length )
58
+ ThrowIndexOutOfRangeException ( ) ;
59
+ return _polyItems [ index ] ;
60
+ }
61
+ set {
62
+ if ( ( uint ) index >= _length )
63
+ ThrowIndexOutOfRangeException ( ) ;
64
+ _polyItems [ index ] = value ;
65
+ }
66
+ }
67
+
68
+ #if NET6_0_OR_GREATER
69
+ [ StackTraceHidden ]
70
+ #endif
71
+ private static void ThrowIndexOutOfRangeException ( )
72
+ {
73
+ throw new IndexOutOfRangeException ( ) ;
74
+ }
75
+
76
+
77
+ /// <summary>
78
+ /// Gets the number of polynomial terms in the polynomial.
79
+ /// </summary>
80
+ public int Count => _length ;
81
+
82
+ /// <summary>
83
+ /// Removes all polynomial terms from the polynomial.
84
+ /// </summary>
85
+ public void Clear ( )
86
+ {
87
+ _length = 0 ;
20
88
}
21
89
22
90
/// <summary>
23
- /// Gets or sets the list of polynomial items, where each item represents a term in the polynomial.
91
+ /// Clones the polynomial, creating a new instance with the same polynomial terms .
24
92
/// </summary>
25
- public List < PolynomItem > PolyItems { get ; set ; }
93
+ public Polynom Clone ( )
94
+ {
95
+ var newPolynom = new Polynom ( _length ) ;
96
+ Array . Copy ( _polyItems , newPolynom . _polyItems , _length ) ;
97
+ newPolynom . _length = _length ;
98
+ return newPolynom ;
99
+ }
100
+
101
+ /// <summary>
102
+ /// Sorts the collection of <see cref="PolynomItem"/> using a custom comparer function.
103
+ /// </summary>
104
+ /// <param name="comparer">
105
+ /// A function that compares two <see cref="PolynomItem"/> objects and returns an integer indicating their relative order:
106
+ /// less than zero if the first is less than the second, zero if they are equal, or greater than zero if the first is greater than the second.
107
+ /// </param>
108
+ public void Sort ( Func < PolynomItem , PolynomItem , int > comparer )
109
+ {
110
+ if ( comparer == null ) throw new ArgumentNullException ( nameof ( comparer ) ) ;
111
+
112
+ var items = _polyItems ;
113
+ if ( items == null ) throw new ObjectDisposedException ( nameof ( Polynom ) ) ;
114
+
115
+ if ( _length <= 1 )
116
+ {
117
+ return ; // Nothing to sort if the list is empty or contains only one element
118
+ }
119
+
120
+ void QuickSort ( int left , int right )
121
+ {
122
+ int i = left ;
123
+ int j = right ;
124
+ PolynomItem pivot = items [ ( left + right ) / 2 ] ;
125
+
126
+ while ( i <= j )
127
+ {
128
+ while ( comparer ( items [ i ] , pivot ) < 0 ) i ++ ;
129
+ while ( comparer ( items [ j ] , pivot ) > 0 ) j -- ;
130
+
131
+ if ( i <= j )
132
+ {
133
+ // Swap items[i] and items[j]
134
+ PolynomItem temp = items [ i ] ;
135
+ items [ i ] = items [ j ] ;
136
+ items [ j ] = temp ;
137
+ i ++ ;
138
+ j -- ;
139
+ }
140
+ }
141
+
142
+ // Recursively sort the sub-arrays
143
+ if ( left < j ) QuickSort ( left , j ) ;
144
+ if ( i < right ) QuickSort ( i , right ) ;
145
+ }
146
+
147
+ QuickSort ( 0 , _length - 1 ) ;
148
+ }
26
149
27
150
/// <summary>
28
151
/// Returns a string that represents the polynomial in standard algebraic notation.
@@ -32,7 +155,7 @@ public override string ToString()
32
155
{
33
156
var sb = new StringBuilder ( ) ;
34
157
35
- foreach ( var polyItem in this . PolyItems )
158
+ foreach ( var polyItem in _polyItems )
36
159
{
37
160
sb . Append ( "a^" + polyItem . Coefficient + "*x^" + polyItem . Exponent + " + " ) ;
38
161
}
@@ -43,6 +166,137 @@ public override string ToString()
43
166
44
167
return sb . ToString ( ) ;
45
168
}
169
+
170
+ /// <inheritdoc/>
171
+ public void Dispose ( )
172
+ {
173
+ ReturnArray ( _polyItems ) ;
174
+ _polyItems = null ;
175
+ }
176
+
177
+ /// <summary>
178
+ /// Ensures that the polynomial has enough capacity to store the specified number of polynomial terms.
179
+ /// </summary>
180
+ private void AssertCapacity ( int min )
181
+ {
182
+ if ( _polyItems . Length < min )
183
+ {
184
+ // All math by QRCoder should be done with fixed polynomials, so we don't need to grow the capacity.
185
+ ThrowNotSupportedException ( ) ;
186
+
187
+ // Sample code for growing the capacity:
188
+ //var newArray = RentArray(Math.Max(min - 1, 8) * 2); // Grow by 2x, but at least by 8
189
+ //Array.Copy(_polyItems, newArray, _length);
190
+ //ReturnArray(_polyItems);
191
+ //_polyItems = newArray;
192
+ }
193
+
194
+ #if NET6_0_OR_GREATER
195
+ [ StackTraceHidden ]
196
+ #endif
197
+ void ThrowNotSupportedException ( )
198
+ {
199
+ throw new NotSupportedException ( "The polynomial capacity is fixed and cannot be increased." ) ;
200
+ }
201
+ }
202
+
203
+ #if NETCOREAPP
204
+ /// <summary>
205
+ /// Rents memory for the polynomial terms from the shared memory pool.
206
+ /// </summary>
207
+ private static PolynomItem [ ] RentArray ( int count )
208
+ {
209
+ return System . Buffers . ArrayPool < PolynomItem > . Shared . Rent ( count ) ;
210
+ }
211
+
212
+ /// <summary>
213
+ /// Returns memory allocated for the polynomial terms back to the shared memory pool.
214
+ /// </summary>
215
+ private static void ReturnArray ( PolynomItem [ ] array )
216
+ {
217
+ System . Buffers . ArrayPool < PolynomItem > . Shared . Return ( array ) ;
218
+ }
219
+ #else
220
+ // Implement a poor-man's array pool for .NET Framework
221
+ [ ThreadStatic ]
222
+ private static List < PolynomItem [ ] > _arrayPool ;
223
+
224
+ /// <summary>
225
+ /// Rents memory for the polynomial terms from a shared memory pool.
226
+ /// </summary>
227
+ private static PolynomItem [ ] RentArray ( int count )
228
+ {
229
+ if ( count <= 0 )
230
+ ThrowArgumentOutOfRangeException ( ) ;
231
+
232
+ // Search for a suitable array in the thread-local pool, if it has been initialized
233
+ if ( _arrayPool != null )
234
+ {
235
+ for ( int i = 0 ; i < _arrayPool . Count ; i ++ )
236
+ {
237
+ var array = _arrayPool [ i ] ;
238
+ if ( array . Length >= count )
239
+ {
240
+ _arrayPool . RemoveAt ( i ) ;
241
+ return array ;
242
+ }
243
+ }
244
+ }
245
+
246
+ // No suitable buffer found; create a new one
247
+ return new PolynomItem [ count ] ;
248
+
249
+ void ThrowArgumentOutOfRangeException ( )
250
+ {
251
+ throw new ArgumentOutOfRangeException ( nameof ( count ) , "The count must be a positive number." ) ;
252
+ }
253
+ }
254
+
255
+ /// <summary>
256
+ /// Returns memory allocated for the polynomial terms back to a shared memory pool.
257
+ /// </summary>
258
+ private static void ReturnArray ( PolynomItem [ ] array )
259
+ {
260
+ if ( array == null )
261
+ ThrowArgumentNullException ( ) ;
262
+
263
+ // Initialize the thread-local pool if it's not already done
264
+ if ( _arrayPool == null )
265
+ _arrayPool = new List < PolynomItem [ ] > ( 8 ) ;
266
+
267
+ // Add the buffer back to the pool
268
+ _arrayPool . Add ( array ) ;
269
+
270
+ void ThrowArgumentNullException ( )
271
+ {
272
+ throw new ArgumentNullException ( nameof ( array ) ) ;
273
+ }
274
+ }
275
+ #endif
276
+
277
+ /// <summary>
278
+ /// Returns an enumerator that iterates through the polynomial terms.
279
+ /// </summary>
280
+ public PolynumEnumerator GetEnumerator ( ) => new PolynumEnumerator ( this ) ;
281
+
282
+ /// <summary>
283
+ /// Value type enumerator for the <see cref="Polynom"/> struct.
284
+ /// </summary>
285
+ public struct PolynumEnumerator
286
+ {
287
+ private Polynom _polynom ;
288
+ private int _index ;
289
+
290
+ public PolynumEnumerator ( Polynom polynom )
291
+ {
292
+ _polynom = polynom ;
293
+ _index = - 1 ;
294
+ }
295
+
296
+ public PolynomItem Current => _polynom [ _index ] ;
297
+
298
+ public bool MoveNext ( ) => ++ _index < _polynom . _length ;
299
+ }
46
300
}
47
301
}
48
302
}
0 commit comments