Encode.cs 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. using System.Text;
  2. using BenchmarkDotNet.Attributes;
  3. using Tui = Terminal.Gui;
  4. namespace Terminal.Gui.Benchmarks.Text.RuneExtensions;
  5. /// <summary>
  6. /// Benchmarks for <see cref="Tui.RuneExtensions.Encode"/> performance fine-tuning.
  7. /// </summary>
  8. [MemoryDiagnoser]
  9. [BenchmarkCategory (nameof (Tui.RuneExtensions))]
  10. public class Encode
  11. {
  12. /// <summary>
  13. /// Benchmark for previous implementation.
  14. /// </summary>
  15. [Benchmark]
  16. [ArgumentsSource (nameof (DataSource))]
  17. public byte [] Previous (Rune rune, byte [] destination, int start, int count)
  18. {
  19. _ = StringEncodingGetBytes (rune, destination, start, count);
  20. return destination;
  21. }
  22. /// <summary>
  23. /// Benchmark for current implementation.
  24. ///
  25. /// Avoids intermediate heap allocations with stack allocated intermediate buffer.
  26. /// </summary>
  27. [Benchmark (Baseline = true)]
  28. [ArgumentsSource (nameof (DataSource))]
  29. public byte [] Current (Rune rune, byte [] destination, int start, int count)
  30. {
  31. _ = Tui.RuneExtensions.Encode (rune, destination, start, count);
  32. return destination;
  33. }
  34. /// <summary>
  35. /// Previous implementation with intermediate byte array and string allocation.
  36. /// </summary>
  37. private static int StringEncodingGetBytes (Rune rune, byte [] dest, int start = 0, int count = -1)
  38. {
  39. byte [] bytes = Encoding.UTF8.GetBytes (rune.ToString ());
  40. var length = 0;
  41. for (var i = 0; i < (count == -1 ? bytes.Length : count); i++)
  42. {
  43. if (bytes [i] == 0)
  44. {
  45. break;
  46. }
  47. dest [start + i] = bytes [i];
  48. length++;
  49. }
  50. return length;
  51. }
  52. public static IEnumerable<object []> DataSource ()
  53. {
  54. Rune[] runes = [ new Rune ('a'),"𝔞".EnumerateRunes().Single() ];
  55. foreach (var rune in runes)
  56. {
  57. yield return new object [] { rune, new byte [16], 0, -1 };
  58. yield return new object [] { rune, new byte [16], 8, -1 };
  59. // Does not work in original implementation
  60. //yield return new object [] { rune, new byte [16], 8, 8 };
  61. }
  62. }
  63. }