January 28, 2004
Matthew,

It's interesting how concepts are re-found, refined, enhanced...A couple of years ago I started looking for an STL-compliant iterator over an IEnumXxx.

I found a couple of references on the internet that left much to be desired. Finally, I came accross COM-STL Bridge library from Ray Brown--the page does not exist anymore--from a book published by MS Press.

He had interesting concepts for the iterators _extending_ the original IEnumXxx interface, and was able to provide caching and other concepts with his iterators.  I was not so ambitious in that area, since I just needed something to use with the algorithms.

For the most part, the iterators were what I needed, but they needed a couple of enhancements.  I provided the enhancements and used them extensively in a telephony project.  I tried to publish it with CUJ, too, but they were not interested :-(

I'm including the code for an STL-compliant iterator, that I believe it's a little simpler to use than your approach.  In particular, I do not use a container, but base the iteration on a range.  The end of the iteration is found by using a singular iterator, similar to ostream_iterator.

The usage is as follows:

com_iterator<E, T, C>
---------------------

where:

E - Enumeration interface
T - Enumerated type
C - Iterator category (input or forward)

An example:

typedef com_iterator<IEnumXxx, Xxx> XxxIterator; // input iterator for Xxx ...

XxxIterator first(pEnum);
XxxIterator last;            // singular iterator to mark end of range.

for_each(first, last...);

OR

while(first != last)
  ;

Here's some sample code of how I used it:

// COM iterator support
#include "com_iterator.h"

// Useful typedefs.  Require <tapi3.h>
typedef com_iterator<IEnumAddress, ITAddress, std::forward_iterator_tag>
tapi_address_iterator;
typedef com_iterator<IEnumStream, ITStream, std::forward_iterator_tag>
tapi_stream_iterator;

...


  CComPtr<IEnumAddress> pea;
    // Temporary variable to hold the TAPI address enumerator

  CComPtr<ITAddress> pa;
    // Temporary variable to hold the TAPI address being enumerated

  vector< CComPtr<ITAddress> > tapiAddresses;
    // Temporary vector to hold the tapiAddresses that are associated
    // with my domain criteria

  // Initialize the TAPI address enumerator
  m_pTapi->EnumerateAddresses(&pea);


  // Copy all the TAPI addresses that are associated...
  copy_if(tapi_address_iterator(pea), tapi_address_iterator(),
    back_inserter(tapiAddresses), my_functor_here(...));

I'd be interested in hearing from you, or if you think there's something useful that can be incorporated in STLSoft from the code, I'd be happy to contribute.

You can reach me at:

jestrada*at*developeer*dot*com

Regards,

Javier Estrada

-----------------------------------------
#if !defined INCLUDED_COM_ITERATOR

#define INCLUDED_COM_ITERATOR

#include <comdef.h>

#include <atlbase.h>

#include <iterator>

#include <cassert>

#pragma once

template <typename E, typename T, typename C = std::input_iterator_tag >

class com_iterator : public std::iterator<C, T, ptrdiff_t, T*, T*&>

{

typedef std::iterator<C, T,

ptrdiff_t, T*, T*&> base;

typedef base::iterator_category iterator_category;

typedef base::value_type value_type;

typedef base::reference reference;

typedef base::pointer pointer;

public:

com_iterator() : past_end(true)

{ // Construct a singular iterator

}

com_iterator(const com_iterator &rhs)

{ // Copy constructor

past_end = rhs.past_end;

if (!past_end)

{

// Do I use Clone or add ref?

_copy(rhs.enumerator, iterator_category());

// Increment the ref count on the underlying enumerator...

// enumerator = rhs.enumerator;

// ...and the current value

current = rhs.current;

}

}

explicit com_iterator(E *e):past_end(false)

{ // Constructs from an enumerator

_copy(e, iterator_category());


// enumerator = e;

acquire();

}

com_iterator& operator = (const com_iterator& rhs)

{ // Assignment operator

if (*this == rhs)

return *this;

past_end = rhs.past_end;

if (!past_end)

{

_copy(rhs.enumerator, iterator_category());

// ...and the current value

current = rhs.current;

}

return *this;

}

~com_iterator()

{ // Destructor

}

bool operator == (const com_iterator& rhs) const

{

return _equal(rhs, iterator_category());

}

inline bool operator != (const com_iterator& rhs) const

{ // Invokes operator ==

return !(*this == rhs);

}

reference operator * () const

{ // Return designated value

// Requires IEnumXxx::Next()

assert(!past_end);

return reference(CAdapt< CComPtr<T> >(current));

//return reference(current);

}

pointer operator -> () const

{ // Return designated value

// Requires IEnumXxx::Next()

return pointer(current);

}

com_iterator& operator ++ ()

{ // Pre-increment

acquire();

return *this;

}

com_iterator operator ++ (int)

{ // Post-increment

com_iterator result(*this);

acquire();

return result;

}

private:

void _copy(const CComPtr<E> &e, std::input_iterator_tag)

{

enumerator = e;

}

void _copy(const CComPtr<E> &e, std::forward_iterator_tag)

{

enumerator = 0; // Release if necessary

e->Clone(&enumerator);

}

bool _equal(const com_iterator& rhs, std::input_iterator_tag) const

{ // Two com_iterators compare equal when they're

// past-the-end iterators.

if (past_end && rhs.past_end)

return true;

if (past_end || rhs.past_end)

return false;

if (enumerator != rhs.enumerator)

return false;

return current == rhs.current;

}

bool _equal(const com_iterator& rhs, std::forward_iterator_tag) const

{ // Two com_iterators compare equal when they're

// past-the-end iterators.

if (past_end && rhs.past_end)

return true;

if (past_end || rhs.past_end)

return false;

return current == rhs.current;

}

void acquire()

{ // Reads the iterator value

current = 0; // Release current value

HRESULT hr = enumerator->Next(1, &current, 0);

if (FAILED(hr) || hr == S_FALSE)

{

past_end = true;

}

}

private:

CComPtr<E> enumerator;

// Underlying enumerator

CComPtr<T> current;

// Current value;

bool past_end;

// Maintains past-the-end status

};

#endif // INCLUDED_COM_ITERATOR


January 28, 2004
Hi Javier

I've heard of CSB, but never seen it for the reasons you describe.

If it's ok with you I'll check this out in a week or two, as I'm in the final review stage of my book at the moment. It's quite likely we might look at incorporating some of your techniques. :)

You'll here from me soon.

Cheers

Matthew Wilson

STLSoft moderator
    (http://www.stlsoft.org)
Contributing editor, C/C++ Users Journal
    (www.synesis.com.au/articles.html#columns)

"But if less is more, think how much more more will be!" -- Dr Frazier Crane

----------------------------------------------------------------------------
---

"Javier Estrada" <ljestrada@hotmail.com> wrote in message news:bv98us$1mvn$1@digitaldaemon.com...
> Matthew,
>
> It's interesting how concepts are re-found, refined, enhanced...A couple
of
> years ago I started looking for an STL-compliant iterator over an
IEnumXxx.
>
> I found a couple of references on the internet that left much to be
desired.
> Finally, I came accross COM-STL Bridge library from Ray Brown--the page
does
> not exist anymore--from a book published by MS Press.
>
> He had interesting concepts for the iterators _extending_ the original IEnumXxx interface, and was able to provide caching and other concepts
with
> his iterators.  I was not so ambitious in that area, since I just needed something to use with the algorithms.
>
> For the most part, the iterators were what I needed, but they needed a couple of enhancements.  I provided the enhancements and used them extensively in a telephony project.  I tried to publish it with CUJ, too, but they were not interested :-(
>
> I'm including the code for an STL-compliant iterator, that I believe it's
a
> little simpler to use than your approach.  In particular, I do not use a container, but base the iteration on a range.  The end of the iteration is found by using a singular iterator, similar to ostream_iterator.
>
> The usage is as follows:
>
> com_iterator<E, T, C>
> ---------------------
>
> where:
>
> E - Enumeration interface
> T - Enumerated type
> C - Iterator category (input or forward)
>
> An example:
>
> typedef com_iterator<IEnumXxx, Xxx> XxxIterator; // input iterator for Xxx ...
>
> XxxIterator first(pEnum);
> XxxIterator last;            // singular iterator to mark end of range.
>
> for_each(first, last...);
>
> OR
>
> while(first != last)
>   ;
>
> Here's some sample code of how I used it:
>
> // COM iterator support
> #include "com_iterator.h"
>
> // Useful typedefs.  Require <tapi3.h>
> typedef com_iterator<IEnumAddress, ITAddress, std::forward_iterator_tag>
> tapi_address_iterator;
> typedef com_iterator<IEnumStream, ITStream, std::forward_iterator_tag>
> tapi_stream_iterator;
>
> ...
>
>
>   CComPtr<IEnumAddress> pea;
>     // Temporary variable to hold the TAPI address enumerator
>
>   CComPtr<ITAddress> pa;
>     // Temporary variable to hold the TAPI address being enumerated
>
>   vector< CComPtr<ITAddress> > tapiAddresses;
>     // Temporary vector to hold the tapiAddresses that are associated
>     // with my domain criteria
>
>   // Initialize the TAPI address enumerator
>   m_pTapi->EnumerateAddresses(&pea);
>
>
>   // Copy all the TAPI addresses that are associated...
>   copy_if(tapi_address_iterator(pea), tapi_address_iterator(),
>     back_inserter(tapiAddresses), my_functor_here(...));
>
> I'd be interested in hearing from you, or if you think there's something useful that can be incorporated in STLSoft from the code, I'd be happy to contribute.
>
> You can reach me at:
>
> jestrada*at*developeer*dot*com
>
> Regards,
>
> Javier Estrada
>
> -----------------------------------------
> #if !defined INCLUDED_COM_ITERATOR
>
> #define INCLUDED_COM_ITERATOR
>
> #include <comdef.h>
>
> #include <atlbase.h>
>
> #include <iterator>
>
> #include <cassert>
>
> #pragma once
>
> template <typename E, typename T, typename C = std::input_iterator_tag >
>
> class com_iterator : public std::iterator<C, T, ptrdiff_t, T*, T*&>
>
> {
>
> typedef std::iterator<C, T,
>
> ptrdiff_t, T*, T*&> base;
>
> typedef base::iterator_category iterator_category;
>
> typedef base::value_type value_type;
>
> typedef base::reference reference;
>
> typedef base::pointer pointer;
>
> public:
>
> com_iterator() : past_end(true)
>
> { // Construct a singular iterator
>
> }
>
> com_iterator(const com_iterator &rhs)
>
> { // Copy constructor
>
> past_end = rhs.past_end;
>
> if (!past_end)
>
> {
>
> // Do I use Clone or add ref?
>
> _copy(rhs.enumerator, iterator_category());
>
> // Increment the ref count on the underlying enumerator...
>
> // enumerator = rhs.enumerator;
>
> // ...and the current value
>
> current = rhs.current;
>
> }
>
> }
>
> explicit com_iterator(E *e):past_end(false)
>
> { // Constructs from an enumerator
>
> _copy(e, iterator_category());
>
>
> // enumerator = e;
>
> acquire();
>
> }
>
> com_iterator& operator = (const com_iterator& rhs)
>
> { // Assignment operator
>
> if (*this == rhs)
>
> return *this;
>
> past_end = rhs.past_end;
>
> if (!past_end)
>
> {
>
> _copy(rhs.enumerator, iterator_category());
>
> // ...and the current value
>
> current = rhs.current;
>
> }
>
> return *this;
>
> }
>
> ~com_iterator()
>
> { // Destructor
>
> }
>
> bool operator == (const com_iterator& rhs) const
>
> {
>
> return _equal(rhs, iterator_category());
>
> }
>
> inline bool operator != (const com_iterator& rhs) const
>
> { // Invokes operator ==
>
> return !(*this == rhs);
>
> }
>
> reference operator * () const
>
> { // Return designated value
>
> // Requires IEnumXxx::Next()
>
> assert(!past_end);
>
> return reference(CAdapt< CComPtr<T> >(current));
>
> //return reference(current);
>
> }
>
> pointer operator -> () const
>
> { // Return designated value
>
> // Requires IEnumXxx::Next()
>
> return pointer(current);
>
> }
>
> com_iterator& operator ++ ()
>
> { // Pre-increment
>
> acquire();
>
> return *this;
>
> }
>
> com_iterator operator ++ (int)
>
> { // Post-increment
>
> com_iterator result(*this);
>
> acquire();
>
> return result;
>
> }
>
> private:
>
> void _copy(const CComPtr<E> &e, std::input_iterator_tag)
>
> {
>
> enumerator = e;
>
> }
>
> void _copy(const CComPtr<E> &e, std::forward_iterator_tag)
>
> {
>
> enumerator = 0; // Release if necessary
>
> e->Clone(&enumerator);
>
> }
>
> bool _equal(const com_iterator& rhs, std::input_iterator_tag) const
>
> { // Two com_iterators compare equal when they're
>
> // past-the-end iterators.
>
> if (past_end && rhs.past_end)
>
> return true;
>
> if (past_end || rhs.past_end)
>
> return false;
>
> if (enumerator != rhs.enumerator)
>
> return false;
>
> return current == rhs.current;
>
> }
>
> bool _equal(const com_iterator& rhs, std::forward_iterator_tag) const
>
> { // Two com_iterators compare equal when they're
>
> // past-the-end iterators.
>
> if (past_end && rhs.past_end)
>
> return true;
>
> if (past_end || rhs.past_end)
>
> return false;
>
> return current == rhs.current;
>
> }
>
> void acquire()
>
> { // Reads the iterator value
>
> current = 0; // Release current value
>
> HRESULT hr = enumerator->Next(1, &current, 0);
>
> if (FAILED(hr) || hr == S_FALSE)
>
> {
>
> past_end = true;
>
> }
>
> }
>
> private:
>
> CComPtr<E> enumerator;
>
> // Underlying enumerator
>
> CComPtr<T> current;
>
> // Current value;
>
> bool past_end;
>
> // Maintains past-the-end status
>
> };
>
> #endif // INCLUDED_COM_ITERATOR
>
>