numpy  2.0.0
src/multiarray/lowlevel_strided_loops.c.src File Reference
#include "Python.h"
#include "structmember.h"
#include <numpy/arrayobject.h>
#include <numpy/npy_cpu.h>
#include <numpy/halffloat.h>
#include "lowlevel_strided_loops.h"

Defines

#define PY_SSIZE_T_CLEAN
#define NPY_NO_DEPRECATED_API   NPY_API_VERSION
#define _MULTIARRAYMODULE
#define _ALIGN(type)   offsetof(struct {char c; type v;}, v)
#define NPY_USE_UNALIGNED_ACCESS   0
#define _NPY_NOP1(x)   (x)
#define _NPY_NOP2(x)   (x)
#define _NPY_NOP4(x)   (x)
#define _NPY_NOP8(x)   (x)
#define _NPY_SWAP2(x)   npy_bswap2(x)
#define _NPY_SWAP4(x)   npy_bswap4(x)
#define _NPY_SWAP_PAIR4(x)
#define _NPY_SWAP8(x)   npy_bswap8(x)
#define _NPY_SWAP_PAIR8(x)
#define _NPY_SWAP_INPLACE2(x)   npy_bswap2_unaligned(x)
#define _NPY_SWAP_INPLACE4(x)   npy_bswap4_unaligned(x)
#define _NPY_SWAP_INPLACE8(x)   npy_bswap8_unaligned(x)
#define _NPY_SWAP_INPLACE16(x)

Functions

static void _strided_to_strided (char *dst, npy_intp dst_stride, char *src, npy_intp src_stride, npy_intp N, npy_intp src_itemsize, NpyAuxData *NPY_UNUSED(data))
static void _swap_strided_to_strided (char *dst, npy_intp dst_stride, char *src, npy_intp src_stride, npy_intp N, npy_intp src_itemsize, NpyAuxData *NPY_UNUSED(data))
static void _swap_pair_strided_to_strided (char *dst, npy_intp dst_stride, char *src, npy_intp src_stride, npy_intp N, npy_intp src_itemsize, NpyAuxData *NPY_UNUSED(data))
static void _contig_to_contig (char *dst, npy_intp NPY_UNUSED(dst_stride), char *src, npy_intp NPY_UNUSED(src_stride), npy_intp N, npy_intp src_itemsize, NpyAuxData *NPY_UNUSED(data))
NPY_NO_EXPORT
PyArray_StridedUnaryOp
PyArray_GetStridedCopyFn (int aligned, npy_intp src_stride, npy_intp dst_stride, npy_intp itemsize)
NPY_NO_EXPORT
PyArray_StridedUnaryOp
function (int aligned, npy_intp src_stride, npy_intp dst_stride, npy_intp itemsize)
NPY_NO_EXPORT
PyArray_StridedUnaryOp
PyArray_GetStridedNumericCastFn (int aligned, npy_intp src_stride, npy_intp dst_stride, int src_type_num, int dst_type_num)
NPY_NO_EXPORT npy_intp PyArray_TransferNDimToStrided (npy_intp ndim, char *dst, npy_intp dst_stride, char *src, npy_intp *src_strides, npy_intp src_strides_inc, npy_intp *coords, npy_intp coords_inc, npy_intp *shape, npy_intp shape_inc, npy_intp count, npy_intp src_itemsize, PyArray_StridedUnaryOp *stransfer, NpyAuxData *data)
NPY_NO_EXPORT npy_intp PyArray_TransferStridedToNDim (npy_intp ndim, char *dst, npy_intp *dst_strides, npy_intp dst_strides_inc, char *src, npy_intp src_stride, npy_intp *coords, npy_intp coords_inc, npy_intp *shape, npy_intp shape_inc, npy_intp count, npy_intp src_itemsize, PyArray_StridedUnaryOp *stransfer, NpyAuxData *data)
NPY_NO_EXPORT npy_intp PyArray_TransferMaskedStridedToNDim (npy_intp ndim, char *dst, npy_intp *dst_strides, npy_intp dst_strides_inc, char *src, npy_intp src_stride, npy_uint8 *mask, npy_intp mask_stride, npy_intp *coords, npy_intp coords_inc, npy_intp *shape, npy_intp shape_inc, npy_intp count, npy_intp src_itemsize, PyArray_MaskedStridedUnaryOp *stransfer, NpyAuxData *data)
NPY_NO_EXPORT int mapiter_trivial_ name (PyArrayObject *self, PyArrayObject *ind, PyArrayObject *result)
NPY_NO_EXPORT int mapiter_ name (PyArrayMapIterObject *mit)

Define Documentation

#define _ALIGN (   type)    offsetof(struct {char c; type v;}, v)
used for some alignment checks
#define _NPY_NOP1 (   x)    (x)
#define _NPY_NOP2 (   x)    (x)
#define _NPY_NOP4 (   x)    (x)
#define _NPY_NOP8 (   x)    (x)
#define _NPY_SWAP2 (   x)    npy_bswap2(x)
#define _NPY_SWAP4 (   x)    npy_bswap4(x)
#define _NPY_SWAP8 (   x)    npy_bswap8(x)
#define _NPY_SWAP_INPLACE16 (   x)
Value:
{ \
        char a = (x)[0]; (x)[0] = (x)[15]; (x)[15] = a; \
        a = (x)[1]; (x)[1] = (x)[14]; (x)[14] = a; \
        a = (x)[2]; (x)[2] = (x)[13]; (x)[13] = a; \
        a = (x)[3]; (x)[3] = (x)[12]; (x)[12] = a; \
        a = (x)[4]; (x)[4] = (x)[11]; (x)[11] = a; \
        a = (x)[5]; (x)[5] = (x)[10]; (x)[10] = a; \
        a = (x)[6]; (x)[6] = (x)[9]; (x)[9] = a; \
        a = (x)[7]; (x)[7] = (x)[8]; (x)[8] = a; \
        }
#define _NPY_SWAP_INPLACE2 (   x)    npy_bswap2_unaligned(x)
#define _NPY_SWAP_INPLACE4 (   x)    npy_bswap4_unaligned(x)
#define _NPY_SWAP_INPLACE8 (   x)    npy_bswap8_unaligned(x)
#define _NPY_SWAP_PAIR4 (   x)
Value:
(((((npy_uint32)x)&0xffu) << 8) | \
                       ((((npy_uint32)x)&0xff00u) >> 8) | \
                       ((((npy_uint32)x)&0xff0000u) << 8) | \
                       ((((npy_uint32)x)&0xff000000u) >> 8))
#define _NPY_SWAP_PAIR8 (   x)
Value:
(((((npy_uint64)x)&0xffULL) << 24) | \
                       ((((npy_uint64)x)&0xff00ULL) << 8) | \
                       ((((npy_uint64)x)&0xff0000ULL) >> 8) | \
                       ((((npy_uint64)x)&0xff000000ULL) >> 24) | \
                       ((((npy_uint64)x)&0xff00000000ULL) << 24) | \
                       ((((npy_uint64)x)&0xff0000000000ULL) << 8) | \
                       ((((npy_uint64)x)&0xff000000000000ULL) >> 8) | \
                       ((((npy_uint64)x)&0xff00000000000000ULL) >> 24))
#define NPY_NO_DEPRECATED_API   NPY_API_VERSION
#define NPY_USE_UNALIGNED_ACCESS   0
Disable harmless compiler warning "4116: unnamed type definition in parentheses" which is caused by the _ALIGN macro.
x86 platform works with unaligned access but the compiler is allowed to assume all data is aligned to its size by the C standard. This means it can vectorize instructions peeling only by the size of the type, if the data is not aligned to this size one ends up with data not correctly aligned for SSE instructions (16 byte). So this flag can only be enabled if autovectorization is disabled.

Function Documentation

static void _contig_to_contig ( char *  dst,
npy_intp   NPY_UNUSEDdst_stride,
char *  src,
npy_intp   NPY_UNUSEDsrc_stride,
npy_intp  N,
npy_intp  src_itemsize,
NpyAuxData NPY_UNUSEDdata 
) [static]
static void _strided_to_strided ( char *  dst,
npy_intp  dst_stride,
char *  src,
npy_intp  src_stride,
npy_intp  N,
npy_intp  src_itemsize,
NpyAuxData NPY_UNUSEDdata 
) [static]
******* STRIDED COPYING/SWAPPING SPECIALIZED FUNCTIONS ********
begin repeat
#elsize = 1, 2, 4, 8, 16# #elsize_half = 0, 1, 2, 4, 8# #type = npy_uint8, npy_uint16, npy_uint32, npy_uint64, npy_uint128#
begin repeat1
oper = strided_to_strided, strided_to_contig,
contig_to_strided, contig_to_contig#
System Message: WARNING/2 (<string>, line 4) Definition list ends without a blank line; unexpected unindent.

#src_contig = 0, 0, 1 ,1# #dst_contig = 0, 1, 0 ,1#

begin repeat2
#swap = _NPY_NOP, _NPY_NOP, _NPY_SWAP_INPLACE, _NPY_SWAP,
_NPY_SWAP_INPLACE, _NPY_SWAP_PAIR#
System Message: WARNING/2 (<string>, line 4) Definition list ends without a blank line; unexpected unindent.

#prefix = , _aligned, _swap, _aligned_swap, _swap_pair, _aligned_swap_pair# #is_aligned = 0, 1, 0, 1, 0, 1# #minelsize = 1, 1, 2, 2, 4, 4# #is_swap = 0, 0, 1, 1, 2, 2#

<

&#64;elsize&#64; >= &#64;minelsize&#64;
end repeat2*
end repeat1*
end repeat*
static void _swap_pair_strided_to_strided ( char *  dst,
npy_intp  dst_stride,
char *  src,
npy_intp  src_stride,
npy_intp  N,
npy_intp  src_itemsize,
NpyAuxData NPY_UNUSEDdata 
) [static]
general in-place swap
general in-place swap

References _contig_to_contig().

static void _swap_strided_to_strided ( char *  dst,
npy_intp  dst_stride,
char *  src,
npy_intp  src_stride,
npy_intp  N,
npy_intp  src_itemsize,
NpyAuxData NPY_UNUSEDdata 
) [static]
general in-place swap
NPY_NO_EXPORT PyArray_StridedUnaryOp* function ( int  aligned,
npy_intp  src_stride,
npy_intp  dst_stride,
npy_intp  itemsize 
)
PyArray_GetStridedCopySwapFn and PyArray_GetStridedCopySwapPairFn are nearly identical, so can do a repeat for them.
begin repeat
function = PyArray_GetStridedCopySwapFn, PyArray_GetStridedCopySwapPairFn# #tag = , _pair# #not_pair = 1, 0#
Skip the "unaligned" versions on CPUs which support unaligned memory accesses.

<

!NPY_USE_UNALIGNED_ACCESS
contiguous dst
constant src
begin repeat1
#elsize = 2, 4, 8, 16#
end repeat1*
contiguous src
begin repeat1
#elsize = 2, 4, 8, 16#
end repeat1*
general src
begin repeat1
#elsize = 2, 4, 8, 16#
end repeat1*
general dst
constant src
begin repeat1
#elsize = 2, 4, 8, 16#
end repeat1*
contiguous src
begin repeat1
#elsize = 2, 4, 8, 16#
end repeat1*
begin repeat1
#elsize = 2, 4, 8, 16#
end repeat1*
contiguous dst
contiguous src
begin repeat1
#elsize = 2, 4, 8, 16#
end repeat1*
general src
begin repeat1
#elsize = 2, 4, 8, 16#
end repeat1*
general dst
contiguous src
begin repeat1
#elsize = 2, 4, 8, 16#
end repeat1*
general src
begin repeat1
#elsize = 2, 4, 8, 16#
end repeat1*
NPY_NO_EXPORT int mapiter_trivial_ name ( PyArrayObject self,
PyArrayObject ind,
PyArrayObject result 
)
System Message: ERROR/3 (<string>, line 1) Document or section may not begin with a transition.

System Message: ERROR/3 (<string>, line 1) Document may not end with a transition.
************ MapIter (Advanced indexing) Get/Set ***************
System Message: ERROR/3 (<string>, line 1) Document or section may not begin with a transition.

System Message: ERROR/3 (<string>, line 1) Document may not end with a transition.
begin repeat
name = set, get# #isget = 0, 1#
Advanded indexing iteration of arrays when there is a single indexing array which has the same memory order as the value array and both can be trivally iterated (single stride, aligned, no casting necessary).
Check the indices beforehand
Reset the ind_ptr and itersize, due to broadcasting it is always the size of ind.
Optimization for aligned types that do not need the api
begin repeat1
#elsize = 1, 2, 4, 8, 0# #copytype = npy_uint8, npy_uint16, npy_uint32, npy_uint64, 0#

<

!&#64;isget&#64;
end repeat1*
NPY_NO_EXPORT int mapiter_ name ( PyArrayMapIterObject mit)
General advanced indexing iteration.
Cached mit info
Constant information
Fill constant information
Alignment information (swapping is never needed, since we buffer), could also check extra_op is buffered, but it should rarely matter.
Item by item copy situation, the operand is buffered so use copyswap.
We have only one iterator handling everything
****** Optimized inner loops without subspace ********
begin repeat1
#one_iter = 1, 0# #numiter = 1, numiter#
Optimization for aligned types that do not need the api
begin repeat2
#elsize = 1, 2, 4, 8, 0# #copytype = npy_uint8, npy_uint16, npy_uint32, npy_uint64, 0#
Outer iteration (safe because mit->size != 0)
When the API is needed the casting might fail TODO: (only if buffering is enabled).
advance indexing arrays
advance extra operand
end repeat2*
end repeat1*
************* Nested Iteration Situation **************

<

has three states
Use strided transfer functions for the inner loop
Get a dtype transfer function, since there are no buffers, this is safe.
subspace is trivially iterable. manipulate pointers to avoid expensive resetting
begin repeat1
#one_iter = 1, 0# #numiter = 1, numiter#
Outer iteration (safe because mit->size != 0)
Resetting is slow, so try to avoid resetting if subspace iteration is trivial. Watch out: reset_offsets are kept outside of the loop, assuming the subspaces of different external iterations share the same structure.
slower resetting: first iteration or non-trivial subspace
(can't really fail, since no buffering necessary)
reset_offsets are nonzero for negative strides.
use the faster adjustment further on
faster resetting if the subspace iteration is trival. reset_offsets are zero for positive strides, for negative strides this shifts the pointer to the last item.
When the API is needed the casting might fail TODO: Could only check if casting is unsafe, or even just

System Message: ERROR/3 (<string>, line 3) Unexpected indentation.

<blockquote> not at all...</blockquote>

end repeat1*
NPY_NO_EXPORT PyArray_StridedUnaryOp* PyArray_GetStridedCopyFn ( int  aligned,
npy_intp  src_stride,
npy_intp  dst_stride,
npy_intp  itemsize 
)
Gives back a function pointer to a specialized function for copying strided memory. Returns NULL if there is a problem with the inputs.

aligned:
Should be 1 if the src and dst pointers are always aligned, 0 otherwise.
src_stride:
Should be the src stride if it will always be the same, NPY_MAX_INTP otherwise.
dst_stride:
Should be the dst stride if it will always be the same, NPY_MAX_INTP otherwise.
itemsize:
Should be the item size if it will always be the same, 0 otherwise.
Skip the "unaligned" versions on CPUs which support unaligned memory accesses.

<

!NPY_USE_UNALIGNED_ACCESS
contiguous dst
constant src
begin repeat
#elsize = 1, 2, 4, 8, 16#
end repeat*
contiguous src
general src
begin repeat
#elsize = 1, 2, 4, 8, 16#
end repeat*
general dst
constant src
begin repeat
#elsize = 1, 2, 4, 8, 16#
end repeat*
contiguous src
begin repeat
#elsize = 1, 2, 4, 8, 16#
end repeat*
begin repeat
#elsize = 1, 2, 4, 8, 16#
end repeat*
contiguous dst
contiguous src
general src
begin repeat
#elsize = 2, 4, 8, 16#
end repeat*
general dst
contiguous src
begin repeat
#elsize = 2, 4, 8, 16#
end repeat*
general src
begin repeat
#elsize = 2, 4, 8, 16#
end repeat*

Referenced by _strided_to_strided_truncate_copy().

NPY_NO_EXPORT PyArray_StridedUnaryOp* PyArray_GetStridedNumericCastFn ( int  aligned,
npy_intp  src_stride,
npy_intp  dst_stride,
int  src_type_num,
int  dst_type_num 
)
end repeat*
******* STRIDED CASTING SPECIALIZED FUNCTIONS ********
begin repeat <blockquote>

#NAME1 = BOOL,
UBYTE, USHORT, UINT, ULONG, ULONGLONG, BYTE, SHORT, INT, LONG, LONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE#
#name1 = bool,
ubyte, ushort, uint, ulong, ulonglong, byte, short, int, long, longlong, half, float, double, longdouble, cfloat, cdouble, clongdouble#
#type1 = npy_bool,
npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong, npy_byte, npy_short, npy_int, npy_long, npy_longlong, npy_half, npy_float, npy_double, npy_longdouble, npy_cfloat, npy_cdouble, npy_clongdouble#
#rtype1 = npy_bool,
npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong, npy_byte, npy_short, npy_int, npy_long, npy_longlong, npy_half, npy_float, npy_double, npy_longdouble, npy_float, npy_double, npy_longdouble#
System Message: WARNING/2 (<string>, line 23) Definition list ends without a blank line; unexpected unindent.
#is_bool1 = 1, 0*17# #is_half1 = 0*11, 1, 0*6# #is_float1 = 0*12, 1, 0, 0, 1, 0, 0# #is_double1 = 0*13, 1, 0, 0, 1, 0# #is_complex1 = 0*15, 1*3# </blockquote>
begin repeat1 <blockquote>

#NAME2 = BOOL,
UBYTE, USHORT, UINT, ULONG, ULONGLONG, BYTE, SHORT, INT, LONG, LONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE#
#name2 = bool,
ubyte, ushort, uint, ulong, ulonglong, byte, short, int, long, longlong, half, float, double, longdouble, cfloat, cdouble, clongdouble#
#type2 = npy_bool,
npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong, npy_byte, npy_short, npy_int, npy_long, npy_longlong, npy_half, npy_float, npy_double, npy_longdouble, npy_cfloat, npy_cdouble, npy_clongdouble#
#rtype2 = npy_bool,
npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong, npy_byte, npy_short, npy_int, npy_long, npy_longlong, npy_half, npy_float, npy_double, npy_longdouble, npy_float, npy_double, npy_longdouble#
System Message: WARNING/2 (<string>, line 23) Definition list ends without a blank line; unexpected unindent.
#is_bool2 = 1, 0*17# #is_half2 = 0*11, 1, 0*6# #is_float2 = 0*12, 1, 0, 0, 1, 0, 0# #is_double2 = 0*13, 1, 0, 0, 1, 0# #is_complex2 = 0*15, 1*3# </blockquote>
begin repeat2
#prefix = _aligned,,_aligned_contig,_contig# #aligned = 1,0,1,0# #contig = 0,0,1,1#
end repeat2*
end repeat1*
end repeat*
begin repeat <blockquote>

#NAME1 = BOOL,
UBYTE, USHORT, UINT, ULONG, ULONGLONG, BYTE, SHORT, INT, LONG, LONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE#
#name1 = bool,
ubyte, ushort, uint, ulong, ulonglong, byte, short, int, long, longlong, half, float, double, longdouble, cfloat, cdouble, clongdouble#
#type1 = npy_bool,
npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong, npy_byte, npy_short, npy_int, npy_long, npy_longlong, npy_half, npy_float, npy_double, npy_longdouble, npy_cfloat, npy_cdouble, npy_clongdouble#

</blockquote>

printf("test fn d - second dn", NPY_&#64;NAME1&#64;, dst_type_num);
begin repeat1 <blockquote>

#NAME2 = BOOL,
UBYTE, USHORT, UINT, ULONG, ULONGLONG, BYTE, SHORT, INT, LONG, LONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE#
#name2 = bool,
ubyte, ushort, uint, ulong, ulonglong, byte, short, int, long, longlong, half, float, double, longdouble, cfloat, cdouble, clongdouble#
#type2 = npy_bool,
npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong, npy_byte, npy_short, npy_int, npy_long, npy_longlong, npy_half, npy_float, npy_double, npy_longdouble, npy_cfloat, npy_cdouble, npy_clongdouble#

</blockquote>

printf("ret fn d dn", NPY_&#64;NAME1&#64;, NPY_&#64;NAME2&#64;);
end repeat1*
printf("switched test fn d - second dn", NPY_&#64;NAME1&#64;, dst_type_num);
end repeat*
NPY_NO_EXPORT npy_intp PyArray_TransferMaskedStridedToNDim ( npy_intp  ndim,
char *  dst,
npy_intp dst_strides,
npy_intp  dst_strides_inc,
char *  src,
npy_intp  src_stride,
npy_uint8 *  mask,
npy_intp  mask_stride,
npy_intp coords,
npy_intp  coords_inc,
npy_intp shape,
npy_intp  shape_inc,
npy_intp  count,
npy_intp  src_itemsize,
PyArray_MaskedStridedUnaryOp stransfer,
NpyAuxData data 
)
See documentation of arguments in lowlevel_strided_loops.h
Finish off dimension 0
If it's 1-dimensional, there's no more to copy
Adjust the src and dst pointers
Finish off dimension 1
If it's 2-dimensional, there's no more to copy
General-case loop for everything else
Iteration structure for dimensions 2 and up
Copy the coordinates and shape
Adjust the dst pointer from the dimension 0 and 1 loop
Increment to the next coordinate
If the last dimension rolled over, we're done
A loop for dimensions 0 and 1

References check_and_adjust_index(), NPY_AUXDATA_FREE, NPY_BEGIN_THREADS, NPY_BEGIN_THREADS_DEF, NPY_END_THREADS, and NpyIter_ResetBasePointers().

NPY_NO_EXPORT npy_intp PyArray_TransferNDimToStrided ( npy_intp  ndim,
char *  dst,
npy_intp  dst_stride,
char *  src,
npy_intp src_strides,
npy_intp  src_strides_inc,
npy_intp coords,
npy_intp  coords_inc,
npy_intp shape,
npy_intp  shape_inc,
npy_intp  count,
npy_intp  src_itemsize,
PyArray_StridedUnaryOp stransfer,
NpyAuxData data 
)
************ PRIMITIVE FLAT TO/FROM NDIM FUNCTIONS *************
See documentation of arguments in lowlevel_strided_loops.h
Finish off dimension 0
If it's 1-dimensional, there's no more to copy
Adjust the src and dst pointers
Finish off dimension 1
If it's 2-dimensional, there's no more to copy
General-case loop for everything else
Iteration structure for dimensions 2 and up
Copy the coordinates and shape
Adjust the src pointer from the dimension 0 and 1 loop
Increment to the next coordinate
If the last dimension rolled over, we're done
A loop for dimensions 0 and 1
NPY_NO_EXPORT npy_intp PyArray_TransferStridedToNDim ( npy_intp  ndim,
char *  dst,
npy_intp dst_strides,
npy_intp  dst_strides_inc,
char *  src,
npy_intp  src_stride,
npy_intp coords,
npy_intp  coords_inc,
npy_intp shape,
npy_intp  shape_inc,
npy_intp  count,
npy_intp  src_itemsize,
PyArray_StridedUnaryOp stransfer,
NpyAuxData data 
)
See documentation of arguments in lowlevel_strided_loops.h
Finish off dimension 0
If it's 1-dimensional, there's no more to copy
Adjust the src and dst pointers
Finish off dimension 1
If it's 2-dimensional, there's no more to copy
General-case loop for everything else
Iteration structure for dimensions 2 and up
Copy the coordinates and shape
Adjust the dst pointer from the dimension 0 and 1 loop
Increment to the next coordinate
If the last dimension rolled over, we're done
A loop for dimensions 0 and 1

Referenced by npyiter_allocate_buffers().