Actually in Praxis PChar in FreePascal is the missing String Byte Iterator to get access to the Data and avoid Copying. Widely found in the FCL.
The PChar psdata is a Pointer to the Bytes in stream.DataString.
While the String sdata is a Copy of the whole String stream.DataString.
Not quite. As long as you don't
change sdata it will point to the same string data as the internal field of
TStringStream. But once you change the string it will be made unique. This is the Copy-On-Write mechanism of managed strings. To see this in action you should adjust your example like this:
//...
writeln('stream 2 (length: ', chr(39), idatalength, chr(39), '): ', chr(39), stream.DataString, chr(39));
sdata := stream.DataString;
Writeln(StringRefCount(sdata));
sdata[1] := 'I';
Writeln(StringRefCount(sdata));
sdata[2] := ' ';
sdata[3] := 'a';
//...
Notice the two calls to
StringRefCount which will return the current reference count of the string. The output will then be:
PS E:\fpc\git> .\testoutput\tstrstrm.exe
stream 0 (length: '57'): 'My unchangeable Source String. Is it really unchangeable? '
stream 1 (length: '57'): 'bla nchangeable Source String. Is it really unchangeable? '
stream 2 (length: '57'): 'foo nchangeable Source String. Is it really unchangeable? '
2
1
stream 3 (length: '57'): 'foo nchangeable Source String. Is it really unchangeable? '
data 3 (length: '58'): 'I am a Copy ble Source String. Is it really unchangeable? '
stream 4 (length: '58'): 'I am original e Source String. Is it really unchangeable? '
As you can see the reference count is first 2, because both the stream and
sdata reference the string data, but upon modifying the string the reference count becomes one, because the string has been made unique. This can also be seen in the assembly code:
# [45] sdata := stream.DataString;
movl -4(%ebp),%eax
movl 4(%eax),%edx
leal -8(%ebp),%eax
call fpc_ansistr_assign
# [46] Writeln(StringRefCount(sdata));
call fpc_get_output
movl %eax,%ebx
movl -8(%ebp),%eax
call SYSTEM_$$_STRINGREFCOUNT$RAWBYTESTRING$$LONGINT
movl %eax,%ecx
movl %ebx,%edx
movl $0,%eax
call fpc_write_text_sint
call FPC_IOCHECK
movl %ebx,%eax
call fpc_writeln_end
call FPC_IOCHECK
# [48] sdata[1] := 'I';
leal -8(%ebp),%eax
call fpc_ansistr_unique
movb $73,(%eax)
Thus, as long as you don't
change the string you don't need to access it as a
PChar.