7.4. Performing I/O with External Data Access

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));
}