[Insight-users] Data Representation Objects

Ofri Sadowsky ofri@cs.jhu.edu
Thu, 21 Nov 2002 15:09:46 -0500


I added the following code in the public section of my copy of itkVectorContainer.h

<<< BEGIN >>>
 /* forward declaration */
 class STLVectorAdapter;
 class STLConstVectorAdapter;

 /** \class STLVectorAdapter
  * An adapter object that casts a VectorContainer into std::vector
  * and enables access to the underlying data structure. When the STLVectorAdapter
  * is destroyed, it automatically calls VectorContainer::Modified().
  * Here's a usage example of STLVectorAdapter
  *     VectorContainer::STLVectorAdapter vecAdapter =
aContainer.GetStlVectorAdapter();
  *     std::vector<ElementType> & vec = vecAdapter.GetStlVectorRef();
  *     // do things with vec ...
  *     // upon return from function, vecAdapter is destroyed and aContainer is
Modified()
  */
  class STLVectorAdapter
  {
  public:
   VectorType & GetStlVectorRef()
   {
    return (VectorType &)m_VectorRef;
   }

   ~STLVectorAdapter()
   {
    m_VectorRef.Modified();
   }

   /** public copy ctor to enable
    *   VectorContainer::STLVectorAdapter vecAdapter =
aContainer.GetStlVectorAdapter();
    */
   STLVectorAdapter(const STLVectorAdapter & r)
    : m_VectorRef(r.m_VectorRef) {}
  private:
   VectorContainer & m_VectorRef;
   friend class VectorContainer;
   friend class STLConstVectorAdapter;

   /* hide ctor */
   STLVectorAdapter(VectorContainer & vc)
    : m_VectorRef(vc) {}

   /* hide and avoid operator= */
   const STLVectorAdapter & operator=(const STLVectorAdapter & r);
  };


  /** Create a STLVectorAdapter that adapts this object to std::vector<ElementType>
  */
  STLVectorAdapter GetStlVectorAdapter()
  {
   return STLVectorAdapter(*this);
  }

  /** \class STLConstVectorAdapter
   * An adapter object that casts a VectorContainer into const std::vector
   * and enables access to the underlying data structure. STLConstVectorAdapter
   * does not call VectorContainer::Modified(), because it is cast to const.
   * Here's a usage example of STLConstVectorAdapter
   *     VectorContainer::STLConstVectorAdapter vecAdapter =
   *                aContainer.GetConstStlVectorAdapter();
   *     const std::vector<ElementType> & vec = vecAdapter.GetStlConstVectorRef();
   *     // do things with vec ... but it can't be modified.
   */
  class STLConstVectorAdapter
  {
  public:
   const VectorType & GetStlConstVectorRef() const
   {
    return (const VectorType &)m_VectorRef;
   }

   /* no need to declare dtor, as the Adapter is const */

   /* public copy ctor. See StlVectorAdapter */
   STLConstVectorAdapter(const STLConstVectorAdapter & r)
    : m_ConstVectorRef(r.m_ConstVectorRef) {}

   /* "copy" ctor from the non-const STLVectorAdapter */
   STLConstVectorAdapter(const STLVectorAdapter & r)
    : m_ConstVectorRef(r.m_VectorRef) {}

  private:
   const VectorContainer & m_ConstVectorRef;
   friend class VectorContainer;

   /* hide main ctor */
   STLConstVectorAdapter(const VectorContainer & vc)
    : m_ConstVectorRef(vc) {}

   /* hide and avoid operator= */
   const STLConstVectorAdapter & operator=(const STLConstVectorAdapter & r);
  };

  STLConstVectorAdapter GetStlConstVectorAdapter() const
  {
   return STLConstVectorAdapter(*this);
  }

<<< END >>>

The least I can say is that the code compiles, although I have not used it yet.

Does it look good enough to be included in the itk code? I would not like to
maintain my own version forever.

Ofri

Ofri Sadowsky wrote:

> Luis Ibanez wrote:
>
> > Hi Ofri,
> >
> > I inserted comments below...
> >
> > Ofri Sadowsky wrote:
> > > Thinking about it so far, I see two main obstacles:
> > >
> > > 1. The VectorContainer must be Modified() on every change. That means, that
> > > if we have an adapter with a public interface of std::vector that directly
> > > manipulates an underlying VectorContainer, the std::vector adapter methods
> > > have to be cleverly overloaded. Unfortunately, STL has not declared the
> > > containers methods virtual, and therefore we cannot overload them to simulate
> > > a std::vector behavior by anything else than std::vector.
> >  >
> >
> > Yeap,
> > I guess that the lack of virtual methods was motivated by an
> > efficiency concern. However in principle the adapter doesn't have to
> > derive from the std::vector. It only has to provide the same interface.
> > The unfortunate thing with STL is that the "interface" has so many
> > hidden types and traits that it may be a hard work to get them all
> > right.
>
> Not necessarily so, I think. If one already has code that uses std::vector and is
> not templated, the new type, even with identicla public interface to std::vector,
> is incompatible. For example, if you defined
>
> typedef std::vector<int> MyContainerType;
>
> And then wrote a bunch of functions accepting MyContainerType, you won't be able
> to use the adapter instead.
>
> Then, about the types and traits in STL, it's not so hard a job either, I
> believe.  Basically, you can copy/paste almost everything from the public header
> <vector>, and you can use the same "allocator" traits, which defines most of what
> you need. Then, you don't have to implement all the iterator mechanics and the
> rest of the stuff, just delegate them. I guess I could give such a thing a try.
>
> >
> >
> > >
> > > 2. Furthermore, it may be impossible to create a VectorContainer adapter for
> > > std::vector, as the underlying std::vector should have to report its wrapper
> > > about modifications. But std::vector does not have that capability.
> > >
> >
> > Well, the VectorContainer do not invoke "Modified" every time (also for
> > efficiency). In practice is up to the user of the class to invoke
> > Modified() whenever this is appropriate.
>
> >
> > >
> > > So it seems that creating adapters in the strong sense -- wrappers that
> > > expose a public interface of type A while delegating to internal structure of
> > > type B, should be really hard, if not impossible.
> > >
> >
> > Well, one option could be simple change the "private" derivation of the
> > Vector container for a public derivation. This will allow the
> > VectorContainer to be used in wherever a std::vector is expected.
>
> That is a very easy solution, and if it does not compromise things such as thread
> safety, it may be worthwhile. However, I would not declare the derivation
> "public", but rather provide an accessor method such as
>
> std::vector<ElementType> & VectorContainer::GetSTLVectorAdapter()
>
> So as not to over-expose the class encapsulation.
>
> >
> >
> > The other aspect (adapting a std::vector to make it look like a
> > itk::VectorContainer) will still be an open issue.
> >
> > > A very simple workaround would be to write extraction methods, that extract
> > > data from type A container object to type B container object, and vice versa.
> > > That is not  "adapter", but it may still come handy at times. I could make
> > > something for that, and it should only use the currently available API, and
> > > therefore be compatible with whatever the current API is compatible with.
> > >
> >
> > Agree,
> >
> > Actually this is almost already there since we could access the
> > iterators to the underlying STL structure. After all, most STL algorithm
> > interact with the iterators of the containers rather than the containers
> > themselves.
> >
> >     Luis