Botan  1.10.9
algo_cache.h
Go to the documentation of this file.
1 /*
2 * An algorithm cache (used by Algorithm_Factory)
3 * (C) 2008-2009,2011 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7 
8 #ifndef BOTAN_ALGORITHM_CACHE_TEMPLATE_H__
9 #define BOTAN_ALGORITHM_CACHE_TEMPLATE_H__
10 
11 #include <botan/internal/mutex.h>
12 #include <botan/internal/stl_util.h>
13 #include <string>
14 #include <vector>
15 #include <map>
16 
17 namespace Botan {
18 
19 /**
20 * @param prov_name a provider name
21 * @return weight for this provider
22 */
23 size_t static_provider_weight(const std::string& prov_name);
24 
25 /**
26 * Algorithm_Cache (used by Algorithm_Factory)
27 */
28 template<typename T>
30  {
31  public:
32  /**
33  * @param algo_spec names the requested algorithm
34  * @param pref_provider suggests a preferred provider
35  * @return prototype object, or NULL
36  */
37  const T* get(const std::string& algo_spec,
38  const std::string& pref_provider);
39 
40  /**
41  * Add a new algorithm implementation to the cache
42  * @param algo the algorithm prototype object
43  * @param requested_name how this name will be requested
44  * @param provider_name is the name of the provider of this prototype
45  */
46  void add(T* algo,
47  const std::string& requested_name,
48  const std::string& provider_name);
49 
50  /**
51  * Set the preferred provider
52  * @param algo_spec names the algorithm
53  * @param provider names the preferred provider
54  */
55  void set_preferred_provider(const std::string& algo_spec,
56  const std::string& provider);
57 
58  /**
59  * Return the list of providers of this algorithm
60  * @param algo_name names the algorithm
61  * @return list of providers of this algorithm
62  */
63  std::vector<std::string> providers_of(const std::string& algo_name);
64 
65  /**
66  * Clear the cache
67  */
68  void clear_cache();
69 
70  /**
71  * Constructor
72  * @param m a mutex to serialize internal access
73  */
74  Algorithm_Cache(Mutex* m) : mutex(m) {}
75  ~Algorithm_Cache() { clear_cache(); delete mutex; }
76  private:
77  typedef typename std::map<std::string, std::map<std::string, T*> >::iterator
78  algorithms_iterator;
79 
80  typedef typename std::map<std::string, T*>::iterator provider_iterator;
81 
82  algorithms_iterator find_algorithm(const std::string& algo_spec);
83 
84  Mutex* mutex;
85  std::map<std::string, std::string> aliases;
86  std::map<std::string, std::string> pref_providers;
87  std::map<std::string, std::map<std::string, T*> > algorithms;
88  };
89 
90 /*
91 * Look for an algorithm implementation in the cache, also checking aliases
92 * Assumes object lock is held
93 */
94 template<typename T>
95 typename Algorithm_Cache<T>::algorithms_iterator
96 Algorithm_Cache<T>::find_algorithm(const std::string& algo_spec)
97  {
98  algorithms_iterator algo = algorithms.find(algo_spec);
99 
100  // Not found? Check if a known alias
101  if(algo == algorithms.end())
102  {
103  std::map<std::string, std::string>::const_iterator alias =
104  aliases.find(algo_spec);
105 
106  if(alias != aliases.end())
107  algo = algorithms.find(alias->second);
108  }
109 
110  return algo;
111  }
112 
113 /*
114 * Look for an algorithm implementation by a particular provider
115 */
116 template<typename T>
117 const T* Algorithm_Cache<T>::get(const std::string& algo_spec,
118  const std::string& requested_provider)
119  {
120  Mutex_Holder lock(mutex);
121 
122  algorithms_iterator algo = find_algorithm(algo_spec);
123  if(algo == algorithms.end()) // algo not found at all (no providers)
124  return 0;
125 
126  // If a provider is requested specifically, return it or fail entirely
127  if(requested_provider != "")
128  {
129  provider_iterator prov = algo->second.find(requested_provider);
130  if(prov != algo->second.end())
131  return prov->second;
132  return 0;
133  }
134 
135  const T* prototype = 0;
136  std::string prototype_provider;
137  size_t prototype_prov_weight = 0;
138 
139  const std::string pref_provider = search_map(pref_providers, algo_spec);
140 
141  for(provider_iterator i = algo->second.begin(); i != algo->second.end(); ++i)
142  {
143  const std::string prov_name = i->first;
144  const size_t prov_weight = static_provider_weight(prov_name);
145 
146  // preferred prov exists, return immediately
147  if(prov_name == pref_provider)
148  return i->second;
149 
150  if(prototype == 0 || prov_weight > prototype_prov_weight)
151  {
152  prototype = i->second;
153  prototype_provider = i->first;
154  prototype_prov_weight = prov_weight;
155  }
156  }
157 
158  return prototype;
159  }
160 
161 /*
162 * Add an implementation to the cache
163 */
164 template<typename T>
166  const std::string& requested_name,
167  const std::string& provider)
168  {
169  if(!algo)
170  return;
171 
172  Mutex_Holder lock(mutex);
173 
174  if(algo->name() != requested_name &&
175  aliases.find(requested_name) == aliases.end())
176  {
177  aliases[requested_name] = algo->name();
178  }
179 
180  if(!algorithms[algo->name()][provider])
181  algorithms[algo->name()][provider] = algo;
182  else
183  delete algo;
184  }
185 
186 /*
187 * Find the providers of this algo (if any)
188 */
189 template<typename T> std::vector<std::string>
191  {
192  Mutex_Holder lock(mutex);
193 
194  std::vector<std::string> providers;
195 
196  algorithms_iterator algo = find_algorithm(algo_name);
197 
198  if(algo != algorithms.end())
199  {
200  provider_iterator provider = algo->second.begin();
201 
202  while(provider != algo->second.end())
203  {
204  providers.push_back(provider->first);
205  ++provider;
206  }
207  }
208 
209  return providers;
210  }
211 
212 /*
213 * Set the preferred provider for an algorithm
214 */
215 template<typename T>
216 void Algorithm_Cache<T>::set_preferred_provider(const std::string& algo_spec,
217  const std::string& provider)
218  {
219  Mutex_Holder lock(mutex);
220 
221  pref_providers[algo_spec] = provider;
222  }
223 
224 /*
225 * Clear out the cache
226 */
227 template<typename T>
229  {
230  algorithms_iterator algo = algorithms.begin();
231 
232  while(algo != algorithms.end())
233  {
234  provider_iterator provider = algo->second.begin();
235 
236  while(provider != algo->second.end())
237  {
238  delete provider->second;
239  ++provider;
240  }
241 
242  ++algo;
243  }
244 
245  algorithms.clear();
246  }
247 
248 }
249 
250 #endif
const T * get(const std::string &algo_spec, const std::string &pref_provider)
Definition: algo_cache.h:117
V search_map(const std::map< K, V > &mapping, const K &key, const V &null_result=V())
Definition: stl_util.h:43
std::vector< std::string > providers_of(const std::string &algo_name)
Definition: algo_cache.h:190
Mutex * mutex
Definition: global_rng.cpp:164
std::string algo_name
Definition: ossl_md.cpp:42
size_t static_provider_weight(const std::string &prov_name)
Definition: prov_weight.cpp:15
void add(T *algo, const std::string &requested_name, const std::string &provider_name)
Definition: algo_cache.h:165
void set_preferred_provider(const std::string &algo_spec, const std::string &provider)
Definition: algo_cache.h:216
Algorithm_Cache(Mutex *m)
Definition: algo_cache.h:74