blob: 46e238cdd4269055159c9afe28ab459ecb838d9e [file] [log] [blame]
Jens Geyerd5436f52014-10-03 19:50:38 +02001(*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *)
19
20unit Thrift.Utils;
21
22interface
23
Jens Geyer9f7f11e2016-04-14 21:37:11 +020024{$I Thrift.Defines.inc}
Nick4f5229e2016-04-14 16:43:22 +030025
Jens Geyerd5436f52014-10-03 19:50:38 +020026uses
Jens Geyer9f7f11e2016-04-14 21:37:11 +020027 {$IFDEF OLD_UNIT_NAMES}
Jens Geyer8f7487e2019-05-09 22:21:32 +020028 Classes, Windows, SysUtils, Character, SyncObjs, TypInfo, Rtti;
Jens Geyer9f7f11e2016-04-14 21:37:11 +020029 {$ELSE}
Jens Geyer8f7487e2019-05-09 22:21:32 +020030 System.Classes, Winapi.Windows, System.SysUtils, System.Character,
31 System.SyncObjs, System.TypInfo, System.Rtti;
Jens Geyer9f7f11e2016-04-14 21:37:11 +020032 {$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +020033
34type
Jens Geyer8f7487e2019-05-09 22:21:32 +020035 ISupportsToString = interface
36 ['{AF71C350-E0CD-4E94-B77C-0310DC8227FF}']
37 function ToString : string;
38 end;
39
40
Jens Geyerd5436f52014-10-03 19:50:38 +020041 IOverlappedHelper = interface
42 ['{A1832EFA-2E02-4884-8F09-F0A0277157FA}']
43 function Overlapped : TOverlapped;
44 function OverlappedPtr : POverlapped;
45 function WaitHandle : THandle;
46 function WaitFor(dwTimeout: DWORD) : DWORD;
47 end;
48
49 TOverlappedHelperImpl = class( TInterfacedObject, IOverlappedHelper)
50 strict protected
51 FOverlapped : TOverlapped;
52 FEvent : TEvent;
53
54 // IOverlappedHelper
55 function Overlapped : TOverlapped;
56 function OverlappedPtr : POverlapped;
57 function WaitHandle : THandle;
58 function WaitFor(dwTimeout: DWORD) : DWORD;
59 public
60 constructor Create;
61 destructor Destroy; override;
62 end;
63
64
Jens Geyer8f7487e2019-05-09 22:21:32 +020065 TThriftStringBuilder = class( TStringBuilder)
66 public
67 function Append(const Value: TBytes): TStringBuilder; overload;
68 function Append(const Value: ISupportsToString): TStringBuilder; overload;
69 end;
70
71
Jens Geyerd8bddbc2014-12-14 00:41:33 +010072 Base64Utils = class sealed
73 public
74 class function Encode( const src : TBytes; srcOff, len : Integer; dst : TBytes; dstOff : Integer) : Integer; static;
75 class function Decode( const src : TBytes; srcOff, len : Integer; dst : TBytes; dstOff : Integer) : Integer; static;
76 end;
77
78
Jens Geyer71070432016-01-29 10:08:39 +010079 CharUtils = class sealed
80 public
81 class function IsHighSurrogate( const c : Char) : Boolean; static; inline;
82 class function IsLowSurrogate( const c : Char) : Boolean; static; inline;
83 end;
84
Jens Geyer8f7487e2019-05-09 22:21:32 +020085 EnumUtils<T> = class sealed
86 public
87 class function ToString(const value : Integer) : string; reintroduce; static; inline;
88 end;
89
90 StringUtils<T> = class sealed
91 public
92 class function ToString(const value : T) : string; reintroduce; static; inline;
93 end;
94
Jens Geyer71070432016-01-29 10:08:39 +010095
Jens Geyerf7904452017-07-26 15:02:12 +020096{$IFDEF Win64}
97function InterlockedExchangeAdd64( var Addend : Int64; Value : Int64) : Int64;
98{$ENDIF}
Jens Geyer9f7f11e2016-04-14 21:37:11 +020099
Jens Geyer71070432016-01-29 10:08:39 +0100100
Jens Geyerd5436f52014-10-03 19:50:38 +0200101implementation
102
Jens Geyerd5436f52014-10-03 19:50:38 +0200103{ TOverlappedHelperImpl }
104
105constructor TOverlappedHelperImpl.Create;
106begin
107 inherited Create;
108 FillChar( FOverlapped, SizeOf(FOverlapped), 0);
109 FEvent := TEvent.Create( nil, TRUE, FALSE, ''); // always ManualReset, see MSDN
110 FOverlapped.hEvent := FEvent.Handle;
111end;
112
113
114
115destructor TOverlappedHelperImpl.Destroy;
116begin
117 try
118 FOverlapped.hEvent := 0;
119 FreeAndNil( FEvent);
120
121 finally
122 inherited Destroy;
123 end;
124
125end;
126
127
128function TOverlappedHelperImpl.Overlapped : TOverlapped;
129begin
130 result := FOverlapped;
131end;
132
133
134function TOverlappedHelperImpl.OverlappedPtr : POverlapped;
135begin
136 result := @FOverlapped;
137end;
138
139
140function TOverlappedHelperImpl.WaitHandle : THandle;
141begin
142 result := FOverlapped.hEvent;
143end;
144
145
146function TOverlappedHelperImpl.WaitFor( dwTimeout : DWORD) : DWORD;
147begin
148 result := WaitForSingleObject( FOverlapped.hEvent, dwTimeout);
149end;
150
151
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100152{ Base64Utils }
153
154class function Base64Utils.Encode( const src : TBytes; srcOff, len : Integer; dst : TBytes; dstOff : Integer) : Integer;
155const ENCODE_TABLE : PAnsiChar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
156begin
157 ASSERT( len in [1..3]);
158 dst[dstOff] := Byte( ENCODE_TABLE[ (src[srcOff] shr 2) and $3F]);
159 case len of
160 3 : begin
161 Inc(dstOff);
162 dst[dstOff] := Byte( ENCODE_TABLE[ ((src[srcOff] shl 4) and $30) or ((src[srcOff + 1] shr 4) and $0F)]);
163 Inc(dstOff);
164 dst[dstOff] := Byte( ENCODE_TABLE[ ((src[srcOff + 1] shl 2) and $3C) or ((src[srcOff + 2] shr 6) and $03)]);
165 Inc(dstOff);
166 dst[dstOff] := Byte( ENCODE_TABLE[ src[srcOff + 2] and $3F]);
167 result := 4;
168 end;
169
170 2 : begin
171 Inc(dstOff);
172 dst[dstOff] := Byte( ENCODE_TABLE[ ((src[srcOff] shl 4) and $30) or ((src[srcOff + 1] shr 4) and $0F)]);
173 Inc(dstOff);
174 dst[dstOff] := Byte( ENCODE_TABLE[ (src[srcOff + 1] shl 2) and $3C]);
175 result := 3;
176 end;
177
178 1 : begin
179 Inc(dstOff);
180 dst[dstOff] := Byte( ENCODE_TABLE[ (src[srcOff] shl 4) and $30]);
181 result := 2;
182 end;
183
184 else
185 ASSERT( FALSE);
Jens Geyer9f9535c2014-12-14 04:16:05 +0100186 result := 0; // because invalid call
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100187 end;
188end;
189
190
191class function Base64Utils.Decode( const src : TBytes; srcOff, len : Integer; dst : TBytes; dstOff : Integer) : Integer;
192const DECODE_TABLE : array[0..$FF] of Integer
193 = ( -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
194 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
195 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
196 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
197 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
198 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
199 -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
200 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
201 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
202 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
203 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
204 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
205 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
206 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
207 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
208 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 );
209begin
210 ASSERT( len in [1..4]);
211 result := 1;
212 dst[dstOff] := ((DECODE_TABLE[src[srcOff] and $0FF] shl 2)
213 or (DECODE_TABLE[src[srcOff + 1] and $0FF] shr 4));
214
215 if (len > 2) then begin
216 Inc( result);
217 Inc( dstOff);
218 dst[dstOff] := (((DECODE_TABLE[src[srcOff + 1] and $0FF] shl 4) and $F0)
219 or (DECODE_TABLE[src[srcOff + 2] and $0FF] shr 2));
220
221 if (len > 3) then begin
222 Inc( result);
223 Inc( dstOff);
224 dst[dstOff] := (((DECODE_TABLE[src[srcOff + 2] and $0FF] shl 6) and $C0)
225 or DECODE_TABLE[src[srcOff + 3] and $0FF]);
226 end;
227 end;
228end;
Jens Geyerd5436f52014-10-03 19:50:38 +0200229
230
Jens Geyer71070432016-01-29 10:08:39 +0100231class function CharUtils.IsHighSurrogate( const c : Char) : Boolean;
232begin
Jens Geyer36c0b342018-01-19 19:17:33 +0100233 {$IF CompilerVersion < 25.0}
234 {$IFDEF OLD_UNIT_NAMES}
235 result := Character.IsHighSurrogate(c);
236 {$ELSE}
237 result := System.Character.IsHighSurrogate(c);
238 {$ENDIF}
Jens Geyer71070432016-01-29 10:08:39 +0100239 {$ELSE}
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200240 result := c.IsHighSurrogate();
Jens Geyer71070432016-01-29 10:08:39 +0100241 {$IFEND}
242end;
243
244
245class function CharUtils.IsLowSurrogate( const c : Char) : Boolean;
246begin
Jens Geyer36c0b342018-01-19 19:17:33 +0100247 {$IF CompilerVersion < 25.0}
248 {$IFDEF OLD_UNIT_NAMES}
249 result := Character.IsLowSurrogate(c);
250 {$ELSE}
251 result := System.Character.IsLowSurrogate(c);
252 {$ENDIF}
Jens Geyer71070432016-01-29 10:08:39 +0100253 {$ELSE}
Jens Geyer36c0b342018-01-19 19:17:33 +0100254 result := c.IsLowSurrogate();
Jens Geyer71070432016-01-29 10:08:39 +0100255 {$IFEND}
256end;
257
258
Jens Geyerf7904452017-07-26 15:02:12 +0200259{$IFDEF Win64}
260
261function InterlockedCompareExchange64( var Target : Int64; Exchange, Comparand : Int64) : Int64; inline;
262begin
263 {$IFDEF OLD_UNIT_NAMES}
264 result := Windows.InterlockedCompareExchange64( Target, Exchange, Comparand);
265 {$ELSE}
266 result := WinApi.Windows.InterlockedCompareExchange64( Target, Exchange, Comparand);
267 {$ENDIF}
268end;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200269
270
Jens Geyerf7904452017-07-26 15:02:12 +0200271function InterlockedExchangeAdd64( var Addend : Int64; Value : Int64) : Int64;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200272var old : Int64;
273begin
274 repeat
275 Old := Addend;
276 until (InterlockedCompareExchange64( Addend, Old + Value, Old) = Old);
277 result := Old;
278end;
279
Jens Geyerf7904452017-07-26 15:02:12 +0200280{$ENDIF}
Jens Geyer71070432016-01-29 10:08:39 +0100281
282
Jens Geyer8f7487e2019-05-09 22:21:32 +0200283{ EnumUtils<T> }
284
285class function EnumUtils<T>.ToString(const value : Integer) : string;
286var pType : PTypeInfo;
287begin
288 pType := PTypeInfo(TypeInfo(T));
289 if Assigned(pType) and (pType^.Kind = tkEnumeration)
290 then result := GetEnumName(pType,value)
291 else result := IntToStr(Ord(value));
292end;
293
294
295{ StringUtils<T> }
296
297class function StringUtils<T>.ToString(const value : T) : string;
298var pType : PTypeInfo;
299 base : ISupportsToString;
300begin
301 pType := PTypeInfo(TypeInfo(T));
302 if Assigned(pType) then begin
303 case pType^.Kind of
304 tkInterface : begin
305 if Supports(IInterface(value), ISupportsToString, base) then begin
306 result := base.toString;
307 Exit;
308 end;
309 end;
310 end;
311 end;
312
313 result := TValue.From<T>(value).ToString;
314end;
315
316
317{ TThriftStringBuilder }
318
319function TThriftStringBuilder.Append(const Value: TBytes): TStringBuilder;
320begin
321 Result := Append( string( RawByteString(Value)) );
322end;
323
324function TThriftStringBuilder.Append( const Value: ISupportsToString): TStringBuilder;
325begin
326 Result := Append( Value.ToString );
327end;
328
329
Jens Geyerd5436f52014-10-03 19:50:38 +0200330end.