Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members

deque.h

Go to the documentation of this file.
00001 // deque.h      (C) 2006 [email protected]
00002 
00010 #include <exception> // std::length_error && std::bad_alloc
00011 #include <iostream>  // cin && cout
00012 
00013 // using namespace std;
00015 namespace std {} // Está acá para que Doxygen lo documente
00016 
00017 template <class T> class test_deque;
00018 
00026 template <class T>
00027 class deque {
00028 public:
00029     typedef typename T    value_type; 
00030     typedef typename T *  pointer;    
00031     typedef typename T &  reference;  
00032 
00033     typedef typename const value_type const_value_type; 
00034     typedef typename const T *        const_pointer; 
00035     typedef typename const T &        const_reference; 
00036 
00037     typedef typename unsigned size_type;  
00038 
00040     deque( size_type N );
00041     ~deque() { if (m_vec != 0) { delete [] m_vec; } } 
00042 
00044     bool empty() const { return (size() == 0); }
00045 
00047     size_type size()     const { return m_size; }     
00049     size_type capacity() const { return m_capacity; }
00050 
00055     value_type& front() { return at_check(m_front); }
00056 
00061     const value_type& front() const { return const_cast<deque*>(this)->front(); }
00062     // const_cast<deque*>(this) hace que "this" ya NO sea un puntero "const".
00063 
00068     value_type& back() { return at_check(m_front+m_size-1); }
00069 
00074     const value_type& back() const { return const_cast<deque*>(this)->back(); }
00075 
00078     value_type& operator[](size_type i) {
00079         size_type  i_real = m_front + i;
00080         i_real = ( i_real < m_capacity ? i_real : i_real - m_capacity );
00081         return m_vec[ i_real ]; // uso "+" y "-" que es más eficiente que "%"
00082     }
00085     value_type& operator[](size_type i) const { return const_cast<deque*>(this)->operator[](i); }
00086 
00089     value_type& at(size_type i)       { return at_check(m_front+i); }
00092     value_type& at(size_type i) const { return const_cast<deque*>(this)->at(i); }
00093 
00094     void push_front( const value_type& val );
00095     void push_back(  const value_type& val );
00096     void pop_front();
00097     void pop_back();
00098 
00099     template <class T> friend std::istream& operator>>( std::istream& CIN,        deque<T>& Q);
00100     template <class T> friend std::ostream& operator<<( std::ostream& COUT, const deque<T>& Q);
00101 private:
00102     bool ok() const;
00103     inline friend bool check_ok( const deque<T>& Q) { return Q.ok(); }
00104     value_type& at_check(size_type i);
00105     explicit deque(const deque&); 
00106 
00107     template <class T> friend class test_deque; 
00108 private:
00109     unsigned     m_front;    
00110     unsigned     m_size;     
00111     unsigned     m_capacity; 
00112     value_type * m_vec;      
00113 };
00114 
00115 template <class T>
00116 deque<T>::deque( size_type N ) : m_front(0), m_size(0), m_capacity(0), m_vec(0) {
00117     if (N == 0) {
00118         throw std::length_error("deque<T>::deque(0)");
00119     }
00120     else {
00121         try {
00122             m_capacity = N;
00123             m_vec = new value_type [ m_capacity ];
00124         }
00125         catch (std::bad_alloc) {
00126             throw; // new[] tira std::bad_alloc si ya no hay memoria
00127         }
00128     }
00129 }
00130 
00154 template <class T>
00155 T& deque<T>::at_check(size_type i) {
00156     // uso "+" y "-" que es más eficiente que "%"
00157     size_type i_real = ( i < m_capacity ? i : i - m_capacity );
00158     if ( (m_front <= i) && (i < m_front + m_size) ) {
00159         return m_vec[i_real];
00160     }
00161     else {
00162         throw std::out_of_range("deque<T>::at()");
00163     }
00164 }
00165 
00170 template <class T>
00171 void deque<T>::push_back(const value_type& val) {
00172     if (m_size < m_capacity) {
00173         size_type i_real = m_front + m_size;
00174         i_real = (i_real < m_capacity ? i_real : i_real - m_capacity);
00175         m_vec[i_real] = val;
00176         m_size++;
00177     }
00178     else {
00179         throw std::out_of_range("deque<T>::push_back()");
00180     }
00181 }
00182 
00187 template <class T>
00188 void deque<T>::push_front(const value_type& val) {
00189     if (m_size < m_capacity) {
00190         m_front = ( m_front>0 ? m_front-1 : m_capacity-1 );
00191         m_vec[m_front] = val;
00192         m_size++;
00193     }
00194     else {
00195         throw std::out_of_range("deque<T>::push_front()");
00196     }
00197 }
00202 template <class T>
00203 inline void deque<T>::pop_front() {
00204     if (m_size > 0) {
00205     //  unsigned temp = m_front;
00206         m_front++;
00207         m_size--;
00208         if (m_front >= m_capacity) {
00209             m_front = 0;
00210         }
00211     //  return m_vec[temp];
00212     }
00213     else {
00214         throw std::out_of_range("deque<T>::pop_front()");
00215     }
00216 }
00217 
00222 template <class T>
00223 inline void deque<T>::pop_back() {
00224     if (m_size > 0) {
00225         m_size--;
00226     }
00227     else {
00228         throw std::out_of_range("deque<T>::pop_front()");
00229     }
00230 }
00231 
00232 #if 0
00233 
00234     template <class T>
00235     inline bool deque<T>::full() const {
00236         return (m_size == m_ capacity);
00237     }
00238 #endif
00239 
00289 template <class T>
00290 bool check_ok( const deque<T>& Q);
00291 
00308 template <class T>
00309 bool deque<T>::ok() const {
00310     if (this == 0) {
00312         return false;
00313     }
00314 
00315     if ( ! (m_capacity > 0) ) {
00317         return false;
00318     }
00319     if ( ! (m_front < m_capacity) ) {
00321         return false;
00322     }
00323     if ( ! (m_size <= m_capacity) ) {
00325         return false;
00326     }
00327     if ( ! (size() <= m_capacity) ) {
00329         return false;
00330     }
00331     if ( ! (m_vec != 0) ) {
00333         return false;
00334     }
00335 
00336     // Declaración previa del verificador del objeto contenido
00337     // - Con este se le quita trabajo al programador cliente de la clase
00338     //   pues deberá implementar \c check_ok( const T& ) sólo en el caso
00339     //   de que utilice \c check_ok() para \c deque<T> .
00340     // - En otras palabras: el programador cliente está obligado a implementar
00341     //   este método sólo si invoca \c check_ok( const deque<T>& ).
00342     // - Por eso es preferible que \c check_ok() sea una función y no un método.
00343     bool check_ok( const deque<T>::value_type & );
00344 
00345     for (unsigned i=0; i<m_capacity; ++i) {
00346         if ( ! check_ok( m_vec[i] ) ) {
00349             return false;
00350         }
00351     }
00352     return true;
00353 /*  NOTA: VC++ v7 .net
00354     La documentación del compilador pide que check_ok( const deque<T>& ) sea declarado
00355     dentro de la plantilla deque<T> como una función "friend" de la siguiente forma:
00356         template <class T> friend bool check_ok( const deque<T>& Q);
00357 
00358     Desafortunadamente, el compilador produce un error interno si check_ok() es una
00359     función. Por eso, en esta implementación se usa el método deque<T>::ok(), el que
00360     sí es aceptado por el compilador. Para evitar una pequeña degradación en la
00361     eficiencia, la función check_ok() queda definida dentro de la clase como una
00362     función "inline", que el compilador compila sin dar problemas.
00363 
00364     A primera vista parece inocuo exigir que quien use deque<T> esté obligado a 
00365     implementar el método T::ok(), pero en la práctica eso es contraproducente por
00366     2 razones:
00367     - Algunos "tipos" en C++ no son clases, como "int" o "float", por lo que no
00368       es posible definirles su método ok().
00369     - Para un programador cliente es incómodo agregar un método que no piensa usar
00370       Por eso, si el programador cliente invoca check_ok( const deque<T>& ) deberá
00371       implementar check_ok( const T& ), pero de otra forma ni siquiera tiene que
00372       enterarse de que check_ok() existe.
00373 */
00374 }
00375 
00376 // EOF: deque.h

Generated on Tue Aug 21 16:47:52 2007 by  doxygen 1.4.1
Hosted by www.Geocities.ws

1