Skip to content

Commit 5af6b6b

Browse files
committed
Update Polynom
1 parent 9bd5770 commit 5af6b6b

File tree

2 files changed

+338
-74
lines changed

2 files changed

+338
-74
lines changed

QRCoder/QRCodeGenerator.Polynom.cs

Lines changed: 247 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.Text;
4+
using System.Threading;
35

46
namespace QRCoder
57
{
@@ -8,21 +10,132 @@ 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 = Allocate(count);
26+
}
27+
28+
/// <summary>
29+
/// Adds a polynomial term to the polynomial.
30+
/// </summary>
31+
public void Add(PolynomItem item)
32+
{
33+
EnsureCapacity(_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 (index < 0 || index >= _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 (index < 0 || index >= _length)
58+
throw new IndexOutOfRangeException();
59+
return _polyItems[index];
60+
}
61+
set {
62+
if (index < 0 || index >= _length)
63+
throw new IndexOutOfRangeException();
64+
_polyItems[index] = value;
65+
}
66+
}
67+
68+
/// <summary>
69+
/// Gets the number of polynomial terms in the polynomial.
70+
/// </summary>
71+
public int Count => _length;
72+
73+
/// <summary>
74+
/// Removes all polynomial terms from the polynomial.
75+
/// </summary>
76+
public void Clear()
77+
{
78+
_length = 0;
79+
}
80+
81+
/// <summary>
82+
/// Clones the polynomial, creating a new instance with the same polynomial terms.
83+
/// </summary>
84+
public Polynom Clone()
85+
{
86+
var newPolynom = new Polynom(_length);
87+
Array.Copy(_polyItems, newPolynom._polyItems, _length);
88+
newPolynom._length = _length;
89+
return newPolynom;
2090
}
2191

2292
/// <summary>
23-
/// Gets or sets the list of polynomial items, where each item represents a term in the polynomial.
93+
/// Sorts the collection of <see cref="PolynomItem"/> using a custom comparer function.
2494
/// </summary>
25-
public List<PolynomItem> PolyItems { get; set; }
95+
/// <param name="comparer">
96+
/// A function that compares two <see cref="PolynomItem"/> objects and returns an integer indicating their relative order:
97+
/// 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.
98+
/// </param>
99+
public void Sort(Func<PolynomItem, PolynomItem, int> comparer)
100+
{
101+
if (comparer == null) throw new ArgumentNullException(nameof(comparer));
102+
103+
// Assuming you have a list or array to sort within your class
104+
var items = _polyItems;
105+
if (items == null || _length <= 1)
106+
{
107+
return; // Nothing to sort if the list is empty or contains only one element
108+
}
109+
110+
void QuickSort(int left, int right)
111+
{
112+
int i = left;
113+
int j = right;
114+
PolynomItem pivot = items[(left + right) / 2];
115+
116+
while (i <= j)
117+
{
118+
while (comparer(items[i], pivot) < 0) i++;
119+
while (comparer(items[j], pivot) > 0) j--;
120+
121+
if (i <= j)
122+
{
123+
// Swap items[i] and items[j]
124+
PolynomItem temp = items[i];
125+
items[i] = items[j];
126+
items[j] = temp;
127+
i++;
128+
j--;
129+
}
130+
}
131+
132+
// Recursively sort the sub-arrays
133+
if (left < j) QuickSort(left, j);
134+
if (i < right) QuickSort(i, right);
135+
}
136+
137+
QuickSort(0, _length - 1);
138+
}
26139

27140
/// <summary>
28141
/// Returns a string that represents the polynomial in standard algebraic notation.
@@ -32,7 +145,7 @@ public override string ToString()
32145
{
33146
var sb = new StringBuilder();
34147

35-
foreach (var polyItem in this.PolyItems)
148+
foreach (var polyItem in _polyItems)
36149
{
37150
sb.Append("a^" + polyItem.Coefficient + "*x^" + polyItem.Exponent + " + ");
38151
}
@@ -43,6 +156,134 @@ public override string ToString()
43156

44157
return sb.ToString();
45158
}
159+
160+
/// <inheritdoc/>
161+
public void Dispose()
162+
{
163+
Free(_polyItems);
164+
_polyItems = null;
165+
}
166+
167+
/// <summary>
168+
/// Ensures that the polynomial has enough capacity to store the specified number of polynomial terms.
169+
/// </summary>
170+
private void EnsureCapacity(int min)
171+
{
172+
if (_polyItems.Length < min)
173+
{
174+
// All math by QRCoder should be done with fixed polynomials, so we don't need to grow the capacity.
175+
ThrowNotSupportedException();
176+
177+
// Sample code for growing the capacity:
178+
//var newArray = Allocate(Math.Max(min - 1, 8) * 2); // Grow by 2x, but at least by 8
179+
//Array.Copy(_polyItems, newArray, _length);
180+
//Free(_polyItems);
181+
//_polyItems = newArray;
182+
}
183+
184+
void ThrowNotSupportedException()
185+
{
186+
throw new NotSupportedException("The polynomial capacity is fixed and cannot be increased.");
187+
}
188+
}
189+
190+
#if NETCOREAPP
191+
/// <summary>
192+
/// Allocates memory for the polynomial terms.
193+
/// </summary>
194+
private static PolynomItem[] Allocate(int count)
195+
{
196+
return System.Buffers.ArrayPool<PolynomItem>.Shared.Rent(count);
197+
}
198+
199+
/// <summary>
200+
/// Frees memory allocated for the polynomial terms.
201+
/// </summary>
202+
private static void Free(PolynomItem[] array)
203+
{
204+
System.Buffers.ArrayPool<PolynomItem>.Shared.Return(array);
205+
}
206+
#else
207+
// Implement a poor-man's array pool for .NET Framework
208+
[ThreadStatic]
209+
private static List<PolynomItem[]> _arrayPool;
210+
211+
/// <summary>
212+
/// Allocates memory for the polynomial terms.
213+
/// </summary>
214+
private static PolynomItem[] Allocate(int count)
215+
{
216+
if (count <= 0)
217+
ThrowArgumentOutOfRangeException();
218+
219+
// Search for a suitable array in the thread-local pool, if it has been initialized
220+
if (_arrayPool != null)
221+
{
222+
for (int i = 0; i < _arrayPool.Count; i++)
223+
{
224+
var array = _arrayPool[i];
225+
if (array.Length >= count)
226+
{
227+
_arrayPool.RemoveAt(i);
228+
return array;
229+
}
230+
}
231+
}
232+
233+
// No suitable buffer found; create a new one
234+
return new PolynomItem[count];
235+
236+
void ThrowArgumentOutOfRangeException()
237+
{
238+
throw new ArgumentOutOfRangeException(nameof(count), "The count must be a positive number.");
239+
}
240+
}
241+
242+
/// <summary>
243+
/// Frees memory allocated for the polynomial terms.
244+
/// </summary>
245+
private static void Free(PolynomItem[] array)
246+
{
247+
if (array == null)
248+
ThrowArgumentNullException();
249+
250+
// Initialize the thread-local pool if it's not already done
251+
if (_arrayPool == null)
252+
_arrayPool = new List<PolynomItem[]>(8);
253+
254+
// Add the buffer back to the pool
255+
_arrayPool.Add(array);
256+
257+
void ThrowArgumentNullException()
258+
{
259+
throw new ArgumentNullException(nameof(array));
260+
}
261+
}
262+
#endif
263+
264+
/// <summary>
265+
/// Returns an enumerator that iterates through the polynomial terms.
266+
/// </summary>
267+
public PolynumEnumerator GetEnumerator() => new PolynumEnumerator(this);
268+
269+
/// <summary>
270+
/// Value type enumerator for the <see cref="Polynom"/> struct.
271+
/// </summary>
272+
public struct PolynumEnumerator
273+
{
274+
private Polynom _polynom;
275+
private int _index;
276+
277+
public PolynumEnumerator(Polynom polynom)
278+
{
279+
_polynom = polynom;
280+
_index = -1;
281+
}
282+
283+
public PolynomItem Current => _polynom[_index];
284+
285+
public bool MoveNext() => ++_index < _polynom._length;
286+
}
46287
}
47288
}
48289
}

0 commit comments

Comments
 (0)