⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unaclasses.pas

📁 Voice Commnucation Components for Delphi
💻 PAS
📖 第 1 页 / 共 5 页
字号:

(*
	----------------------------------------------

	  unaClasses.pas
	  basic classes

	----------------------------------------------
	  This source code cannot be used without
	  proper license granted to you as a private
	  person or an entity by the Lake of Soft, Ltd

	  Visit http://lakeofsoft.com/ for more information.

	  Copyright (c) 2001, 2007 Lake of Soft, Ltd
		     All rights reserved
	----------------------------------------------

	  created by:
		Lake, 25 Aug 2001

	  modified by:
		Lake, Aug-Dec 2001
		Lake, Jan-Dec 2002
		Lake, Jan-Dec 2003
		Lake, Jan-Dec 2004
		Lake, Jan-Dec 2005
		Lake, Jan-Dec 2006
		Lake, Jan-Apr 2007

	----------------------------------------------
*)

{$I unaDef.inc }

{xxx $DEFINE UNA_GATE_DEBUG }
{xxx $DEFINE UNA_GATE_DEBUG_TIMEOUT }

{$DEFINE UNA_USE_CS }	// use CriticalSections instead of own gates

{$IFDEF UNA_USE_CS }
  {xx $DEFINE UNA_USE_CS_LOG }	// use CriticalSections logging
{$ENDIF }


unit
  unaClasses;

{DP:UNIT
  Contains base classes, such as lists, threads and events, which are often used by other classes and routines.
}

interface

uses
  Windows,
  unaTypes, unaUtils
{$IFDEF UNA_PROFILE}
  , unaProfile
{$ENDIF}
{$IFDEF __SYSUTILS_H_ }
  , Math, SysUtils
{$ENDIF}
  ;

type
  //
  // -- basic class --
  //
  unaObject = class
  private
    f_inheritedCreateWasCalled: bool;
    //
    function getThis(): unaObject;
    function getClassID(): string;
  public
    constructor create();
    //
    property _this: unaObject read getThis;
    property _classID: string read getClassID;
    //
    procedure AfterConstruction(); override;
  end;

  //
  // -- unaEvent --
  //

  {DP:CLASS
    This is a wrapper class for Windows Events.
  }
  unaEvent = class(unaObject)
  private
    f_handle: tHandle;
    f_name: wideString;
  public
    {DP:METHOD
      Constructs an event. Specify initialState and manualReset parameters.
      If manualReset is true you have to reset the event manually every time it was set to signaled state.
      By default this parameter is false, what means event will be reset automatically.
      initialState parameter specifies the initial state of event.
      Default value is false (non-signaled). Specify optional name parameter to set the name of event.
      You can use this name later to reopen the event.
      Refer to MSDN documentation for more details about Windows events.
    }
    constructor create(manualReset: bool = false; initialState: bool = false; const name: wideString = '');
    destructor Destroy(); override;
    //
    {DP:METHOD
      Sets state of the event to signaled or non-signaled.
    }
    procedure setState(signaled: bool = true);
    {DP:METHOD
      Used to wait until the state of event will be set to signaled.
      Returns true if the event was set to signaled state and false if timeout was expired (event remains in non-signaled state).
      timeout parameter specifies the timeout in milliseconds.
      This method blocks execution of caller thread, so use it carefully when specifying INFINITE value for timeout.
    }
    function waitFor(timeout: unsigned = 1): bool;
    //
    {DP:METHOD
      Windows handle of event.
    }
    property handle: tHandle read f_handle;
    property name: wideString read f_name;
  end;


  //
  // -- unaAbstractGate --
  //

  unaAbstractGate = class(unaObject)
  private
  {$IFDEF DEBUG}
    f_title: string;
    f_masterName: string;
  {$ENDIF}
  {$IFDEF UNA_GATE_PROFILE}
    f_profileIndex: unsigned;
  {$ENDIF}
  protected
    f_isBusy: bool;
    //
    function gateEnter(timeout: unsigned = INFINITE{$IFDEF DEBUG}; const masterName: string = ''{$ENDIF}): bool; virtual;
    procedure gateLeave(); virtual;
  public
    constructor create({$IFDEF DEBUG}const title: string = ''{$ENDIF});
    {DP:METHOD
      Enters the gate. timeout parameter specifies the amount of time (in milliseconds) attempt to enter the gate should last.
      Returns false if gate cannot be entered and timeout was expired.
      Returns true if gate was entered successfully.
      Default timeout value is INFINITE. That means routine should wait forever, until gate will be freed.
      Use this default value carefully, as it could lead to deadlocks in your application.
    }
    function enter(timeout: unsigned = INFINITE{$IFDEF DEBUG}; const masterName: string = ''{$ENDIF}): bool;
    {DP:METHOD
      Every successful enter() must be followed by leave().
      Do not call leave() unless enter() returns true.
    }
    procedure leave();
  {$IFDEF DEBUG}
    property masterName: string read f_masterName;
  {$ENDIF}
    {DP:METHOD
      Indicates if gate is busy by one ore more threads.
      Do not use this property if you want to make sure gate is free. Use enter() instead.
      The only good use for this property is in some kind of visual indication to end-user whether the gate is free.
    }
    property isBusy: bool read f_isBusy;
  end;


  //
  // -- unaOutProcessGate --
  //

  {DP:CLASS
    This class is useful when you wish to ensure some block of code to be executed only by one thread at a time.
    Only one instance can enter the gate. You should use <STRONG>try</STRONG> <STRONG>finally</STRONG> block to ensure you always leave the gate.
  }
  unaOutProcessGate = class(unaAbstractGate)
  private
    f_inside: bool;
    f_masterThread: tHandle;
  {$IFDEF DEBUG}
    f_title: string;
  {$ENDIF}
    f_event: unaEvent;
  protected
    function gateEnter(timeout: unsigned = INFINITE{$IFDEF DEBUG}; const masterName: string = ''{$ENDIF}): bool; override;
    procedure gateLeave(); override;
  public
    constructor create({$IFDEF DEBUG}const title: string = ''{$ENDIF});
    destructor Destroy(); override;
    //
    function checkDeadlock(timeout: unsigned = INFINITE; const name: string = ''): bool;
    //
  {$IFDEF DEBUG}
    property title: string read f_title;
  {$ENDIF}
  end;


  //
  // -- unaInProcessGate --
  //

  {DP:CLASS
    Only one thead at a time can enter this gate. This thread can enter the gate as many times as required.
    Gate will be released when thread will leave it exactly same number of times as was entered.
  }
  unaInProcessGate = class(unaAbstractGate)
  private
{$IFDEF UNA_USE_CS }
    f_CS: _RTL_CRITICAL_SECTION;
{$ELSE }
    f_waitEvent: handle;	// event used to wait for gate to became free
    f_tryLockCount: unsigned;	// gate try lock count
				// zero when gate is free
    f_recursionLockCount: int;
    f_owningThreadId: unsigned;
{$ENDIF }
    //
{$IFDEF UNA_GATE_DEBUG}
    f_leaveCount: unsigned;
{$ENDIF}
    //
{$IFDEF UNA_USE_CS }
{$ELSE }
    function getWaitEvent(): handle;
{$ENDIF }
    //
    function getOwningThread: unsigned;
    function getRecursionLockCount: int;
    function getTryLockCount: int;
    //
  protected
    function gateEnter(timeout: unsigned = INFINITE{$IFDEF DEBUG}; const masterName: string = ''{$ENDIF}): bool; override;
    procedure gateLeave(); override;
    //
  public
    procedure AfterConstruction(); override;
    procedure BeforeDestruction(); override;
    {DP:METHOD
      Owning thread ID.
    }
    property owningThreadId: unsigned read getOwningThread;
    {DP:METHOD
      Number of locks made by owning thread.
    }
    property recursionLockCount: int read getRecursionLockCount;
    {DP:METHOD
      Gate try lock count. Number of tries made to lock the gate at the same time from different threads.
      <BR />zero when gate is free.
      Avoid the usage "if (0 = lockCount) then ..." for checking the gate availability.
      Use "if (gateEnter(0)) then try ... finally gateLeave(); end;" code instead.
    }
    property tryLockCount: int read getTryLockCount;
  end;


  // --  --
  unaListCopyOpEnum = (unaco_add, unaco_replaceExisting, unaco_insert, unaco_assign);

  //
  // -- unaList --
  //

  {DP:METHOD
    Fires when list item is needed to be released. NOTE: item[index] could be nil.
  }
  unaListOnItemReleaseEvent = procedure(index: unsigned; var doFree: unsigned) of object;
  {DP:METHOD
    Fires when list item is about to be removed from the list.
  }
  unaListOnItemBeforeRemoveEvent = procedure(index: unsigned) of object;

  {DP:CLASS
    This is general purpose list of items.
    It is multi-threaded safe, so you can use it by several threads without any special care.
  }
  unaList = class(unaObject)
  private
    f_count: unsigned;
    f_capacity: unsigned;
    f_timeout: unsigned;
    f_isObjects: bool;
    f_autoFree: bool;
    f_oneThreadUser: bool;
    f_onItemRelease: unaListOnItemReleaseEvent;
    f_onItemBeforeRemove: unaListOnItemBeforeRemoveEvent;
    //
    f_forceZeroFree: bool;	// used in doSetCapacity
				// usually set to true only in destructor
  {$IFDEF DEBUG }
    f_debugTitle: string;
  {$ENDIF }
    //
    f_list: pPtrArray;
    f_gate: unaInProcessGate;
    f_aboutToDestroy: bool;
    f_dataEvent: unaEvent;
    //
    procedure doSetItem(index: unsigned; value: pointer);
  protected
    function mapDoFree(doFree: unsigned): bool;
    //
    procedure doSetCapacity(value: unsigned); virtual;
    {DP:METHOD
      Disposes the item.
    }
    procedure releaseItem(index: unsigned; doFree: unsigned); virtual;
    procedure notifyBeforeRemove(index: unsigned); virtual;
    //
    function add2(item: pointer): unsigned; overload; virtual;
    function insert2(index: unsigned; item: pointer): int; virtual;
    procedure setItem2(index: unsigned; item: pointer; doFree: unsigned = 2); overload; virtual;
    //
    procedure doReverse(); virtual;
    function doCopyFrom(list: pInt32Array; listSize: int = -1; copyOperation: unaListCopyOpEnum = unaco_add; startIndex: unsigned = 0): int; virtual;
  public
    constructor create(isObjects: bool = false{$IFDEF DEBUG}; const debugTitle: string = ''{$ENDIF});
    procedure BeforeDestruction(); override;
    //
    {DP:METHOD
      Locks the list. Returns false if lock cannot be set in a timeout period.
      If INFINITE is passed timeOut property will be used instead.
    }
    function lock(timeout: unsigned = INFINITE): bool;
    procedure unlock();
    {DP:METHOD
      Clears the list. All items will be removed and count will be reset to 0.
    }
    procedure clear(doFree: unsigned = 2);
    {DP:METHOD
      Adds item to the end of the list.
      Returns list index of inserted item (usually count - 1).
    }
    function add(item: pointer): unsigned; overload;
    function add(item: int): unsigned; overload;
    {DP:METHOD
      Inserts an item at specified position (index parameter) in the list.
      Does nothing if index is bigger than count.
      Returns index.
    }
    function insert(index: unsigned; item: pointer): unsigned;
    {DP:METHOD
      Removes an item from the list.
      index specifies the index of item to be removed.
      doFree specifies an action which should be taken if item is object (see unaObjectList):
      <UL>
	<LI>0 -- do not free the object</LI>
	<LI>1 -- free object always</LI>
	<LI>2 -- use the autoFree member of unaObjectList to decide whether to free the object.</LI>
      <UL>
    }
    {DP:METHOD
      Reverses items in the list.
    }
    procedure reverse();
    {DP:METHOD
      Removes item with specified index from the list.
      Returns true if item was removed, or false otherwise.
    }
    function removeByIndex(index: unsigned; doFree: unsigned = 2): bool; overload;
    {DP:METHOD
      Removes specifed item from the list.
      Returns true if item was removed, or false otherwise.
    }
    function removeItem(item: int; doFree: unsigned = 0): bool; overload;
    {DP:METHOD
      Removes specified item from the list.
      Returns true if item was removed, or false otherwise.
    }
    function removeItem(item: pointer; doFree: unsigned = 2): bool; overload;
    {DP:METHOD
      Removes first (removeFirst = true) or last (removeFirst = false) item from the list (if it presents).
      Returns true if item was removed, or false otherwise.
    }
    function removeFromEdge(removeFromBegining: bool = true): bool;
    {DP:METHOD
    }
    function asString(const delimiter: string; treatAsSigned: bool = true; base: unsigned = 10): string;
    {DP:METHOD
      Returns item from the list.
      index specifies the index of item to be returned.
    }
    function get(index: unsigned): pointer;
    {DP:METHOD
      Returns item with specified index as object.
    }
    function getObject(index: unsigned): tObject;
    {DP:METHOD
      Sets item value in the list.
      index specifies the index of item to be set.
      item is value of item. Old item will be freed.
      If old item is object, doFree parameter specifies the action should be taken.
    }
    procedure setItem(index: unsigned; item: pointer; doFree: unsigned = 2); overload;
    procedure setItem(index: unsigned; item: int); overload;
    function setItem(itemToReplace: pointer; newItem: pointer; doFree: unsigned = 2): unsigned; overload;
    {DP:METHOD
    }
    procedure setCapacity(value: unsigned);
    {DP:METHOD
      Searches the list for specified item. Returns -1 if no item was found.
    }
    function locate(value: pointer): int; overload;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -