namespace SharpChat.Snowflake; public class SnowflakeGenerator { public const long MASK = 0x7FFFFFFFFFFFFFFF; // previous default epoch was 1588377600000, but snowflakes are much larger than SharpIds public const long EPOCH = 1356998400000; public const byte SHIFT = 16; public readonly long Epoch; public readonly byte Shift; public readonly long TimestampMask; public readonly long SequenceMask; public SnowflakeGenerator(long epoch = EPOCH, byte shift = SHIFT) { if(epoch is < 0 or > MASK) throw new ArgumentException("Epoch must be a positive int64.", nameof(epoch)); if(shift is < 1 or > 63) throw new ArgumentException("Shift must be between or equal to 1 and 63", nameof(shift)); Epoch = epoch; Shift = shift; // i think Index only does this as a hack for how integers work in PHP but its gonna run Once per application instance lol TimestampMask = ~(~0L << (63 - shift)); SequenceMask = ~(~0L << shift); } public long Now(DateTimeOffset? at = null) { return Math.Max(0, (at ?? DateTimeOffset.UtcNow).ToUnixTimeMilliseconds() - Epoch); } public long Next(long sequence, DateTimeOffset? at = null) { return ((Now(at) & TimestampMask) << Shift) | (sequence & SequenceMask); } }