1 // =================================
  2 // Copyright (c) 2024 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System.IO;
  7 
  8 public delegate void PrintFn();
  9 
 10 public PrintFn printFn;
 11 
 12 public void SetPrintFn(PrintFn fn)
 13 {
 14     printFn = fn;
 15 }
 16 
 17 public void Print()
 18 {
 19     if (printFn != PrintFn())
 20     {
 21         printFn();
 22     }
 23 }
 24 
 25 namespace System
 26 {
 27     public class Uuid
 28     {
 29         public const long size = 16;
 30 
 31         public typedef byte[size].Iterator Iterator;
 32         public typedef byte[size].ConstIterator ConstIterator;
 33 
 34         public inline Iterator Begin()
 35         {
 36             return data.Begin();
 37         }
 38         public inline ConstIterator Begin() const
 39         {
 40             return data.CBegin();
 41         }
 42         public inline ConstIterator CBegin() const
 43         {
 44             return data.CBegin();
 45         }
 46         public inline Iterator End()
 47         {
 48             return data.End();
 49         }
 50         public inline ConstIterator End() const
 51         {
 52             return data.CEnd();
 53         }
 54         public inline ConstIterator CEnd() const
 55         {
 56             return data.CEnd();
 57         }
 58 
 59         public Uuid() : data()
 60         {
 61         }
 62         public Uuid(ulong leftHalfulong rightHalf) : data()
 63         {
 64             ulong* l = cast<ulong*>(cast<void*>(Begin()));
 65             *l = leftHalf;
 66             ulong* r = cast<ulong*>(cast<void*>(Begin() + sizeof(ulong)));
 67             *r = rightHalf;
 68         }
 69         public ulong LeftHalf() const
 70         {
 71             ulong* l = cast<ulong*>(cast<void*>(Begin()));
 72             return *l;
 73         }
 74         public ulong RightHalf() const
 75         {
 76             ulong* r = cast<ulong*>(cast<void*>(Begin() + sizeof(ulong)));
 77             return *r;
 78         }
 79         public static Uuid Random()
 80         {
 81             return Uuid(Random64()Random64());
 82         }
 83         public bool IsNil() const
 84         {
 85             for (byte x : data)
 86             {
 87                 if (x != 0u) return false;
 88             }
 89             return true;
 90         }
 91         public byte[size] data;
 92     }
 93 
 94     public bool operator==(const Uuid& leftconst Uuid& right)
 95     {
 96         void* l = cast<void*>(&left);
 97         ulong lx = cast<ulong>(l);
 98         if (lx <= 256u               )
 99         {
100             Print();
101         }
102         void* r = cast<void*>(&right);
103         ulong rx = cast<ulong>(r);
104         if (rx <= 256u               )
105         {
106             Print();
107         }
108         #assert(lx > 256u);
109         #assert(rx > 256u);
110         for (long i = 0; i < Uuid.size; ++i;)
111         {
112             if (left.data[i] != right.data[i]) return false;
113         }
114         return true;
115     }
116 
117     public bool operator<(const Uuid& leftconst Uuid& right)
118     {
119         if (left.LeftHalf() < right.LeftHalf()) return true;
120         if (left.LeftHalf() > right.LeftHalf()) return false;
121         return left.RightHalf() < right.RightHalf();
122     }
123 
124     [nodiscard]
125     public Result<string> ToString(const Uuid& uuid)
126     {
127         string s;
128         int index = 0;
129         for (byte x : uuid)
130         {
131             auto hexStringResult = ToHexString(x);
132             if (hexStringResult.Error())
133             {
134                 return Result<string>(ErrorId(hexStringResult.GetErrorId()));
135             }
136             auto toLowerResult = ToLower(hexStringResult.Value());
137             if (toLowerResult.Error())
138             {
139                 return Result<string>(ErrorId(toLowerResult.GetErrorId()));
140             }
141             s.Append(toLowerResult.Value());
142             if (index == 3 || index == 5 || index == 7 || index == 9)
143             {
144                 s.Append('-');
145             }
146             ++index;
147         }
148         return Result<string>(s);
149     }
150 
151     [nodiscard]
152     public Result<Uuid> ParseUuid(const string& uuidHexString)
153     {
154         if (uuidHexString.Length() != 2 * Uuid.size + 4)
155         {
156             string errorMessage = "wrong number of hex bytes in uuid string \'" + uuidHexString + "\'." + ToString(Uuid.size) + " hex bytes + 4 hyphens expected.";
157             int errorId = RtmAllocateError(errorMessage.Chars());
158             return Result<Uuid>(ErrorId(errorId));
159         }
160         Uuid uuid;
161         int index = 0;
162         for (long i = 0; i < Uuid.size; ++i;)
163         {
164             string hexByteStr = uuidHexString.Substring(index2);
165             auto hexByte = ParseHexByte(hexByteStr);
166             if (hexByte.Error())
167             {
168                 return Result<Uuid>(ErrorId(hexByte.GetErrorId()));
169             }
170             uuid.data[i] = hexByte.Value();
171             ++index;
172             ++index;
173             if (i == 3 || i == 5 || i == 7 || i == 9)
174             {
175                 ++index;
176             }
177         }
178         return Result<Uuid>(uuid);
179     }
180 
181     public TextWriter& operator<<(TextWriter& writerconst Uuid& uuid)
182     {
183         auto result = ToString(uuid);
184         if (result.Error())
185         {
186             writer.SetErrorId(result.GetErrorId());
187             return writer;
188         }
189         return writer << result.Value();
190     }
191