昨天装了个D2010,发现2010中的StringBuilder对象用的比较爽快!于是稍作了一些修改(增加了几个函数和属性)然后移植到D2007中来使用了!效果不错,共享一下!
代码
unit DxStringBuilder;
interface
uses RTLConsts,Classes,SysUtils;
type
EExternal = class(Exception)
public
{$IFDEF MSWINDOWS}
ExceptionRecord: PExceptionRecord platform;
{$ENDIF}
{$IF defined(LINUX) or defined(MACOSX)}
ExceptionAddress: LongWord platform;
AccessAddress: LongWord platform;
SignalNumber: Integer platform;
{$IFEND LINUX or MACOSX}
end;
EIntError = class(EExternal);
ERangeError = class(EIntError);
TCharArray = array of Char;
TStringBuilder = class
private
const DefaultCapacity = $10;
function GetCapacity: Integer;
procedure SetCapacity(const Value: Integer);
function GetLength: Integer;
procedure Set_Length(const Value: Integer);
function GetMaxCapacity: Integer;
procedure ReduceCapacity;
procedure ExpandCapacity;
procedure CheckBounds(Index: Integer);
function _Replace(Index: Integer; const Old, New: string): Boolean;
function GetChars(index: Integer): Char;
procedure SetChars(index: Integer; const Value: Char);
protected
FData: TCharArray;
FLength: Integer;
FMaxCapacity: Integer;
public
constructor Create; overload;
constructor Create(aCapacity: Integer); overload;
constructor Create(const Value: string); 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;
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;
function ToString(StartIndex: Integer; StrLength: Integer): string; reintroduce; overload;
procedure SaveToStream(Stream: TStream);
procedure SaveToFile(FileName: string);
procedure LoadFromStream(Stream: TStream);
procedure LoadFromFile(FileName: string);
property Capacity: Integer read GetCapacity write SetCapacity;
property Chars[index: Integer]: Char read GetChars write SetChars; default;
property Length: Integer read GetLength write Set_Length;
property MaxCapacity: Integer read GetMaxCapacity;
end;
function UIntToStr(Value: Cardinal): string; overload;
function UIntToStr(Value: UInt64): string; overload;
resourcestring
SParamIsNegative = 'Parameter %s cannot be a negative value';
SInputBufferExceed = 'Input buffer exceeded for %s = %d, %s = %d';
implementation
function UIntToStr(Value: Cardinal): string;
begin
FmtStr(Result, '%u', [Value]);
end;
function UIntToStr(Value: UInt64): string;
begin
FmtStr(Result, '%u', [Value]);
end;
{ TStringBuilder }
constructor TStringBuilder.Create;
begin
inherited Create;
FMaxCapacity := MaxInt;
Capacity := DefaultCapacity;
FLength := 0;
end;
constructor TStringBuilder.Create(aCapacity: Integer);
begin
inherited Create;
FMaxCapacity := MaxInt;
Capacity := aCapacity;
FLength := 0;
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: Currency): TStringBuilder;
begin
Append(CurrToStr(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: Double): TStringBuilder;
begin
Append(FloatToStr(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: 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: Smallint): TStringBuilder;
begin
Append(IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: Shortint): TStringBuilder;
begin
Append(IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: Single): TStringBuilder;
begin
Append(FloatToStr(Value));
Result := self;
end;
function TStringBuilder.Append(const Value: TObject): TStringBuilder;
begin
{$if CompilerVersion >= 19}
Append(Value.ToString());
{$else}
if Value.InheritsFrom(TComponent) then
Append(TComponent(Value).Name+': '+Value.ClassName)
else Append(Value.ClassName);
{$ifend}
Result := Self;
end;
function TStringBuilder.Append(const Value: Integer): TStringBuilder;
begin
Append(IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: Int64): TStringBuilder;
begin
Append(IntToStr(Value));
Result := Self;
end;
procedure TStringBuilder.CheckBounds(Index: Integer);
begin
if Cardinal(Index) >= Cardinal(Length) then
raise ERangeError.CreateResFmt(@SListIndexError, [Index]);
end;
procedure TStringBuilder.Clear;
begin
Length := 0;
Capacity := DefaultCapacity;
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(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.GetLength: Integer;
begin
Result := FLength;
end;
function TStringBuilder.GetMaxCapacity: Integer;
begin
Result := FMaxCapacity;
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: Int64): 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: Double): TStringBuilder;
begin
Insert(Index, FloatToStr(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: Boolean): TStringBuilder;
begin
Insert(Index, BoolToStr(Value, True));
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: UInt64): TStringBuilder;
begin
Insert(Index, IntToStr(Value));
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: 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;
procedure TStringBuilder.LoadFromFile(FileName: string);
var
F: TFileStream;
begin
F := TFileStream.Create(FileName,fmOpenRead);
LoadFromStream(F);
F.Free;
end;
procedure TStringBuilder.LoadFromStream(Stream: TStream);
begin
Capacity := Stream.Size;
Stream.Position := 0;
Stream.ReadBuffer(FData[0],Stream.Size);
Length := Stream.Size;
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): TStringBuilder;
begin
Result := self;
Replace(OldValue, NewValue, 0, Length);
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; 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[1] 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.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: 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: TObject): TStringBuilder;
begin
{$if CompilerVersion >= 19}
Insert(Index, Value.ToString());
{$else}
Insert(Index, IntToStr(Integer(Value)));
{$ifend}
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[1], FData[Index], System.Length(Value) * SizeOf(Char));
Result := Self;
end;
function TStringBuilder.Insert(Index: Integer;
const Value: Single): TStringBuilder;
begin
Insert(Index, FloatToStr(Value));
Result := Self;
end;
procedure TStringBuilder.SaveToFile(FileName: string);
var
FileStream: TFileStream;
begin
FileStream := TFileStream.Create(FileName,fmOpenWrite);
SaveToStream(FileStream);
FileStream.Free;
end;
procedure TStringBuilder.SaveToStream(Stream: TStream);
begin
Stream.WriteBuffer(FData[0],Length * SizeOf(Char));
end;
procedure TStringBuilder.SetCapacity(const Value: Integer);
begin
if Value < Length then
raise ERangeError.CreateResFmt(@SListCapacityError, [Value]);
if Value > FMaxCapacity then
raise ERangeError.CreateResFmt(@SListCapacityError, [Value]);
SetLength(FData, Value);
end;
procedure TStringBuilder.SetChars(index: Integer; const Value: Char);
begin
if Index < 0 then
raise ERangeError.CreateResFmt(@SParamIsNegative, ['Index']); // DO NOT LOCALIZE
CheckBounds(Index);
FData[Index] := Value;
end;
procedure TStringBuilder.Set_Length(const 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
FLength := LOldLength;
end;
end;
function TStringBuilder.ToString: string;
begin
SetLength(Result, Length);
Move(FData[0], Result[1], Length * SizeOf(Char));
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);
SetLength(Result, StrLength);
Move(FData[StartIndex], Result[1], StrLength * SizeOf(Char));
end
else Result := '';
end;
function TStringBuilder._Replace(Index: Integer; const Old,
New: string): Boolean;
var
OldCapacity: Integer;
SizeChange: Integer;
begin
Result := False;
SizeChange := System.Length(New) - System.Length(Old);
if SizeChange = 0 then
begin
Move(New[1], FData[Index], System.Length(New) * SizeOf(Char));
end
else
begin
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)], (Length - (System.Length(Old) + Index)) * SizeOf(Char));
Move(New[1], FData[Index], System.Length(New) * SizeOf(Char));
if SizeChange < 0 then
Length := Length + SizeChange;
end;
end;
function TStringBuilder.Append(const Value: Word): TStringBuilder;
begin
Append(IntToStr(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: UInt64): TStringBuilder;
begin
Append(UIntToStr(Value));
Result := self;
end;
function TStringBuilder.Append(const Value: Cardinal): TStringBuilder;
begin
Append(UIntToStr(Value));
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 + 1], FData[Length - Count], Count * SizeOf(Char));
Result := Self;
end;
function TStringBuilder.AppendFormat(const Format: string;
const Args: array of const): TStringBuilder;
begin
Append(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;
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: Char;
RepeatCount: Integer): TStringBuilder;
begin
Append(System.StringOfChar(Value, RepeatCount));
Result := Self;
end;
end.
interface
uses RTLConsts,Classes,SysUtils;
type
EExternal = class(Exception)
public
{$IFDEF MSWINDOWS}
ExceptionRecord: PExceptionRecord platform;
{$ENDIF}
{$IF defined(LINUX) or defined(MACOSX)}
ExceptionAddress: LongWord platform;
AccessAddress: LongWord platform;
SignalNumber: Integer platform;
{$IFEND LINUX or MACOSX}
end;
EIntError = class(EExternal);
ERangeError = class(EIntError);
TCharArray = array of Char;
TStringBuilder = class
private
const DefaultCapacity = $10;
function GetCapacity: Integer;
procedure SetCapacity(const Value: Integer);
function GetLength: Integer;
procedure Set_Length(const Value: Integer);
function GetMaxCapacity: Integer;
procedure ReduceCapacity;
procedure ExpandCapacity;
procedure CheckBounds(Index: Integer);
function _Replace(Index: Integer; const Old, New: string): Boolean;
function GetChars(index: Integer): Char;
procedure SetChars(index: Integer; const Value: Char);
protected
FData: TCharArray;
FLength: Integer;
FMaxCapacity: Integer;
public
constructor Create; overload;
constructor Create(aCapacity: Integer); overload;
constructor Create(const Value: string); 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;
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;
function ToString(StartIndex: Integer; StrLength: Integer): string; reintroduce; overload;
procedure SaveToStream(Stream: TStream);
procedure SaveToFile(FileName: string);
procedure LoadFromStream(Stream: TStream);
procedure LoadFromFile(FileName: string);
property Capacity: Integer read GetCapacity write SetCapacity;
property Chars[index: Integer]: Char read GetChars write SetChars; default;
property Length: Integer read GetLength write Set_Length;
property MaxCapacity: Integer read GetMaxCapacity;
end;
function UIntToStr(Value: Cardinal): string; overload;
function UIntToStr(Value: UInt64): string; overload;
resourcestring
SParamIsNegative = 'Parameter %s cannot be a negative value';
SInputBufferExceed = 'Input buffer exceeded for %s = %d, %s = %d';
implementation
function UIntToStr(Value: Cardinal): string;
begin
FmtStr(Result, '%u', [Value]);
end;
function UIntToStr(Value: UInt64): string;
begin
FmtStr(Result, '%u', [Value]);
end;
{ TStringBuilder }
constructor TStringBuilder.Create;
begin
inherited Create;
FMaxCapacity := MaxInt;
Capacity := DefaultCapacity;
FLength := 0;
end;
constructor TStringBuilder.Create(aCapacity: Integer);
begin
inherited Create;
FMaxCapacity := MaxInt;
Capacity := aCapacity;
FLength := 0;
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: Currency): TStringBuilder;
begin
Append(CurrToStr(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: Double): TStringBuilder;
begin
Append(FloatToStr(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: 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: Smallint): TStringBuilder;
begin
Append(IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: Shortint): TStringBuilder;
begin
Append(IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: Single): TStringBuilder;
begin
Append(FloatToStr(Value));
Result := self;
end;
function TStringBuilder.Append(const Value: TObject): TStringBuilder;
begin
{$if CompilerVersion >= 19}
Append(Value.ToString());
{$else}
if Value.InheritsFrom(TComponent) then
Append(TComponent(Value).Name+': '+Value.ClassName)
else Append(Value.ClassName);
{$ifend}
Result := Self;
end;
function TStringBuilder.Append(const Value: Integer): TStringBuilder;
begin
Append(IntToStr(Value));
Result := Self;
end;
function TStringBuilder.Append(const Value: Int64): TStringBuilder;
begin
Append(IntToStr(Value));
Result := Self;
end;
procedure TStringBuilder.CheckBounds(Index: Integer);
begin
if Cardinal(Index) >= Cardinal(Length) then
raise ERangeError.CreateResFmt(@SListIndexError, [Index]);
end;
procedure TStringBuilder.Clear;
begin
Length := 0;
Capacity := DefaultCapacity;
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(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.GetLength: Integer;
begin
Result := FLength;
end;
function TStringBuilder.GetMaxCapacity: Integer;
begin
Result := FMaxCapacity;
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: Int64): 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: Double): TStringBuilder;
begin
Insert(Index, FloatToStr(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: Boolean): TStringBuilder;
begin
Insert(Index, BoolToStr(Value, True));
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: UInt64): TStringBuilder;
begin
Insert(Index, IntToStr(Value));
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: 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;
procedure TStringBuilder.LoadFromFile(FileName: string);
var
F: TFileStream;
begin
F := TFileStream.Create(FileName,fmOpenRead);
LoadFromStream(F);
F.Free;
end;
procedure TStringBuilder.LoadFromStream(Stream: TStream);
begin
Capacity := Stream.Size;
Stream.Position := 0;
Stream.ReadBuffer(FData[0],Stream.Size);
Length := Stream.Size;
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): TStringBuilder;
begin
Result := self;
Replace(OldValue, NewValue, 0, Length);
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; 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[1] 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.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: 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: TObject): TStringBuilder;
begin
{$if CompilerVersion >= 19}
Insert(Index, Value.ToString());
{$else}
Insert(Index, IntToStr(Integer(Value)));
{$ifend}
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[1], FData[Index], System.Length(Value) * SizeOf(Char));
Result := Self;
end;
function TStringBuilder.Insert(Index: Integer;
const Value: Single): TStringBuilder;
begin
Insert(Index, FloatToStr(Value));
Result := Self;
end;
procedure TStringBuilder.SaveToFile(FileName: string);
var
FileStream: TFileStream;
begin
FileStream := TFileStream.Create(FileName,fmOpenWrite);
SaveToStream(FileStream);
FileStream.Free;
end;
procedure TStringBuilder.SaveToStream(Stream: TStream);
begin
Stream.WriteBuffer(FData[0],Length * SizeOf(Char));
end;
procedure TStringBuilder.SetCapacity(const Value: Integer);
begin
if Value < Length then
raise ERangeError.CreateResFmt(@SListCapacityError, [Value]);
if Value > FMaxCapacity then
raise ERangeError.CreateResFmt(@SListCapacityError, [Value]);
SetLength(FData, Value);
end;
procedure TStringBuilder.SetChars(index: Integer; const Value: Char);
begin
if Index < 0 then
raise ERangeError.CreateResFmt(@SParamIsNegative, ['Index']); // DO NOT LOCALIZE
CheckBounds(Index);
FData[Index] := Value;
end;
procedure TStringBuilder.Set_Length(const 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
FLength := LOldLength;
end;
end;
function TStringBuilder.ToString: string;
begin
SetLength(Result, Length);
Move(FData[0], Result[1], Length * SizeOf(Char));
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);
SetLength(Result, StrLength);
Move(FData[StartIndex], Result[1], StrLength * SizeOf(Char));
end
else Result := '';
end;
function TStringBuilder._Replace(Index: Integer; const Old,
New: string): Boolean;
var
OldCapacity: Integer;
SizeChange: Integer;
begin
Result := False;
SizeChange := System.Length(New) - System.Length(Old);
if SizeChange = 0 then
begin
Move(New[1], FData[Index], System.Length(New) * SizeOf(Char));
end
else
begin
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)], (Length - (System.Length(Old) + Index)) * SizeOf(Char));
Move(New[1], FData[Index], System.Length(New) * SizeOf(Char));
if SizeChange < 0 then
Length := Length + SizeChange;
end;
end;
function TStringBuilder.Append(const Value: Word): TStringBuilder;
begin
Append(IntToStr(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: UInt64): TStringBuilder;
begin
Append(UIntToStr(Value));
Result := self;
end;
function TStringBuilder.Append(const Value: Cardinal): TStringBuilder;
begin
Append(UIntToStr(Value));
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 + 1], FData[Length - Count], Count * SizeOf(Char));
Result := Self;
end;
function TStringBuilder.AppendFormat(const Format: string;
const Args: array of const): TStringBuilder;
begin
Append(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;
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: Char;
RepeatCount: Integer): TStringBuilder;
begin
Append(System.StringOfChar(Value, RepeatCount));
Result := Self;
end;
end.
作者:不得闲
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原
文连接,否则保留追究法律责任的权利。
文连接,否则保留追究法律责任的权利。