/*
 *
 * This file and its contents are the property of The MathWorks, Inc.
 * 
 * This file contains confidential proprietary information.
 * The reproduction, distribution, utilization or the communication
 * of this file or any part thereof is strictly prohibited.
 * Offenders will be held liable for the payment of damages.
 *
 * Copyright 1999-2012 The MathWorks, Inc.
 *
 */
#ifndef PST_STL_ITERATOR
#define PST_STL_ITERATOR

#include <iosfwd>

// macros undefined at the end of the file
#define REQUIRE(e) assert(e)

#ifdef PST_VISUAL
#pragma pack(push,8)
#endif

// For iterator, reverse_iterator and other iterator types which 
// are not related to streams.
#include <__polyspace__iterator.h>
#include <iostream>

namespace std {

  // 24.3, primitives: moved to __polyspace__iterator.h
  // struct iterator_traits<Iterator>
  // struct iterator<Category, T, Distance, Pointer, Reference>

  // 24.3.4, iterator operations: moved to __polyspace__iterator.

  // 24.4, predefined iterators: moved to __polyspace__iterator.h
  // class reverse_iterator<Iterator>
  // class reverse_bidirectional_iterator<bid_it, T, Reference, Pointer, Diff>
  // class back_insert_iterator<Container>
  // class front_insert_iterator<Container>
  // class insert_iterator<Container>

  // 24.5 : stream iterators
  
  template <class T, class charT=char, class traits = char_traits<charT>,
	    class Distance = ptrdiff_t>
  class istream_iterator : public iterator<input_iterator_tag, T, Distance, const T*, const T&>
  {
  public:
    
    typedef charT char_type ;
    typedef traits traits_type ;
    typedef basic_istream<charT, traits> istream_type ;

    istream_iterator() { in_stream = 0 ; }
    istream_iterator(istream_type& in ) { in_stream = &in ; (*in_stream) >> value ;  }
    
    // use default copy ctor

    ~istream_iterator() { ; }
    
    const T& operator*() const { return value ; }
    const T* operator->() const { return &value ; }

    istream_iterator& operator++()
    {
      if (in_stream)
      {
	(*in_stream) >> value ;
      }
      return *this ;
    }

    istream_iterator operator++(int)
    {
      if (in_stream)
      {
	(*in_stream) >> value ;
      }
      return *this ;
    }

    /* friends */

  template <class T2, class charT2, class traits2, class Distance2>
  friend __ps_bool operator==(const istream_iterator<T2, charT2, traits2, Distance2>& i1, 
			 const istream_iterator<T2, charT2, traits2, Distance2>& i2) ;

  template <class T2, class charT2, class traits2, class Distance2>
  friend __ps_bool operator!=(const istream_iterator<T2, charT2, traits2, Distance2>& i1, 
			 const istream_iterator<T2, charT2, traits2, Distance2>& i2) ;


private:
    istream_type* in_stream ;
    T value ;
  } ;

  template <class T, class charT, class traits, class Distance>
  __ps_bool operator==(const istream_iterator<T, charT, traits, Distance>& i1, 
		  const istream_iterator<T, charT, traits, Distance>& i2)
  {
    return i1.in_stream == i2.in_stream ;
  }

  template <class T, class charT, class traits, class Distance>
  __ps_bool operator!=(const istream_iterator<T, charT, traits, Distance>& i1, 
		  const istream_iterator<T, charT, traits, Distance>& i2)
  {
    return !(i1.in_stream == i2.in_stream) ;
  }


  template <class T, class charT=char, class traits = char_traits<charT> >
  class ostream_iterator : public iterator<output_iterator_tag, void, void, void, void>
  {
  public:

#ifdef PST_VISUAL
    // Visual 6
#if _MSC_VER <= 1200
    typedef T value_type ;
#endif
#endif
    
    typedef charT char_type ;
    typedef traits traits_type ;
    typedef basic_ostream<charT, traits> ostream_type ;

    ostream_iterator(ostream_type& out ) : out_stream(out) { delim = 0 ; }
    ostream_iterator(ostream_type& out, const charT* d ) : out_stream(out) { delim = d ; }
    
    // use default copy ctor

    ~ostream_iterator() { ; }
    
    ostream_iterator& operator=(const T& value) 
    { 
      out_stream << value ;
      if (delim != 0) out_stream << delim ;
      return *this ;
    } 

    ostream_iterator& operator*() { return *this ; }
    ostream_iterator& operator++() { return *this ; }
    ostream_iterator& operator++(int) { return *this ; }

  private:
    
    ostream_type& out_stream ;
    const charT *delim ;
  } ;


  // implementation choice : do not use a proxy calss, rather store the current value of the stream
  // DRe : Rem : iosfwd declare default arg

// We need a full definition for the class basic_streambuf but we must not
// include streambuf before the class iterator is defined. Otherwise, a cyclic
// dependency will cause the compilation to fail.
#include <streambuf>

  template <class charT, class traits >
  class istreambuf_iterator : public iterator<input_iterator_tag, charT, __ps_typename traits::off_type, charT*, charT&>
  {
  public:
    typedef charT                          char_type ;
    typedef traits                         traits_type ;
    typedef __ps_typename traits::int_type      int_type ;
    typedef basic_streambuf<charT, traits> streambuf_type ;
    typedef basic_istream<charT, traits>   istream_type ;

    istreambuf_iterator() throw() { sbuf = 0 ; }
    istreambuf_iterator(streambuf_type* s) throw() 
    { 
      sbuf = s ; 
      if (sbuf != 0) value = sbuf->sgetc() ;
    }
    istreambuf_iterator(istream_type&  in) throw() 
    { 
      sbuf = in.rdbuf() ; 
      if (sbuf != 0) value = sbuf->sgetc() ;      
    }

    charT operator*() const { return traits::to_char_type(value); }

    istreambuf_iterator& operator++()
    {
      sbuf->sbumpc() ;
      value = sbuf->sgetc() ;
      if (traits::eq_int_type(value, traits::eof())) { sbuf = 0 ; }
      return *this ;
    }

    istreambuf_iterator operator++(int)
    { 
      istreambuf_iterator ret = *this ;
      
      sbuf->sbumpc() ;
      value = sbuf->sgetc() ;
      if (traits::eq_int_type(value, traits::eof())) { sbuf = 0 ; }
      
      return ret ;
      
    }

    __ps_bool equal(istreambuf_iterator& b ) const /* PST : const seems OK */
    {
      return (b.sbuf==0) ? (sbuf==0)  : (sbuf!=0) ;
    }
    
    template <class charT2, class traits2>
    friend __ps_bool operator==(const istreambuf_iterator<charT2, traits2>& i1, 
                           const istreambuf_iterator<charT2, traits2>& i2);

    template <class charT2, class traits2>
    friend __ps_bool operator!=(const istreambuf_iterator<charT2, traits2>& i1, 
                           const istreambuf_iterator<charT2, traits2>& i2);
    
  private:
    streambuf_type* sbuf ;
    int_type        value ;
  } ;

  template <class charT, class traits>
  __ps_bool operator==(const istreambuf_iterator<charT, traits>& i1,
                  const istreambuf_iterator<charT, traits>& i2)
  {
    return (i1.sbuf==0) ? (i2.sbuf==0) : (i2.sbuf!=0) ;
  }

  template <class charT, class traits>
  __ps_bool operator!=(const istreambuf_iterator<charT, traits>& i1,
                  const istreambuf_iterator<charT, traits>& i2)
  {
    return (i1.sbuf!=0) ? (i2.sbuf==0) : (i2.sbuf!=0) ;
  }

  // DRe : Rem : iosfwd declare default arg

  template <class charT, class traits >
  class ostreambuf_iterator : public iterator<output_iterator_tag, void, void, void, void>
  {
  public:    
    typedef charT                          char_type ;
    typedef traits                         traits_type ;
    typedef basic_streambuf<charT, traits> streambuf_type ;
    typedef basic_ostream<charT, traits>   ostream_type ;

    ostreambuf_iterator(ostream_type& s) throw() { sbuf = s.rdbuf() ; bad_status = __ps_false ; }
    ostreambuf_iterator(streambuf_type *s) throw() { sbuf = s ; bad_status = __ps_false ; }
    ostreambuf_iterator& operator=(charT c) 
    {
      if (!bad_status)
      {
	int_type ret = sbuf->sputc(c) ;
	bad_status = traits::eq_int_type(ret, traits::eof()) ;
      }
      
      return *this ;
    }
    
    __ps_bool failed() const throw() 
    {
      return bad_status ;
    }
    
    ostreambuf_iterator& operator*() { return *this ; }
    ostreambuf_iterator& operator++() { return *this ; }
    ostreambuf_iterator& operator++(int) { return *this ; }
    
    private:
      typedef __ps_typename traits::int_type      int_type ;
      streambuf_type* sbuf ;
      __ps_bool bad_status ;    
  } ;

} /* namespace std */

#ifdef __PST_IMPLICIT_USING_STD
/* Implicitly include a using directive for the STD namespace when this
   preprocessing flag is TRUE. */
using namespace std;
#endif /* ifdef __PST_IMPLICIT_USING_STD */

#ifdef PST_VISUAL
#pragma pack(pop)
#endif

#endif /* PST_STL_ITERATOR */
