[Insight-users] Data Representation Objects

Luis Ibanez luis.ibanez@kitware.com
Thu, 21 Nov 2002 16:09:59 -0500


Hi Ofri,

The code of the STL adpator looks good.

It seems however that we could take better advantage
of the natural derivation of the VectorContainer from
the std::vector.

In principle a simple casting to

          const   std::vector<TElement>   &

could provide the same functionality.



Something like adding the following to the
VectorContainer class:


     typedef std::vector< TElement >  STLContainerType;

     const STLContainerType & GetSTLContainer() const {
       return static_cast<const STLContainerType &>( *this );
       }



With this lines you can now do:


    typedef itk::VectorContainer<
                      unsigned int,
                      double         > VectorContainerType;

    VectorContainerType::Pointer vector = VectorContainerType::New();

    const std::vector<double>  & vectorref = vector->GetSTLContainer();


and now use the "vectorref" as to access the content
of the itk::VectorContainer.


Note that only the "const" access is allowed here. The reason
is that the itk container should maintain the association between
identifiers and elements. This is quite important in the Mesh
class for example since the identifiers to points are supplied
to the cells. Allowing access to the std::vector under the
PointsContainer could facilitate the removal or insertion of a
point and this will corrupt all the identifiers stored in the
Mesh cells.


Do you see use cases in the proposed adaptor that
may not be covered by the casting above ?


Thanks


    Luis


==================================================================

Ofri Sadowsky wrote:

> 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
>>>
> 
> _______________________________________________
> Insight-users mailing list
> Insight-users@public.kitware.com
> http://public.kitware.com/mailman/listinfo/insight-users
> 
>