unit SANPSD2PNG.FileOrDirectoryMonitor;
interface
uses
Winapi.Windows,
System.SysUtils, System.Classes, System.StrUtils;
const
/// <summary>
/// Набор флагов мониторинга всего.
/// </summary>
FILE_NOTIFY_ALL = FILE_NOTIFY_CHANGE_FILE_NAME
or FILE_NOTIFY_CHANGE_DIR_NAME
or FILE_NOTIFY_CHANGE_ATTRIBUTES
or FILE_NOTIFY_CHANGE_SIZE
or FILE_NOTIFY_CHANGE_LAST_WRITE
or FILE_NOTIFY_CHANGE_LAST_ACCESS
or FILE_NOTIFY_CHANGE_CREATION
or FILE_NOTIFY_CHANGE_SECURITY
;
/// <summary>
/// Таймаут ожидания событий в потоках.
/// </summary>
/// <remarks>
/// Влияет на тормоза при завершении приложения.
/// </remarks>
THREAD_WAIT_TIMEOUT = 500;
type
/// <summary>
/// Событие монитора в потоке.
/// </summary>
TFileOrDirectoryMonitorFileEvent = procedure(Sender : TObject;
AThread : TThread; const AFileName : string; AAction : Cardinal) of object;
/// <summary>
/// Монитор изменений папки/файла.
/// </summary>
TFileOrDirectoryMonitor = class(TObject)
private
FPath : string;
FFileNotifyFlags : integer;
FThread : TThread;
FOnChange : TFileOrDirectoryMonitorFileEvent;
procedure MonitoringNotification(const ABufferPtr : Pointer);
public
/// <summary>
/// Конструктор.
/// </summary>
/// <param name="AFileOrDirectory">
/// Имя объекта файловой системы, за которым следим.
/// </param>
/// <param name="AFileNotifyFlags">
/// Перечень событий.
/// </param>
constructor Create(const AFileOrDirectory : string; const AFileNotifyFlags : integer = FILE_NOTIFY_ALL);
destructor Destroy; override;
/// <summary>
/// Имя объекта файловой системы, за которым следим.
/// </summary>
property FileOrDirectory : string read FPath;
/// <summary>
/// Событие изменения файла в потоке мониторинга.
/// </summary>
property OnChange : TFileOrDirectoryMonitorFileEvent read FOnChange write FOnChange;
end;
implementation
const
MONITORING_BUF_SIZE = 2048;
type
/// <summary>
/// Указатель на буфер мониторинга.
/// </summary>
PMonitoringBuffer = ^TMonitoringBuffer;
/// <summary>
/// Буфер мониторинга.
/// </summary>
TMonitoringBuffer = array [0..MONITORING_BUF_SIZE - 1] of byte;
/// <summary>
/// Массив из двух описателей.
/// </summary>
THandles2 = array [0..1] of THandle;
/// <summary>
/// Внутренний поток мониторинга.
/// </summary>
TFileOrDirectoryMonitorThread = class(TThread)
strict private
FMonitor : TFileOrDirectoryMonitor;
FTerminateEvent : THandle;
procedure HandleException;
protected
procedure TerminatedSet; override;
procedure Execute; override;
public
constructor Create(const AMonitor : TFileOrDirectoryMonitor);
destructor Destroy; override;
end;
{$REGION 'TFileOrDirectoryMonitorThread'}
constructor TFileOrDirectoryMonitorThread.Create(
const AMonitor : TFileOrDirectoryMonitor);
begin
FMonitor := AMonitor;
FTerminateEvent := CreateEvent(nil, True, False, nil);
if FTerminateEvent = 0 then
RaiseLastOSError;
inherited Create(False);
end;
destructor TFileOrDirectoryMonitorThread.Destroy;
begin
CloseHandle(FTerminateEvent);
inherited;
end;
procedure TFileOrDirectoryMonitorThread.TerminatedSet;
begin
inherited;
if not SetEvent(FTerminateEvent) then
RaiseLastOSError;
end;
procedure TFileOrDirectoryMonitorThread.Execute;
function OpenFileHandle : THandle;
begin
Result := CreateFile(PChar(FMonitor.FPath), GENERIC_READ,FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
if Result = INVALID_HANDLE_VALUE then
RaiseLastOSError;
end;
var
FileHandle: THandle;
Buffer : TMonitoringBuffer;
Overlapped : TOverlapped;
Handles : THandles2;
procedure ResetMonitoring;
begin
FillChar(Buffer, MONITORING_BUF_SIZE, 0);
FillChar(Overlapped, SizeOf(TOverlapped), 0);
Overlapped.hEvent := Handles[1];
if not ReadDirectoryChangesW(FileHandle, @Buffer, MONITORING_BUF_SIZE, True, FMonitor.FFileNotifyFlags, nil, @Overlapped, nil) then
RaiseLastOSError;
end;
var
WaitRes : Cardinal;
begin
NameThreadForDebugging('FileOrDirectoryMonitor for "' + FMonitor.FPath + '"');
try
Handles[0] := FTerminateEvent;
Handles[1] := CreateEvent(nil, False, False, nil);
if Handles[1] = 0 then
RaiseLastOSError;
try
FileHandle := OpenFileHandle;
try
ResetMonitoring;
repeat
WaitRes := WaitForMultipleObjects(High(Handles) + 1, @Handles, False, THREAD_WAIT_TIMEOUT);
case WaitRes of
WAIT_OBJECT_0 + 0:
Break;
WAIT_OBJECT_0 + 1:
begin
FMonitor.MonitoringNotification(@Buffer);
ResetMonitoring;
end;
WAIT_TIMEOUT:
Sleep(1);
WAIT_FAILED:
RaiseLastOSError;
else
Assert(False, 'WaitForMultipleObjects = ' + IntToStr(WaitRes));
end;
until Terminated;
finally
CloseHandle(FileHandle)
end;
finally
CloseHandle(Handles[1]);
end;
except
HandleException;
end;
end;
procedure TFileOrDirectoryMonitorThread.HandleException;
var
P : TThreadProcedure;
E : Exception;
begin
P := procedure
begin
Self.WaitFor;
try
raise E;
except
Exception.RaiseOuterException(EThread.CreateFmt('Исключение в потоке мониторинга для "%s"', [FMonitor.FPath]));
end;
end;
E := Exception(AcquireExceptionObject);
Queue(P);
end;
{$ENDREGION}
{$REGION 'TFileOrDirectoryMonitor'}
constructor TFileOrDirectoryMonitor.Create(const AFileOrDirectory: string;
const AFileNotifyFlags: integer);
begin
inherited Create;
FPath := AFileOrDirectory;
FFileNotifyFlags := AFileNotifyFlags;
FThread := TFileOrDirectoryMonitorThread.Create(Self);
end;
destructor TFileOrDirectoryMonitor.Destroy;
begin
if Assigned(FThread) then
begin
FThread.Terminate;
FThread.WaitFor;
FThread.Destroy;
end;
inherited;
end;
procedure TFileOrDirectoryMonitor.MonitoringNotification(
const ABufferPtr: Pointer);
procedure Changed(const ABuffer : TMonitoringBuffer);
var
// FNLength,
Offset, NextOffset, Action : Cardinal;
FileName : PChar;
begin
Offset := 0;
repeat
NextOffset := PDWORD(@ABuffer[Offset + 0*SizeOf(DWORD)])^;
Action := PDWORD(@ABuffer[Offset + 1*SizeOf(DWORD)])^;
// FNLength := PDWORD(@ABuffer[Offset + 2*SizeOf(DWORD)])^;
FileName := PCHAR(@ABuffer[Offset + 3*SizeOf(DWORD)]);
if Assigned(FOnChange) then
FOnChange(Self, FThread, FPath + IfThen(FPath[Length(FPath)] <> PathDelim, PathDelim) + FileName, Action);
Offset := NextOffset;
until (NextOffset = 0) or (NextOffset >= MONITORING_BUF_SIZE - 3*SizeOf(DWORD));
end;
begin
Changed( PMonitoringBuffer(ABufferPtr)^ );
end;
{$ENDREGION}
end.
{$IFNDEF USE_ALIASES}
/// <summary>
/// Постпроцессор.
/// </summary>
unit San.PostProcessor;
{$I San.inc}
interface
{$REGION 'uses'}
uses
{$REGION 'Winapi'}
Winapi.Windows, Winapi.Messages,
{$ENDREGION}
{$REGION 'System'}
System.SysUtils, System.Classes, System.Generics.Collections
{$ENDREGION}
;
{$ENDREGION}
{$ENDIF}
type
/// <summary>
/// Процедура объекта без параметров.
/// </summary>
TObjProcedure =
{$IFDEF USE_ALIASES}
San.PostProcessor.TObjProcedure;
{$ELSE}
procedure of object;
{$ENDIF}
{$IFNDEF USE_ALIASES}
/// <summary>
/// Процедура объекта c 1 параметром.
/// </summary>
TObjProcedure<T> = procedure (Arg1: T) of object;
/// <summary>
/// Процедура объекта c 2 параметрами.
/// </summary>
TObjProcedure<T1, T2> = procedure (Arg1: T1; Arg2: T2) of object;
{$ENDIF}
/// <summary>
/// Постпроцессор. Выполняет действия через PostMessage внутреннему окну.
/// </summary>
TPostProcessor =
{$IFDEF USE_ALIASES}
San.PostProcessor.TPostProcessor;
{$ELSE}
class(TObject)
private
const CM_PROCESSING = WM_USER + 1;
private
FHandle : HWND;
/// <summary>
/// Обработка сообщения.
/// </summary>
procedure Processing(var AMessage : TMessage);
public
constructor Create;
destructor Destroy; override;
/// <summary>
/// Выполнить процедуру без параметров.
/// </summary>
procedure Execute(const AProc : TProc); overload;
/// <summary>
/// Выполнить процедуру c 1 параметром.
/// </summary>
procedure Execute<T>(const AProc : TProc<T>; const AParam : T); overload;
/// <summary>
/// Выполнить процедуру c 2 параметрами.
/// </summary>
procedure Execute<T1, T2>(const AProc : TProc<T1, T2>; const AParam1 : T1; const AParam2 : T2); overload;
/// <summary>
/// Выполнить процедуру объекта без параметров.
/// </summary>
procedure Execute(const AProc : TObjProcedure); overload;
/// <summary>
/// Выполнить процедуру объекта c 1 параметром.
/// </summary>
procedure Execute<T>(const AProc : TObjProcedure<T>; const AParam : T); overload;
/// <summary>
/// Выполнить процедуру объекта c 2 параметрами.
/// </summary>
procedure Execute<T1, T2>(const AProc : TObjProcedure<T1, T2>; const AParam1 : T1; const AParam2 : T2); overload;
end;
{$ENDIF}
{$IFNDEF USE_ALIASES}
/// <summary>
/// Постпроцессор. Внутренние данные.
/// </summary>
TPostProcessorData = class abstract(TObject)
private
procedure Execute; virtual; abstract;
end;
/// <summary>
/// Постпроцессор. Внутренние данные. 0.
/// </summary>
TPostProcessorData0Param = class(TPostProcessorData)
private
FProc : TProc;
procedure Execute; override;
end;
/// <summary>
/// Постпроцессор. Внутренние данные. 1.
/// </summary>
TPostProcessorData1Param<T> = class(TPostProcessorData)
private
FProc : TProc<T>;
FParam : T;
procedure Execute; override;
end;
/// <summary>
/// Постпроцессор. Внутренние данные. 2.
/// </summary>
TPostProcessorData2Param<T1, T2> = class(TPostProcessorData)
private
FProc : TProc<T1, T2>;
FParam1 : T1;
FParam2 : T2;
procedure Execute; override;
end;
/// <summary>
/// Постпроцессор. Внутренние данные. Метод.
/// </summary>
TPostProcessorDataMethod = class(TPostProcessorData)
private
FProc : TObjProcedure;
procedure Execute; override;
end;
/// <summary>
/// Постпроцессор. Внутренние данные. Метод 1.
/// </summary>
TPostProcessorDataMethod1<T> = class(TPostProcessorData)
private
FProc : TObjProcedure<T>;
FParam : T;
procedure Execute; override;
end;
/// <summary>
/// Постпроцессор. Внутренние данные. Метод 2.
/// </summary>
TPostProcessorDataMethod2<T1, T2> = class(TPostProcessorData)
private
FProc : TObjProcedure<T1, T2>;
FParam1 : T1;
FParam2 : T2;
procedure Execute; override;
end;
implementation
{$REGION 'TPostProcessorData0Param'}
procedure TPostProcessorData0Param.Execute;
begin
FProc();
end;
{$ENDREGION}
{$REGION 'TPostProcessorData1Param<T>'}
procedure TPostProcessorData1Param<T>.Execute;
begin
FProc(FParam);
end;
{$ENDREGION}
{$REGION 'TPostProcessorData2Param<T1, T2>'}
procedure TPostProcessorData2Param<T1, T2>.Execute;
begin
FProc(FParam1, FParam2);
end;
{$ENDREGION}
{$REGION 'TPostProcessorDataMethod'}
procedure TPostProcessorDataMethod.Execute;
begin
FProc;
end;
{$ENDREGION}
{$REGION 'TPostProcessorDataMethod1<T>'}
procedure TPostProcessorDataMethod1<T>.Execute;
begin
FProc(FParam);
end;
{$ENDREGION}
{$REGION 'TPostProcessorDataMethod2<T1, T2>'}
procedure TPostProcessorDataMethod2<T1, T2>.Execute;
begin
FProc(FParam1, FParam2);
end;
{$ENDREGION}
{$REGION 'TPostProcessor'}
constructor TPostProcessor.Create;
begin
inherited Create;
FHandle := AllocateHWnd(Processing);
if FHandle = 0 then
RaiseLastOSError;
end;
destructor TPostProcessor.Destroy;
begin
DeallocateHWnd(FHandle);
inherited;
end;
procedure TPostProcessor.Execute(const AProc: TProc);
var
Data : TPostProcessorData0Param;
begin
Data := TPostProcessorData0Param.Create;
Data.FProc := AProc;
PostMessage(FHandle, CM_PROCESSING, 0, IntPtr(Data))
end;
procedure TPostProcessor.Execute<T>(const AProc: TProc<T>; const AParam: T);
var
Data : TPostProcessorData1Param<T>;
begin
Data := TPostProcessorData1Param<T>.Create;
Data.FProc := AProc;
Data.FParam := AParam;
PostMessage(FHandle, CM_PROCESSING, 0, IntPtr(Data))
end;
procedure TPostProcessor.Execute<T1, T2>(const AProc: TProc<T1, T2>;
const AParam1: T1; const AParam2: T2);
var
Data : TPostProcessorData2Param<T1, T2>;
begin
Data := TPostProcessorData2Param<T1, T2>.Create;
Data.FProc := AProc;
Data.FParam1 := AParam1;
Data.FParam2 := AParam2;
PostMessage(FHandle, CM_PROCESSING, 0, IntPtr(Data))
end;
procedure TPostProcessor.Execute(const AProc: TObjProcedure);
var
Data : TPostProcessorDataMethod;
begin
Data := TPostProcessorDataMethod.Create;
Data.FProc := AProc;
PostMessage(FHandle, CM_PROCESSING, 0, IntPtr(Data))
end;
procedure TPostProcessor.Execute<T>(const AProc: TObjProcedure<T>; const AParam : T);
var
Data : TPostProcessorDataMethod1<T>;
begin
Data := TPostProcessorDataMethod1<T>.Create;
Data.FProc := AProc;
Data.FParam := AParam;
PostMessage(FHandle, CM_PROCESSING, 0, IntPtr(Data))
end;
procedure TPostProcessor.Execute<T1, T2>(const AProc: TObjProcedure<T1, T2>; const AParam1 : T1; const AParam2 : T2);
var
Data : TPostProcessorDataMethod2<T1, T2>;
begin
Data := TPostProcessorDataMethod2<T1, T2>.Create;
Data.FProc := AProc;
Data.FParam1 := AParam1;
Data.FParam2 := AParam2;
PostMessage(FHandle, CM_PROCESSING, 0, IntPtr(Data))
end;
procedure TPostProcessor.Processing(var AMessage: TMessage);
var
Data : TPostProcessorData;
begin
if AMessage.Msg <> CM_PROCESSING then
Exit;
Data := TPostProcessorData(AMessage.LParam);
try
Data.Execute;
finally
FreeAndNil(Data);
end;
end;
{$ENDREGION}
end{$WARNINGS OFF}.
{$ENDIF}
{*******************************************************}
{ }
{ Логический тип троичной логики. }
{ }
{ Разработано А.В.Станцо }
{ https://www.avstantso.ru/programming/ }
{ }
{ Copyright (C) 2017 Станцо А.В. }
{ }
{*******************************************************}
{$IFNDEF USE_ALIASES}
/// <summary>
/// Логический тип троичной логики.
/// </summary>
unit San.Bool3;
{$I San.inc}
{.$DEFINE BOOL3_INLINE}
interface
{$ENDIF}
type
/// <summary>
/// Возможные значения троичной логики.
/// </summary>
/// <remarks>
/// Сравнения значений для данного типа происходят,
/// как для прочих порядклвых типов. В отличии от Bool3.
/// </remarks>
Bool3Value = (False3, Null3, True3);
/// <summary>
/// Хелпер для <c>Bool3Value</c>
/// </summary>
TBool3ValueHelper = record helper for Bool3Value
strict private
function GetIsFalse: boolean; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
function GetIsNull: boolean; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
function GetIsTrue: boolean; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
public
function ToString() : string;{$IFDEF BOOL3_INLINE}inline;{$ENDIF}
/// <summary>
/// Имеет значение False3.
/// </summary>
property IsFalse : boolean read GetIsFalse;
/// <summary>
/// Имеет значение Null3.
/// </summary>
property IsNull : boolean read GetIsNull;
/// <summary>
/// Имеет значение True3.
/// </summary>
property IsTrue : boolean read GetIsTrue;
end;
/// <summary>
/// Множество возможных значений троичной логики.
/// </summary>
Bool3ValueSet = set of Bool3Value;
/// <summary>
/// Указатель на значение троичной логики.
/// </summary>
PBool3 =
{$IFDEF USE_ALIASES}
San.Bool3.PBool3;
{$ELSE}
^Bool3;
{$ENDIF}
/// <summary>
/// Значение троичной логики.
/// </summary>
/// <remarks>
/// Сравнения значений происходят в рамках троичной логики.
/// </remarks>
Bool3 =
{$IFDEF USE_ALIASES}
San.Bool3.Bool3;
{$ELSE}
record
strict private
function GetIsFalse: boolean; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
function GetIsNull: boolean; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
function GetIsTrue: boolean; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
private
FData : Bool3Value;
class procedure RaiseConvertErrorNull3ToBool2(out AResult); static; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
public
class operator In(const A: Bool3; const B: Bool3ValueSet) : Boolean; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalNot(const A: Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator Implicit(const A : Bool3): Bool3Value; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator Implicit(const A : Bool3): boolean; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator Implicit(const A : Bool3Value): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator Implicit(const A : boolean): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator Equal(const A, B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator Equal(const A : Bool3Value; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator Equal(const A : Bool3; const B : Bool3Value): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator Equal(const A : boolean; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator Equal(const A : Bool3; const B : boolean): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator NotEqual(const A, B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator NotEqual(const A : Bool3Value; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator NotEqual(const A : Bool3; const B : Bool3Value): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator NotEqual(const A : boolean; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator NotEqual(const A : Bool3; const B : boolean): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator GreaterThan(const A, B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator GreaterThan(const A : Bool3Value; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator GreaterThan(const A : Bool3; const B : Bool3Value): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator GreaterThan(const A : boolean; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator GreaterThan(const A : Bool3; const B : boolean): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator GreaterThanOrEqual(const A, B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator GreaterThanOrEqual(const A : Bool3Value; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator GreaterThanOrEqual(const A : Bool3; const B : Bool3Value): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator GreaterThanOrEqual(const A : boolean; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator GreaterThanOrEqual(const A : Bool3; const B : boolean): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LessThan(const A, B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LessThan(const A : Bool3Value; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LessThan(const A : Bool3; const B : Bool3Value): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LessThan(const A : boolean; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LessThan(const A : Bool3; const B : boolean): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LessThanOrEqual(const A, B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LessThanOrEqual(const A : Bool3Value; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LessThanOrEqual(const A : Bool3; const B : Bool3Value): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LessThanOrEqual(const A : Bool3; const B : boolean): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LessThanOrEqual(const A : boolean; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalAnd(const A, B: Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalAnd(const A : Bool3Value; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalAnd(const A : Bool3; const B : Bool3Value): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalAnd(const A : Bool3; const B : boolean): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalAnd(const A : boolean; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalOr(const A, B: Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalOr(const A : Bool3Value; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalOr(const A : Bool3; const B : Bool3Value): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalOr(const A : Bool3; const B : boolean): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalOr(const A : boolean; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalXor(const A, B: Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalXor(const A : Bool3Value; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalXor(const A : Bool3; const B : Bool3Value): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalXor(const A : Bool3; const B : boolean): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
class operator LogicalXor(const A : boolean; const B : Bool3): Bool3; {$IFDEF BOOL3_INLINE}inline;{$ENDIF}
function ToString() : string;{$IFDEF BOOL3_INLINE}inline;{$ENDIF}
/// <summary>
/// Имеет значение False3.
/// </summary>
property IsFalse : boolean read GetIsFalse;
/// <summary>
/// Имеет значение Null3.
/// </summary>
property IsNull : boolean read GetIsNull;
/// <summary>
/// Имеет значение True3.
/// </summary>
property IsTrue : boolean read GetIsTrue;
/// <summary>
/// Значение
/// </summary>
property Value : Bool3Value read FData;
end;
{$ENDIF}
{$IFNDEF USE_ALIASES}
implementation
uses
System.SysUtils, System.TypInfo;
{$REGION 'TBool3ValueHelper'}
function TBool3ValueHelper.GetIsFalse: boolean;
begin
Result := Self = False3;
end;
function TBool3ValueHelper.GetIsNull: boolean;
begin
Result := Self = Null3;
end;
function TBool3ValueHelper.GetIsTrue: boolean;
begin
Result := Self = True3;
end;
function TBool3ValueHelper.ToString: string;
begin
Result := GetEnumName(TypeInfo(Bool3Value), Ord(Self));
end;
{$ENDREGION}
{$REGION 'TBool3'}
class procedure Bool3.RaiseConvertErrorNull3ToBool2(out AResult);
begin
raise EConvertError.Create('Can not implicit convert ' + Null3.ToString + ' to ' + string(PTypeInfo(TypeInfo(boolean))^.NameFld.ToString) );
end;
class operator Bool3.In(const A: Bool3; const B: Bool3ValueSet): Boolean;
begin
Result := A.FData in B;
end;
class operator Bool3.LogicalNot(const A: Bool3): Bool3;
begin
case A.FData of
False3: Result.FData := True3;
True3: Result.FData := False3;
else
Result.FData := Null3;
end;
end;
{$REGION 'Implicit'}
class operator Bool3.Implicit(const A: Bool3): boolean;
begin
case A.FData of
False3: Result := False;
True3: Result := True;
else
RaiseConvertErrorNull3ToBool2(Result);
end;
end;
class operator Bool3.Implicit(const A: Bool3): Bool3Value;
begin
Result := A.FData;
end;
class operator Bool3.Implicit(const A: boolean): Bool3;
begin
if A then
Result.FData := True3
else
Result.FData := False3
end;
class operator Bool3.Implicit(const A: Bool3Value): Bool3;
begin
Result.FData := A;
end;
{$ENDREGION}
{$REGION 'Equal'}
class operator Bool3.Equal(const A, B: Bool3): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A.FData = B.FData;
end;
class operator Bool3.Equal(const A: Bool3Value; const B: Bool3): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A = B.FData;
end;
class operator Bool3.Equal(const A: Bool3; const B: Bool3Value): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A.FData = B;
end;
class operator Bool3.Equal(const A: boolean; const B: Bool3): Bool3;
begin
if A then
Result := B
else
Result := not B;
end;
class operator Bool3.Equal(const A: Bool3; const B: boolean): Bool3;
begin
if B then
Result := A
else
Result := not A;
end;
{$ENDREGION}
{$REGION 'NotEqual'}
class operator Bool3.NotEqual(const A, B: Bool3): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A.FData <> B.FData;
end;
class operator Bool3.NotEqual(const A: Bool3Value; const B: Bool3): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A <> B.FData;
end;
class operator Bool3.NotEqual(const A: Bool3; const B: Bool3Value): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A.FData <> B;
end;
class operator Bool3.NotEqual(const A: Bool3; const B: boolean): Bool3;
begin
if B then
Result := not A
else
Result := A;
end;
class operator Bool3.NotEqual(const A: boolean; const B: Bool3): Bool3;
begin
if A then
Result := not B
else
Result := B;
end;
{$ENDREGION}
{$REGION 'GreaterThan'}
class operator Bool3.GreaterThan(const A, B: Bool3): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A.FData > B.FData
end;
class operator Bool3.GreaterThan(const A: Bool3Value;
const B: Bool3): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A > B.FData
end;
class operator Bool3.GreaterThan(const A: Bool3;
const B: Bool3Value): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A.FData > B;
end;
class operator Bool3.GreaterThan(const A: boolean; const B: Bool3): Bool3;
begin
if B.IsNull then
Result := Null3
else
Result := A > Boolean(B);
end;
class operator Bool3.GreaterThan(const A: Bool3; const B: boolean): Bool3;
begin
if A.IsNull then
Result := Null3
else
Result := Boolean(A) > B;
end;
{$ENDREGION}
{$REGION 'GreaterThanOrEqual'}
class operator Bool3.GreaterThanOrEqual(const A: Bool3Value;
const B: Bool3): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A >= B.FData;
end;
class operator Bool3.GreaterThanOrEqual(const A, B: Bool3): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A.FData >= B.FData;
end;
class operator Bool3.GreaterThanOrEqual(const A: Bool3;
const B: Bool3Value): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A.FData >= B;
end;
class operator Bool3.GreaterThanOrEqual(const A: boolean;
const B: Bool3): Bool3;
begin
if B.IsNull then
Result := Null3
else
Result := A >= Boolean(B);
end;
class operator Bool3.GreaterThanOrEqual(const A: Bool3;
const B: boolean): Bool3;
begin
if A.IsNull then
Result := Null3
else
Result := Boolean(A) >= B;
end;
{$ENDREGION}
{$REGION 'LessThan'}
class operator Bool3.LessThan(const A: Bool3Value; const B: Bool3): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A < B.FData;
end;
class operator Bool3.LessThan(const A, B: Bool3): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A.FData < B.FData;
end;
class operator Bool3.LessThan(const A: Bool3; const B: Bool3Value): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A.FData < B;
end;
class operator Bool3.LessThan(const A: Bool3; const B: boolean): Bool3;
begin
if A.IsNull then
Result := Null3
else
Result := Boolean(A) < B;
end;
class operator Bool3.LessThan(const A: boolean; const B: Bool3): Bool3;
begin
if B.IsNull then
Result := Null3
else
Result := A < Boolean(B);
end;
{$ENDREGION}
{$REGION 'LessThanOrEqual'}
class operator Bool3.LessThanOrEqual(const A, B: Bool3): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A.FData <= B.FData;
end;
class operator Bool3.LessThanOrEqual(const A: Bool3Value;
const B: Bool3): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A <= B.FData;
end;
class operator Bool3.LessThanOrEqual(const A: Bool3;
const B: Bool3Value): Bool3;
begin
if A.IsNull or B.IsNull then
Result := Null3
else
Result := A.FData <= B;
end;
class operator Bool3.LessThanOrEqual(const A: boolean;
const B: Bool3): Bool3;
begin
if B.IsNull then
Result := Null3
else
Result := A <= Boolean(B);
end;
class operator Bool3.LessThanOrEqual(const A: Bool3;
const B: boolean): Bool3;
begin
if A.IsNull then
Result := Null3
else
Result := Boolean(A) <= B;
end;
{$ENDREGION}
{$REGION 'LogicalAnd'}
class operator Bool3.LogicalAnd(const A: Bool3Value; const B: Bool3): Bool3;
begin
if A.IsTrue and B.IsTrue then
Result := True3
else
if A.IsFalse or B.IsFalse then
Result := False3
else
Result := Null3;
end;
class operator Bool3.LogicalAnd(const A, B: Bool3): Bool3;
begin
if A.IsTrue and B.IsTrue then
Result := True3
else
if A.IsFalse or B.IsFalse then
Result := False3
else
Result := Null3;
end;
class operator Bool3.LogicalAnd(const A: Bool3; const B: Bool3Value): Bool3;
begin
if A.IsTrue and B.IsTrue then
Result := True3
else
if A.IsFalse or B.IsFalse then
Result := False3
else
Result := Null3;
end;
class operator Bool3.LogicalAnd(const A: boolean; const B: Bool3): Bool3;
begin
if A and B.IsTrue then
Result := True3
else
if not A or B.IsFalse then
Result := False3
else
Result := Null3;
end;
class operator Bool3.LogicalAnd(const A: Bool3; const B: boolean): Bool3;
begin
if A.IsTrue and B then
Result := True3
else
if A.IsFalse or not B then
Result := False3
else
Result := Null3;
end;
{$ENDREGION}
{$REGION 'LogicalOr'}
class operator Bool3.LogicalOr(const A: Bool3Value; const B: Bool3): Bool3;
begin
if A.IsTrue or B.IsTrue then
Result := True3
else
if A.IsFalse and B.IsFalse then
Result := False3
else
Result := Null3;
end;
class operator Bool3.LogicalOr(const A, B: Bool3): Bool3;
begin
if A.IsTrue or B.IsTrue then
Result := True3
else
if A.IsFalse and B.IsFalse then
Result := False3
else
Result := Null3;
end;
class operator Bool3.LogicalOr(const A: Bool3; const B: Bool3Value): Bool3;
begin
if A.IsTrue or B.IsTrue then
Result := True3
else
if A.IsFalse and B.IsFalse then
Result := False3
else
Result := Null3;
end;
class operator Bool3.LogicalOr(const A: boolean; const B: Bool3): Bool3;
begin
if A or B.IsTrue then
Result := True3
else
if not A and B.IsFalse then
Result := False3
else
Result := Null3;
end;
class operator Bool3.LogicalOr(const A: Bool3; const B: boolean): Bool3;
begin
if A.IsTrue or B then
Result := True3
else
if A.IsFalse and not B then
Result := False3
else
Result := Null3;
end;
{$ENDREGION}
{$REGION 'LogicalXor'}
class operator Bool3.LogicalXor(const A: Bool3Value; const B: Bool3): Bool3;
begin
if A.IsTrue xor B.IsTrue then
Result := True3
else
if A.IsFalse and B.IsFalse then
Result := False3
else
Result := Null3;
end;
class operator Bool3.LogicalXor(const A, B: Bool3): Bool3;
begin
if A.IsTrue xor B.IsTrue then
Result := True3
else
if A.IsFalse and B.IsFalse then
Result := False3
else
Result := Null3;
end;
class operator Bool3.LogicalXor(const A: Bool3; const B: Bool3Value): Bool3;
begin
if A.IsTrue xor B.IsTrue then
Result := True3
else
if A.IsFalse and B.IsFalse then
Result := False3
else
Result := Null3;
end;
class operator Bool3.LogicalXor(const A: boolean; const B: Bool3): Bool3;
begin
if A xor B.IsTrue then
Result := True3
else
if not A and B.IsFalse then
Result := False3
else
Result := Null3;
end;
class operator Bool3.LogicalXor(const A: Bool3; const B: boolean): Bool3;
begin
if A.IsTrue xor B then
Result := True3
else
if A.IsFalse and not B then
Result := False3
else
Result := Null3;
end;
{$ENDREGION}
function Bool3.GetIsFalse: boolean;
begin
Result := FData = False3;
end;
function Bool3.GetIsNull: boolean;
begin
Result := FData = Null3;
end;
function Bool3.GetIsTrue: boolean;
begin
Result := FData = True3;
end;
function Bool3.ToString: string;
begin
Result := FData.ToString;
end;
{$ENDREGION}
//// Test
//var
// b2 : boolean;
// b3 : bool3;
//
//initialization
// if b3 and b2 then
// ;
end{$WARNINGS OFF}.
{$ENDIF}
{*******************************************************}
{ }
{ Строка в верхнем регистре. }
{ }
{ Разработано А.В.Станцо }
{ https://www.avstantso.ru/programming/ }
{ }
{ Copyright (C) 2016 Станцо А.В. }
{ }
{*******************************************************}
{$IFNDEF USE_ALIASES}
/// <summary>
/// Механизм хранения строк в верхнем регистре с приведением регистра по необходимости.
/// </summary>
unit San.UpperString;
{$I San.inc}
{.$DEFINE UPPER_STR_INLINE}
{.$DEFINE UPPER_STR_USE_SAME}
interface
{$REGION 'uses'}
uses
System.SysUtils, System.Generics.Defaults, System.Generics.Collections,
{$IF RTLVersion >= 31}
System.Hash,
{$ENDIF}
System.TypInfo;
{$ENDREGION}
{$ENDIF}
type
/// <summary>
/// Указатель на строку в верхнем регистре.
/// </summary>
PUpperString =
{$IFDEF USE_ALIASES}
San.UpperString.PUpperString;
{$ELSE}
^TUpperString;
{$ENDIF}
/// <summary>
/// Строка в верхнем регистре.
/// </summary>
/// <remarks>
/// При использовании в Dictionary в качестве ключа,
/// надо передать TUpperStringEqualityComparer.Create
/// в конструктор Dictionary.
/// </remarks>
TUpperString =
{$IFDEF USE_ALIASES}
San.UpperString.TUpperString;
{$ELSE}
record
strict private
function GetIsEmpty: boolean;
private
FData : string;
public
class operator Implicit(const AStr : string): TUpperString; {$IFDEF UPPER_STR_INLINE}inline;{$ENDIF}
class operator Implicit(const AUpStr : TUpperString): string; {$IFDEF UPPER_STR_INLINE}inline;{$ENDIF}
{$IFNDEF NEXTGEN}
class operator Implicit(const ASymbolName : TSymbolName): TUpperString; {$IFDEF UPPER_STR_INLINE}inline;{$ENDIF}
{$ENDIF}
class operator Equal(const A, B : TUpperString): Boolean; {$IFDEF UPPER_STR_INLINE}inline;{$ENDIF}
class operator Equal(const A : string; const B : TUpperString): Boolean; {$IFDEF UPPER_STR_INLINE}inline;{$ENDIF}
class operator Equal(const A : TUpperString; const B : string): Boolean; {$IFDEF UPPER_STR_INLINE}inline;{$ENDIF}
class operator NotEqual(const A, B : TUpperString): Boolean; {$IFDEF UPPER_STR_INLINE}inline;{$ENDIF}
class operator NotEqual(const A : string; const B : TUpperString): Boolean; {$IFDEF UPPER_STR_INLINE}inline;{$ENDIF}
class operator NotEqual(const A : TUpperString; const B : string): Boolean; {$IFDEF UPPER_STR_INLINE}inline;{$ENDIF}
class operator Add(const A, B : TUpperString): TUpperString; {$IFDEF UPPER_STR_INLINE}inline;{$ENDIF}
class operator Add(const A : string; const B : TUpperString): TUpperString; {$IFDEF UPPER_STR_INLINE}inline;{$ENDIF}
class operator Add(const A : TUpperString; const B : string): TUpperString; {$IFDEF UPPER_STR_INLINE}inline;{$ENDIF}
/// <summary>
/// Явный доступ к строке.
/// </summary>
/// <remarks>
/// Нужен, например, для передачи в аргументы функции Format().
/// </remarks>
function ToString() : string;{$IFDEF UPPER_STR_INLINE}inline;{$ENDIF}
/// <summary>
/// Является ли пустой строкой.
/// </summary>
property IsEmpty : boolean read GetIsEmpty;
end;
{$ENDIF}
/// <summary>
/// Сравнитель строк в верхнем регистре.
/// </summary>
/// <remarks>
/// Необходим для использования в Dictionary.
/// </remarks>
TUpperStringEqualityComparer =
{$IFDEF USE_ALIASES}
San.UpperString.TUpperStringEqualityComparer;
{$ELSE}
class(TEqualityComparer<TUpperString>)
public
function Equals(const Left, Right: TUpperString): Boolean; override;
function GetHashCode(const Value: TUpperString): Integer; override;
end;
{$ENDIF}
{$IFNDEF USE_ALIASES}
implementation
{$REGION 'TUpperString'}
class operator TUpperString.Implicit(const AStr: string): TUpperString;
begin
Result.FData := AnsiUpperCase(AStr);
end;
class operator TUpperString.Implicit(const AUpStr: TUpperString): string;
begin
Result := AUpStr.FData;
end;
{$IFNDEF NEXTGEN}
class operator TUpperString.Implicit(
const ASymbolName: TSymbolName): TUpperString;
begin
Result.FData := AnsiUpperCase(string(ASymbolName));
end;
{$ENDIF}
class operator TUpperString.Equal(const A, B: TUpperString): Boolean;
begin
Result := {$IFDEF UPPER_STR_USE_SAME}AnsiSameStr(A.FData, B.FData){$ELSE}A.FData = B.FData{$ENDIF};
end;
class operator TUpperString.Equal(const A: string;
const B: TUpperString): Boolean;
begin
Result := {$IFDEF UPPER_STR_USE_SAME}AnsiSameStr(AnsiUpperCase(A), B.FData){$ELSE}AnsiUpperCase(A) = B.FData{$ENDIF};
end;
class operator TUpperString.Equal(const A: TUpperString;
const B: string): Boolean;
begin
Result := {$IFDEF UPPER_STR_USE_SAME}AnsiSameStr(A.FData, AnsiUpperCase(B)){$ELSE}A.FData = AnsiUpperCase(B){$ENDIF};
end;
function TUpperString.GetIsEmpty: boolean;
begin
Result := FData = '';
end;
class operator TUpperString.NotEqual(const A, B: TUpperString): Boolean;
begin
Result := {$IFDEF UPPER_STR_USE_SAME}not AnsiSameStr(A.FData, B.FData){$ELSE}A.FData <> B.FData{$ENDIF};
end;
class operator TUpperString.NotEqual(const A: string;
const B: TUpperString): Boolean;
begin
Result := {$IFDEF UPPER_STR_USE_SAME}not AnsiSameStr(AnsiUpperCase(A), B.FData){$ELSE}AnsiUpperCase(A) <> B.FData{$ENDIF};
end;
class operator TUpperString.NotEqual(const A: TUpperString;
const B: string): Boolean;
begin
Result := {$IFDEF UPPER_STR_USE_SAME}not AnsiSameStr(A.FData, AnsiUpperCase(B)){$ELSE}A.FData <> AnsiUpperCase(B){$ENDIF};
end;
class operator TUpperString.Add(const A, B: TUpperString): TUpperString;
begin
Result.FData := A.FData + B.FData;
end;
class operator TUpperString.Add(const A: string; const B: TUpperString): TUpperString;
begin
Result.FData := AnsiUpperCase(A) + B.FData;
end;
class operator TUpperString.Add(const A: TUpperString; const B: string): TUpperString;
begin
Result.FData := A.FData + AnsiUpperCase(B);
end;
function TUpperString.ToString(): string;
begin
Result := FData;
end;
{$ENDREGION}
{$REGION 'TUpperStringEqualityComparer'}
function TUpperStringEqualityComparer.Equals(const Left,
Right: TUpperString): Boolean;
begin
Result := Left = Right;
end;
function TUpperStringEqualityComparer.GetHashCode(
const Value: TUpperString): Integer;
begin
{$IF RTLVersion >= 31}
Result :=System.Hash.THashBobJenkins.GetHashValue(Value.FData);
{$ELSE}
Result := BobJenkinsHash(PChar(Value.FData)^, SizeOf(Char) * Length(Value.FData), 0);
{$ENDIF}
end;
{$ENDREGION}
end{$WARNINGS OFF}.
{$ENDIF}