with Ada.Calendar.Formatting; package body ULID is function Encode (Code : ULID_Number) return String is -- Crockford's Base32 (5 bits per symbol): crockford : constant String := "0123456789ABCDEFGHJKMNPQRSTVWXYZ"; result : String (1 .. 26); -- ^ The first 10 characters contain a time information (50 bits, -- of them 48 are used); the 16 other characters represent a random -- number (80 bits). x : ULID_Number := Code; begin for c of reverse result loop c := crockford (1 + Integer (x and 31)); x := x / 32; end loop; return result; end Encode; procedure Reset (Generator : Random_Generator) is begin Random_Numbers.Reset (Random_Numbers.Generator (Generator)); end Reset; procedure Reset (Generator : Random_Generator; Seed : Integer) is begin Random_Numbers.Reset (Random_Numbers.Generator (Generator), Seed); end Reset; function Generate_Time_Part (Leap_Second : Boolean; Offset : Ada.Calendar.Time_Zones.Time_Offset) return ULID_Number is use Ada.Calendar; unix_epoch : constant Time := Ada.Calendar.Formatting.Time_Of (1970, 1, 1, 0.0, Leap_Second, Offset); milliseconds_clock : constant ULID_Number := ULID_Number (1000.0 * (Clock - unix_epoch)); begin return milliseconds_clock * 2 ** 80; end Generate_Time_Part; function Generate_Random_Part (Generator : Random_Generator) return ULID_Number is begin return ULID_Number (Random_Numbers.Random (Random_Numbers.Generator (Generator))); end Generate_Random_Part; function Generate (Generator : Random_Generator; Leap_Second : Boolean := False; Offset : Ada.Calendar.Time_Zones.Time_Offset := 0) return ULID_Number is (Generate_Time_Part (Leap_Second, Offset) + Generate_Random_Part (Generator)); function Generate_Monotonic (Previous : ULID_Number; Generator : Random_Generator; Leap_Second : Boolean := False; Offset : Ada.Calendar.Time_Zones.Time_Offset := 0) return ULID_Number is mask : constant := (2 ** 128 - 1) - (2 ** 80 - 1); old_time_part : constant ULID_Number := Previous and mask; new_time_part : constant ULID_Number := Generate_Time_Part (Leap_Second, Offset); begin if new_time_part <= old_time_part then return Previous + 1; else return new_time_part + Generate_Random_Part (Generator); end if; end Generate_Monotonic; function Network_Byte_Order (Code : ULID_Number) return Byte_Array is result : Byte_Array; rest : ULID_Number := Code; begin for i in reverse result'Range loop result (i) := Byte (rest and 255); rest := rest / 256; end loop; return result; end Network_Byte_Order; end ULID;