Skip to content

Huntk23/SequentialRadixCodec

Repository files navigation

Sequential Radix Codec

CI NuGet NuGet Downloads

A .NET library for sequential, sortable base-N (radix) encoding over a custom alphabet. It maps non-negative integers to left-padded, monotonically increasing codes and back - for serial numbers, license keys, and sortable short IDs.

Targets net10.0 and netstandard2.0. The net10.0 build adds a FrozenDictionary lookup, AOT/trim compatibility, and a zero-allocation TryEncode(Span<char>).

NOTE: Codes are predictable and reversible: the next code is trivially guessable and any code decodes straight back to its number. Don't use this where you need unguessable or non-enumerable IDs (use a GUID) or obfuscated IDs that hide the underlying sequence (use Hashids/Sqids). It also doesn't generate uniqueness; feed it unique numbers (e.g. a database sequence) and the codes are unique; feed it duplicates and they will collide.

Install

dotnet add package SequentialRadixCodec

Pre-built codecs

Codec Alphabet Min width
RadixCodec.Base10 0-9 5
RadixCodec.Base26 A-Z 5
RadixCodec.Base36 0-9A-Z 5

Encode / Decode

using SequentialRadixCodec;

string code = RadixCodec.Base26.Encode(1001);               // "AABMN"

// Pick the return width you want (no BigInteger required):
int i = RadixCodec.Base26.DecodeInt32("AABMN");             // 1001
long l = RadixCodec.Base26.DecodeInt64("AABMN");            // 1001
BigInteger b = RadixCodec.Base26.DecodeBigInteger("AABMN"); // 1001

// Non-throwing decode (false on null/empty/invalid/out-of-range):
if (RadixCodec.Base26.TryDecodeInt64(userInput, out long value)) { }

DecodeInt32 / DecodeInt64 throw OverflowException if the decoded value exceeds int.MaxValue / long.MaxValue; the TryDecode* variants return false instead. DecodeBigInteger never overflows, so values beyond int/long round-trip cleanly.

Custom Alphabet

var codec = new RadixCodec("02357ABC");      // first char '0' is the pad digit
string code = codec.Encode(1001);            // "2CA2"
BigInteger n = codec.DecodeBigInteger(code); // 1001

Custom codecs default to minLength: 1 (no padding). Pass a minLength to pad.

Padding

The minimum width left-pads with alphabet[0]; a longer natural encoding is never truncated. Override per call:

var codec = new RadixCodec("ABCDEFGHIJKLMNOPQRSTUVWXYZ", minLength: 4);
codec.Encode(1001);      // "ABMN"
// Override call
codec.Encode(1001, 8);   // "AAAAABMN"

Generating Sequences

// Next 100 Base26 codes after a stored value:
BigInteger last = RadixCodec.Base26.DecodeBigInteger("AABMM");
foreach (var code in RadixSequence.From(RadixCodec.Base26, start: last + 1, count: 100))
    Console.Write($"{code} ");

// Unbounded + LINQ:
var page = RadixSequence.From(RadixCodec.Base10).Skip(1000).Take(50);

Zero-allocation Enumeration (net10.0+)

Stream consecutive codes into a reused buffer — no per-item string allocation, no BigInteger. Current is valid only until the next iteration.

// Caller owns the buffer (zero heap allocation):
Span<char> buf = stackalloc char[16];
foreach (ReadOnlySpan<char> code in RadixSequence.EnumerateInto(RadixCodec.Base26, buf, start: 1001, count: 100))
{
    // Do something with "code"
}

// Pooled buffer (no sizing needed; foreach returns it to the pool):
foreach (ReadOnlySpan<char> code in RadixSequence.Enumerate(RadixCodec.Base36, start: 10_000_000_000))
{
    // Do Something with "code"
}

start/count are long (count omitted = unbounded). For EnumerateInto, a bounded range whose largest code cannot fit the buffer throws ArgumentException up front; an unbounded range stops when the next code no longer fits.

Zero-allocation Encode (net10.0+)

Span<char> buffer = stackalloc char[16];
if (RadixCodec.Base36.TryEncode(value, buffer, out int written))
{
    // Do something with "buffer[..written];"
}
    

License

MIT

About

Sequential, sortable base-N (radix) codec over a custom alphabet. Encodes and decodes non-negative integers to left-padded, monotonically ordered codes, serial numbers, license keys, sortable short IDs.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages