1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
17 // * Neither the name of the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
37 #ifndef anna_core_util_Recycler_hpp
38 #define anna_core_util_Recycler_hpp
43 #include <anna/core/RuntimeException.hpp>
44 #include <anna/core/Allocator.hpp>
49 Mantiene una lista de punteros que puede crecer dinamicamente, no obstante, siempre que sea posible
50 intenta reusar punteros creados previamente.
52 @param T Clase de la que mantener la lista de punteros pre-asignados.
53 @param Allocator Clase encargada de reservar la memoria para los objetos T en el momento en que sea necesaria
56 \warning no actua como clase segura en MT, ver #anna::SafeRecycler
58 template < typename T, typename _Allocator = Allocator <T> > class Recycler {
60 typedef typename std::list <T*> container;
61 typedef typename container::iterator iterator;
62 typedef typename container::const_iterator const_iterator;
64 typedef typename std::map <T*, iterator> random_container;
65 typedef typename random_container::iterator random_iterator;
66 typedef typename random_container::value_type random_item;
70 \param randomAccess Indicador que permite activar el uso de estructuras de datos adicionales
71 que permite que los métodos #find y #release realicen la búsqueda del objeto de forma optimizada.
72 Se ha comprobado que si necesitamos tratar en torno a un centenar de instancias
73 es más eficiente no activar las estructuras para acceso directo, para más objetos resulta
76 Recycler(const bool randomAccess = false) {
78 a_randomContainer = (randomAccess == true) ? new random_container : NULL;
85 clear(); // Pasa todos los punteros a_holes
87 for(iterator ii = a_holes.begin(), maxii = a_holes.end(); ii != maxii; ii ++) {
88 _Allocator::destroy(data(ii));
92 delete a_randomContainer;
96 Devuelve el número de elementos realmente utilizados hasta ahora.
97 @return El número de elementos realmente utilizados hasta ahora.
99 int getSize() const throw() { return a_size; }
102 Devuelve el número de elementos realmente utilizados hasta ahora.
103 @return El número de elementos realmente utilizados hasta ahora.
105 int size() const throw() { return a_size; }
108 Devuelve un puntero de tipo T. Solo crearia una nueva instancia de la clase T si al invocar a este
109 metoodo no existe ninguna otra instancia que se pueda reutilizar, en cuyo caso haria una nueva reserva.
111 Cada una de las llamadas a este metodo debe tener su correspondiente llamada al metodo #release cuando
112 el puntero deje de ser util.
114 @return Un puntero a una instancia de tipo T.
117 throw(RuntimeException) {
120 if(a_holes.empty() == false) {
121 iterator top = a_holes.begin();
123 a_objects.splice(a_objects.end(), a_holes, top);
125 a_objects.push_back(result = _Allocator::create());
127 if(a_randomContainer != NULL) {
128 iterator ii = a_objects.end();
130 a_randomContainer->insert(random_item(result, ii));
138 Devuelve el iterador que apunta al objeto recibido como parametro. Si el objeto no se encuentra dentro de la
139 lista devolverá #end ()
140 \return el iterador que apunta al objeto recibido como parametro.
143 throw(RuntimeException) {
144 iterator result = end();
146 if(a_randomContainer != NULL) {
147 random_iterator jj = a_randomContainer->find(t);
149 if(jj != a_randomContainer->end())
150 result = the_iterator(jj);
152 for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
164 Libera el puntero recibido como parametro. No se libera fisicamente sino que se deja marcado como
167 Si el puntero pasado como parametro no ha sido obtenido mediante el metodo #create los resultados
170 @param t Instancia de un puntero de tipo T obtenido a partir del metodo #create.
177 iterator result = end();
179 if(a_randomContainer != NULL) {
180 random_iterator jj = a_randomContainer->find(t);
182 if(jj != a_randomContainer->end()) {
183 result = the_iterator(jj);
184 a_randomContainer->erase(jj);
187 for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
198 a_holes.splice(a_holes.end(), a_objects, result);
205 Libera el puntero asociado al iterador recibido como parametro.
206 \param ii Instancia a liberar.
208 void release(iterator ii) throw() { release(data(ii)); }
211 Libera el puntero recibido como parametro. No se libera fisicamente sino que se deja marcado como
214 Si el puntero pasado como parametro no ha sido obtenido mediante el metodo #create los resultados
217 @param t Instancia de un puntero de tipo T obtenido a partir del metodo #create.
219 void release(const T* t) throw() { release(const_cast <T*>(t)); }
222 Marca como disponibles todos los objetos contenidos en memoria.
226 a_holes.splice(a_holes.end(), a_objects);
229 if(a_randomContainer)
230 a_randomContainer->clear();
234 Devuelve un iterator al primer elemento, activo, contenido en el reciclador.
235 \return Un iterator al primer elemento, activo, contenido en el reciclador.
237 iterator begin() throw() { return a_objects.begin(); }
240 Devuelve un iterator al primer elemento, activo, contenido en el reciclador.
241 \return Un iterator al primer elemento, activo, contenido en el reciclador.
243 const_iterator begin() const throw() { return a_objects.begin(); }
246 Devuelve un iterator al final de la lista de elementos activos en el reciclador.
247 \return Un iterator al final de la lista de elementos activos en el reciclador.
249 iterator end() throw() { return a_objects.end(); }
252 Devuelve un iterator al final de la lista de elementos activos en el reciclador.
253 \return Un iterator al final de la lista de elementos activos en el reciclador.
255 const_iterator end() const throw() { return a_objects.end(); }
258 Devuelve el objeto referenciado por el iterator recibido como parametro.
259 \return El objeto referenciado por el iterator recibido como parametro.
261 static T* data(iterator ii) throw() { return *ii; }
264 Devuelve el objeto referenciado por el iterator recibido como parametro.
265 \return El objeto referenciado por el iterator recibido como parametro.
267 static const T* data(const_iterator ii) throw() { return *ii; }
272 random_container* a_randomContainer;
274 // Recordar que el list<T>::size tiene una eficiencia de O(N), mientras
275 // que nuestro size, debería ser O(1), por eso hay que llevar la cuenta "a mano".
278 // static T* random_data (random_iterator ii) throw () { return ii->first; }
279 static iterator the_iterator(random_iterator ii) throw() { return ii->second; }