其实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;interfaceuses 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();beginend;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. |