其实Managed Record有很多方便使用的场景
其实Managed Record有很多方便使用的场景。
比如下面的就是把TStringBuilder由Class改成了Managed Record。好处就是不再需要释放了。
{ Managed Record版本的StringBuilder。 Delphi在10.4开始终于支持Managed Record了。 加了这个有很多可以玩的了。 比如说有些原先是class实现的东西,可以用Managed Record来实现。 这样的好处是很多东西想用就用,用了不需要管什么时候释放。 因为Record是在栈里面的,系统会自动回收,回收前还会调用Finalize操作符。 不仅仅StringBuilder,其实很多都可以变成Managed Record。 例如用Managed Record,实现智能锁,离开代码块,锁就会自动释放了。 2020.9.9 武稀松 wr960204 } unit ManagedStringBuilder; interface uses System . Classes, System . SysUtils, System . RTLConsts, System . SysConst; type TCharArray = TArray< Char >; type TCharSearch = record ArrayPtr: PChar ; MatchPtr: PChar ; end ; TStringBuilder = record private type TEnumerator = record private FPtr: PChar ; FEndPtr: PChar ; public procedure Initialize( const ABuilder: TStringBuilder); inline; function GetCurrent: Char ; inline; function MoveNext: Boolean ; inline; property Current: Char read GetCurrent; end ; private const DefaultCapacity = $10 ; LineBreak: string = sLineBreak; private function GetCapacity: Integer ; inline; procedure SetCapacity(Value: Integer ); function GetChars(Index: Integer ): Char ; procedure SetChars(Index: Integer ; Value: Char ); function GetLength: Integer ; inline; procedure SetLength(Value: Integer ); function GetMaxCapacity: Integer ; inline; procedure ExpandCapacity; procedure ReduceCapacity; procedure CheckBounds(Index: Integer ); function _Replace(Index: Integer ; const Old, New: string ): Boolean ; private FData: string ; FLength: Integer ; FMaxCapacity: Integer ; public //constructor Create; class operator Initialize(out Dest: TStringBuilder); class operator Finalize( var Dest: TStringBuilder); //:=不需要处理 //class operator Assign(var Dest: TStringBuilder; const [ref] Src: TStringBuilder); constructor Create(aCapacity: Integer ); overload; constructor Create( const Value: string ); overload; constructor Create(aCapacity: Integer ; aMaxCapacity: Integer ); overload; constructor Create( const Value: string ; aCapacity: Integer ); overload; constructor Create( const Value: string ; StartIndex: Integer ; Length: Integer ; aCapacity: Integer ); overload; //占位,兼容class版本的TStringBuilder,这里是为了移植不需要改代码。空函数. procedure Free(); inline; function Append( const Value: Boolean ): TStringBuilder; overload; function Append( const Value: Byte ): TStringBuilder; overload; function Append( const Value: Char ): TStringBuilder; overload; function Append( const Value: Currency ): TStringBuilder; overload; function Append( const Value: Double ): TStringBuilder; overload; function Append( const Value: Smallint ): TStringBuilder; overload; function Append( const Value: Integer ): TStringBuilder; overload; function Append( const Value: Int64 ): TStringBuilder; overload; function Append( const Value: TObject): TStringBuilder; overload; function Append( const Value: Shortint ): TStringBuilder; overload; function Append( const Value: Single ): TStringBuilder; overload; function Append( const Value: string ): TStringBuilder; overload; function Append( const Value: UInt64): TStringBuilder; overload; function Append( const Value: TCharArray): TStringBuilder; overload; function Append( const Value: Word ): TStringBuilder; overload; function Append( const Value: Cardinal ): TStringBuilder; overload; {$IFNDEF NEXTGEN} function Append( const Value: PAnsiChar ): TStringBuilder; overload; function Append( const Value: RawByteString): TStringBuilder; overload; {$ENDIF !NEXTGEN} function Append( const Value: Char ; RepeatCount: Integer ): TStringBuilder; overload; function Append( const Value: TCharArray; StartIndex: Integer ; CharCount: Integer ): TStringBuilder; overload; function Append( const Value: string ; StartIndex: Integer ; Count: Integer = - 1 ): TStringBuilder; overload; function Append( const Value: PChar ; StartIndex: Integer ; Count: Integer = - 1 ): TStringBuilder; overload; function AppendFormat( const Format: string ; const Args: array of const ): TStringBuilder; overload; function AppendLine: TStringBuilder; overload; inline; function AppendLine( const Value: string ): TStringBuilder; overload; function AppendLineFormat( const Format: string ; const Args: array of const ): TStringBuilder; overload; procedure Clear; procedure CopyTo(SourceIndex: Integer ; const Destination: TCharArray; DestinationIndex: Integer ; Count: Integer ); function EnsureCapacity(aCapacity: Integer ): Integer ; function Equals(StringBuilder: TStringBuilder): Boolean ; reintroduce; function Insert(Index: Integer ; const Value: Boolean ): TStringBuilder; overload; function Insert(Index: Integer ; const Value: Byte ): TStringBuilder; overload; function Insert(Index: Integer ; const Value: Char ): TStringBuilder; overload; function Insert(Index: Integer ; const Value: Currency ): TStringBuilder; overload; function Insert(Index: Integer ; const Value: Double ): TStringBuilder; overload; function Insert(Index: Integer ; const Value: Smallint ): TStringBuilder; overload; function Insert(Index: Integer ; const Value: Integer ): TStringBuilder; overload; function Insert(Index: Integer ; const Value: TCharArray): TStringBuilder; overload; function Insert(Index: Integer ; const Value: Int64 ): TStringBuilder; overload; function Insert(Index: Integer ; const Value: TObject): TStringBuilder; overload; function Insert(Index: Integer ; const Value: Shortint ): TStringBuilder; overload; function Insert(Index: Integer ; const Value: Single ): TStringBuilder; overload; function Insert(Index: Integer ; const Value: string ): TStringBuilder; overload; function Insert(Index: Integer ; const Value: Word ): TStringBuilder; overload; function Insert(Index: Integer ; const Value: Cardinal ): TStringBuilder; overload; function Insert(Index: Integer ; const Value: UInt64): TStringBuilder; overload; function Insert(Index: Integer ; const Value: string ; count: Integer ): TStringBuilder; overload; function Insert(Index: Integer ; const Value: TCharArray; startIndex: Integer ; charCount: Integer ): TStringBuilder; overload; function Remove(StartIndex: Integer ; RemLength: Integer ): TStringBuilder; function Replace( const OldChar: Char ; const NewChar: Char ): TStringBuilder; overload; function Replace( const OldValue: string ; const NewValue: string ): TStringBuilder; overload; function Replace( const OldChar: Char ; const NewChar: Char ; StartIndex: Integer ; Count: Integer ): TStringBuilder; overload; function Replace( const OldValue: string ; const NewValue: string ; StartIndex: Integer ; Count: Integer ): TStringBuilder; overload; function ToString: string ; overload; function ToString(UpdateCapacity: Boolean ): string ; reintroduce; overload; function ToString(StartIndex: Integer ; StrLength: Integer ): string ; reintroduce; overload; function GetEnumerator: TEnumerator; inline; property Capacity: Integer read GetCapacity write SetCapacity; property Chars[index: Integer ]: Char read GetChars write SetChars; default; property Length: Integer read GetLength write SetLength; property MaxCapacity: Integer read GetMaxCapacity; end ; TManagedStringBuilder = TStringBuilder; TMSB = TStringBuilder; //function NewManagedStringBuilder():TManagedStringBuilder; overload; function NewManagedStringBuilder(aCapacity: Integer ):TManagedStringBuilder; overload; function NewManagedStringBuilder( const Value: string ):TManagedStringBuilder; overload; function NewManagedStringBuilder(aCapacity: Integer ; aMaxCapacity: Integer ):TManagedStringBuilder; overload; function NewManagedStringBuilder( const Value: string ; aCapacity: Integer ):TManagedStringBuilder; overload; function NewManagedStringBuilder( const Value: string ; StartIndex: Integer ; Length: Integer ; aCapacity: Integer ):TManagedStringBuilder; overload; implementation { function NewManagedStringBuilder():TManagedStringBuilder; begin Result := NewManagedStringBuilder(MaxInt); end; } function NewManagedStringBuilder(aCapacity: Integer ):TManagedStringBuilder; begin Result := TManagedStringBuilder . Create(aCapacity); end ; function NewManagedStringBuilder( const Value: string ):TManagedStringBuilder; begin Result := TManagedStringBuilder . Create(Value); end ; function NewManagedStringBuilder(aCapacity: Integer ; aMaxCapacity: Integer ):TManagedStringBuilder; begin Result := TManagedStringBuilder . Create(aCapacity, aMaxCapacity); end ; function NewManagedStringBuilder( const Value: string ; aCapacity: Integer ):TManagedStringBuilder; begin Result := TManagedStringBuilder . Create(Value, aCapacity); end ; function NewManagedStringBuilder( const Value: string ; StartIndex: Integer ; Length: Integer ; aCapacity: Integer ):TManagedStringBuilder; begin Result := TManagedStringBuilder . Create(Value, StartIndex, Length, aCapacity); end ; { TStringBuilder } {$ZEROBASEDSTRINGS ON} function TStringBuilder . GetLength: Integer ; begin Result := FLength; end ; function TStringBuilder . GetCapacity: Integer ; begin Result := System . Length(FData); end ; function TStringBuilder . GetMaxCapacity: Integer ; begin Result := FMaxCapacity; end ; function TStringBuilder . Append( const Value: UInt64): TStringBuilder; begin Result := Append(UIntToStr(Value)); end ; function TStringBuilder . Append( const Value: TCharArray): TStringBuilder; var I: Integer ; begin I := 0 ; while (I < System . Length(Value)) and (Value[I] <> # 0 ) do Inc(I); Result := Append(Value, 0 , I); end ; function TStringBuilder . Append( const Value: Single ): TStringBuilder; begin Result := Append(FloatToStr(Value)); end ; function TStringBuilder . Append( const Value: string ): TStringBuilder; var Delta, OldLength: Integer ; begin Delta := System . Length(Value); if Delta <> 0 then begin OldLength := Length; FLength := Length + Delta; if Length > Capacity then ExpandCapacity; Move( Pointer (Value)^, ( PChar ( Pointer (FData)) + OldLength)^, Delta * SizeOf( Char )); end ; Result := self; end ; function TStringBuilder . Append( const Value: Word ): TStringBuilder; begin Result := Append(IntToStr(Value)); end ; function TStringBuilder . Append( const Value: TCharArray; StartIndex, CharCount: Integer ): TStringBuilder; var OldLength: Integer ; begin if StartIndex + CharCount > System . Length(Value) then raise ERangeError . CreateResFmt(@SListIndexError, [StartIndex]); if StartIndex < 0 then raise ERangeError . CreateResFmt(@SListIndexError, [StartIndex]); if CharCount > 0 then begin OldLength := Length; Length := Length + CharCount; Move(Value[StartIndex], FData[OldLength], CharCount * SizeOf( Char )); end ; Result := self; end ; function TStringBuilder . Append( const Value: string ; StartIndex, Count: Integer ): TStringBuilder; var OldLength: Integer ; begin if Count < 0 then Count := System . Length(Value) - StartIndex; if StartIndex + Count > System . Length(Value) then raise ERangeError . CreateResFmt(@SListIndexError, [StartIndex]); if StartIndex < 0 then raise ERangeError . CreateResFmt(@SListIndexError, [StartIndex]); if Count > 0 then begin OldLength := Length; Length := Length + Count; Move(Value[StartIndex + Low( string )], FData[OldLength], Count * SizeOf( Char )); end ; Result := Self; end ; function TStringBuilder . Append( const Value: PChar ; StartIndex, Count: Integer ): TStringBuilder; var OldLength: Integer ; begin if Count < 0 then Count := Integer (StrLen(Value)) - StartIndex; if StartIndex < 0 then raise ERangeError . CreateResFmt(@SListIndexError, [StartIndex]); if Count > 0 then begin OldLength := Length; Length := Length + Count; Move((Value + StartIndex)^, FData[OldLength], Count * SizeOf( Char )); end ; Result := Self; end ; {$IFNDEF NEXTGEN} function TStringBuilder . Append( const Value: PAnsiChar ): TStringBuilder; begin Result := Append( string (Value)); end ; function TStringBuilder . Append( const Value: RawByteString): TStringBuilder; begin Result := Append( string (Value)); end ; {$ENDIF !NEXTGEN} function TStringBuilder . Append( const Value: Cardinal ): TStringBuilder; begin Result := Append(UIntToStr(Value)); end ; function TStringBuilder . Append( const Value: Char ; RepeatCount: Integer ): TStringBuilder; begin Result := Append(System . StringOfChar(Value, RepeatCount)); end ; function TStringBuilder . Append( const Value: Shortint ): TStringBuilder; begin Result := Append(IntToStr(Value)); end ; function TStringBuilder . Append( const Value: Char ): TStringBuilder; begin FLength := Length + 1 ; if Length > Capacity then ExpandCapacity; FData[Length - 1 ] := Value; Result := Self; end ; function TStringBuilder . Append( const Value: Currency ): TStringBuilder; begin Result := Append(CurrToStr(Value)); end ; function TStringBuilder . Append( const Value: Boolean ): TStringBuilder; begin Result := Append(BoolToStr(Value, True )); end ; function TStringBuilder . Append( const Value: Byte ): TStringBuilder; begin Result := Append(IntToStr(Value)); end ; function TStringBuilder . Append( const Value: Double ): TStringBuilder; begin Result := Append(FloatToStr(Value)); end ; function TStringBuilder . Append( const Value: Int64 ): TStringBuilder; begin Result := Append(IntToStr(Value)); end ; function TStringBuilder . Append( const Value: TObject): TStringBuilder; begin {$if CompilerVersion >= 19} Result := Append(Value . ToString()); { $else } Result := Append(IntToStr( Integer (Value))); { $ENDIF } end ; function TStringBuilder . Append( const Value: Smallint ): TStringBuilder; begin Result := Append(IntToStr(Value)); end ; function TStringBuilder . Append( const Value: Integer ): TStringBuilder; begin Result := Append(IntToStr(Value)); end ; function TStringBuilder . AppendFormat( const Format: string ; const Args: array of const ): TStringBuilder; begin Result := Append(System . SysUtils . Format(Format, Args)); end ; function TStringBuilder . AppendLineFormat( const Format: string ; const Args: array of const ): TStringBuilder; begin Result := AppendLine(System . SysUtils . Format(Format, Args)); end ; function TStringBuilder . AppendLine: TStringBuilder; begin Result := Append(LineBreak); end ; function TStringBuilder . AppendLine( const Value: string ): TStringBuilder; begin Result := Append(Value).AppendLine; end ; procedure TStringBuilder . Clear; begin Length := 0 ; Capacity := DefaultCapacity; end ; procedure TStringBuilder . CheckBounds(Index: Integer ); begin if Cardinal (Index) >= Cardinal (Length) then raise ERangeError . CreateResFmt(@SListIndexError, [Index]); end ; procedure TStringBuilder . CopyTo(SourceIndex: Integer ; const Destination: TCharArray; DestinationIndex, Count: Integer ); begin if Count < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'Count' ]); // DO NOT LOCALIZE if DestinationIndex < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'DestinationIndex' ]); // DO NOT LOCALIZE if DestinationIndex + Count > System . Length(Destination) then raise ERangeError . CreateResFmt(@SInputBufferExceed, [ 'DestinationIndex' , DestinationIndex, 'Count' , Count]); if Count > 0 then begin CheckBounds(SourceIndex); CheckBounds(SourceIndex + Count - 1 ); Move(FData[SourceIndex], Destination[DestinationIndex], Count * SizeOf( Char )); end ; end ; //constructor TStringBuilder.Create; class operator TStringBuilder . Initialize(out Dest: TStringBuilder); begin Dest . FLength := 0 ; //record不是class,FLength不会自动初始化为0,所以要先初始化FLength Dest . FMaxCapacity := MaxInt; Dest . Capacity := DefaultCapacity; end ; class operator TStringBuilder . Finalize( var Dest: TStringBuilder); begin //暂时没有需要释放的 end ; constructor TStringBuilder . Create( const Value: string ; aCapacity: Integer ); begin FMaxCapacity := MaxInt; Capacity := aCapacity; FLength := 0 ; Append(Value); end ; constructor TStringBuilder . Create( const Value: string ; StartIndex, length, aCapacity: Integer ); begin Create(Value . Substring(StartIndex, length), aCapacity); end ; constructor TStringBuilder . Create(aCapacity, aMaxCapacity: Integer ); begin if aMaxCapacity <= 0 then raise ERangeError . CreateRes(@SRangeError); if aCapacity > aMaxCapacity then raise ERangeError . CreateResFmt(@SListCapacityError, [aCapacity]); Create(aCapacity); FMaxCapacity := aMaxCapacity; end ; constructor TStringBuilder . Create(aCapacity: Integer ); begin FMaxCapacity := MaxInt; Capacity := aCapacity; FLength := 0 ; end ; constructor TStringBuilder . Create( const Value: string ); begin Append(Value); end ; procedure TStringBuilder . Free(); begin end ; function TStringBuilder . EnsureCapacity(aCapacity: Integer ): Integer ; begin if Cardinal (aCapacity) > Cardinal (MaxCapacity) then raise ERangeError . CreateResFmt(@SListIndexError, [aCapacity]); if Capacity < aCapacity then Capacity := aCapacity; Result := Capacity; end ; function TStringBuilder . Equals(StringBuilder: TStringBuilder): Boolean ; begin Result := (Length = StringBuilder . Length) and (MaxCapacity = StringBuilder . MaxCapacity) and ((Length = 0 ) or CompareMem( Pointer (FData), Pointer (StringBuilder . FData), Length * SizeOf( Char ))); end ; procedure TStringBuilder . ExpandCapacity; var NewCapacity: Integer ; begin NewCapacity := (Capacity * 3 ) div 2 ; if Length > NewCapacity then NewCapacity := Length * 2 ; // this line may overflow NewCapacity to a negative value if NewCapacity > MaxCapacity then NewCapacity := MaxCapacity; if NewCapacity < 0 then // if NewCapacity has been overflowed NewCapacity := Length; Capacity := NewCapacity; end ; function TStringBuilder . GetChars(Index: Integer ): Char ; begin if Index < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'Index' ]); // DO NOT LOCALIZE CheckBounds(Index); Result := FData[Index]; end ; function TStringBuilder . Insert(Index: Integer ; const Value: TObject): TStringBuilder; begin {$if CompilerVersion >= 19} Result := Insert(Index, Value . ToString()); { $else } Result := Insert(Index, IntToStr( Integer (Value))); { $ENDIF } end ; function TStringBuilder . Insert(Index: Integer ; const Value: Int64 ): TStringBuilder; begin Result := Insert(Index, IntToStr(Value)); end ; function TStringBuilder . Insert(Index: Integer ; const Value: Single ): TStringBuilder; begin Result := Insert(Index, FloatToStr(Value)); end ; function TStringBuilder . Insert(Index: Integer ; const Value: string ): TStringBuilder; var OldLength: Integer ; begin if Index < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'Index' ]); // DO NOT LOCALIZE if Index > Length then raise ERangeError . CreateResFmt(@SListIndexError, [Index]); OldLength := Length; Length := Length + System . Length(Value); if OldLength > Index then Move(FData[Index], FData[Index + System . Length(Value)], (OldLength - Index) * SizeOf( Char )); Move(Value[Low( string )], FData[Index], System . Length(Value) * SizeOf( Char )); Result := Self; end ; function TStringBuilder . Insert(Index: Integer ; const Value: Word ): TStringBuilder; begin Result := Insert(Index, IntToStr(Value)); end ; function TStringBuilder . Insert(Index: Integer ; const Value: Shortint ): TStringBuilder; begin Result := Insert(Index, IntToStr(Value)); end ; function TStringBuilder . Insert(Index: Integer ; const Value: TCharArray): TStringBuilder; var OldLength: Integer ; begin if Index < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'Index' ]); // DO NOT LOCALIZE if Index > Length then raise ERangeError . CreateResFmt(@SListIndexError, [Index]); OldLength := Length; Length := Length + System . Length(Value); if OldLength > 0 then Move(FData[Index], FData[Index + System . Length(Value)], OldLength * SizeOf( Char )); Move(Value[ 0 ], FData[Index], System . Length(Value) * SizeOf( Char )); Result := Self; end ; function TStringBuilder . Insert(Index: Integer ; const Value: Currency ): TStringBuilder; begin Result := Insert(Index, CurrToStr(Value)); end ; function TStringBuilder . Insert(Index: Integer ; const Value: Char ): TStringBuilder; var OldLength: Integer ; begin if Index < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'Index' ]); // DO NOT LOCALIZE if Index > Length then raise ERangeError . CreateResFmt(@SListIndexError, [Index]); OldLength := Length; Length := Length + 1 ; if OldLength > Index then Move(FData[Index], FData[Index + 1 ], (OldLength - Index) * SizeOf( Char )); FData[Index] := Value; Result := Self; end ; function TStringBuilder . Insert(Index: Integer ; const Value: Byte ): TStringBuilder; begin Result := Insert(Index, IntToStr(Value)); end ; function TStringBuilder . Insert(Index: Integer ; const Value: Double ): TStringBuilder; begin Result := Insert(Index, FloatToStr(Value)); end ; function TStringBuilder . Insert(Index: Integer ; const Value: Integer ): TStringBuilder; begin Result := Insert(Index, IntToStr(Value)); end ; function TStringBuilder . Insert(Index: Integer ; const Value: Smallint ): TStringBuilder; begin Result := Insert(Index, IntToStr(Value)); end ; function TStringBuilder . Insert(Index: Integer ; const Value: Boolean ): TStringBuilder; begin Result := Insert(Index, BoolToStr(Value, True )); end ; function TStringBuilder . Insert(Index: Integer ; const Value: string ; Count: Integer ): TStringBuilder; var I: Integer ; begin for I := 0 to Count - 1 do Insert(Index, Value); Result := Self; end ; function TStringBuilder . Insert(Index: Integer ; const Value: TCharArray; StartIndex, CharCount: Integer ): TStringBuilder; var OldLength: Integer ; begin if Index - 1 >= Length then raise ERangeError . CreateResFmt(@SListIndexError, [Index]) else if Index < 0 then raise ERangeError . CreateResFmt(@SListIndexError, [Index]); if StartIndex < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'StartIndex' ]); // DO NOT LOCALIZE if CharCount < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'CharCount' ]); // DO NOT LOCALIZE if StartIndex + CharCount > System . Length(Value) then raise ERangeError . CreateResFmt(@SInputBufferExceed, [ 'StartIndex' , StartIndex, 'CharCount' , CharCount]); OldLength := Length; Length := Length + CharCount; if OldLength > Index then Move(FData[Index], FData[Index + CharCount], (OldLength - Index) * SizeOf( Char )); Move(Value[StartIndex], FData[Index], CharCount * SizeOf( Char )); Result := Self; end ; function TStringBuilder . Insert(Index: Integer ; const Value: Cardinal ): TStringBuilder; begin Result := Insert(Index, IntToStr(Value)); end ; function TStringBuilder . Insert(Index: Integer ; const Value: UInt64): TStringBuilder; begin Result := Insert(Index, UIntToStr(Value)); end ; procedure TStringBuilder . ReduceCapacity; var NewCapacity: Integer ; begin if Length > Capacity div 4 then Exit; NewCapacity := Capacity div 2 ; if NewCapacity < Length then NewCapacity := Length; Capacity := NewCapacity; end ; function TStringBuilder . Remove(StartIndex, RemLength: Integer ): TStringBuilder; begin if RemLength <> 0 then begin if StartIndex < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'StartIndex' ]); // DO NOT LOCALIZE if RemLength < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'RemLength' ]); // DO NOT LOCALIZE CheckBounds(StartIndex); CheckBounds(StartIndex + RemLength - 1 ); if (Length - (StartIndex + RemLength)) > 0 then Move(FData[StartIndex + RemLength], FData[StartIndex], (Length - (StartIndex + RemLength)) * SizeOf( Char )); Length := Length - RemLength; ReduceCapacity; end ; Result := Self; end ; function TStringBuilder . Replace( const OldValue, NewValue: string ; StartIndex, Count: Integer ): TStringBuilder; var CurPtr: PChar ; EndPtr: PChar ; Index: Integer ; EndIndex: Integer ; OldLen, NewLen: Integer ; begin Result := Self; if Count <> 0 then begin if StartIndex < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'StartIndex' ]); // DO NOT LOCALIZE if Count < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'Count' ]); // DO NOT LOCALIZE if StartIndex + Count > Length then raise ERangeError . CreateResFmt(@SInputBufferExceed, [ 'StartIndex' , StartIndex, 'Count' , Count]); OldLen := System . Length(OldValue); NewLen := System . Length(NewValue); Index := StartIndex; CurPtr := @FData[StartIndex]; EndIndex := StartIndex + Count - OldLen; EndPtr := @FData[EndIndex]; while CurPtr <= EndPtr do begin if CurPtr^ = OldValue[Low( string )] then begin if StrLComp(CurPtr, PChar (OldValue), OldLen) = 0 then begin if _Replace(Index, OldValue, NewValue) then begin CurPtr := @FData[Index]; EndPtr := @FData[EndIndex]; end ; Inc(CurPtr, NewLen - 1 ); Inc(Index, NewLen - 1 ); Inc(EndPtr, NewLen - OldLen); Inc(EndIndex, NewLen - OldLen); end ; end ; Inc(CurPtr); Inc(Index); end ; end ; end ; function TStringBuilder . Replace( const OldChar, NewChar: Char ; StartIndex, Count: Integer ): TStringBuilder; var Ptr: PChar ; EndPtr: PChar ; begin if Count <> 0 then begin if StartIndex < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'StartIndex' ]); // DO NOT LOCALIZE if Count < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'Count' ]); // DO NOT LOCALIZE CheckBounds(StartIndex); CheckBounds(StartIndex + Count - 1 ); EndPtr := @FData[StartIndex + Count - 1 ]; Ptr := @FData[StartIndex]; while Ptr <= EndPtr do begin if Ptr^ = OldChar then Ptr^ := NewChar; Inc(Ptr); end ; end ; Result := Self; end ; function TStringBuilder . Replace( const OldChar, NewChar: Char ): TStringBuilder; var Ptr: PChar ; EndPtr: PChar ; begin EndPtr := @FData[Length - 1 ]; Ptr := @FData[ 0 ]; while Ptr <= EndPtr do begin if Ptr^ = OldChar then Ptr^ := NewChar; Inc(Ptr); end ; Result := Self; end ; function TStringBuilder . Replace( const OldValue, NewValue: string ): TStringBuilder; begin Result := Replace(OldValue, NewValue, 0 , Length); end ; procedure TStringBuilder . SetCapacity(Value: Integer ); begin if Value < Length then raise ERangeError . CreateResFmt(@SListCapacityError, [Value]); if Value > FMaxCapacity then raise ERangeError . CreateResFmt(@SListCapacityError, [Value]); System . SetLength(FData, Value); end ; procedure TStringBuilder . SetChars(Index: Integer ; Value: Char ); begin if Index < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'Index' ]); // DO NOT LOCALIZE CheckBounds(Index); FData[Index] := Value; end ; procedure TStringBuilder . SetLength(Value: Integer ); var LOldLength: Integer ; begin if Value < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'Value' ]); // DO NOT LOCALIZE if Value > MaxCapacity then raise ERangeError . CreateResFmt(@SListCapacityError, [Value]); LOldLength := FLength; try FLength := Value; if FLength > Capacity then ExpandCapacity; except on E: EOutOfMemory do begin FLength := LOldLength; raise ; end ; end ; end ; function TStringBuilder . ToString: string ; begin Result := ToString( False ); end ; function TStringBuilder . ToString(UpdateCapacity: Boolean ): string ; begin if Length = Capacity then Result := FData else if UpdateCapacity then begin System . SetLength(FData, Length); Result := FData; end else Result := FData . Substring( 0 , Length); end ; function TStringBuilder . ToString(StartIndex, StrLength: Integer ): string ; begin if StrLength <> 0 then begin if StartIndex < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'StartIndex' ]); // DO NOT LOCALIZE if StrLength < 0 then raise ERangeError . CreateResFmt(@SParamIsNegative, [ 'StrLength' ]); // DO NOT LOCALIZE CheckBounds(StartIndex); CheckBounds(StartIndex + StrLength - 1 ); Result := FData . Substring(StartIndex, StrLength); end else Result := '' ; end ; function TStringBuilder . _Replace(Index: Integer ; const Old, New: string ): Boolean ; var OldLength: Integer ; OldCapacity: Integer ; SizeChange: Integer ; begin Result := False ; SizeChange := System . Length(New) - System . Length(Old); if SizeChange = 0 then begin Move(New[Low( string )], FData[Index], System . Length(New) * SizeOf( Char )); end else begin OldLength := Length; if SizeChange > 0 then begin OldCapacity := Capacity; Length := Length + SizeChange; if OldCapacity <> Capacity then Result := True ; end ; Move(FData[Index + System . Length(Old)], FData[Index + System . Length(New)], (OldLength - (System . Length(Old) + Index)) * SizeOf( Char )); Move(New[Low( String )], FData[Index], System . Length(New) * SizeOf( Char )); if SizeChange < 0 then Length := Length + SizeChange; end ; end ; { TStringBuilder.TEnumerator } procedure TStringBuilder . TEnumerator . Initialize( const ABuilder: TStringBuilder); begin FPtr := PChar ( Pointer (ABuilder . FData)) - 1 ; FEndPtr := FPtr + ABuilder . Length; end ; function TStringBuilder . TEnumerator . GetCurrent: Char ; begin Result := FPtr^; end ; function TStringBuilder . TEnumerator . MoveNext: Boolean ; begin Inc(FPtr); Result := FPtr <= FEndPtr; end ; function TStringBuilder . GetEnumerator: TEnumerator; begin Result . Initialize(Self); end ; end . |