Boost logo

Boost :

Subject: Re: [boost] [iterators] Proof-of-concept for a sentinel iterator adapter
From: Simonson, Lucanus J (lucanus.j.simonson_at_[hidden])
Date: 2009-05-13 12:38:42


Thorsten Ottosen wrote:
> joaquin_at_[hidden] skrev:
>> Beman Dawes escribió:
>>> Attached is proof-of-concept code for a sentinel iterator adapter.
>>> It turns a pointer to sentinel terminated sequence, such as a
>>> C-style string, into a forward iterator with a conforming end
>>> iterator.
>>>
>>
>> Having Sentinel specified as a non-type template parameter greatly
>> reduces the category of types this can work with. I'd replace it
>> with some SentinelFactory policy or something.
>
> That is not a bad idea, although it would really be good if
> the basic case can stay as optimaized as currently
> (having a static member). I guess having a static member is
> not an option for a general policy, thus giving us the usual
> iterator problem of double storage.
>
I don't understand the rationale for m_sentinel. Couldn't the code refer to Sentinel directly as a compile time constant as opposed to a static member variable? It seems like Beman had two different things in mind. What he seems to want is for the 2nd template parameter of sentinel_iterator to be something that can cast to T or T itself and default to default constructed T. The code below seems to work...

Regards,
Luke

#include <cassert>

  // sentinel terminated sequence iterator

  template < class T, typename Sentinel = T >
  class sentinel_iterator
  {
  public:
    sentinel_iterator() : m_ptr(0) {} // construct end iterator

    sentinel_iterator( T * p ) : m_ptr( (p && *p != Sentinel()) ? p : 0 ) {}

    sentinel_iterator & operator++()
    {
      assert(m_ptr);
      if ( *++m_ptr == Sentinel() ) m_ptr = 0;
      return *this;
    }

    T & operator*() const
    {
      assert(m_ptr);
      return *m_ptr;
    }

    bool operator==( const sentinel_iterator & rhs ) const
    {
      return m_ptr == rhs.m_ptr;
    }

    bool operator!=( const sentinel_iterator & rhs ) const
    {
      return m_ptr != rhs.m_ptr;
    }

  private:
    T * m_ptr; // 0 == the end iterator
    //static const T m_sentinel = Sentinel();
  };

struct s_val {
        operator int () const { return -1; }
};
int main()
{
  // test cases using default sentinel

  sentinel_iterator<char> it( "abc" );

  assert( it != sentinel_iterator<char>() );
  assert( *it == 'a' );
  assert( *++it == 'b' );
  assert( *++it == 'c' );
  assert( ++it == sentinel_iterator<char>() );

  sentinel_iterator<char> it2( "" );
  assert( it2 == sentinel_iterator<char>() );

  sentinel_iterator<char> it3( 0 );
  assert( it3 == sentinel_iterator<char>() );

  // test cases using non-default sentinel

  typedef sentinel_iterator<unsigned, s_val> my_iter_type;

  unsigned data[] = { 0, 1, -1 };
  my_iter_type my_it( data );

  assert( my_it != my_iter_type() );
  assert( *my_it == 0 );
  assert( *++my_it == 1 );
  assert( ++my_it == my_iter_type() );

  unsigned my_sentinel = -1;
  my_iter_type my_it2( &my_sentinel );
  assert( my_it2 == my_iter_type() );

  my_iter_type my_it3( 0 );
  assert( my_it3 == my_iter_type() );
  return 0;
}


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