- Changes to make it more ANSI-conformant. Stuff detected while trying
[ginac.git] / ginac / remember.cpp
1 /** @file remember.cpp
2  *
3  *  Implementation of helper classes for using the remember option
4  *  in GiNaC functions */
5
6 /*
7  *  GiNaC Copyright (C) 1999-2000 Johannes Gutenberg University Mainz, Germany
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include <stdexcept>
25
26 #include "function.h"
27 #include "utils.h"
28 #include "remember.h"
29
30 #ifndef NO_NAMESPACE_GINAC
31 namespace GiNaC {
32 #endif // ndef NO_NAMESPACE_GINAC
33
34 //////////
35 // class remember_table_entry
36 //////////
37
38 remember_table_entry::remember_table_entry(function const & f, ex const & r)
39   : hashvalue(f.gethash()), seq(f.seq), result(r)
40 {
41         ++last_access = access_counter;
42         successful_hits = 0;
43 }
44
45 bool remember_table_entry::is_equal(function const & f) const
46 {
47         GINAC_ASSERT(f.seq.size()==seq.size());
48         if (f.gethash()!=hashvalue) return false;
49         for (unsigned i=0; i<seq.size(); ++i)
50                 if (!seq[i].is_equal(f.seq[i])) return false;
51         ++last_access = access_counter;
52         ++successful_hits;
53         return true;
54 }
55
56 unsigned long remember_table_entry::access_counter=0;
57
58 //////////
59 // class remember_table_list
60 //////////
61
62 remember_table_list::remember_table_list(unsigned as, unsigned strat)
63 {
64         max_assoc_size = as;
65         remember_strategy = strat;
66 }
67
68
69 void remember_table_list::add_entry(function const & f, ex const & result)
70 {
71         if ((max_assoc_size!=0)&&
72                 (remember_strategy!=remember_strategies::delete_never)&&
73                 (size()>=max_assoc_size)) {
74                 // table is full, we must delete an older entry
75                 GINAC_ASSERT(size()>0); // there must be at least one entry
76                 
77                 switch (remember_strategy) {
78                 case remember_strategies::delete_cyclic: {
79                         // delete oldest entry (first in list)
80                         erase(begin());
81                         break;
82                 }
83                 case remember_strategies::delete_lru: {
84                         // delete least recently used entry
85                         iterator it = begin();
86                         iterator lowest_access_it = it;
87                         unsigned long lowest_access = (*it).get_last_access();
88                         ++it;
89                         while (it!=end()) {
90                                 if ((*it).get_last_access()<lowest_access) {
91                                         lowest_access = (*it).get_last_access();
92                                         lowest_access_it = it;
93                                 }
94                                 ++it;
95                         }
96                         erase(lowest_access_it);
97                         break;
98                 }
99                 case remember_strategies::delete_lfu: {
100                         // delete least frequently used entry
101                         iterator it = begin();
102                         iterator lowest_hits_it = it;
103                         unsigned lowest_hits = (*it).get_successful_hits();
104                         ++it;
105                         while (it!=end()) {
106                                 if ((*it).get_successful_hits()<lowest_hits) {
107                                         lowest_hits = (*it).get_successful_hits();
108                                         lowest_hits_it = it;
109                                 }
110                                 ++it;
111                         }
112                         erase(lowest_hits_it);
113                         break;
114                 }
115                 default:
116                         throw(std::logic_error("remember_table_list::add_entry(): invalid remember_strategy"));
117         }
118                 GINAC_ASSERT(size()==max_assoc_size-1);
119         }
120         push_back(remember_table_entry(f,result));
121 }
122
123 bool remember_table_list::lookup_entry(function const & f, ex & result) const
124 {
125         for (const_iterator cit=begin(); cit!=end(); ++cit) {
126                 if ((*cit).is_equal(f)) {
127                         result = (*cit).get_result();
128                         return true;
129                 }
130         }
131         return false;
132 }
133
134 //////////
135 // class remember_table
136 //////////
137
138 remember_table::remember_table()
139 {
140         table_size=0;
141         max_assoc_size=0;
142         remember_strategy=remember_strategies::delete_never;
143 }
144
145 remember_table::remember_table(unsigned s, unsigned as, unsigned strat)
146   : max_assoc_size(as), remember_strategy(strat)
147 {
148         // we keep max_assoc_size and remember_strategy if we need to clear
149         // all entries
150
151         // use some power of 2 next to s
152         table_size = 1 << log2(s);
153         init_table();
154 }
155
156 bool remember_table::lookup_entry(function const & f, ex & result) const
157 {
158         unsigned entry = f.gethash() & (table_size-1);
159         GINAC_ASSERT(entry<size());
160         return operator[](entry).lookup_entry(f,result);
161 }
162
163 void remember_table::add_entry(function const & f, ex const & result)
164 {
165         unsigned entry = f.gethash() & (table_size-1);
166         GINAC_ASSERT(entry<size());
167         operator[](entry).add_entry(f,result);
168 }        
169
170 void remember_table::clear_all_entries(void)
171 {
172         clear();
173         init_table();
174 }
175
176 void remember_table::init_table(void)
177 {
178         reserve(table_size);
179         for (unsigned i=0; i<table_size; ++i)
180                 push_back(remember_table_list(max_assoc_size,remember_strategy));
181 }
182
183 std::vector<remember_table> & remember_table::remember_tables(void)
184 {
185         static std::vector<remember_table> * rt = new std::vector<remember_table>;
186         return *rt;
187 }
188
189 #ifndef NO_NAMESPACE_GINAC
190 } // namespace GiNaC
191 #endif // ndef NO_NAMESPACE_GINAC