Boost logo

Boost :

From: Kresimir Fresl (fresl_at_[hidden])
Date: 2002-09-26 11:47:35


Michael Stevens wrote:

>> From:
>> nbecker_at_[hidden] (Neal D. Becker)

>> Can ublas matrixes interconvert to/from plain old C pointers (to
>> interop with legacy code)? If so, how can a Matrix be converted to a
>> pointer to the start of storage? Is conversion in the other direction
>> possible?

> It is very easy to get a pointer to the start of storage.

Unfortunately, not always. Or, to be more exact, it seems that there
is no simple `universal' solution.

> The uBLAS
> contianer (matrix,vector etc) all wrap an underling storage type. This
> is usualy the 'unbounded_array' type. You can easily get a reference to
> this array using the accessor functions '.data()'.

> From then it is easy to get a pointer to the begin of the storage
> using '.begin()'

> Therefore to get a pointer to the first element of matrix A used
> A.data().begin()

Yes, ublas::unbounded_array<>::begin() returns
ublas::unbounded_array<>::iterator (or const_iterator),
which *happens* to be a pointer. (The same is true
for ublas::bounded_array<>.)

But, for other storage types this need not be true; e.g. storage
type can be std::vector<> and its iterator can be `proper' class
(and it is in gnu library).

One can try

    &A.data()[0]

that is, take the address of the first element of storage array.

But this does not work when storage type is
ublas::(un)bounded_array<> and A is const. Namely,
return type of `operator[]() const' is
ublas::type_traits<>::const_reference, which for
built-in types (e.g. float and double) is not reference,
but value (e.g. not `double const&' but `double').

Maybe:

    &*A.data().begin()

This works both with ublas::(un)bounded_array<>
and std::vector<>. But if storage type defines
const_iterator type whose const_reference is
ublas::type_traits<>::const_reference, there's again
a problem.

Maybe (let's suppose that A is const boost::vector<double>):

   &const_cast<vector<double>&> (A).data()[0]

i.e. remove vector's const; or:

   &const_cast<unbounded_array<double>&> (A.data())[0]

or (more general):

   &const_cast<vector<double>::array_type&> (A.data())[0]

i.e. remove const from storage.

I think that the proper solution is some kind of a traits class;
something like:

   template <typename V>
   struct storage_traits {
     typedef typename V::pointer pointer;
     static pointer storage (V& v) {
       return &v.data()[0];
     }
   };

   template <typename V>
   struct storage_traits<V const> {
     typedef typename V::const_pointer pointer;
     static pointer storage (V const& v) {
       V& vv = const_cast<V&> (v);
       return &vv.data()[0];
     }
   };

   template <typename V>
   inline typename storage_traits<V>::pointer storage (V& v) {
     return storage_traits<V>::storage (v);
   }

Of course, all these work if storage type has continuous
storage.

[...]

> I don't think it is possible at present to go the other way.

Oh, it is. There is (undocumented) class array_adaptor<>
(in storage.hpp):

   double b[] = { 1., 2. };
   array_adaptor<double> aa1 (2, b); // `2' is array size
   vector<double, array_adaptor<double> > v1 (2, aa1);

   double *c = new double[2];
   array_adaptor<double> aa2 (2, c);
   vector<double, array_adaptor<double> > v2 (2, aa2);
   c[0] = 1.; c[1] = 2.;
   cout << v2 (0) << " " << v2 (1) << endl;

[...]

Sincerely,

fres


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk