zoukankan      html  css  js  c++  java
  • 其实Managed Record有很多方便使用的场景

    其实Managed Record有很多方便使用的场景。
    比如下面的就是把TStringBuilder由Class改成了Managed Record。好处就是不再需要释放了。

    {
    Managed Record版本的StringBuilder。
    Delphi在10.4开始终于支持Managed Record了。
    加了这个有很多可以玩的了。
    比如说有些原先是class实现的东西,可以用Managed Record来实现。
    这样的好处是很多东西想用就用,用了不需要管什么时候释放。
    因为Record是在栈里面的,系统会自动回收,回收前还会调用Finalize操作符。
     
    不仅仅StringBuilder,其实很多都可以变成Managed Record。
    例如用Managed Record,实现智能锁,离开代码块,锁就会自动释放了。
     
    2020.9.9 武稀松 wr960204
    }
    unit ManagedStringBuilder;
     
    interface
    uses
      System.Classes, System.SysUtils, System.RTLConsts, System.SysConst;
     
    type
      TCharArray = TArray<Char>;
     
    type
      TCharSearch = record
        ArrayPtr: PChar;
        MatchPtr: PChar;
      end;
     
      TStringBuilder = record
      private type
        TEnumerator = record
        private
          FPtr: PChar;
          FEndPtr: PChar;
        public
          procedure Initialize(const ABuilder: TStringBuilder); inline;
          function GetCurrent: Char; inline;
          function MoveNext: Boolean; inline;
          property Current: Char read GetCurrent;
        end;
     
      private const
        DefaultCapacity = $10;
        LineBreak: string = sLineBreak;
      private
        function GetCapacity: Integer; inline;
        procedure SetCapacity(Value: Integer);
        function GetChars(Index: Integer): Char;
        procedure SetChars(Index: Integer; Value: Char);
        function GetLength: Integer; inline;
        procedure SetLength(Value: Integer);
        function GetMaxCapacity: Integer; inline;
        procedure ExpandCapacity;
        procedure ReduceCapacity;
        procedure CheckBounds(Index: Integer);
        function _Replace(Index: Integer; const Old, New: string): Boolean;
      private
        FData: string;
        FLength: Integer;
        FMaxCapacity: Integer;
      public
        //constructor Create;
        class operator Initialize(out Dest: TStringBuilder);
        class operator Finalize(var Dest: TStringBuilder);
        //:=不需要处理
        //class operator Assign(var Dest: TStringBuilder; const [ref] Src: TStringBuilder);
     
        constructor Create(aCapacity: Integer); overload;
        constructor Create(const Value: string); overload;
        constructor Create(aCapacity: Integer; aMaxCapacity: Integer); overload;
        constructor Create(const Value: string; aCapacity: Integer); overload;
        constructor Create(const Value: string; StartIndex: Integer; Length: Integer; aCapacity: Integer); overload;
     
        //占位,兼容class版本的TStringBuilder,这里是为了移植不需要改代码。空函数.
        procedure Free(); inline;
     
        function Append(const Value: Boolean): TStringBuilder; overload;
        function Append(const Value: Byte): TStringBuilder; overload;
        function Append(const Value: Char): TStringBuilder; overload;
        function Append(const Value: Currency): TStringBuilder; overload;
        function Append(const Value: Double): TStringBuilder; overload;
        function Append(const Value: Smallint): TStringBuilder; overload;
        function Append(const Value: Integer): TStringBuilder; overload;
        function Append(const Value: Int64): TStringBuilder; overload;
        function Append(const Value: TObject): TStringBuilder; overload;
        function Append(const Value: Shortint): TStringBuilder; overload;
        function Append(const Value: Single): TStringBuilder; overload;
        function Append(const Value: string): TStringBuilder; overload;
        function Append(const Value: UInt64): TStringBuilder; overload;
        function Append(const Value: TCharArray): TStringBuilder; overload;
        function Append(const Value: Word): TStringBuilder; overload;
        function Append(const Value: Cardinal): TStringBuilder; overload;
    {$IFNDEF NEXTGEN}
        function Append(const Value: PAnsiChar): TStringBuilder; overload;
        function Append(const Value: RawByteString): TStringBuilder; overload;
    {$ENDIF !NEXTGEN}
        function Append(const Value: Char; RepeatCount: Integer): TStringBuilder; overload;
        function Append(const Value: TCharArray; StartIndex: Integer; CharCount: Integer): TStringBuilder; overload;
        function Append(const Value: string; StartIndex: Integer; Count: Integer = -1): TStringBuilder; overload;
        function Append(const Value: PChar; StartIndex: Integer; Count: Integer = -1): TStringBuilder; overload;
     
        function AppendFormat(const Format: string; const Args: array of const): TStringBuilder; overload;
        function AppendLine: TStringBuilder; overload; inline;
        function AppendLine(const Value: string): TStringBuilder; overload;
        function AppendLineFormat(const Format: string; const Args: array of const): TStringBuilder; overload;
        procedure Clear;
        procedure CopyTo(SourceIndex: Integer; const Destination: TCharArray; DestinationIndex: Integer; Count: Integer);
        function EnsureCapacity(aCapacity: Integer): Integer;
        function Equals(StringBuilder: TStringBuilder): Boolean; reintroduce;
     
        function Insert(Index: Integer; const Value: Boolean): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: Byte): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: Char): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: Currency): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: Double): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: Smallint): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: Integer): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: TCharArray): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: Int64): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: TObject): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: Shortint): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: Single): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: string): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: Word): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: Cardinal): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: UInt64): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: string; count: Integer): TStringBuilder; overload;
        function Insert(Index: Integer; const Value: TCharArray; startIndex: Integer; charCount: Integer): TStringBuilder; overload;
     
        function Remove(StartIndex: Integer; RemLength: Integer): TStringBuilder;
     
        function Replace(const OldChar: Char; const NewChar: Char): TStringBuilder; overload;
        function Replace(const OldValue: string; const NewValue: string): TStringBuilder; overload;
        function Replace(const OldChar: Char; const NewChar: Char; StartIndex: Integer; Count: Integer): TStringBuilder; overload;
        function Replace(const OldValue: string; const NewValue: string; StartIndex: Integer; Count: Integer): TStringBuilder; overload;
     
        function ToString: string; overload;
        function ToString(UpdateCapacity: Boolean): string; reintroduce; overload;
        function ToString(StartIndex: Integer; StrLength: Integer): string; reintroduce; overload;
     
        function GetEnumerator: TEnumerator; inline;
     
     
        property Capacity: Integer read GetCapacity write SetCapacity;
        property Chars[index: Integer]: Char read GetChars write SetChars; default;
        property Length: Integer read GetLength write SetLength;
        property MaxCapacity: Integer read GetMaxCapacity;
      end;
     
      TManagedStringBuilder = TStringBuilder;
      TMSB = TStringBuilder;
     
    //function NewManagedStringBuilder():TManagedStringBuilder; overload;
    function NewManagedStringBuilder(aCapacity: Integer):TManagedStringBuilder; overload;
    function NewManagedStringBuilder(const Value: string):TManagedStringBuilder; overload;
    function NewManagedStringBuilder(aCapacity: Integer; aMaxCapacity: Integer):TManagedStringBuilder; overload;
    function NewManagedStringBuilder(const Value: string; aCapacity: Integer):TManagedStringBuilder; overload;
    function NewManagedStringBuilder(const Value: string; StartIndex: Integer; Length: Integer; aCapacity: Integer):TManagedStringBuilder; overload;
     
    implementation
     
    {
    function NewManagedStringBuilder():TManagedStringBuilder;
    begin
      Result := NewManagedStringBuilder(MaxInt);
    end;
    }
     
    function NewManagedStringBuilder(aCapacity: Integer):TManagedStringBuilder;
    begin
      Result := TManagedStringBuilder.Create(aCapacity);
    end;
     
    function NewManagedStringBuilder(const Value: string):TManagedStringBuilder;
    begin
      Result := TManagedStringBuilder.Create(Value);
    end;
     
    function NewManagedStringBuilder(aCapacity: Integer; aMaxCapacity: Integer):TManagedStringBuilder;
    begin
      Result := TManagedStringBuilder.Create(aCapacity, aMaxCapacity);
    end;
     
    function NewManagedStringBuilder(const Value: string; aCapacity: Integer):TManagedStringBuilder;
    begin
      Result := TManagedStringBuilder.Create(Value, aCapacity);
    end;
     
    function NewManagedStringBuilder(const Value: string; StartIndex: Integer; Length: Integer; aCapacity: Integer):TManagedStringBuilder;
    begin
      Result := TManagedStringBuilder.Create(Value, StartIndex, Length, aCapacity);
    end;
     
    { TStringBuilder }
     
    {$ZEROBASEDSTRINGS ON}
     
    function TStringBuilder.GetLength: Integer;
    begin
      Result := FLength;
    end;
     
    function TStringBuilder.GetCapacity: Integer;
    begin
      Result := System.Length(FData);
    end;
     
    function TStringBuilder.GetMaxCapacity: Integer;
    begin
      Result := FMaxCapacity;
    end;
     
    function TStringBuilder.Append(const Value: UInt64): TStringBuilder;
    begin
      Result := Append(UIntToStr(Value));
    end;
     
    function TStringBuilder.Append(const Value: TCharArray): TStringBuilder;
    var
      I: Integer;
    begin
      I := 0;
      while (I < System.Length(Value)) and (Value[I] <> #0) do Inc(I);
      Result := Append(Value, 0, I);
    end;
     
    function TStringBuilder.Append(const Value: Single): TStringBuilder;
    begin
      Result := Append(FloatToStr(Value));
    end;
     
    function TStringBuilder.Append(const Value: string): TStringBuilder;
    var
      Delta, OldLength: Integer;
    begin
      Delta := System.Length(Value);
      if Delta <> 0 then
      begin
        OldLength := Length;
        FLength := Length + Delta;
        if Length > Capacity then
          ExpandCapacity;
        Move(Pointer(Value)^, (PChar(Pointer(FData)) + OldLength)^, Delta * SizeOf(Char));
      end;
      Result := self;
    end;
     
    function TStringBuilder.Append(const Value: Word): TStringBuilder;
    begin
      Result := Append(IntToStr(Value));
    end;
     
    function TStringBuilder.Append(const Value: TCharArray; StartIndex,
      CharCount: Integer): TStringBuilder;
    var
      OldLength: Integer;
    begin
      if StartIndex + CharCount > System.Length(Value) then
        raise ERangeError.CreateResFmt(@SListIndexError, [StartIndex]);
      if StartIndex < 0 then
        raise ERangeError.CreateResFmt(@SListIndexError, [StartIndex]);
     
      if CharCount > 0 then
      begin
        OldLength := Length;
        Length := Length + CharCount;
        Move(Value[StartIndex], FData[OldLength], CharCount * SizeOf(Char));
      end;
      Result := self;
    end;
     
    function TStringBuilder.Append(const Value: string; StartIndex,
      Count: Integer): TStringBuilder;
    var
      OldLength: Integer;
    begin
      if Count < 0 then
        Count := System.Length(Value) - StartIndex;
      if StartIndex + Count > System.Length(Value) then
        raise ERangeError.CreateResFmt(@SListIndexError, [StartIndex]);
      if StartIndex < 0 then
        raise ERangeError.CreateResFmt(@SListIndexError, [StartIndex]);
     
      if Count > 0 then
      begin
        OldLength := Length;
        Length := Length + Count;
        Move(Value[StartIndex + Low(string)], FData[OldLength], Count * SizeOf(Char));
      end;
      Result := Self;
    end;
     
    function TStringBuilder.Append(const Value: PChar; StartIndex,
      Count: Integer): TStringBuilder;
    var
      OldLength: Integer;
    begin
      if Count < 0 then
        Count := Integer(StrLen(Value)) - StartIndex;
      if StartIndex < 0 then
        raise ERangeError.CreateResFmt(@SListIndexError, [StartIndex]);
     
      if Count > 0 then
      begin
        OldLength := Length;
        Length := Length + Count;
        Move((Value + StartIndex)^, FData[OldLength], Count * SizeOf(Char));
      end;
      Result := Self;
    end;
     
    {$IFNDEF NEXTGEN}
    function TStringBuilder.Append(const Value: PAnsiChar): TStringBuilder;
    begin
      Result := Append(string(Value));
    end;
     
    function TStringBuilder.Append(const Value: RawByteString): TStringBuilder;
    begin
      Result := Append(string(Value));
    end;
    {$ENDIF !NEXTGEN}
     
    function TStringBuilder.Append(const Value: Cardinal): TStringBuilder;
    begin
      Result := Append(UIntToStr(Value));
    end;
     
    function TStringBuilder.Append(const Value: Char;
      RepeatCount: Integer): TStringBuilder;
    begin
      Result := Append(System.StringOfChar(Value, RepeatCount));
    end;
     
    function TStringBuilder.Append(const Value: Shortint): TStringBuilder;
    begin
      Result := Append(IntToStr(Value));
    end;
     
    function TStringBuilder.Append(const Value: Char): TStringBuilder;
    begin
      FLength := Length + 1;
      if Length > Capacity then
        ExpandCapacity;
      FData[Length - 1] := Value;
      Result := Self;
    end;
     
    function TStringBuilder.Append(const Value: Currency): TStringBuilder;
    begin
      Result := Append(CurrToStr(Value));
    end;
     
    function TStringBuilder.Append(const Value: Boolean): TStringBuilder;
    begin
      Result := Append(BoolToStr(Value, True));
    end;
     
    function TStringBuilder.Append(const Value: Byte): TStringBuilder;
    begin
      Result := Append(IntToStr(Value));
    end;
     
    function TStringBuilder.Append(const Value: Double): TStringBuilder;
    begin
      Result := Append(FloatToStr(Value));
    end;
     
    function TStringBuilder.Append(const Value: Int64): TStringBuilder;
    begin
      Result := Append(IntToStr(Value));
    end;
     
    function TStringBuilder.Append(const Value: TObject): TStringBuilder;
    begin
    {$if CompilerVersion >= 19}
      Result := Append(Value.ToString());
    {$else}
      Result := Append(IntToStr(Integer(Value)));
    {$ENDIF}
    end;
     
    function TStringBuilder.Append(const Value: Smallint): TStringBuilder;
    begin
      Result := Append(IntToStr(Value));
    end;
     
    function TStringBuilder.Append(const Value: Integer): TStringBuilder;
    begin
      Result := Append(IntToStr(Value));
    end;
     
    function TStringBuilder.AppendFormat(const Format: string; const Args: array of const): TStringBuilder;
    begin
      Result := Append(System.SysUtils.Format(Format, Args));
    end;
     
    function TStringBuilder.AppendLineFormat(const Format: string; const Args: array of const): TStringBuilder;
    begin
      Result := AppendLine(System.SysUtils.Format(Format, Args));
    end;
     
    function TStringBuilder.AppendLine: TStringBuilder;
    begin
      Result := Append(LineBreak);
    end;
     
    function TStringBuilder.AppendLine(const Value: string): TStringBuilder;
    begin
      Result := Append(Value).AppendLine;
    end;
     
    procedure TStringBuilder.Clear;
    begin
      Length := 0;
      Capacity := DefaultCapacity;
    end;
     
    procedure TStringBuilder.CheckBounds(Index: Integer);
    begin
      if Cardinal(Index) >= Cardinal(Length) then
        raise ERangeError.CreateResFmt(@SListIndexError, [Index]);
    end;
     
    procedure TStringBuilder.CopyTo(SourceIndex: Integer;
      const Destination: TCharArray; DestinationIndex, Count: Integer);
    begin
      if Count < 0 then
        raise ERangeError.CreateResFmt(@SParamIsNegative, ['Count']); // DO NOT LOCALIZE
      if DestinationIndex < 0 then
        raise ERangeError.CreateResFmt(@SParamIsNegative, ['DestinationIndex']); // DO NOT LOCALIZE
      if DestinationIndex + Count > System.Length(Destination) then
        raise ERangeError.CreateResFmt(@SInputBufferExceed,
          ['DestinationIndex', DestinationIndex, 'Count', Count]);
     
      if Count > 0 then
      begin
        CheckBounds(SourceIndex);
        CheckBounds(SourceIndex + Count - 1);
     
        Move(FData[SourceIndex], Destination[DestinationIndex], Count * SizeOf(Char));
      end;
    end;
     
    //constructor TStringBuilder.Create;
    class operator TStringBuilder.Initialize(out Dest: TStringBuilder);
    begin
      Dest.FLength := 0; //record不是class,FLength不会自动初始化为0,所以要先初始化FLength
      Dest.FMaxCapacity := MaxInt;
      Dest.Capacity := DefaultCapacity;
    end;
     
    class operator TStringBuilder.Finalize(var Dest: TStringBuilder);
    begin
      //暂时没有需要释放的
    end;
     
     
    constructor TStringBuilder.Create(const Value: string; aCapacity: Integer);
    begin
      FMaxCapacity := MaxInt;
      Capacity := aCapacity;
      FLength := 0;
      Append(Value);
    end;
     
    constructor TStringBuilder.Create(const Value: string; StartIndex, length,
      aCapacity: Integer);
    begin
      Create(Value.Substring(StartIndex, length), aCapacity);
    end;
     
    constructor TStringBuilder.Create(aCapacity, aMaxCapacity: Integer);
    begin
      if aMaxCapacity <= 0 then
        raise ERangeError.CreateRes(@SRangeError);
      if aCapacity > aMaxCapacity then
        raise ERangeError.CreateResFmt(@SListCapacityError, [aCapacity]);
      Create(aCapacity);
      FMaxCapacity := aMaxCapacity;
    end;
     
    constructor TStringBuilder.Create(aCapacity: Integer);
    begin
      FMaxCapacity := MaxInt;
      Capacity := aCapacity;
      FLength := 0;
    end;
     
    constructor TStringBuilder.Create(const Value: string);
    begin
      Append(Value);
    end;
     
    procedure TStringBuilder.Free();
    begin
     
    end;
     
    function TStringBuilder.EnsureCapacity(aCapacity: Integer): Integer;
    begin
      if Cardinal(aCapacity) > Cardinal(MaxCapacity) then
        raise ERangeError.CreateResFmt(@SListIndexError, [aCapacity]);
     
      if Capacity < aCapacity then
        Capacity := aCapacity;
     
      Result := Capacity;
    end;
     
    function TStringBuilder.Equals(StringBuilder: TStringBuilder): Boolean;
    begin
      Result := (Length = StringBuilder.Length) and
        (MaxCapacity = StringBuilder.MaxCapacity) and ((Length = 0) or
        CompareMem(Pointer(FData), Pointer(StringBuilder.FData), Length * SizeOf(Char)));
    end;
     
    procedure TStringBuilder.ExpandCapacity;
    var
      NewCapacity: Integer;
    begin
      NewCapacity := (Capacity * 3) div 2;
      if Length > NewCapacity then
        NewCapacity := Length * 2; // this line may overflow NewCapacity to a negative value
      if NewCapacity > MaxCapacity then
        NewCapacity := MaxCapacity;
      if NewCapacity < 0 then // if NewCapacity has been overflowed
        NewCapacity := Length;
      Capacity := NewCapacity;
    end;
     
    function TStringBuilder.GetChars(Index: Integer): Char;
    begin
      if Index < 0 then
        raise ERangeError.CreateResFmt(@SParamIsNegative, ['Index']); // DO NOT LOCALIZE
      CheckBounds(Index);
     
      Result := FData[Index];
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: TObject): TStringBuilder;
    begin
    {$if CompilerVersion >= 19}
      Result := Insert(Index, Value.ToString());
    {$else}
      Result := Insert(Index, IntToStr(Integer(Value)));
    {$ENDIF}
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: Int64): TStringBuilder;
    begin
      Result := Insert(Index, IntToStr(Value));
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: Single): TStringBuilder;
    begin
      Result := Insert(Index, FloatToStr(Value));
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: string): TStringBuilder;
    var
      OldLength: Integer;
    begin
      if Index < 0 then
        raise ERangeError.CreateResFmt(@SParamIsNegative, ['Index']); // DO NOT LOCALIZE
      if Index > Length then
        raise ERangeError.CreateResFmt(@SListIndexError, [Index]);
     
      OldLength := Length;
      Length := Length + System.Length(Value);
      if OldLength > Index then
        Move(FData[Index], FData[Index + System.Length(Value)], (OldLength - Index) * SizeOf(Char));
      Move(Value[Low(string)], FData[Index], System.Length(Value) * SizeOf(Char));
      Result := Self;
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: Word): TStringBuilder;
    begin
      Result := Insert(Index, IntToStr(Value));
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: Shortint): TStringBuilder;
    begin
      Result := Insert(Index, IntToStr(Value));
    end;
     
    function TStringBuilder.Insert(Index: Integer;
      const Value: TCharArray): TStringBuilder;
    var
      OldLength: Integer;
    begin
      if Index < 0 then
        raise ERangeError.CreateResFmt(@SParamIsNegative, ['Index']); // DO NOT LOCALIZE
      if Index > Length then
        raise ERangeError.CreateResFmt(@SListIndexError, [Index]);
     
      OldLength := Length;
      Length := Length + System.Length(Value);
     
      if OldLength > 0 then
        Move(FData[Index], FData[Index + System.Length(Value)], OldLength * SizeOf(Char));
      Move(Value[0], FData[Index], System.Length(Value) * SizeOf(Char));
      Result := Self;
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: Currency): TStringBuilder;
    begin
      Result := Insert(Index, CurrToStr(Value));
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: Char): TStringBuilder;
    var
      OldLength: Integer;
    begin
      if Index < 0 then
        raise ERangeError.CreateResFmt(@SParamIsNegative, ['Index']); // DO NOT LOCALIZE
      if Index > Length then
        raise ERangeError.CreateResFmt(@SListIndexError, [Index]);
     
      OldLength := Length;
      Length := Length + 1;
     
      if OldLength > Index then
        Move(FData[Index], FData[Index + 1], (OldLength - Index) * SizeOf(Char));
      FData[Index] := Value;
      Result := Self;
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: Byte): TStringBuilder;
    begin
      Result := Insert(Index, IntToStr(Value));
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: Double): TStringBuilder;
    begin
      Result := Insert(Index, FloatToStr(Value));
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: Integer): TStringBuilder;
    begin
      Result := Insert(Index, IntToStr(Value));
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: Smallint): TStringBuilder;
    begin
      Result := Insert(Index, IntToStr(Value));
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: Boolean): TStringBuilder;
    begin
      Result := Insert(Index, BoolToStr(Value, True));
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: string;
      Count: Integer): TStringBuilder;
    var
      I: Integer;
    begin
      for I := 0 to Count - 1 do
        Insert(Index, Value);
      Result := Self;
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: TCharArray; StartIndex,
      CharCount: Integer): TStringBuilder;
    var
      OldLength: Integer;
    begin
      if Index - 1 >= Length then
        raise ERangeError.CreateResFmt(@SListIndexError, [Index])
      else if Index < 0 then
        raise ERangeError.CreateResFmt(@SListIndexError, [Index]);
      if StartIndex < 0 then
        raise ERangeError.CreateResFmt(@SParamIsNegative, ['StartIndex']); // DO NOT LOCALIZE
      if CharCount < 0 then
        raise ERangeError.CreateResFmt(@SParamIsNegative, ['CharCount']); // DO NOT LOCALIZE
      if StartIndex + CharCount > System.Length(Value) then
        raise ERangeError.CreateResFmt(@SInputBufferExceed,
          ['StartIndex', StartIndex, 'CharCount', CharCount]);
     
      OldLength := Length;
      Length := Length + CharCount;
     
      if OldLength > Index then
        Move(FData[Index], FData[Index + CharCount], (OldLength - Index) * SizeOf(Char));
      Move(Value[StartIndex], FData[Index], CharCount * SizeOf(Char));
      Result := Self;
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: Cardinal): TStringBuilder;
    begin
      Result := Insert(Index, IntToStr(Value));
    end;
     
    function TStringBuilder.Insert(Index: Integer; const Value: UInt64): TStringBuilder;
    begin
      Result := Insert(Index, UIntToStr(Value));
    end;
     
    procedure TStringBuilder.ReduceCapacity;
    var
      NewCapacity: Integer;
    begin
      if Length > Capacity div 4 then
        Exit;
     
      NewCapacity := Capacity div 2;
      if NewCapacity < Length then
        NewCapacity := Length;
      Capacity := NewCapacity;
    end;
     
    function TStringBuilder.Remove(StartIndex, RemLength: Integer): TStringBuilder;
    begin
      if RemLength <> 0 then
      begin
        if StartIndex < 0 then
          raise ERangeError.CreateResFmt(@SParamIsNegative, ['StartIndex']); // DO NOT LOCALIZE
        if RemLength < 0 then
          raise ERangeError.CreateResFmt(@SParamIsNegative, ['RemLength']); // DO NOT LOCALIZE
        CheckBounds(StartIndex);
        CheckBounds(StartIndex + RemLength - 1);
     
        if (Length - (StartIndex + RemLength)) > 0 then
          Move(FData[StartIndex + RemLength], FData[StartIndex], (Length - (StartIndex + RemLength)) * SizeOf(Char));
        Length := Length - RemLength;
     
        ReduceCapacity;
      end;
      Result := Self;
    end;
     
    function TStringBuilder.Replace(const OldValue, NewValue: string; StartIndex,
      Count: Integer): TStringBuilder;
    var
      CurPtr: PChar;
      EndPtr: PChar;
      Index: Integer;
      EndIndex: Integer;
      OldLen, NewLen: Integer;
    begin
      Result := Self;
     
      if Count <> 0 then
      begin
        if StartIndex < 0 then
          raise ERangeError.CreateResFmt(@SParamIsNegative, ['StartIndex']); // DO NOT LOCALIZE
        if Count < 0 then
          raise ERangeError.CreateResFmt(@SParamIsNegative, ['Count']); // DO NOT LOCALIZE
        if StartIndex + Count > Length then
          raise ERangeError.CreateResFmt(@SInputBufferExceed,
            ['StartIndex', StartIndex, 'Count', Count]);
     
        OldLen := System.Length(OldValue);
        NewLen := System.Length(NewValue);
        Index := StartIndex;
        CurPtr := @FData[StartIndex];
        EndIndex := StartIndex + Count - OldLen;
        EndPtr := @FData[EndIndex];
     
        while CurPtr <= EndPtr do
        begin
          if CurPtr^ = OldValue[Low(string)] then
          begin
            if StrLComp(CurPtr, PChar(OldValue), OldLen) = 0 then
            begin
              if _Replace(Index, OldValue, NewValue) then
              begin
                CurPtr := @FData[Index];
                EndPtr := @FData[EndIndex];
              end;
              Inc(CurPtr, NewLen - 1);
              Inc(Index, NewLen - 1);
              Inc(EndPtr, NewLen - OldLen);
              Inc(EndIndex, NewLen - OldLen);
            end;
          end;
     
          Inc(CurPtr);
          Inc(Index);
        end;
      end;
    end;
     
    function TStringBuilder.Replace(const OldChar, NewChar: Char; StartIndex,
      Count: Integer): TStringBuilder;
    var
      Ptr: PChar;
      EndPtr: PChar;
    begin
      if Count <> 0 then
      begin
        if StartIndex < 0 then
          raise ERangeError.CreateResFmt(@SParamIsNegative, ['StartIndex']); // DO NOT LOCALIZE
        if Count < 0 then
          raise ERangeError.CreateResFmt(@SParamIsNegative, ['Count']); // DO NOT LOCALIZE
        CheckBounds(StartIndex);
        CheckBounds(StartIndex + Count - 1);
     
        EndPtr := @FData[StartIndex + Count - 1];
        Ptr := @FData[StartIndex];
        while Ptr <= EndPtr do
        begin
          if Ptr^ = OldChar then
            Ptr^ := NewChar;
          Inc(Ptr);
        end;
      end;
      Result := Self;
    end;
     
    function TStringBuilder.Replace(const OldChar, NewChar: Char): TStringBuilder;
    var
      Ptr: PChar;
      EndPtr: PChar;
    begin
      EndPtr := @FData[Length - 1];
      Ptr := @FData[0];
      while Ptr <= EndPtr do
      begin
        if Ptr^ = OldChar then
          Ptr^ := NewChar;
        Inc(Ptr);
      end;
      Result := Self;
    end;
     
    function TStringBuilder.Replace(const OldValue, NewValue: string): TStringBuilder;
    begin
      Result := Replace(OldValue, NewValue, 0, Length);
    end;
     
    procedure TStringBuilder.SetCapacity(Value: Integer);
    begin
      if Value < Length then
        raise ERangeError.CreateResFmt(@SListCapacityError, [Value]);
      if Value > FMaxCapacity then
        raise ERangeError.CreateResFmt(@SListCapacityError, [Value]);
     
      System.SetLength(FData, Value);
    end;
     
    procedure TStringBuilder.SetChars(Index: Integer; Value: Char);
    begin
      if Index < 0 then
        raise ERangeError.CreateResFmt(@SParamIsNegative, ['Index']); // DO NOT LOCALIZE
      CheckBounds(Index);
     
      FData[Index] := Value;
    end;
     
    procedure TStringBuilder.SetLength(Value: Integer);
    var
      LOldLength: Integer;
    begin
      if Value < 0 then
        raise ERangeError.CreateResFmt(@SParamIsNegative, ['Value']); // DO NOT LOCALIZE
      if Value > MaxCapacity then
        raise ERangeError.CreateResFmt(@SListCapacityError, [Value]);
     
      LOldLength := FLength;
      try
        FLength := Value;
        if FLength > Capacity then
          ExpandCapacity;
      except
        on E: EOutOfMemory do
        begin
          FLength := LOldLength;
          raise;
        end;
      end;
    end;
     
    function TStringBuilder.ToString: string;
    begin
      Result := ToString(False);
    end;
     
    function TStringBuilder.ToString(UpdateCapacity: Boolean): string;
    begin
      if Length = Capacity then
        Result := FData
      else if UpdateCapacity then
      begin
        System.SetLength(FData, Length);
        Result := FData;
      end
      else
        Result := FData.Substring(0, Length);
    end;
     
    function TStringBuilder.ToString(StartIndex, StrLength: Integer): string;
    begin
      if StrLength <> 0 then
      begin
        if StartIndex < 0 then
          raise ERangeError.CreateResFmt(@SParamIsNegative, ['StartIndex']); // DO NOT LOCALIZE
        if StrLength < 0 then
          raise ERangeError.CreateResFmt(@SParamIsNegative, ['StrLength']); // DO NOT LOCALIZE
        CheckBounds(StartIndex);
        CheckBounds(StartIndex + StrLength - 1);
     
        Result := FData.Substring(StartIndex, StrLength);
      end
      else
        Result := '';
    end;
     
    function TStringBuilder._Replace(Index: Integer; const Old, New: string): Boolean;
    var
      OldLength: Integer;
      OldCapacity: Integer;
      SizeChange: Integer;
    begin
      Result := False;
      SizeChange := System.Length(New) - System.Length(Old);
     
      if SizeChange = 0 then
      begin
        Move(New[Low(string)], FData[Index], System.Length(New) * SizeOf(Char));
      end
      else
      begin
        OldLength := Length;
        if SizeChange > 0 then
        begin
          OldCapacity := Capacity;
          Length := Length + SizeChange;
          if OldCapacity <> Capacity then
            Result := True;
        end;
     
        Move(FData[Index + System.Length(Old)], FData[Index + System.Length(New)],
          (OldLength - (System.Length(Old) + Index)) * SizeOf(Char));
        Move(New[Low(String)], FData[Index], System.Length(New) * SizeOf(Char));
     
        if SizeChange < 0 then
          Length := Length + SizeChange;
      end;
    end;
     
    { TStringBuilder.TEnumerator }
     
    procedure TStringBuilder.TEnumerator.Initialize(const ABuilder: TStringBuilder);
    begin
      FPtr := PChar(Pointer(ABuilder.FData)) - 1;
      FEndPtr := FPtr + ABuilder.Length;
    end;
     
    function TStringBuilder.TEnumerator.GetCurrent: Char;
    begin
      Result := FPtr^;
    end;
     
    function TStringBuilder.TEnumerator.MoveNext: Boolean;
    begin
      Inc(FPtr);
      Result := FPtr <= FEndPtr;
    end;
     
    function TStringBuilder.GetEnumerator: TEnumerator;
    begin
      Result.Initialize(Self);
    end;
     
    end.
    此条目发表在Delphi分类目录,贴了标签。将固定链接加入收藏夹。
    http://www.raysoftware.cn/?p=621
  • 相关阅读:
    sql-select for update
    java-JDK动态代理
    idea-热部署jreble的使用
    vue-【el-table】转成【pl-table】
    mybatis-字段值为null或为''无法存储到数据库
    vue-本地开发热部署编译缓慢
    chrome-截长图
    el-cascader 级联选择器中选中任意一级去掉圆形按钮
    idea-绿色注释颜色16进制
    markdown 语法
  • 原文地址:https://www.cnblogs.com/findumars/p/13805538.html
Copyright © 2011-2022 走看看