summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Williamson <khw@cpan.org>2022-05-18 09:07:49 -0600
committerKarl Williamson <khw@cpan.org>2022-05-20 14:32:29 -0600
commite815fc9e521a3f7203f08588dfcd102261bdacd7 (patch)
tree8bcb46f28c5a7d9c8995ab8e54fd569246a64c2e
parent550c0c1fea3148fcdb3c19fa616d4902b1f3058d (diff)
downloadperl-e815fc9e521a3f7203f08588dfcd102261bdacd7.tar.gz
perlapi: Clean up some AV documentation
The consolidation of newAV with newAV_alloc_xz? included nonsensical juxtapositions. This cleans that up, adds a bit of markup, moves the function implementing the newAV_alloc ones to internal, as there are no CPAN uses, and we prefer the macro interface.
-rw-r--r--av.c21
-rw-r--r--av.h100
-rw-r--r--embed.fnc2
3 files changed, 79 insertions, 44 deletions
diff --git a/av.c b/av.c
index 335121a951..090c5a93f4 100644
--- a/av.c
+++ b/av.c
@@ -210,9 +210,9 @@ Perl_av_extend_guts(pTHX_ AV *av, SSize_t key, SSize_t *maxp, SV ***allocp,
=for apidoc av_fetch
Returns the SV at the specified index in the array. The C<key> is the
-index. If lval is true, you are guaranteed to get a real SV back (in case
+index. If C<lval> is true, you are guaranteed to get a real SV back (in case
it wasn't real before), which you can then modify. Check that the return
-value is non-null before dereferencing it to a C<SV*>.
+value is non-NULL before dereferencing it to a C<SV*>.
See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for
more information on how to use this function on tied arrays.
@@ -395,17 +395,22 @@ Perl_av_store(pTHX_ AV *av, SSize_t key, SV *val)
/*
=for apidoc av_new_alloc
+This implements L<perlapi/C<newAV_alloc_x>>
+and L<perlapi/C<newAV_alloc_xz>>, which are the public API for this
+functionality.
+
Creates a new AV and allocates its SV* array.
-This is similar to but more efficient than doing:
+This is similar to, but more efficient than doing:
AV *av = newAV();
av_extend(av, key);
The size parameter is used to pre-allocate a SV* array large enough to
-hold at least elements 0..(size-1). size must be at least 1.
+hold at least elements C<0..(size-1)>. C<size> must be at least 1.
-The zeroflag parameter controls whether the array is NULL initialized.
+The C<zeroflag> parameter controls whether or not the array is NULL
+initialized.
=cut
*/
@@ -432,9 +437,9 @@ Perl_av_new_alloc(pTHX_ SSize_t size, bool zeroflag)
/*
=for apidoc av_make
-Creates a new AV and populates it with a list of SVs. The SVs are copied
-into the array, so they may be freed after the call to C<av_make>. The new AV
-will have a reference count of 1.
+Creates a new AV and populates it with a list (C<**strp>, length C<size>) of
+SVs. A copy is made of each SV, so their refcounts are not changed. The new
+AV will have a reference count of 1.
Perl equivalent: C<my @new_array = ($scalar1, $scalar2, $scalar3...);>
diff --git a/av.h b/av.h
index 505620fa78..4d263a21b7 100644
--- a/av.h
+++ b/av.h
@@ -112,64 +112,94 @@ If all you need is to look up an array element, then prefer C<av_fetch>.
=for apidoc_item newAV_alloc_x
=for apidoc_item newAV_alloc_xz
-These all create a new AV, setting the reference count to 1. They differ
-in the allocation and population of the array of SV*s that always
-accompanies a non-empty AV.
+These all create a new AV, setting the reference count to 1.
-The Perl equivalent is approximately C<my @array;>.
+As background, an array consists of three things:
-newAV does not allocate a SV* array.
- AV *av = newAV();
+=over
+
+=item 1.
+
+A data structure containing information about the array as a whole, such as its
+size and reference count.
+
+=item 2.
+
+A C language array of pointers to the individual elements. These are treated
+as pointers to SVs, so all must be castable to SV*.
+
+=item 3.
+
+The individual elements themselves. These could be, for instance, SVs and/or
+AVs and/or HVs, etc.
+
+=back
+
+An empty array need only have the first data structure, and all these functions
+create that. They differ in what else they do, as follows:
+
+=over
+
+=item C<newAV> form
+
+=for comment
+'form' above and below is because otherwise have two =items with the same name,
+can't link to them.
+
+This does nothing beyond creating the whole-array data structure.
+The Perl equivalent is approximately S<C<my @array;>>
-This is very useful when an AV is required, but populating it may be
-deferred, or even never actually take place. (Memory is not allocated
-unnecessarily.)
+This is useful when the minimum size of the array could be zero (perhaps there
+are likely code paths that will entirely skip using it).
-Subsequent SV* array allocation would be performed via C<L</av_extend>>.
-This might be called directly:
- av_extend(av, key);
+If the array does get used, the pointers data structure will need to be
+allocated at that time. This will end up being done by L</av_extend>>,
+either explicitly:
+
+ av_extend(av, len);
+
+or implicitly when the first element is stored:
-Or it might be called implicitly when the first element is stored:
(void)av_store(av, 0, sv);
Unused array elements are typically initialized by C<av_extend>. (Only
core maintainers should have need to concern themseleves with when that
-is not the case. Refer to F<av.h> and F<av.c> for the differences between
+is not the case. Refer to F<av.h> and F<av.c> for the differences between
real and fake AVs.)
-In contrast, when an AV is created for immediate population with a known
-(or likely) number of elements, it is more efficient to immediately
-allocate a SV* array of the necessary size. (This avoids inefficient use
-of C<av_extend> and the potential for the first allocation being too small
-and then having to resize it.)
+=item C<newAV_alloc_x> form
+
+This effectively does a C<newAV> followed by also allocating (uninitialized)
+space for the pointers array. This is used when you know ahead of time the
+likely minimum size of the array. It is more efficient to do this than doing a
+plain C<newAV> followed by an C<av_extend>.
+
+Of course the array can be extended later should it become necessary.
+
+C<size> must be at least 1.
+
+=item C<newAV_alloc_xz> form
-For that scenario, newAV_alloc_x and newAV_alloc_xz can be used to create
-an AV and allocate a SV* array to fit the specified number of elements.
-(As a result, these macros MUST NOT be called with a size less than 1.)
+This is C<newAV_alloc_x>, but initializes each pointer in it to NULL. This
+gives added safety to guard against them being read before being set. If you
+know now what those elements should be, instead use L</C<av_make>>.
-newAV_alloc_x does not initialize the array elements - and so the
-expectation is that all will be initialized elsewhere prior to any
-potentials reads. newAV_alloc_xz does initialize the array elements.
+C<size> must be at least 1.
+
+=back
The following examples all result in an array that can fit four elements
(indexes 0 .. 3):
AV *av = newAV();
- av_extend(av, 1);
-
- AV *av = newAV();
av_extend(av, 3);
- AV *av = newAV_alloc_xz(4);
-
AV *av = newAV_alloc_x(4);
-In the newAV_alloc_x case, the array elements will not be initialized
-and their contents are therefore undefined. In the other cases, the
-array elements are all initialized.
+ AV *av = newAV_alloc_xz(4);
-In contrast, the following examples allocate an SV* array that is only
-guaranteed to fit one element:
+In contrast, the following examples allocate an array that is only guaranteed
+to fit one element without extending:
AV *av = newAV_alloc_x(1);
AV *av = newAV_alloc_xz(1);
diff --git a/embed.fnc b/embed.fnc
index 04c8b87a0e..cd37f58db7 100644
--- a/embed.fnc
+++ b/embed.fnc
@@ -640,7 +640,7 @@ CipdR |SV** |av_fetch_simple|NN AV *av|SSize_t key|I32 lval
Apd |void |av_fill |NN AV *av|SSize_t fill
ApdR |SSize_t|av_len |NN AV *av
ApdR |AV* |av_make |SSize_t size|NN SV **strp
-ApdR |AV* |av_new_alloc |SSize_t size|bool zeroflag
+CpdR |AV* |av_new_alloc |SSize_t size|bool zeroflag
p |SV* |av_nonelem |NN AV *av|SSize_t ix
Apd |SV* |av_pop |NN AV *av
Apdoe |void |av_create_and_push|NN AV **const avp|NN SV *const val