reduce amount allocation for single number decode#65
reduce amount allocation for single number decode#65manigandham merged 12 commits intoullmark:masterfrom jetersen:feat/improveSingleDecode
Conversation
|
I may have missed the purpose of the |
|
The following code throws var hashids = new HashidsNet.Hashids("salt", minHashLength: 4);
var hash = hashids.Encode(123);
Console.WriteLine(hash);
var decoded = hashids.DecodeSingle(hash); // <-- Exception here
Console.WriteLine(decoded); |
|
Thanks I'll take a look. |
|
I think I managed to find a way to actually improve Decode for multiple numbers without allocating string arrays for guards 😄 |
@jetersen this still throws with |
|
Damn empty entries 🤣🤣🤣🤣 |
The slight speed difference I think is only down to outliers... Which is set to not remove 🤔 Before: a7478cd After: a7478cd |
|
Hmm, the following code produces different exception for var hashids = new HashidsNet.Hashids("salt", minHashLength: 0, alphabet: "0123456789ABCDEF");
var hash = hashids.EncodeLong(long.MaxValue);
Console.WriteLine(hash);
var decoded = hashids.DecodeSingleLong(hash + "1"); // HashidsNet.NoResultException on main branch and HashidsNet.MultipleResultsException on PR branch
Console.WriteLine(decoded); |
I've checked the 1.4.1 version and following sample produces array of 0 length: var hashids = new HashidsNet.Hashids("salt", minHashLength: 0, alphabet: "0123456789ABCDEF");
var hash = hashids.EncodeLong(1000);
Console.WriteLine(hash);
var decodedArray = hashids.DecodeLong(hash + "1");
Console.WriteLine(decodedArray.Length); // <-- 0 (No results decoded)While on the PR branch this gives a MultipleResultsException. |
|
I took your example @KeterSCP You specifically added a So how can I can remove the check for separators but than I should also remove the I tried to keep the behavior of hashids.net/src/Hashids.net/Hashids.cs Lines 180 to 181 in b2c7877 |
|
Rebased |
The log doesn't show the changes. You might need to pull down the changes on |
Signed-off-by: Joseph Petersen <josephp90@gmail.com>
|
Rebased successfully 😅 I forgot to fetch upstream before rebasing. |
Well, I just checked how it behaves for invalid hashes and compared how it did before. If such change is ok for the author of library, then i suppose it can be merged. Code looks good. |
As this can never happen without checking for separators.
|
I created 535df3d as another way. This would result in NoResultException when trying to parse multiple when using I can remove the commit as well. I have added my reasons for the PRs in the description. |
| return Array.Empty<long>(); | ||
| } | ||
|
|
||
| private long[] NumbersFrom(string hash) |
There was a problem hiding this comment.
Created this new method to reset stack and avoid stackoverflow 😅
|
Before: After 99a41e4, 395a2d6 and 7567d90: I would like to see if it possible to get them to return But |
| public string EncodeLong(long number) => GenerateHashFrom(stackalloc[] { number }); | ||
| public string EncodeLong(long number) | ||
| { | ||
| Span<char> result = stackalloc char[20]; |
There was a problem hiding this comment.
Why there is a limit of 20 chars? Now it throws if you try to encode value with minHashLength parameter set to >20, however previously it was possible to get string of any length
There was a problem hiding this comment.
I thought the max length for a long was 19 plus 1 for lottery hence 20.
We should have a test that validate any length.
There was a problem hiding this comment.
Also potentially any length does not make sense when it comes to max url length or other serialization issues or memory optimization.
There was a problem hiding this comment.
Don't confuse input number length (e.g var num = 1234 has length of 4) and output hash length (which can differ)
|
hey @jetersen The fundamental problem here is that As nice as it is to have improved performance, I don't think it should come at the cost of correct results. Is there a way to fix this? |
|
@manigandham As you can see there was an argument about this Whether it returns But as you can see I suggest I can revert that change in 535df3d Before 535df3d it is possible to detect multiple entries but apparently the way I do that was not appreciated. I was looking for any Separator characters, and throw Again What difference does it make |
An exception being thrown signals that there's an issue with the operation, but the actual exception type describes why there was an issue. I think it's very important for the user to know so they understand why the result didn't decode (whether there's multiple numbers or none). I'll leave it to @ullmark to decide how to proceed. |
|
@manigandham If the performance increases of this library is important for the ones who uses it, and this looks good we should merge this. tbh; it uses some syntax I've never seen or used (or had any need to) in C#, so @jetersen you are welcome to come in and maintain if you like. :) Re. the errors, if it's not possible to detect multiple entries in a good way, just throw a "NoResultException" since that is still true, given the alphabet + salt, and how you use the library, we weren't able to get a result. 🤷♂️ |
|
@jetersen if you want to change the exception to say |
|
@manigandham it is already throwing |
|
@ullmark I would be happy to help maintain and review PRs 😄 |
|
v1.6.0 released https://www.nuget.org/packages/Hashids.net/1.6.0 |

Reason for change:
Almost 5x saving for single decode
After further changes by adding a optimized splitter using
Span<char>it is only a 2x saving.By adding a specific
GetNumberFromthat handles a single number we avoid creating unnecessary array forlong[]and can simply pass backlongI think it would greatly benefit to also actually have a
GenerateHashFromthat takes single int/long that would mean single encode decode could be 100% allocation free.