Click here to Skip to main content
15,878,959 members
Articles / Desktop Programming / MFC

How to wrap an MFC collection into an STL compliant iterator with the Boost iterator_facade

Rate me:
Please Sign up or sign in to vote.
4.56/5 (22 votes)
20 Oct 2008CPOL5 min read 55.5K   502   34  
How to wrap an MFC collection into an STL compliant iterator with the Boost iterator_facade.
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2008  
// 
// The following code is supplied "as-is" and 
// is given without warranty of any kind. 
// It may be freely distributed and used. 
// The user holds author blameless from any complications or 
// problems that may arise from the use of this code.
// 
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//  $Workfile: $   created: 04/05/2008 11:52
////////////////////////////////////////////////////////////////////////////////
//  $Revision: $  $Modtime: $
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Author: steveb
//
// History:
//
////////////////////////////////////////////////////////////////////////////////

#pragma once 
#include < boost/iterator/iterator_facade.hpp >

/*


//
// Iterator skeleton 
//
template < typename _Type >
class mfc_iterator : 
   public boost::iterator_facade < mfc_iterator, _Type, boost::forward_traversal_tag 
    // boost::bidirectional_traversal_tag  
   >
{
public:
   ///////////////////////////////////////////////
   /// TODO: Write begin code logic here
   ///////////////////////////////////////////////
   mfc_iterator & begin()
   {
      //....
      return *this;
   }

   ///////////////////////////////////////////////
   /// just call default private contructor.
   /// end is a state when everything in this iterator is set to NULL
   /// or whatever variables values you choose for that
   ///////////////////////////////////////////////
   mfc_iterator end()
   {
      return mfc_iterator ();
   }

private:
   friend class boost::iterator_core_access;

   ///////////////////////////////////////////////
   /// TODO: Write end() constructor here. See end()
   ///////////////////////////////////////////////
   mfc_iterator ():m_node(0)
   {}

   ///////////////////////////////////////////////
   /// TODO: Write increment code here 
   ///////////////////////////////////////////////
   void increment() 
   {
      //....
   }

   ///////////////////////////////////////////////
   /// TODO: Write decrement code here 
   ///////////////////////////////////////////////
   void decrement() 
   {
      //....
   }

   ///////////////////////////////////////////////
   /// TODO white compare criteria here
   ///////////////////////////////////////////////
   bool equal(mfc_cview_iterator const & other) const
   {
      //....
   }

   ///////////////////////////////////////////////
   /// 
   ///////////////////////////////////////////////
   _Type& dereference() const 
   { 
      return *m_node; 
   }

   _Type* m_node;
};

*/

template < typename _Type, typename _Tcontainer = CArray<_Type>>
class mfc_carray_iterator : 
   public boost::iterator_facade < mfc_carray_iterator < _Type, _Tcontainer >,   _Type, boost::bidirectional_traversal_tag >
{
   _Type    m_node;      // element type
   _Tcontainer* m_pCont; // Pointer to underlying CArray container 
   INT_PTR  m_nIndex;    // current CArray index

public:
   ///////////////////////////////////////////////
   ///
   ///////////////////////////////////////////////
   explicit mfc_carray_iterator(_Tcontainer* pCont)
      : m_node(0)
      , m_nIndex(0)
      , m_pCont(pCont)
   {}

   ///////////////////////////////////////////////
   /// Point to first element in CArray
   ///////////////////////////////////////////////
   mfc_carray_iterator& begin()
   {
      m_nIndex = 0;
      if(m_pCont->GetSize() == 0) // safety checks
         *this = end();
      else
         m_node = m_pCont->GetAt(m_nIndex);

      return *this;
   }

   ///////////////////////////////////////////////
   /// just call private conrtuctor
   ///////////////////////////////////////////////
   mfc_carray_iterator end()
   {
      return mfc_carray_iterator();
   }

private:
   friend class boost::iterator_core_access;

   ///////////////////////////////////////////////
   /// constructs end()
   ///////////////////////////////////////////////
   mfc_carray_iterator(): 
   m_node(0)
      , m_nIndex(0)
      , m_pCont(0)
   {
   }

   ///////////////////////////////////////////////
   /// Increment CArray
   ///////////////////////////////////////////////
   void increment() 
   {
      // CArray specific increment code
      m_nIndex++;
      if(m_nIndex >= m_pCont->GetSize())// safety checks
      {
         *this = end();
         return;
      }
      m_node = m_pCont->GetAt(m_nIndex);
   }

   ///////////////////////////////////////////////
   /// Decrement CArray
   ///////////////////////////////////////////////
   void decrement()
   {
      // CArray specific decrement code
      m_nIndex--;
      if(m_nIndex >= m_pCont->GetSize()) // safety checks
         return;

      m_node = m_pCont->GetAt(m_nIndex);
   }

   ///////////////////////////////////////////////
   /// 
   ///////////////////////////////////////////////
   bool equal(mfc_carray_iterator const& other) const
   {
      return m_pCont == other.m_pCont && m_node == other.m_node && m_nIndex == other.m_nIndex;
   }

   _Type& dereference() const 
   { 
      return (_Type&) m_node; 
   }    
};


//
// CList iterator
//
#include < boost/iterator/iterator_facade.hpp >

template < typename _Type, typename _Tcontainer = CList<_Type> >
class mfc_clist_iterator : 
   public boost::iterator_facade < mfc_clist_iterator < _Type, _Tcontainer >, _Type, boost::bidirectional_traversal_tag >
{
   _Type    m_node;      // element type
   _Tcontainer* m_pCont; // Pointer to underlying CList container 
   POSITION  m_pos;    // current CList position

public:
   ///////////////////////////////////////////////
   ///
   ///////////////////////////////////////////////
   explicit mfc_clist_iterator(_Tcontainer* pCont)
      : m_node(0)
      , m_pos(0)
      , m_pCont(pCont)
   {}

   ///////////////////////////////////////////////
   /// Point to first element in CList
   ///////////////////////////////////////////////
   mfc_clist_iterator& begin()
   {
      m_pos = m_pCont->GetHeadPosition();

      if(m_pos == 0) // safety checks
         *this = end();
      else
         m_node = m_pCont->GetNext(m_pos);
      return *this;
   }

   ///////////////////////////////////////////////
   /// just call private constructor
   ///////////////////////////////////////////////
   mfc_clist_iterator end()
   {
      return mfc_clist_iterator();
   }

private:
   friend class boost::iterator_core_access;

   ///////////////////////////////////////////////
   /// constructs end()
   ///////////////////////////////////////////////
   mfc_clist_iterator(): 
   m_node(0)
      , m_pos(0)
      , m_pCont(0)
   {
   }

   ///////////////////////////////////////////////
   /// Increment CList
   ///////////////////////////////////////////////
   void increment() 
   {
      if(m_pos == NULL)// safety checks
      {
         *this = end();
         return;
      }

      m_node = m_pCont->GetNext(m_pos);
   }

   ///////////////////////////////////////////////
   /// Decrement CList
   ///////////////////////////////////////////////
   void decrement()
   {
      if(m_pos == NULL)// safety checks
      {
         *this = end();
         return;
      }

      m_node = m_pCont->GetPrev(m_pos);
   }

   ///////////////////////////////////////////////
   /// 
   ///////////////////////////////////////////////
   bool equal(mfc_clist_iterator const & other) const
   {
      return m_pCont == other.m_pCont && m_node == other.m_node && m_pos == other.m_pos;
   }

   _Type& dereference() const 
   { 
      return (_Type&)m_node; 
   }

};

#include < boost/iterator/iterator_facade.hpp >

// CView 
class mfc_cview_iterator : 
   public boost::iterator_facade< mfc_cview_iterator, CView, boost::forward_traversal_tag >
{
   CView* m_node;
   POSITION m_pos;
   CDocument* m_pDoc;

public:
   ///////////////////////////////////////////////
   ///
   ///////////////////////////////////////////////
   explicit mfc_cview_iterator(CDocument* pDoc)
      : m_node(0)
      , m_pos(0)
      , m_pDoc(pDoc)
   {}

   ///////////////////////////////////////////////
   ///
   ///////////////////////////////////////////////
   mfc_cview_iterator& begin()
   {
      m_pos = m_pDoc->GetFirstViewPosition();
      m_node = m_pDoc->GetNextView(m_pos);
      return *this;
   }

   ///////////////////////////////////////////////
   ///
   ///////////////////////////////////////////////
   mfc_cview_iterator end()
   {
      return mfc_cview_iterator();
   }

private:
   friend class boost::iterator_core_access;

   ///////////////////////////////////////////////
   /// for end()
   ///////////////////////////////////////////////
   mfc_cview_iterator()
      : m_node(0)
      , m_pos(0)
      , m_pDoc(0)
   {}

   ///////////////////////////////////////////////
   ///
   ///////////////////////////////////////////////
   void increment() 
   {
      if(m_node == 0)
      {
         m_pos = m_pDoc->GetFirstViewPosition();
         m_node = m_pDoc->GetNextView(m_pos);
      }
      else
         m_node = m_pDoc->GetNextView(m_pos);
   }

   ///////////////////////////////////////////////
   ///
   ///////////////////////////////////////////////
   bool equal(mfc_cview_iterator const& other) const
   {
      return this->m_node == other.m_node;
   }

   ///////////////////////////////////////////////
   ///
   ///////////////////////////////////////////////
   CView& dereference() const 
   { 
      return *m_node; 
   }

};


// CDocTemplate
class mfc_doc_templ_iterator : 
   public boost::iterator_facade< mfc_doc_templ_iterator, CDocTemplate, boost::forward_traversal_tag >
{
   CDocTemplate* m_node;
   POSITION m_pos;
   CWinApp* m_pApp;

public:
   ///////////////////////////////////////////////
   ///
   ///////////////////////////////////////////////
   explicit mfc_doc_templ_iterator(CWinApp* pApp)
      : m_node(0)
      , m_pos(0)
      , m_pApp(pApp)
   {}

   ///////////////////////////////////////////////
   ///
   ///////////////////////////////////////////////
   mfc_doc_templ_iterator& begin()
   {
      m_pos = m_pApp->GetFirstDocTemplatePosition();
      m_node = m_pApp->GetNextDocTemplate(m_pos);
      return *this;
   }

   ///////////////////////////////////////////////
   ///
   ///////////////////////////////////////////////
   mfc_doc_templ_iterator end()
   {
      return mfc_doc_templ_iterator();
   }

   CDocTemplate* operator*()
   {
      return m_node;
   }
   CDocTemplate* operator->()
   {
      return m_node;
   }

private:
   friend class boost::iterator_core_access;

   ///////////////////////////////////////////////
   /// for end()
   ///////////////////////////////////////////////
   mfc_doc_templ_iterator()
      : m_node(0)
      , m_pos(0)
      , m_pApp(0)
   {}

   ///////////////////////////////////////////////
   ///
   ///////////////////////////////////////////////
   void increment() 
   {
      if(m_pos == 0)
      {
         *this = end();
         return;
      }
      else
         m_node = m_pApp->GetNextDocTemplate(m_pos);
   }

   ///////////////////////////////////////////////
   ///
   ///////////////////////////////////////////////
   bool equal(mfc_doc_templ_iterator const& other) const
   {
      return this->m_node == other.m_node;
   }

   ///////////////////////////////////////////////
   ///
   ///////////////////////////////////////////////
   CDocTemplate& dereference() const 
   { 
      return *m_node; 
   }
};


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Robotz Software
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions