perlguts.pod - mention SV_THINKFIRST* macros, move blocks around

This commit:
* Adds some initial description of the SV_THINKFIRST* macros to perlguts
* Places that new content, along with Read-only and Copy-on-write sections
  closer to the sections which describe how to modify string contents.

This commit is far from perfect. Reworking the the "Working with SVs"
part of perlguts, such that there is a more obviously dedicated section
for discussing string handling, seems like it would be definite
future improvement.
This commit is contained in:
Richard Leach 2024-08-02 21:52:59 +00:00 committed by Karl Williamson
parent 65e079e634
commit 0fcb0a1c99

View File

@ -540,6 +540,96 @@ IV with loss, SvIOKp, SvNOKp and SvNOK will be set, while SvIOK won't be.
In general, though, it's best to use the C<Sv*V> macros.
=head2 Read-Only Values
In Perl 5.16 and earlier, copy-on-write (see the next section) shared a
flag bit with read-only scalars. So the only way to test whether
C<sv_setsv>, etc., will raise a "Modification of a read-only value" error
in those versions is:
SvREADONLY(sv) && !SvIsCOW(sv)
Under Perl 5.18 and later, SvREADONLY only applies to read-only variables,
and, under 5.20, copy-on-write scalars can also be read-only, so the above
check is incorrect. You just want:
SvREADONLY(sv)
If you need to do this check often, define your own macro like this:
#if PERL_VERSION >= 18
# define SvTRULYREADONLY(sv) SvREADONLY(sv)
#else
# define SvTRULYREADONLY(sv) (SvREADONLY(sv) && !SvIsCOW(sv))
#endif
Or better yet, read about THINKFIRST macros below.
=head2 Copy on Write
Perl implements a copy-on-write (COW) mechanism for scalars, in which
string copies are not immediately made when requested, but are deferred
until made necessary by one or the other scalar changing. This is mostly
transparent, but one must take care not to modify string buffers that are
shared by multiple SVs.
You can test whether an SV is using copy-on-write with C<SvIsCOW(sv)>.
You can force an SV to make its own copy of its string buffer by calling
C<sv_force_normal(sv)> or SvPV_force_nolen(sv).
If you want to make the SV drop its string buffer, use
C<sv_force_normal_flags(sv, SV_COW_DROP_PV)> or simply
C<sv_setsv(sv, NULL)>.
All of these functions will croak on read-only scalars (see the previous
section for more on those).
To test that your code is behaving correctly and not modifying COW buffers,
on systems that support L<mmap(2)> (e.g. Unix, Linux, BSDs, macOS) you can
configure perl with C<-Accflags=-DPERL_DEBUG_READONLY_COW> and it will turn
buffer violations into crashes. You will find it to be marvellously slow,
so you may want to skip perl's own tests.
=head2 THINKFIRST before writing to a string buffer
You are more likely to (and usually I<should>) see the C<SvTHINKFIRST(sv)>
macro used to check whether an SV is ready to be written to, as this is a
combined single check to see if the SV:
=over 4
=item *
Points to a COW buffer
=item *
Is READONLY
=item *
Contains a reference
=item *
Has some relevant magic assigned
=back
Two related macros can be used to perform those checks and, if required,
also perform some action:
=over 4
=item *
C<SV_CHECK_THINKFIRST(sv)> calls C<sv_force_normal(sv)> to copy the
string buffer, turning it into a mutable string.
=item *
C<SV_CHECK_THINKFIRST_COW_DROP(sv)> calls C<sv_force_normal_flags(sv, SV_COW_DROP_PV)>
which drops any string buffer pointed to by C<sv>. This is usually
used to avoid copying any COW string to a new buffer, prior to
writing some completely new string to C<sv>.
=back
=head2 Working with AVs
There are two main, longstanding ways to create and load an AV. The first
@ -1344,54 +1434,6 @@ following code:
If the order of C<sv_setiv> and C<sv_setpv> had been reversed, then the
macro C<SvPOK_on> would need to be called instead of C<SvIOK_on>.
=head2 Read-Only Values
In Perl 5.16 and earlier, copy-on-write (see the next section) shared a
flag bit with read-only scalars. So the only way to test whether
C<sv_setsv>, etc., will raise a "Modification of a read-only value" error
in those versions is:
SvREADONLY(sv) && !SvIsCOW(sv)
Under Perl 5.18 and later, SvREADONLY only applies to read-only variables,
and, under 5.20, copy-on-write scalars can also be read-only, so the above
check is incorrect. You just want:
SvREADONLY(sv)
If you need to do this check often, define your own macro like this:
#if PERL_VERSION >= 18
# define SvTRULYREADONLY(sv) SvREADONLY(sv)
#else
# define SvTRULYREADONLY(sv) (SvREADONLY(sv) && !SvIsCOW(sv))
#endif
=head2 Copy on Write
Perl implements a copy-on-write (COW) mechanism for scalars, in which
string copies are not immediately made when requested, but are deferred
until made necessary by one or the other scalar changing. This is mostly
transparent, but one must take care not to modify string buffers that are
shared by multiple SVs.
You can test whether an SV is using copy-on-write with C<SvIsCOW(sv)>.
You can force an SV to make its own copy of its string buffer by calling C<sv_force_normal(sv)> or SvPV_force_nolen(sv).
If you want to make the SV drop its string buffer, use
C<sv_force_normal_flags(sv, SV_COW_DROP_PV)> or simply
C<sv_setsv(sv, NULL)>.
All of these functions will croak on read-only scalars (see the previous
section for more on those).
To test that your code is behaving correctly and not modifying COW buffers,
on systems that support L<mmap(2)> (i.e., Unix) you can configure perl with
C<-Accflags=-DPERL_DEBUG_READONLY_COW> and it will turn buffer violations
into crashes. You will find it to be marvellously slow, so you may want to
skip perl's own tests.
=head2 Magic Variables
[This section still under construction. Ignore everything here. Post no