IRC parsing, tokenization, and state handling in C#
at ircrobotsv2 112 lines 3.6 kB view raw
1namespace IRCTokens; 2 3public static class EnumerableExtensions 4{ 5 public static IEnumerable<byte[]> Split(this byte[] bytes, byte separator) 6 { 7 if (bytes == null || bytes.Length == 0) 8 { 9 return []; 10 } 11 12 var newLineIndices = bytes.Select((b, i) => b == separator ? i : -1).Where(i => i != -1).ToArray(); 13 var lines = new byte[newLineIndices.Length + 1][]; 14 var currentIndex = 0; 15 var arrIndex = 0; 16 17 for (var i = 0; i < newLineIndices.Length && currentIndex < bytes.Length; ++i) 18 { 19 var n = new byte[newLineIndices[i] - currentIndex]; 20 Array.Copy(bytes, currentIndex, n, 0, newLineIndices[i] - currentIndex); 21 currentIndex = newLineIndices[i] + 1; 22 lines[arrIndex++] = n; 23 } 24 25 // Handle the last string at the end of the array if there is one. 26 if (currentIndex < bytes.Length) 27 { 28 lines[arrIndex] = bytes.Skip(currentIndex).ToArray(); 29 } 30 // We had a separator character at the end of a string. Rather than just allowing 31 // a null character, we'll replace the last element in the array with an empty string. 32 else if (arrIndex == newLineIndices.Length) 33 { 34 lines[arrIndex] = []; 35 } 36 37 return lines.ToArray(); 38 } 39 40 public static byte[] Trim(this IEnumerable<byte> bytes, byte separator) 41 { 42 if (bytes == null) 43 { 44 return []; 45 } 46 47 var byteList = new List<byte>(bytes); 48 var i = 0; 49 50 if (!byteList.Any()) 51 { 52 return byteList.ToArray(); 53 } 54 55 while (byteList[i] == separator) 56 { 57 byteList.RemoveAt(i); 58 i++; 59 } 60 61 i = byteList.Count - 1; 62 while (byteList[i] == separator) 63 { 64 byteList.RemoveAt(i); 65 i--; 66 } 67 68 return byteList.ToArray(); 69 } 70 71#if !(REFERENCE_ASSEMBLY && (NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER)) 72 /// <summary> 73 /// Bypasses a specified number of contiguous elements from the end of the sequence and returns the remaining elements. 74 /// Backported from <a href="https://github.com/dotnet/reactive/blob/ebab5fc37e8c0888f7b96107852a8794e9af1735/Ix.NET/Source/System.Interactive/System/Linq/Operators/SkipLast.cs">netcore</a> 75 /// </summary> 76 /// <typeparam name="TSource">Source sequence element type.</typeparam> 77 /// <param name="source">Source sequence.</param> 78 /// <param name="count"> 79 /// The number of elements to skip from the end of the sequence before returning the remaining elements. 80 /// </param> 81 /// <returns>Sequence bypassing the specified number of elements counting from the end of the source sequence.</returns> 82 public static IEnumerable<TSource> SkipLast<TSource>(this IEnumerable<TSource> source, int count) 83 { 84 if (source == null) 85 { 86 throw new ArgumentNullException(nameof(source)); 87 } 88 89 if (count < 0) 90 { 91 throw new ArgumentOutOfRangeException(nameof(count)); 92 } 93 94 return SkipLastCore(source, count); 95 } 96 97 private static IEnumerable<TSource> SkipLastCore<TSource>(this IEnumerable<TSource> source, int count) 98 { 99 var q = new Queue<TSource>(); 100 101 foreach (var x in source) 102 { 103 q.Enqueue(x); 104 105 if (q.Count > count) 106 { 107 yield return q.Dequeue(); 108 } 109 } 110 } 111#endif 112}