/
Utility.cs
320 lines (296 loc) · 16.9 KB
/
Utility.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using JetBrains.Annotations;
using SadRogue.Primitives.GridViews;
namespace GoRogue
{
/// <summary>
/// Static class containing extension helper methods for various built-in C# classes, as well as a
/// static helper method for "swapping" references.
/// </summary>
[PublicAPI]
public static class Utility
{
/// <summary>
/// Adds an AsReadOnly method to <see cref="IDictionary{K, V}" />, similar to the AsReadOnly method of
/// <see cref="IList{T}" />, that returns a read-only reference to the dictionary.
/// </summary>
/// <typeparam name="TKey">Type of keys of the dictionary.</typeparam>
/// <typeparam name="TValue">Type of values of the dictionary.</typeparam>
/// <param name="dictionary" />
/// <returns>A ReadOnlyDictionary instance for the specified dictionary.</returns>
public static ReadOnlyDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(
this IDictionary<TKey, TValue> dictionary)
where TKey : notnull
=> new ReadOnlyDictionary<TKey, TValue>(dictionary);
/// <summary>
/// Extension method for <see cref="IEnumerable{T}" /> that allows retrieving a string
/// representing the contents.
/// </summary>
/// <remarks>
/// Built-in C# data structures like <see cref="List{T}" /> implement <see cref="IEnumerable{T}" />,
/// and as such this method can be used to stringify the contents of C# built-in data structures.
/// When no customization parameters are specified, it defaults to a representation looking something
/// like [elem1, elem2, elem3].
/// </remarks>
/// <typeparam name="T" />
/// <param name="enumerable" />
/// <param name="begin">Character(s) that should precede the string representation of the IEnumerable's elements.</param>
/// <param name="elementStringifier">
/// Function to use to get the string representation of each element. Specifying null uses the ToString
/// function of type T.
/// </param>
/// <param name="separator">Characters to separate the IEnumerable's elements by.</param>
/// <param name="end">Character(s) that should follow the string representation of the IEnumerable's elements.</param>
/// <returns>A string representation of the IEnumerable.</returns>
public static string ExtendToString<T>(this IEnumerable<T> enumerable, string begin = "[",
Func<T, string>? elementStringifier = null, string separator = ", ",
string end = "]")
{
elementStringifier ??= obj => obj?.ToString() ?? "null";
var result = new StringBuilder(begin);
var first = true;
foreach (var item in enumerable)
{
if (first)
first = false;
else
result.Append(separator);
result.Append(elementStringifier(item));
}
result.Append(end);
return result.ToString();
}
/// <summary>
/// Extension method for <see cref="ISet{T}" /> that allows retrieving a string representing the
/// contents.
/// </summary>
/// <remarks>
/// Built-in C# data structures like <see cref="HashSet{T}" /> implement <see cref="ISet{T}" />,
/// and as such this method can be used to stringify the contents of C# built-in set structures.
/// When no customization parameters are specified, it defaults to a representation looking something
/// like set(elem1, elem2, elem3).
/// </remarks>
/// <typeparam name="T" />
/// <param name="set" />
/// <param name="begin">Character(s) that should precede the string representation of the set's elements.</param>
/// <param name="elementStringifier">
/// Function to use to get the string representation of each element. Specifying null uses the ToString
/// function of type T.
/// </param>
/// <param name="separator">Characters to separate the set's items by.</param>
/// <param name="end">Character(s) that should follow the string representation of the set's elements.</param>
/// <returns>A string representation of the ISet.</returns>
public static string ExtendToString<T>(this ISet<T> set, string begin = "set(",
Func<T, string>? elementStringifier = null, string separator = ", ",
string end = ")")
=> ExtendToString((IEnumerable<T>)set, begin, elementStringifier, separator, end);
/// <summary>
/// Extension method for dictionaries that allows retrieving a string representing the dictionary's contents.
/// </summary>
/// <remarks>
/// Built-in C# data structures like <see cref="Dictionary{T, V}" /> implement <see cref="IDictionary{T, V}" />,
/// and as such this method can be used to stringify the contents of C# built-in dictionary structures.
/// When no customization parameters are specified, it defaults to a representation looking something
/// like {key1 : value, key2 : value}.
/// </remarks>
/// <typeparam name="TKey" />
/// <typeparam name="TValue" />
/// <param name="dictionary" />
/// <param name="begin">Character(s) that should precede the string representation of the dictionary's elements.</param>
/// <param name="keyStringifier">
/// Function to use to get the string representation of each key. Specifying null uses the ToString
/// function of type K.
/// </param>
/// <param name="valueStringifier">
/// Function to use to get the string representation of each value. Specifying null uses the ToString
/// function of type V.
/// </param>
/// <param name="kvSeparator">Characters used to separate each value from its key.</param>
/// <param name="pairSeparator">Characters used to separate each key-value pair from the next.</param>
/// <param name="end">Character(s) that should follow the string representation of the dictionary's elements.</param>
/// <returns>A string representation of the IDictionary.</returns>
public static string ExtendToString<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, string begin = "{",
Func<TKey, string>? keyStringifier = null,
Func<TValue, string>? valueStringifier = null,
string kvSeparator = " : ", string pairSeparator = ", ",
string end = "}")
where TKey : notnull
{
keyStringifier ??= obj => obj.ToString() ?? "null";
valueStringifier ??= obj => obj?.ToString() ?? "null";
var result = new StringBuilder(begin);
var first = true;
foreach (var (key, value) in dictionary)
{
if (first)
first = false;
else
result.Append(pairSeparator);
result.Append(keyStringifier(key) + kvSeparator + valueStringifier(value));
}
result.Append(end);
return result.ToString();
}
/// <summary>
/// Extension method for 2D arrays that allows retrieving a string representing the contents.
/// </summary>
/// <typeparam name="T" />
/// <param name="array" />
/// <param name="begin">Character(s) that should precede the string representation of the 2D array.</param>
/// <param name="beginRow">Character(s) that should precede the string representation of each row.</param>
/// <param name="elementStringifier">
/// Function to use to get the string representation of each value. Specifying null uses the ToString
/// function of type T.
/// </param>
/// <param name="rowSeparator">Character(s) used to separate each row from the next.</param>
/// <param name="elementSeparator">Character(s) used to separate each element from the next.</param>
/// <param name="endRow">Character(s) that should follow the string representation of each row.</param>
/// <param name="end">Character(s) that should follow the string representation of the 2D array.</param>
/// <returns>A string representation of the 2D array.</returns>
public static string ExtendToString<T>(this T[,] array, string begin = "[\n", string beginRow = "\t[",
Func<T, string>? elementStringifier = null,
string rowSeparator = ",\n", string elementSeparator = ", ",
string endRow = "]", string end = "\n]")
{
elementStringifier ??= obj => obj?.ToString() ?? "null";
var result = new StringBuilder(begin);
for (var x = 0; x < array.GetLength(0); x++)
{
result.Append(beginRow);
for (var y = 0; y < array.GetLength(1); y++)
{
result.Append(elementStringifier(array[x, y]));
if (y != array.GetLength(1) - 1) result.Append(elementSeparator);
}
result.Append(endRow);
if (x != array.GetLength(0) - 1) result.Append(rowSeparator);
}
result.Append(end);
return result.ToString();
}
/// <summary>
/// Extension method for 2D arrays that allows retrieving a string representing the contents,
/// formatted as if the 2D array represents a coordinate plane/grid.
/// </summary>
/// <remarks>
/// This differs from
/// <see cref="ExtendToString{T}(T[,], string, string, Func{T, string}, string, string, string, string)" />
/// in that this method prints the array
/// such that array[x+1, y] is printed to the RIGHT of array[x, y], rather than BELOW it.
/// Effectively it assumes the indexes being used are grid/coordinate plane coordinates.
/// </remarks>
/// <typeparam name="T" />
/// <param name="array" />
/// <param name="begin">Character(s) that should precede the string representation of the 2D array.</param>
/// <param name="beginRow">Character(s) that should precede the string representation of each row.</param>
/// <param name="elementStringifier">
/// Function to use to get the string representation of each value. Specifying null uses the ToString
/// function of type T.
/// </param>
/// <param name="rowSeparator">Character(s) used to separate each row from the next.</param>
/// <param name="elementSeparator">Character(s) used to separate each element from the next.</param>
/// <param name="endRow">Character(s) that should follow the string representation of each row.</param>
/// <param name="end">Character(s) that should follow the string representation of the 2D array.</param>
/// <returns>
/// A string representation of the 2D array, formatted as if the array represents a 2D coordinate plane/grid map.
/// </returns>
public static string ExtendToStringGrid<T>(this T[,] array, string begin = "", string beginRow = "",
Func<T, string>? elementStringifier = null,
string rowSeparator = "\n", string elementSeparator = " ",
string endRow = "", string end = "")
=> new ArrayView2D<T>(array).ExtendToString(begin, beginRow, elementStringifier, rowSeparator,
elementSeparator, endRow, end);
/// <summary>
/// Extension method for 2D arrays that allows retrieving a string representing the contents,
/// formatted as if the 2D array represents a coordinate plane/grid.
/// </summary>
/// <remarks>
/// This differs from
/// <see cref="ExtendToString{T}(T[,], string, string, Func{T, string}, string, string, string, string)" />
/// in that this method prints the array such that array[x+1, y] is printed to the RIGHT of array[x, y], rather than BELOW
/// it.
/// Effectively it assumes the indexes being used are grid/coordinate plane coordinates.
/// </remarks>
/// <typeparam name="T" />
/// <param name="array" />
/// <param name="fieldSize">
/// The amount of space each element should take up in characters. A positive number aligns
/// the text to the right of the space, while a negative number aligns the text to the left.
/// </param>
/// <param name="begin">Character(s) that should precede the string representation of the 2D array.</param>
/// <param name="beginRow">Character(s) that should precede the string representation of each row.</param>
/// <param name="elementStringifier">
/// Function to use to get the string representation of each value. Specifying null uses the ToString
/// function of type T.
/// </param>
/// <param name="rowSeparator">Character(s) used to separate each row from the next.</param>
/// <param name="elementSeparator">Character(s) used to separate each element from the next.</param>
/// <param name="endRow">Character(s) that should follow the string representation of each row.</param>
/// <param name="end">Character(s) that should follow the string representation of the 2D array.</param>
/// <returns>
/// A string representation of the 2D array, formatted as if the array represents a 2D coordinate plane/grid map.
/// </returns>
public static string ExtendToStringGrid<T>(this T[,] array, int fieldSize, string begin = "",
string beginRow = "", Func<T, string>? elementStringifier = null,
string rowSeparator = "\n", string elementSeparator = " ",
string endRow = "", string end = "")
=> new ArrayView2D<T>(array).ExtendToString(fieldSize, begin, beginRow, elementStringifier, rowSeparator,
elementSeparator, endRow, end);
/// <summary>
/// "Multiplies", aka repeats, a string the given number of times.
/// </summary>
/// <param name="str" />
/// <param name="numTimes">The number of times to repeat the string.</param>
/// <returns>The current string repeated <paramref name="numTimes" /> times.</returns>
public static string Multiply(this string str, int numTimes) => string.Concat(Enumerable.Repeat(str, numTimes));
/// <summary>
/// Swaps the values pointed to by <paramref name="lhs" /> and <paramref name="rhs" />.
/// </summary>
/// <typeparam name="T" />
/// <param name="lhs" />
/// <param name="rhs" />
public static void Swap<T>(ref T lhs, ref T rhs)
{
(lhs, rhs) = (rhs, lhs);
}
/// <summary>
/// Convenience function that yields the given item as a single-item IEnumerable.
/// </summary>
/// <typeparam name="T" />
/// <param name="item" />
/// <returns>An IEnumerable containing only the item the function is called on.</returns>
public static IEnumerable<T> Yield<T>(this T item)
{
yield return item;
}
/// <summary>
/// Takes multiple parameters and converts them to an IEnumerable.
/// </summary>
/// <typeparam name="T" />
/// <param name="values">Parameters (specified as multiple parameters to the function).</param>
/// <returns>
/// An IEnumerable of all of the given items, in the order they were given to the function.
/// </returns>
public static IEnumerable<T> Yield<T>(params T[] values)
{
foreach (var value in values)
yield return value;
}
/// <summary>
/// Takes multiple enumerables of items, and flattens them into a single IEnumerable.
/// </summary>
/// <typeparam name="T" />
/// <param name="lists">Lists to "flatten".</param>
/// <returns>An IEnumerable containing the items of all the enumerables passed in.</returns>
public static IEnumerable<T> Flatten<T>(params IEnumerable<T>[] lists)
{
foreach (var list in lists)
foreach (var i in list)
yield return i;
}
}
}