@@ -14,7 +14,7 @@ public partial class Hashids : IHashids
1414 public const string DEFAULT_ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" ;
1515 public const string DEFAULT_SEPS = "cfhistuCFHISTU" ;
1616 public const int MIN_ALPHABET_LENGTH = 16 ;
17- public const int MAX_STACKALLOC_SIZE = 512 ;
17+ private const int MAX_STACKALLOC_SIZE = 512 ;
1818
1919 private const double SEP_DIV = 3.5 ;
2020 private const double GUARD_DIV = 12.0 ;
@@ -24,6 +24,7 @@ public partial class Hashids : IHashids
2424 private readonly char [ ] _guards ;
2525 private readonly char [ ] _salt ;
2626 private readonly int _minHashLength ;
27+ private readonly int _minBufferSize ;
2728
2829 // Creates the Regex in the first usage, speed up first use of non-hex methods
2930 private static readonly Lazy < Regex > HexValidator = new ( ( ) => new Regex ( "^[0-9a-fA-F]+$" , RegexOptions . Compiled ) ) ;
@@ -61,6 +62,9 @@ public Hashids(
6162 _minHashLength = minHashLength ;
6263 _alphabet = alphabet . ToCharArray ( ) . Distinct ( ) . ToArray ( ) ;
6364 _seps = seps . ToCharArray ( ) ;
65+
66+ // use min buffer size of 20 which is 1 digit longer than the biggest 64-bit integer (long.MaxValue = 9223372036854775807)
67+ _minBufferSize = Math . Max ( 20 , minHashLength ) ;
6468
6569 if ( _alphabet . Length < MIN_ALPHABET_LENGTH )
6670 throw new ArgumentException ( $ "Alphabet must contain at least { MIN_ALPHABET_LENGTH : N0} unique characters.", paramName : nameof ( alphabet ) ) ;
@@ -142,8 +146,8 @@ public Hashids(
142146 /// <returns>the hashed string</returns>
143147 public string EncodeLong ( long number )
144148 {
145- var numberLength = _minHashLength > 20 ? _minHashLength : 20 ;
146- var result = numberLength < 512 ? stackalloc char [ numberLength ] : new char [ numberLength ] ;
149+ var numberLength = _minBufferSize ;
150+ var result = numberLength < MAX_STACKALLOC_SIZE ? stackalloc char [ numberLength ] : new char [ numberLength ] ;
147151 var length = GenerateHashFrom ( number , ref result ) ;
148152 return length == - 1 ? string . Empty : result . Slice ( 0 , length ) . ToString ( ) ;
149153 }
@@ -155,8 +159,8 @@ public string EncodeLong(long number)
155159 /// <returns>Encoded hash string.</returns>
156160 public string EncodeLong ( params long [ ] numbers )
157161 {
158- var numbersLength = _minHashLength > 20 ? _minHashLength * numbers . Length : numbers . Length * 20 ;
159- var result = numbersLength < 512 ? stackalloc char [ numbersLength ] : new char [ numbersLength ] ;
162+ var numbersLength = _minBufferSize * numbers . Length ;
163+ var result = numbersLength < MAX_STACKALLOC_SIZE ? stackalloc char [ numbersLength ] : new char [ numbersLength ] ;
160164 var length = GenerateHashFrom ( numbers , ref result ) ;
161165 return length == - 1 ? string . Empty : result . Slice ( 0 , length ) . ToString ( ) ;
162166 }
@@ -290,21 +294,20 @@ private int GenerateHashFrom(long number, ref Span<char> result)
290294
291295 var numberHashInt = number % 100 ;
292296
293- var alphabet = _alphabet . Length < 512 ? stackalloc char [ _alphabet . Length ] : new char [ _alphabet . Length ] ;
297+ var alphabet = _alphabet . Length < MAX_STACKALLOC_SIZE ? stackalloc char [ _alphabet . Length ] : new char [ _alphabet . Length ] ;
294298 _alphabet . CopyTo ( alphabet ) ;
295299
296300 var lottery = alphabet [ ( int ) ( numberHashInt % _alphabet . Length ) ] ;
297301 result [ 0 ] = lottery ;
298302
299- var shuffleBuffer = _alphabet . Length < 512 ? stackalloc char [ _alphabet . Length ] : new char [ _alphabet . Length ] ;
303+ var shuffleBuffer = _alphabet . Length < MAX_STACKALLOC_SIZE ? stackalloc char [ _alphabet . Length ] : new char [ _alphabet . Length ] ;
300304 shuffleBuffer [ 0 ] = lottery ;
301305 _salt . AsSpan ( ) . Slice ( 0 , Math . Min ( _salt . Length , _alphabet . Length - 1 ) ) . CopyTo ( shuffleBuffer . Slice ( 1 ) ) ;
302306
303307 var startIndex = 1 + _salt . Length ;
304308 var length = _alphabet . Length - startIndex ;
305309
306- // use buffer size of 19 which is the length of the biggest 64-bit integer (long.MaxValue = 9223372036854775807)
307- Span < char > hashBuffer = stackalloc char [ 19 ] ;
310+ Span < char > hashBuffer = stackalloc char [ _minBufferSize ] ;
308311
309312 if ( length > 0 )
310313 alphabet . Slice ( 0 , length ) . CopyTo ( shuffleBuffer . Slice ( startIndex ) ) ;
@@ -409,8 +412,7 @@ private int GenerateHashFrom(ReadOnlySpan<long> numbers, ref Span<char> result)
409412 var startIndex = 1 + _salt . Length ;
410413 var length = _alphabet . Length - startIndex ;
411414
412- // use buffer size of 19 which is the length of the biggest 64-bit integer (long.MaxValue = 9223372036854775807)
413- Span < char > hashBuffer = stackalloc char [ 19 ] ;
415+ Span < char > hashBuffer = stackalloc char [ _minBufferSize ] ;
414416
415417 for ( var i = 0 ; i < numbers . Length ; i ++ )
416418 {
@@ -495,8 +497,7 @@ private int BuildReversedHash(long input, ReadOnlySpan<char> alphabet, Span<char
495497 hashBuffer [ length ] = alphabet [ idx ] ;
496498 length += 1 ;
497499 input /= _alphabet . Length ;
498- }
499- while ( input > 0 ) ;
500+ } while ( input > 0 ) ;
500501
501502 return length ;
502503 }
@@ -534,10 +535,10 @@ private long GetNumberFrom(string hash)
534535
535536 var hashBuffer = hashBreakdown . Slice ( 1 ) ;
536537
537- Span < char > alphabet = _alphabet . Length < 512 ? stackalloc char [ _alphabet . Length ] : new char [ _alphabet . Length ] ;
538+ Span < char > alphabet = _alphabet . Length < MAX_STACKALLOC_SIZE ? stackalloc char [ _alphabet . Length ] : new char [ _alphabet . Length ] ;
538539 _alphabet . CopyTo ( alphabet ) ;
539540
540- Span < char > buffer = _alphabet . Length < 512 ? stackalloc char [ _alphabet . Length ] : new char [ _alphabet . Length ] ;
541+ Span < char > buffer = _alphabet . Length < MAX_STACKALLOC_SIZE ? stackalloc char [ _alphabet . Length ] : new char [ _alphabet . Length ] ;
541542 buffer [ 0 ] = lottery ;
542543 _salt . AsSpan ( ) . Slice ( 0 , Math . Min ( _salt . Length , _alphabet . Length - 1 ) ) . CopyTo ( buffer . Slice ( 1 ) ) ;
543544
@@ -550,10 +551,12 @@ private long GetNumberFrom(string hash)
550551 ConsistentShuffle ( alphabet , buffer ) ;
551552 var result = Unhash ( hashBuffer , alphabet ) ;
552553
553- Span < char > resultBuffer = stackalloc char [ guardedHash . Length ] ;
554+ // regenerate hash from numbers and compare to given hash to ensure the correct parameters were used
555+ // ensure buffer is big enough based on what was generated
556+ var bufferSize = Math . Max ( _minBufferSize , guardedHash . Length ) ;
557+ Span < char > resultBuffer = stackalloc char [ bufferSize ] ;
554558 var hashLength = GenerateHashFrom ( result , ref resultBuffer ) ;
555559 ReadOnlySpan < char > rehash = resultBuffer . Slice ( 0 , hashLength ) ;
556- // regenerate hash from numbers and compare to given hash to ensure the correct parameters were used
557560 if ( guardedHash . Equals ( rehash , StringComparison . Ordinal ) )
558561 return result ;
559562
@@ -564,10 +567,11 @@ private long[] GetNumbersFrom(string hash)
564567 {
565568 var result = NumbersFrom ( hash ) ;
566569
567- Span < char > hashBuffer = hash . Length < 512 ? stackalloc char [ hash . Length ] : new char [ hash . Length ] ;
570+ Span < char > hashBuffer = hash . Length < MAX_STACKALLOC_SIZE ? stackalloc char [ hash . Length ] : new char [ hash . Length ] ;
568571 var hashLength = GenerateHashFrom ( result , ref hashBuffer ) ;
569572 if ( hashLength == - 1 )
570573 return Array . Empty < long > ( ) ;
574+
571575 ReadOnlySpan < char > rehash = hashBuffer . Slice ( 0 , hashLength ) ;
572576 // regenerate hash from numbers and compare to given hash to ensure the correct parameters were used
573577 if ( hash . AsSpan ( ) . Equals ( rehash , StringComparison . Ordinal ) )
0 commit comments