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_Recycler_hpp
10 #define anna_core_util_Recycler_hpp
15 #include <anna/core/RuntimeException.hpp>
16 #include <anna/core/Allocator.hpp>
21 Mantiene una lista de punteros que puede crecer dinamicamente, no obstante, siempre que sea posible
22 intenta reusar punteros creados previamente.
24 @param T Clase de la que mantener la lista de punteros pre-asignados.
25 @param Allocator Clase encargada de reservar la memoria para los objetos T en el momento en que sea necesaria
28 \warning no actua como clase segura en MT, ver #anna::SafeRecycler
30 template < typename T, typename _Allocator = Allocator <T> > class Recycler {
32 typedef typename std::list <T*> container;
33 typedef typename container::iterator iterator;
34 typedef typename container::const_iterator const_iterator;
36 typedef typename std::map <T*, iterator> random_container;
37 typedef typename random_container::iterator random_iterator;
38 typedef typename random_container::value_type random_item;
42 \param randomAccess Indicador que permite activar el uso de estructuras de datos adicionales
43 que permite que los métodos #find y #release realicen la búsqueda del objeto de forma optimizada.
44 Se ha comprobado que si necesitamos tratar en torno a un centenar de instancias
45 es más eficiente no activar las estructuras para acceso directo, para más objetos resulta
48 Recycler(const bool randomAccess = false) {
50 a_randomContainer = (randomAccess == true) ? new random_container : NULL;
57 clear(); // Pasa todos los punteros a_holes
59 for(iterator ii = a_holes.begin(), maxii = a_holes.end(); ii != maxii; ii ++) {
60 _Allocator::destroy(data(ii));
64 delete a_randomContainer;
68 Devuelve el número de elementos realmente utilizados hasta ahora.
69 @return El número de elementos realmente utilizados hasta ahora.
71 int getSize() const throw() { return a_size; }
74 Devuelve el número de elementos realmente utilizados hasta ahora.
75 @return El número de elementos realmente utilizados hasta ahora.
77 int size() const throw() { return a_size; }
80 Devuelve un puntero de tipo T. Solo crearia una nueva instancia de la clase T si al invocar a este
81 metoodo no existe ninguna otra instancia que se pueda reutilizar, en cuyo caso haria una nueva reserva.
83 Cada una de las llamadas a este metodo debe tener su correspondiente llamada al metodo #release cuando
84 el puntero deje de ser util.
86 @return Un puntero a una instancia de tipo T.
89 throw(RuntimeException) {
92 if(a_holes.empty() == false) {
93 iterator top = a_holes.begin();
95 a_objects.splice(a_objects.end(), a_holes, top);
97 a_objects.push_back(result = _Allocator::create());
99 if(a_randomContainer != NULL) {
100 iterator ii = a_objects.end();
102 a_randomContainer->insert(random_item(result, ii));
110 Devuelve el iterador que apunta al objeto recibido como parametro. Si el objeto no se encuentra dentro de la
111 lista devolverá #end ()
112 \return el iterador que apunta al objeto recibido como parametro.
115 throw(RuntimeException) {
116 iterator result = end();
118 if(a_randomContainer != NULL) {
119 random_iterator jj = a_randomContainer->find(t);
121 if(jj != a_randomContainer->end())
122 result = the_iterator(jj);
124 for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
136 Libera el puntero recibido como parametro. No se libera fisicamente sino que se deja marcado como
139 Si el puntero pasado como parametro no ha sido obtenido mediante el metodo #create los resultados
142 @param t Instancia de un puntero de tipo T obtenido a partir del metodo #create.
149 iterator result = end();
151 if(a_randomContainer != NULL) {
152 random_iterator jj = a_randomContainer->find(t);
154 if(jj != a_randomContainer->end()) {
155 result = the_iterator(jj);
156 a_randomContainer->erase(jj);
159 for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
170 a_holes.splice(a_holes.end(), a_objects, result);
177 Libera el puntero asociado al iterador recibido como parametro.
178 \param ii Instancia a liberar.
180 void release(iterator ii) throw() { release(data(ii)); }
183 Libera el puntero recibido como parametro. No se libera fisicamente sino que se deja marcado como
186 Si el puntero pasado como parametro no ha sido obtenido mediante el metodo #create los resultados
189 @param t Instancia de un puntero de tipo T obtenido a partir del metodo #create.
191 void release(const T* t) throw() { release(const_cast <T*>(t)); }
194 Marca como disponibles todos los objetos contenidos en memoria.
198 a_holes.splice(a_holes.end(), a_objects);
201 if(a_randomContainer)
202 a_randomContainer->clear();
206 Devuelve un iterator al primer elemento, activo, contenido en el reciclador.
207 \return Un iterator al primer elemento, activo, contenido en el reciclador.
209 iterator begin() throw() { return a_objects.begin(); }
212 Devuelve un iterator al primer elemento, activo, contenido en el reciclador.
213 \return Un iterator al primer elemento, activo, contenido en el reciclador.
215 const_iterator begin() const throw() { return a_objects.begin(); }
218 Devuelve un iterator al final de la lista de elementos activos en el reciclador.
219 \return Un iterator al final de la lista de elementos activos en el reciclador.
221 iterator end() throw() { return a_objects.end(); }
224 Devuelve un iterator al final de la lista de elementos activos en el reciclador.
225 \return Un iterator al final de la lista de elementos activos en el reciclador.
227 const_iterator end() const throw() { return a_objects.end(); }
230 Devuelve el objeto referenciado por el iterator recibido como parametro.
231 \return El objeto referenciado por el iterator recibido como parametro.
233 static T* data(iterator ii) throw() { return *ii; }
236 Devuelve el objeto referenciado por el iterator recibido como parametro.
237 \return El objeto referenciado por el iterator recibido como parametro.
239 static const T* data(const_iterator ii) throw() { return *ii; }
244 random_container* a_randomContainer;
246 // Recordar que el list<T>::size tiene una eficiencia de O(N), mientras
247 // que nuestro size, debería ser O(1), por eso hay que llevar la cuenta "a mano".
250 // static T* random_data (random_iterator ii) throw () { return ii->first; }
251 static iterator the_iterator(random_iterator ii) throw() { return ii->second; }