1- using System . Collections . Generic ;
1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . Diagnostics ;
24using System . Text ;
35
46namespace QRCoder
@@ -8,21 +10,142 @@ public partial class QRCodeGenerator
810 /// <summary>
911 /// Represents a polynomial, which is a sum of polynomial terms.
1012 /// </summary>
11- private struct Polynom
13+ private struct Polynom : IDisposable
1214 {
15+ private PolynomItem [ ] _polyItems ;
16+ private int _length ;
17+
1318 /// <summary>
1419 /// Initializes a new instance of the <see cref="Polynom"/> struct with a specified number of initial capacity for polynomial terms.
1520 /// </summary>
1621 /// <param name="count">The initial capacity of the polynomial items list.</param>
1722 public Polynom ( int count )
1823 {
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 ;
2088 }
2189
2290 /// <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 .
2492 /// </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+ }
26149
27150 /// <summary>
28151 /// Returns a string that represents the polynomial in standard algebraic notation.
@@ -32,7 +155,7 @@ public override string ToString()
32155 {
33156 var sb = new StringBuilder ( ) ;
34157
35- foreach ( var polyItem in this . PolyItems )
158+ foreach ( var polyItem in _polyItems )
36159 {
37160 sb . Append ( "a^" + polyItem . Coefficient + "*x^" + polyItem . Exponent + " + " ) ;
38161 }
@@ -43,6 +166,137 @@ public override string ToString()
43166
44167 return sb . ToString ( ) ;
45168 }
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+ }
46300 }
47301 }
48302}
0 commit comments