1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
9 #ifndef anna_core_util_LRUMap_hpp
10 #define anna_core_util_LRUMap_hpp
14 #include <anna/config/defines.hpp>
19 Patrón que permite mantener una lista de N elementos de pares (Clave, Valor).
21 Es capaz de realizar una búsqueda indexada de la clave para obtener el valor,
22 pero además es capaz de mantener estable el número de elementos contenidos
25 Si se alcanza el número máximo de elementos indicados en el constructor, si se requiere
26 incluir un nuevo objeto, primero liberará el objeto que lleve más tiempo si ser usado.
28 \param K clase que actuará como clave del mapa. Requiere el contructor de copia, y los operadores de comparación == y <.
29 \param V clase que actuará como dato asociado a la clave. Requiere el constructor copia y el operador copia.
31 template <typename K, typename V> class LRUMap {
32 typedef typename std::pair <V, anna::Millisecond> timed_value;
33 typedef typename std::map <K, timed_value> container;
34 typedef typename container::value_type value_type;
37 typedef typename container::iterator iterator;
38 typedef typename container::const_iterator const_iterator;
42 \param name Nombre logico de esta instancia.
43 \param measure Unidad de medida. Solo se usa a efecto de salida de datos.
45 LRUMap(const char* name, const int maxSize) : a_name(name), a_maxSize(maxSize) { ;}
50 ~LRUMap() { clear(); }
53 Devuelve el indicador de validez de esta media.
54 \return \em true Si la media no tiene ningun valor o \em false en caso contrario.
56 bool isEmpty() const throw() { return a_container.size() == 0; }
59 * Devuelve el número de elementos contenidos en este contenedor.
60 * \return el número de elementos contenidos en este contenedor.
62 int size() const throw() { return a_container.size(); }
65 * Devuelve el puntero al valor asociado a la clave recibida como parámetro.
66 * Puede ser NULL si la pareja (K,V) no está registrada en el contenedor.
68 * \param key Clave de la que obtener el valor asociado.
70 * \return El puntero al valor asociado a la clave recibida como parámetro.
72 V* find(const K& key) throw() {
73 iterator ii = a_container.find(key);
79 * Recupera el valor asociado a la clave K y actualiza el momento de acceso.
81 millisecond(ii) = functions::millisecond();
86 * Establece el valor de pareja (K,V). Si no existe se crea y si existe se sobre escribe el
87 * valor asociado a V, y se actualiza su tiempo de acceso.
89 * \param key Clave de la pareja (K,V).
90 * \param v Valor asociado a la clave.
92 void add(const K& key, const V& v) throw() {
93 iterator ii = a_container.find(key);
95 // Sobreescribe el valor asociado a K y actualiza su tiempo de acceso.
98 millisecond(ii) = functions::millisecond();
102 // Si no se ha alcanzado el máximo, sólo hay que insertar el nuevo (K,V)
103 if(size() < a_maxSize) {
104 timed_value tvalue(v, functions::millisecond());
105 a_container.insert(value_type(key, tvalue));
109 // Se ha alcanzado el máximo, hay que buscar el que haga más tiempo que no se
110 // accede => el que tenga el menor 'Time' asociado.
111 iterator minii = begin();
112 Millisecond minTime = millisecond(minii);
114 for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
115 if(millisecond(ii) < minTime)
116 minTime = millisecond(minii = ii);
120 * El map no permite sobre-escribir la clave => por eso tenemos que borrar el nodo
121 * más antiguo y crear otro nuevo.
123 a_container.erase(minii);
124 timed_value tvalue(v, functions::millisecond());
125 a_container.insert(value_type(key, tvalue));
129 Vacía este contenedor.
131 void clear() throw() { a_container.clear(); }
134 * Devuelve un iterator al primer elemento del contenedor, teniendo que la ordenación de los
135 * pares (K,V) se hará en base a K.
136 * \return El primer elemento del contenedor.
138 iterator begin() throw() { return a_container.begin(); }
141 * Devuelve un iterator al primer elemento del contenedor, teniendo que la ordenación de los
142 * pares (K,V) se hará en base a K.
143 * \return El primer elemento del contenedor.
145 const_iterator begin() const throw() { return a_container.begin(); }
148 * Devuelve un iterator al final del contenedor, teniendo que la ordenación de los pares (K,V) se hará en
150 * \return El primer elemento del contenedor.
152 iterator end() throw() { return a_container.end(); }
155 * Devuelve un iterator al final del contenedor, teniendo que la ordenación de los pares (K,V) se hará en
157 * \return El primer elemento del contenedor.
159 const_iterator end() const throw() { return a_container.end(); }
162 * Devuelve la clave asociada al iterador recibido como parámetro.
163 * \param ii Iterador que debe estar comprendido entre [#begin (), #end).
164 * \return la clave asociada al iterador recibido como parámetro.
165 * \warning Los acceso mediante iterador no actualiza el tiempo de acceso a la pareja (K,V).
167 static K key(iterator& ii) throw() { return ii->first; }
170 * Devuelve el valor asociado al iterador recibido como parámetro.
171 * \param ii Iterador que debe estar comprendido entre [#begin (), #end).
172 * \return el valor asociado al iterador recibido como parámetro.
173 * \warning Los acceso mediante iterador no actualiza el tiempo de acceso a la pareja (K,V).
175 static V& value(iterator& ii) throw() {
176 timed_value* v = &ii->second;
181 * Devuelve el tiempo de acceso asociado al iterador recibido como parámetro.
182 * \param ii Iterador que debe estar comprendido entre [#begin (), #end).
183 * \return el tiempo de acceso asociado al iterador recibido como parámetro.
185 static Millisecond& millisecond(iterator& ii) throw() {
186 timed_value* v = &ii->second;
191 * Devuelve la clave asociada al iterador recibido como parámetro.
192 * \param ii Iterador que debe estar comprendido entre [#begin (), #end).
193 * \return la clave asociada al iterador recibido como parámetro.
194 * \warning Los acceso mediante iterador no actualiza el tiempo de acceso a la pareja (K,V).
196 static K key(const_iterator& ii) throw() { return ii->first; }
199 * Devuelve el valor asociado al iterador recibido como parámetro.
200 * \param ii Iterador que debe estar comprendido entre [#begin (), #end).
201 * \return el valor asociado al iterador recibido como parámetro.
202 * \warning Los acceso mediante iterador no actualiza el tiempo de acceso a la pareja (K,V).
204 static const V& value(const_iterator& ii) throw() {
205 const timed_value* v = &ii->second;
210 * Devuelve el tiempo de acceso asociado al iterador recibido como parámetro.
211 * \param ii Iterador que debe estar comprendido entre [#begin (), #end).
212 * \return el tiempo de acceso asociado al iterador recibido como parámetro.
214 static Millisecond millisecond(const_iterator& ii) throw() {
215 const timed_value* v = &ii->second;
220 Devuelve una cadena con la informacion referente a esta clase.
221 \return Una cadena con la informacion referente a esta clase.
223 std::string asString() const
225 std::string msg("LRUMap { Name: ");
227 msg += functions::asText(" | N: ", a_maxSize);
228 msg += functions::asText(" | n: ", size());
235 container a_container;