00001 // deque.h (C) 2006 [email protected] 00002 00003 /** \file deque.h 00004 \brief Vector extendible a ambos lados, almacenado en un vector circular. 00005 00006 \author Adolfo Di Mare <[email protected]> 00007 \date 2006 00008 */ 00009 00010 #include <exception> // std::length_error && std::bad_alloc 00011 #include <iostream> // cin && cout 00012 00013 // using namespace std; 00014 /// Definido por la biblioteca C++ estándar. 00015 namespace std {} // Está acá para que Doxygen lo documente 00016 00017 template <class T> class test_deque; 00018 00019 /** Vector extendible a ambos lados, almacenado en un vector circular. 00020 - Es posible agregar valores al principio o al final del vector extendible. 00021 - El tamaño del vector extendible no puede cambiar, pues se establece en el 00022 constructor. 00023 00024 - Why English names??? ==> http://www.di-mare.com/adolfo/binder/c01.htm#sc04 00025 */ 00026 template <class T> 00027 class deque { 00028 public: 00029 typedef typename T value_type; ///< Nombre estándar del objeto contenido 00030 typedef typename T * pointer; ///< Nombre estándar del puntero al objeto contenido 00031 typedef typename T & reference; ///< Nombre estándar de la referencia al objeto contenido 00032 00033 typedef typename const value_type const_value_type; ///< Nombre estándar del objeto contenido \c const 00034 typedef typename const T * const_pointer; ///< Nombre estándar del puntero al objeto contenido \c const 00035 typedef typename const T & const_reference; ///< Nombre estándar de la referencia al objeto contenido \c const 00036 00037 typedef typename unsigned size_type; ///< Nombre estándar del tipo retornado por \c size() 00038 00039 /// Constructor: Vector extendible con capacidad para almacenar \c "N" valores 00040 deque( size_type N ); 00041 ~deque() { if (m_vec != 0) { delete [] m_vec; } } ///< Destructor 00042 00043 /// Retorna \c "true" si el vector extendible está vacía 00044 bool empty() const { return (size() == 0); } 00045 00046 /// Cantidad de valores almacenados en el vector extendible. 00047 size_type size() const { return m_size; } 00048 /// Cantidad máxima de valores que se pueden almacenar en el vector extendible. 00049 size_type capacity() const { return m_capacity; } 00050 00051 /// Retorna una referencia al primer valor del vector extendible. 00052 /// - El primero valor es el que está "al frente" en el vector extendible. 00053 /// \pre \c !empty() 00054 /// \see test_deque<T>::test_front() 00055 value_type& front() { return at_check(m_front); } 00056 00057 /// Retorna una referencia constante al primer valor del vector extendible. 00058 /// - El primero valor es el que está "al frente" en el vector extendible. 00059 /// \pre \c !empty() 00060 /// \see test_deque<T>::test_front_const() 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 00064 /// Retorna una referencia al último valor del vector extendible. 00065 /// - El úlimo valor es el que está "al final" en el vector extendible. 00066 /// \pre \c !empty() 00067 /// \see test_deque<T>::test_back() 00068 value_type& back() { return at_check(m_front+m_size-1); } 00069 00070 /// Retorna una referencia constante al último valor del vector extendible. 00071 /// - El úlimo valor es el que está "al final" en el vector extendible. 00072 /// \pre \c !empty() 00073 /// \see test_deque<T>::test_back_const() 00074 const value_type& back() const { return const_cast<deque*>(this)->back(); } 00075 00076 /// Acceso al \c "i"-ésimo valor almacenado en el contenedor. 00077 /// - No levanta ninguna excepción si \c "i" está fuera del rango válido. 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 } 00083 /// Acceso al \c "i"-ésimo valor almacenado en el contenedor ( \c const ). 00084 /// - No levanta ninguna excepción si \c "i" está fuera del rango válido. 00085 value_type& operator[](size_type i) const { return const_cast<deque*>(this)->operator[](i); } 00086 00087 /// Acceso al \c "i"-ésimo valor almacenado en el contenedor. 00088 /// - Levanta la excepción \c std::out_of_range si \c "i" está fuera del rango válido. 00089 value_type& at(size_type i) { return at_check(m_front+i); } 00090 /// Acceso al \c "i"-ésimo valor almacenado en el contenedor ( \c const ). 00091 /// - Levanta la excepción \c std::out_of_range si \c "i" está fuera del rango válido. 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&); ///< \c "private" evita que el objeto sea copiado 00106 00107 template <class T> friend class test_deque; ///< Datos de prueba para la clase 00108 private: 00109 unsigned m_front; ///< Indice del primero del vector extendible. 00110 unsigned m_size; ///< Cantidad de valores almacenados en el vector extendible (puede ser cero). 00111 unsigned m_capacity; ///< Cantidad máxima de valores que pueden estar almacenados en el vector extendible. 00112 value_type * m_vec; ///< Bloque de memoria para para almacenar los \c m_capacity valores que caben en el vector extendible. 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 00131 /** Acceso al \c "i"-ésimo valor del vector extendible. 00132 - Si <code>(i=>m_capacity)</code> retorna el valor \c m_vec[i-m_capacity]. 00133 - Verifica que el valor de \c "i" esté en el rango válido. 00134 - Está implementado de manera que el índice de \c at(m_front+m_size-1) 00135 siempre esté en el rango válido. 00136 - Funciona como si los índices que están a partir de \c m_capacity estuvieran en un 00137 vector, a la par de \c m_vec[]. 00138 - Rango válido para \c "i": <code>[[ m_front ==> m_front + m_size - 1 ]]</code>. 00139 - Levanta la excepción \c std::out_of_range si \c "i" está fuera del rango válido. 00140 \code 00141 m_vec[] m_capacity==7 00142 || 00143 \/ m_front==<5> <6> 00144 +---+---+---+---+---+---+---+ - at_check(<5>) es m_vec[5] 00145 | 5 | 6 | _ | _ | _ | 3 | 4 | - at_check(<6>) es m_vec[6] 00146 +---+---+---+---+---+---+---+ - at_check(<7>) es m_vec[0] 00147 +-------+ |-------+ - at_check(<8>) es m_vec[1] 00148 | #3 #4 m_front---+ #2 | 00149 | | - Sólo estos accesos son válidos 00150 +-<-<-----------------------<-<-+ - los demás levantan \c std::out_of_range 00151 m_size == 4 00152 \endcode 00153 */ 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 00166 /// Agrega una copia de \c "val" al final del vector extendible. 00167 /// \pre 00168 /// <code>size() < m_capacity</code> 00169 /// \see test_deque<T>::test_push_back() 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 00183 /// Agrega una copia de \c "val" al principio del vector extendible. 00184 /// \pre 00185 /// <code>size() < m_capacity</code> 00186 /// \see test_deque<T>::test_push_front() 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 } 00198 /// Saca del vector extendible al valor que está al frente. 00199 /// \pre 00200 /// <code>!empty()</code> 00201 /// \see test_deque<T>::test_pop_front() 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 00218 /// Saca del vector extendible al valor que está al frente. 00219 /// \pre 00220 /// <code>!empty()</code> 00221 /// \see test_deque<T>::test_pop_back() 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 /// Retorna \c "true" si el vector extendible está llena 00234 template <class T> 00235 inline bool deque<T>::full() const { 00236 return (m_size == m_ capacity); 00237 } 00238 #endif 00239 00240 /** Verifica la invariante de la clase \c deque<T>. 00241 - Regresa \c "true" si \c "*this" contiene un valor correcto. 00242 - Podría retornar \c "true" aún cuando \c "*this" tenga su valor corrupto. 00243 - Podría no retornar si \c "*this" tiene su valor corrupto. 00244 - http://www.di-mare.com/adolfo/binder/c04.htm#sc11 00245 \see deque<T>::ok( ) 00246 00247 \par Rep: Diagrama de la clase 00248 \code 00249 +-------------------------------+ +-----------------------------------+ 00250 | m_vec[] | | m_vec[] m_capacity==7 | 00251 | || | | || | 00252 | \/ <1> <2>==m_front <6> | | \/ m_front==<5> <6> | 00253 | +---+---+---+---+---+---+---+ | | +---+---+---+---+---+---+---+ | 00254 | | _ | _ | 3 | 9 | 5 | 6 | _ | | | | 5 | 6 | _ | _ | _ | 3 | 9 | | 00255 | +---+---+---+---+---+---+---+ | | +---+---+---+---+---+---+---+ | 00256 | <0> |-----------+ | | +-------+ |-------+ | 00257 | m_front---+ #2 #3 #4 | | | #3 #4 m_front---+ #2 | | 00258 | | | | | | 00259 | m_size == 4 | | +-<-<-----------------------<-<-+ | 00260 +-------------------------------+ +-----------------------------------+ 00261 \endcode 00262 - <em>Rep</em>: http://www.di-mare.com/adolfo/binder/c03.htm#k1-Rep 00263 00264 \par Rep: Descripción en palabras 00265 - Los valores del vector extendible están almacenados en memoria dinámica, 00266 consecutivamente, en el vector \c "m_vec[]" cuyo tamaño no puede 00267 cambiar pues queda definido cómo \c "deque<T>::m_capacity" cuando el 00268 objeto es construido. 00269 - El primer valor del vector extendible siempre está almacenado en 00270 \c "m_vec[m_front]". 00271 - El último valor del vector extendible siempre está almacenado en 00272 \c "m_vec[ (m_front+m_size-1) % m_capacity ]". 00273 - En el diagrama se muestran 2 formas en que puede estar almacenado el 00274 valor de una cola <code>Q = [3,9,5,6]</code> con \c "3" al frente y 00275 \c "6" al final. 00276 - En esta implementación del vector extendible se usa un vector circular en donde 00277 los valores están almacenados desde el índice \c "m_front" de \c "m_vec[]". 00278 - Como siempre el "frente" del vector extendible debe estar "antes" que el "final", 00279 cuando el valor de \c "m_front" no es \c "0", porque no apunta al 00280 principio del vector, lo que ocurre es que el vector extendible está almacenado 00281 llegando al final del vector y luego volviendo al principio 00282 (<em>wrap-around</em>). 00283 - La otra forma de almacenar el vector extendible en un vector circular es usar 00284 los campos \c "m_front" y \c "m_back", pero esta implementación 00285 tiene el problema de que es necesario desperdiciar uno de los 00286 campos del vector \c "m_vec[]" pues de otra manera no es posible 00287 determinar si el vector extendible está lleno o vacío. 00288 */ 00289 template <class T> 00290 bool check_ok( const deque<T>& Q); 00291 00292 /** Verifica la invariante de la clase. 00293 - Implementación para \c check_ok( const deque<T>& Q ). 00294 \see check_ok( const deque<T>& Q) 00295 00296 \remark 00297 - Desafortunadamente no fue posible lograr que el compilador aceptara 00298 una implementación directa para \c check_ok( const deque<T>& Q ) 00299 - El ligador (<em>linker</em>) emite el error LNK2019. El truco para 00300 lidiar con este problema (<em>work arount</em>) es implementar \c ok() 00301 - Es mejor que \c check_ok() sea una función para evitarle al programador 00302 usuario la obligación de implementar el método \c ok() 00303 - http://www.di-mare.com/adolfo/binder/c04.htm#sc11 00304 - http://www.google.com/search?num=100&as_q=LNK2019+template+c%2B%2B 00305 - http://search.yahoo.com/search?n=100&p=LNK2019+template+c%2B%2B 00306 00307 */ 00308 template <class T> 00309 bool deque<T>::ok() const { 00310 if (this == 0) { 00311 /// - Invariante: ningún objeto puede estar almacenado en la posición nula. 00312 return false; 00313 } 00314 00315 if ( ! (m_capacity > 0) ) { 00316 /// - Invariante: La capacidad \c m_capacity debe ser mayor que cero. 00317 return false; 00318 } 00319 if ( ! (m_front < m_capacity) ) { 00320 /// - Invariante: El índice \c m_front no puede exceder \c m_capacity. 00321 return false; 00322 } 00323 if ( ! (m_size <= m_capacity) ) { 00324 /// - Invariante: El índice \c m_size no puede exceder \c m_capacity. 00325 return false; 00326 } 00327 if ( ! (size() <= m_capacity) ) { 00328 /// - Invariante: La cantidad de valores almanenados \c size() no puede exceder \c m_capacity. 00329 return false; 00330 } 00331 if ( ! (m_vec != 0) ) { 00332 /// - Invariante: El vector \c m_vec[] debe existir en memoria dinámica. 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] ) ) { 00347 /// - Invariante: Todos los valores almacenados en el contenedor 00348 /// deben cumplir con su propia invariante 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
1.4.1