Skip to content

Instantly share code, notes, and snippets.

@Athari
Created May 13, 2013 19:19
Show Gist options
  • Save Athari/5570745 to your computer and use it in GitHub Desktop.
Save Athari/5570745 to your computer and use it in GitHub Desktop.
TStringBuilder from Delphi XE3
type
TStringBuilder = class
private const
DefaultCapacity = $10;
private
function GetCapacity: Integer;
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;
procedure ExpandCapacity;
procedure ReduceCapacity;
procedure CheckBounds(Index: Integer);
function _Replace(Index: Integer; const Old, New: string): Boolean;
protected
FData: TCharArray;
FLength: Integer;
FMaxCapacity: Integer;
public
constructor Create; overload;
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;
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): TStringBuilder; overload;
function AppendFormat(const Format: string; const Args: array of const): TStringBuilder; overload;
function AppendLine: TStringBuilder; overload;
function AppendLine(const Value: string): 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; override;
function ToString(StartIndex: Integer; StrLength: Integer): string; reintroduce; overload;
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;
TStringSplitOptions = (None, ExcludeEmpty);
TStringHelper = record helper for string
private
function GetChars(Index: Integer): Char; inline;
function GetLength: Integer; inline;
class function CharInArray(const C: Char; const InArray: array of Char): Boolean; static;
function IndexOfAny(const Values: array of string; var Index: Integer): Integer; overload;
public
const Empty = '';
// Methods
class function Create(C: Char; Count: Integer): string; overload; inline; static;
class function Create(const Value: array of Char; StartIndex: Integer; Length: Integer): string; overload; static;
class function Create(const Value: array of Char): string; overload; static;
class function Compare(const StrA: string; const StrB: string): Integer; overload; static;
class function Compare(const StrA: string; const StrB: string; IgnoreCase: Boolean): Integer; overload; static;
class function Compare(const StrA: string; IndexA: Integer; const StrB: string; IndexB: Integer; Length: Integer): Integer; overload; static;
class function Compare(const StrA: string; IndexA: Integer; const StrB: string; IndexB: Integer; Length: Integer; IgnoreCase: Boolean): Integer; overload; static;
class function CompareOrdinal(const strA: string; const strB: string): Integer; overload; static;
class function CompareOrdinal(const strA: string; indexA: Integer; const strB: string; indexB: Integer; length: Integer): Integer; overload; static;
function CompareTo(const strB: string): Integer;
function Contains(const Value: string): Boolean;
class function Copy(const Str: string): string; inline; static;
procedure CopyTo(SourceIndex: Integer; var destination: array of Char; DestinationIndex: Integer; Count: Integer);
class function EndsText(const ASubText, AText: string): Boolean; static;
function EndsWith(const Value: string): Boolean; overload;
function EndsWith(const Value: string; IgnoreCase: Boolean): Boolean; overload;
function Equals(const Value: string): Boolean; overload;
class function Equals(const a: string; const b: string): Boolean; overload; static;
class function Format(const Format: string; const args: array of const): string; overload; static;
function GetHashCode: Integer;
function IndexOf(value: Char): Integer; overload; inline;
function IndexOf(const Value: string): Integer; overload; inline;
function IndexOf(Value: Char; StartIndex: Integer): Integer; overload;
function IndexOf(const Value: string; StartIndex: Integer): Integer; overload;
function IndexOf(Value: Char; StartIndex: Integer; Count: Integer): Integer; overload;
function IndexOf(const Value: string; StartIndex: Integer; Count: Integer): Integer; overload;
function IndexOfAny(const AnyOf: array of Char): Integer; overload;
function IndexOfAny(const AnyOf: array of Char; StartIndex: Integer): Integer; overload;
function IndexOfAny(const AnyOf: array of Char; StartIndex: Integer; Count: Integer): Integer; overload;
function Insert(StartIndex: Integer; const Value: string): string;
// function IsNormalized: Boolean; overload;
// function IsNormalized(NormalizationForm: TNormalizationForm): Boolean; overload;
function IsDelimiter(const Delimiters: string; Index: Integer): Boolean;
function IsEmpty: Boolean;
class function IsNullOrEmpty(const Value: string): Boolean; static;
class function IsNullOrWhiteSpace(const Value: string): Boolean; static;
class function Join(const Separator: string; const values: array of const): string; overload; static;
class function Join(const Separator: string; const Values: array of string): string; overload; static;
// class function Join<T>(Separator: string; const values: IEnumerable<T>): string; overload; static;
class function Join(const Separator: string; const Values: IEnumerable<string>): string; overload; static;
class function Join(const Separator: string; const value: array of string; StartIndex: Integer; Count: Integer): string; overload; static;
function LastDelimiter(const Delims: string): Integer;
function LastIndexOf(Value: Char): Integer; overload;
function LastIndexOf(const Value: string): Integer; overload;
function LastIndexOf(Value: Char; StartIndex: Integer): Integer; overload;
function LastIndexOf(const Value: string; StartIndex: Integer): Integer; overload;
function LastIndexOf(Value: Char; StartIndex: Integer; Count: Integer): Integer; overload;
function LastIndexOf(const Value: string; StartIndex: Integer; Count: Integer): Integer; overload;
function LastIndexOfAny(const AnyOf: array of Char): Integer; overload;
function LastIndexOfAny(const AnyOf: array of Char; StartIndex: Integer): Integer; overload;
function LastIndexOfAny(const AnyOf: array of Char; StartIndex: Integer; Count: Integer): Integer; overload;
function PadLeft(TotalWidth: Integer): string; overload; inline;
function PadLeft(TotalWidth: Integer; PaddingChar: Char): string; overload; inline;
function PadRight(TotalWidth: Integer): string; overload; inline;
function PadRight(TotalWidth: Integer; PaddingChar: Char): string; overload; inline;
function Remove(StartIndex: Integer): string; overload; inline;
function Remove(StartIndex: Integer; Count: Integer): string; overload; inline;
function Replace(OldChar: Char; NewChar: Char): string; overload;
function Replace(OldChar: Char; NewChar: Char; ReplaceFlags: TReplaceFlags): string; overload;
function Replace(const OldValue: string; const NewValue: string): string; overload;
function Replace(const OldValue: string; const NewValue: string; ReplaceFlags: TReplaceFlags): string; overload;
function Split(const Separator: array of Char): TArray<string>; overload;
function Split(const Separator: array of Char; Count: Integer): TArray<string>; overload;
function Split(const Separator: array of Char; Options: TStringSplitOptions): TArray<string>; overload;
function Split(const Separator: array of string; Options: TStringSplitOptions): TArray<string>; overload;
function Split(const Separator: array of Char; Count: Integer; Options: TStringSplitOptions): TArray<string>; overload;
function Split(const Separator: array of string; Count: Integer; Options: TStringSplitOptions): TArray<string>; overload;
function StartsWith(const Value: string): Boolean; overload;
function StartsWith(const Value: string; IgnoreCase: Boolean): Boolean; overload;
function Substring(StartIndex: Integer): string; overload;
function Substring(StartIndex: Integer; Length: Integer): string; overload;
function ToCharArray: TArray<Char>; overload;
function ToCharArray(StartIndex: Integer; Length: Integer): TArray<Char>; overload;
function ToLower: string;
function ToLowerInvariant: string;
function ToUpper: string;
function ToUpperInvariant: string;
function Trim: string; overload;
function Trim(const TrimChars: array of Char): string; overload;
function TrimEnd(const TrimChars: array of Char): string;
function TrimStart(const TrimChars: array of Char): string;
property Chars[Index: Integer]: Char read GetChars;
property Length: Integer read GetLength;
end;
{ TStringBuilder }
function TStringBuilder.GetLength: Integer;
begin
Result := FLength;
end;
function TStringBuilder.Append(const Value: UInt64): TStringBuilder;
begin
Append(UIntToStr(Value));
Result := self;
end;
function TStringBuilder.Append(const Value: TCharArray): TStringBuilder;
var
I: Integer;
begin
Result := self;
for I := 0 to System.Length(Value) - 1 do
if Value[I] = #0 then
Break;
Append(Value, 0, I);
end;
function TStringBuilder.Append(const Value: Single): TStringBuilder;
begin
Append(FloatToStr(Value));
Result := self;
end;
function TStringBuilder.Append(const Value: string): TStringBuilder;
begin
Length := Length + System.Length(Value);
Move(PChar(Value)^, FData[Length - System.Length(Value)], System.Length(Value) * SizeOf(Char));
Result := self;
end;
function TStringBuilder.Append(const Value: Word): TStringBuilder;
begin
Append(IntToStr(Value));
Result := self;
end;
function TStringBuilder.Append(const Value: TCharArray; StartIndex,
CharCount: Integer): TStringBuilder;
begin
if StartIndex + CharCount > System.Length(Value) then
raise ERangeError.CreateResFmt(@SListIndexError, [StartIndex]);
if StartIndex < 0 then
raise ERangeError.CreateResFmt(@SListIndexError, [StartIndex]);
Length := Length + CharCount;
Move(Value[StartIndex], FData[Length - CharCount], CharCount * SizeOf(Char));
Result := self;
end;
function TStringBuilder.Append(const Value: string; StartIndex,
Count: Integer): TStringBuilder;
begin
if StartIndex + Count > System.Length(Value) then
raise ERangeError.CreateResFmt(@SListIndexError, [StartIndex]);
if StartIndex < 0 then
raise ERangeError.CreateResFmt(@SListIndexError, [StartIndex]);
Length := Length + Count;
Move(Value[StartIndex + Low(string)], FData[Length - Count], Count * SizeOf(Char));
Result := Self;
end;
{$IFNDEF NEXTGEN}
function TStringBuilder.Append(const Value: PAnsiChar): TStringBuilder;
begin
Append(string(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: RawByteString): TStringBuilder;
begin
Append(string(Value));
Result := Self;
end;
{$ENDIF !NEXTGEN}
function TStringBuilder.Append(const Value: Cardinal): TStringBuilder;
begin
Append(UIntToStr(Value));
Result := self;
end;
function TStringBuilder.Append(const Value: Char;
RepeatCount: Integer): TStringBuilder;
begin
Append(System.StringOfChar(Value, RepeatCount));
Result := Self;
end;
function TStringBuilder.Append(const Value: Shortint): TStringBuilder;
begin
Append(IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: Char): TStringBuilder;
begin
Length := Length + 1;
FData[Length - 1] := Value;
Result := Self;
end;
function TStringBuilder.Append(const Value: Currency): TStringBuilder;
begin
Append(CurrToStr(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: Boolean): TStringBuilder;
begin
Append(BoolToStr(Value, True));
Result := Self;
end;
function TStringBuilder.Append(const Value: Byte): TStringBuilder;
begin
Append(IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: Double): TStringBuilder;
begin
Append(FloatToStr(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: Int64): TStringBuilder;
begin
Append(IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: TObject): TStringBuilder;
begin
{$if CompilerVersion >= 19}
Append(Value.ToString());
{$else}
Append(IntToStr(Integer(Value)));
{$ENDIF}
Result := Self;
end;
function TStringBuilder.Append(const Value: Smallint): TStringBuilder;
begin
Append(IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: Integer): TStringBuilder;
begin
Append(IntToStr(Value));
Result := Self;
end;
function TStringBuilder.AppendFormat(const Format: string; const Args: array of const): TStringBuilder;
begin
Append(System.SysUtils.Format(Format, Args));
Result := Self;
end;
function TStringBuilder.AppendLine: TStringBuilder;
begin
Append(sLineBreak);
Result := Self;
end;
function TStringBuilder.AppendLine(const Value: string): TStringBuilder;
begin
Append(Value);
AppendLine;
Result := Self;
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;
begin
inherited Create;
FMaxCapacity := MaxInt;
Capacity := DefaultCapacity;
FLength := 0;
end;
constructor TStringBuilder.Create(const Value: string; aCapacity: Integer);
begin
inherited Create;
FMaxCapacity := MaxInt;
Capacity := aCapacity;
FLength := 0;
Append(Value);
end;
constructor TStringBuilder.Create(const Value: string; StartIndex, length,
aCapacity: Integer);
begin
//Create(Copy(Value, StartIndex + 1, length), aCapacity);
Create(Value.Substring( StartIndex, length), aCapacity);
end;
constructor TStringBuilder.Create(aCapacity, aMaxCapacity: Integer);
begin
Create(aCapacity);
FMaxCapacity := aMaxCapacity;
end;
constructor TStringBuilder.Create(aCapacity: Integer);
begin
inherited Create;
FMaxCapacity := MaxInt;
Capacity := aCapacity;
FLength := 0;
end;
constructor TStringBuilder.Create(const Value: string);
begin
Create;
Append(Value);
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 := (StringBuilder <> nil) and (Length = StringBuilder.Length) and
(MaxCapacity = StringBuilder.MaxCapacity) and
CompareMem(@FData[0], @StringBuilder.FData[0], Length * SizeOf(Char));
end;
procedure TStringBuilder.ExpandCapacity;
var
NewCapacity: Integer;
begin
NewCapacity := Capacity * 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.GetCapacity: Integer;
begin
Result := System.Length(FData);
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.GetMaxCapacity: Integer;
begin
Result := FMaxCapacity;
end;
function TStringBuilder.Insert(Index: Integer; const Value: TObject): TStringBuilder;
begin
{$if CompilerVersion >= 19}
Insert(Index, Value.ToString());
{$else}
Insert(Index, IntToStr(Integer(Value)));
{$ENDIF}
Result := Self;
end;
function TStringBuilder.Insert(Index: Integer; const Value: Int64): TStringBuilder;
begin
Insert(Index, IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Insert(Index: Integer; const Value: Single): TStringBuilder;
begin
Insert(Index, FloatToStr(Value));
Result := Self;
end;
function TStringBuilder.Insert(Index: Integer; const Value: string): TStringBuilder;
begin
if Index < 0 then
raise ERangeError.CreateResFmt(@SParamIsNegative, ['Index']); // DO NOT LOCALIZE
if Index > Length then
raise ERangeError.CreateResFmt(@SListIndexError, [Index]);
Length := Length + System.Length(Value);
Move(FData[Index], FData[Index + System.Length(Value)], (Length - System.Length(Value) - 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
Insert(Index, IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Insert(Index: Integer; const Value: Shortint): TStringBuilder;
begin
Insert(Index, IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Insert(Index: Integer;
const Value: TCharArray): TStringBuilder;
begin
if Index < 0 then
raise ERangeError.CreateResFmt(@SParamIsNegative, ['Index']); // DO NOT LOCALIZE
if Index > Length then
raise ERangeError.CreateResFmt(@SListIndexError, [Index]);
Length := Length + System.Length(Value);
Move(FData[Index], FData[Index + System.Length(Value)], System.Length(Value) * 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
Insert(Index, CurrToStr(Value));
Result := Self;
end;
function TStringBuilder.Insert(Index: Integer; const Value: Char): TStringBuilder;
begin
if Index < 0 then
raise ERangeError.CreateResFmt(@SParamIsNegative, ['Index']); // DO NOT LOCALIZE
if Index > Length then
raise ERangeError.CreateResFmt(@SListIndexError, [Index]);
Length := Length + 1;
Move(FData[Index], FData[Index + 1], (Length - Index - 1) * SizeOf(Char));
FData[Index] := Value;
Result := Self;
end;
function TStringBuilder.Insert(Index: Integer; const Value: Byte): TStringBuilder;
begin
Insert(Index, IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Insert(Index: Integer; const Value: Double): TStringBuilder;
begin
Insert(Index, FloatToStr(Value));
Result := Self;
end;
function TStringBuilder.Insert(Index: Integer; const Value: Integer): TStringBuilder;
begin
Insert(Index, IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Insert(Index: Integer; const Value: Smallint): TStringBuilder;
begin
Insert(Index, IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Insert(Index: Integer; const Value: Boolean): TStringBuilder;
begin
Insert(Index, BoolToStr(Value, True));
Result := Self;
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;
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]);
Length := Length + CharCount;
if Length - Index > 0 then
Move(FData[Index], FData[Index + CharCount], (Length - Index) * SizeOf(Char));
Move(Value[StartIndex], FData[Index], CharCount * SizeOf(Char));
Result := Self;
end;
function TStringBuilder.Insert(Index: Integer; const Value: Cardinal): TStringBuilder;
begin
Insert(Index, IntToStr(Value));
Result := self;
end;
function TStringBuilder.Insert(Index: Integer; const Value: UInt64): TStringBuilder;
begin
Insert(Index, UIntToStr(Value));
Result := self;
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 := self;
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
SetString(Result, MarshaledString(FData), 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 := string.Create(FData, 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;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment