Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removed StringBuilder allocation from Base64Encoding #5051

Merged
merged 3 commits into from May 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -4810,6 +4810,7 @@ namespace Akka.Util
{
public const string Base64Chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+~";
public static string Base64Encode(this long value) { }
[System.ObsoleteAttribute("Do not use. Pass in prefix as a string instead.")]
public static System.Text.StringBuilder Base64Encode(this long value, System.Text.StringBuilder sb) { }
public static string Base64Encode(this string s) { }
}
Expand Down
3 changes: 1 addition & 2 deletions src/core/Akka/Actor/ActorCell.Children.cs
Expand Up @@ -135,8 +135,7 @@ private IActorRef ActorOf(Props props, string name, bool isAsync, bool isSystemS
private string GetRandomActorName(string prefix = "$")
{
var id = Interlocked.Increment(ref _nextRandomNameDoNotCallMeDirectly);
var sb = new StringBuilder(prefix);
return id.Base64Encode(sb).ToString();
return id.Base64Encode(prefix);
}

/// <summary>
Expand Down
29 changes: 28 additions & 1 deletion src/core/Akka/Util/Base64Encoding.cs
Expand Up @@ -5,6 +5,7 @@
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Text;

namespace Akka.Util
Expand All @@ -24,14 +25,40 @@ public static class Base64Encoding
/// </summary>
/// <param name="value">TBD</param>
/// <returns>TBD</returns>
public static string Base64Encode(this long value) => Base64Encode(value, new StringBuilder()).ToString();
public static string Base64Encode(this long value)
{
return Base64Encode(value, "");
}

internal static string Base64Encode(this long value, string prefix)
{
// 11 is the number of characters it takes to represent long.MaxValue
// so we will never need a larger size for encoding longs
Span<char> sb = stackalloc char[11 + prefix?.Length ?? 0];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing program is here:

https://gist.github.com/Aaronontheweb/449d565754d5f9bce475653842317277

11 is the number of characters it takes to represent long.MaxValue in base64 encoded strings

var spanIndex = 0;
if (!string.IsNullOrWhiteSpace(prefix) && prefix.Length > 0)
{
prefix.AsSpan().CopyTo(sb);
spanIndex = prefix.Length;
}

var next = value;
do
{
var index = (int)(next & 63);
sb[spanIndex++] = Base64Chars[index];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder, is there any advantage at this point to changing Base64Chars to ReadOnlyMemory?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so since it's basically just integer accessors

next = next >> 6;
} while (next != 0);
return sb.Slice(0, spanIndex).ToString();
}

/// <summary>
/// TBD
/// </summary>
/// <param name="value">TBD</param>
/// <param name="sb">TBD</param>
/// <returns>TBD</returns>
[Obsolete("Do not use. Pass in prefix as a string instead.")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we change this comment, since our method that takes string is internal now?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still useful since this method really shouldn't have been exposed as public anyway, IMHO

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had a bad habit in the very early days of Akka.NET making a lot of the internals public "in case someone wanted to play with them!" and we've been gradually undoing that in our minor version releases....

public static StringBuilder Base64Encode(this long value, StringBuilder sb)
{
var next = value;
Expand Down