Reputation: 309
To take an example, lets say I would like to write a simple procedure that deletes the 'X' characters from a string.
How can I design my procedure so that it works for both string and PCHAR parameters.
If I define it as:
procedure RemoveX( source : PCHAR);
than calls to RemoveX(PCHAR(mystring)) where myString is a string will remove the 'X' but will not take care of updating the string length ... Hence a subsequent myString := myString + 'done' will leave myString unchanged. And I don't want to change the length after the call to RemoveX, I expect the RemoveX procedure to deal with everything.
If on the other hand I define it as:
procedure RemoveX( var source : string);
I don't know how to pass it a PCHAR ...
Upvotes: -2
Views: 254
Reputation: 596307
I would not suggest implementing the string
version in terms of the PChar
version, or vice versa. I would keep them separate so that you can tailor them independently, eg:
procedure RemoveX(source : PChar); overload;
procedure RemoveX(var source : string); overload;
procedure RemoveX(source : PChar);
var
P: PChar;
Len: Integer;
begin
if source = nil then Exit;
Len := StrLen(source);
repeat
P := StrScan(source, 'X');
if P = nil then Exit;
StrMove(P, P+1, Len - Integer(P-source));
Dec(Len);
source := P;
until False;
end;
procedure RemoveX(var source : string);
begin
source := StringReplace(source, 'X', '', [rfReplaceAll]);
end;
Update: If you really want to use a single implementation for both PChar
and String
inputs then you can do something like this:
function RemoveX(source : PChar; sourceLen: Integer): Integer; overload;
procedure RemoveX(source : PChar); overload;
procedure RemoveX(var source : string); overload;
function RemoveX(source : PChar; sourceLen: Integer): Integer;
var
P: PChar;
begin
Result := 0;
if (source = nil) or (sourceLen = 0) then Exit;
repeat
P := StrScan(source, 'X');
if P = nil then Exit;
StrMove(P, P+1, sourceLen - Integer(P-source));
Dec(sourceLen);
source := P;
until False;
Result := sourceLen;
end;
procedure RemoveX(source : PChar);
begin
RemoveX(source, StrLen(source));
end;
procedure RemoveX(var source : string);
begin
UniqueString(source);
SetLength(source, RemoveX(PChar(source), Length(source)));
end;
Upvotes: 5
Reputation: 612963
You cannot implement this using a single parameter. You have two different types.
You could build the string version on top of a PChar
version.
procedure RemoveX(var str: string);
var
P: PChar;
begin
UniqueString(str);
P := PChar(str);
RemoveX(P);
str := P;
end;
An alternative for final line could be:
SetLength(str, StrLen(P));
Either way, this obviously assumes that you already have a functioning overload that operates on PChar
. And that the function removes characters. Clearly it cannot extend the PChar
buffer.
The call to UniqueString
is needed in case the string is shared (ref count greater than one) or constant. After this call the string buffer is editable and not shared.
Whether or not avoiding duplication of implementation in this way is the best approach I cannot say. It depends on your design drivers. If simplicity and clarity of code is key, then avoiding duplication makes sense. If performance is key then it may be desirable to provide two bespoke implementations.
Upvotes: 2