In this section, you will use External Data Access to get a pointer to a block's data. You can use this method with any block, even if the block does not use user-specified storage. The external data access method is useful in contexts where you cannot control how the block is allocate. For example, in this section, you will create a utility routine for I/O that works with any matrix or vector, even if it was not created with user-defined storage.
To access a block's data with external data access, you
create an Ext_data object.
Ext_data<block_type, layout_type> ext(block, SYNC_INOUT);
Ext_data is a class template that takes
template parameters to indicate the block type
block_type and the requested layout
layout_type. The constructor takes
two parameters: the block being accessed, and the type of
synchronization necessary.
The layout_type parameter is a
specialized Layout class template that
determines the layout of data that Ext_data
provides. If no type is given,
the natural layout of the block is used. However, in some
cases you may wish to specify row-major or column-major layout.
The Layout class template takes 4 parameters to
indicate dimensionality, dimension-ordering, packing format,
and complex storage format (if complex). In the example below
you will use the layout_type to request the data access to be dense,
row-major, with interleaved real and imaginary values. This layout
corresponds to a common storage format used for binary files
storing complex data.
The synchronization type is analgous to the update flags for
admit() and release().
SYNC_IN indicates that the block and pointer
should be synchronized when the Ext_data object
is created (like admit(true))
SYNC_OUT indicates that the block and pointer
should be synchronized when the Ext_data object
is destroyed (like release(true))
SYNC_INOUT indicates that the block and pointer
should be syncrhonized at both points.
Once the object has been created, the pointer can be accessed
with the data method.
value_type* ptr = ext.data();
The pointer provided is valid only during the life of the
Ext_data object.
Moreover, the block referred to by the
Ext_data object must not be used during this
period.
Using these capabilities together, you can create a routine to perform I/O into a block. This routine will take two arguments: a filename to read, and a view in which to store the data. The amount of data read from the file will be determined by the view's size.
template <typename ViewT>
void
read_file(ViewT view, char const* filename)
{
using vsip::impl::Ext_data;
using vsip::impl::Layout;
using vsip::impl::Stride_unit_dense;
using vsip::impl::Cmplx_inter_fmt;
using vsip::impl::Row_major;
using vsip::impl::SYNC_OUT;
dimension_type const dim = ViewT::dim;
typedef typename ViewT::block_type block_type;
typedef typename ViewT::value_type value_type;
typedef Layout<dim, typename Row_major<dim>::type,
Stride_unit_dense, Cmplx_inter_fmt>
layout_type;
Ext_data<block_type, layout_type>
ext(view.block(), SYNC_OUT);
std::ifstream ifs(filename);
ifs.read(reinterpret_cast<char*>(ext.data()),
view.size() * sizeof(value_type));
}