aboutsummaryrefslogtreecommitdiffstats
path: root/src/algo_factory/algo_cache.h
blob: dafa59c3e7ff0392163693fb636d17fe4af1997c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/**
* An algorithm cache (used by Algorithm_Factory)
*/

#ifndef BOTAN_ALGORITHM_CACHE_TEMPLATE_H__
#define BOTAN_ALGORITHM_CACHE_TEMPLATE_H__

#include <botan/scan_name.h>
#include <botan/mutex.h>
#include <stdexcept>
#include <map>
#include <string>

namespace Botan {

template<typename T>
class Algorithm_Cache
   {
   public:
      const T* get(const SCAN_Name& request);
      void add(T* algo,
               const std::string& requested_name,
               const std::string& provider);

      std::vector<std::string> providers_of(const std::string& algo_name);

      Algorithm_Cache(Mutex* m) : mutex(m) {}
      ~Algorithm_Cache();
   private:
      typedef typename std::map<std::string, std::map<std::string, T*> >::iterator algorithms_iterator;
      typedef typename std::map<std::string, T*>::iterator provider_iterator;

      algorithms_iterator find_algorithm(const std::string& algo_spec);

      Mutex* mutex;
      std::map<std::string, std::string> aliases;
      std::map<std::string, std::map<std::string, T*> > algorithms;

   };

/**
* Look for an algorithm implementation in the cache, also checking aliases
*/
template<typename T>
typename Algorithm_Cache<T>::algorithms_iterator
Algorithm_Cache<T>::find_algorithm(const std::string& algo_spec)
   {
   // Assumes mutex is held
   algorithms_iterator algo = algorithms.find(algo_spec);

   // Not found? Check if a known alias
   if(algo == algorithms.end())
      {
      std::map<std::string, std::string>::const_iterator alias =
         aliases.find(algo_spec);

      if(alias != aliases.end())
         algo = algorithms.find(alias->second);
      }

   return algo;
   }

/**
* Look for an algorithm implementation in the cache
*/
template<typename T>
const T* Algorithm_Cache<T>::get(const SCAN_Name& request)
   {
   Mutex_Holder lock(mutex);

   algorithms_iterator algo = find_algorithm(request.as_string());
   if(algo == algorithms.end()) // not found at all
      return 0;

   const std::string requested_provider = request.provider();

   if(requested_provider != "") // If a specific request, allow that provider or core
      {
      provider_iterator provider = algo->second.find(requested_provider);

      if(provider != algo->second.end())
         return provider->second;
      }
   else // no specific provider requested: pick one
      {
      printf("No specific provider requested for %s\n", request.as_string().c_str());
      provider_iterator provider = algo->second.begin();

      while(provider != algo->second.end())
         ++provider;

      provider = algo->second.begin();
      // @fixme: Just picks the lexicographically first one
      if(provider != algo->second.end())
         return provider->second;
      }

   return 0; // cache miss
   }

/**
* Add an implementation to the cache
*/
template<typename T>
void Algorithm_Cache<T>::add(T* algo,
                             const std::string& requested_name,
                             const std::string& provider)
   {
   if(!algo)
      return;

   Mutex_Holder lock(mutex);

   delete algorithms[algo->name()][provider];
   algorithms[algo->name()][provider] = algo;

   if(algo->name() != requested_name && aliases.find(requested_name) == aliases.end())
      aliases[requested_name] = algo->name();
   }

/**
* Find the providers of this algo (if any)
*/
template<typename T> std::vector<std::string>
Algorithm_Cache<T>::providers_of(const std::string& algo_name)
   {
   Mutex_Holder lock(mutex);

   std::vector<std::string> providers;

   algorithms_iterator algo = find_algorithm(algo_name);

   if(algo != algorithms.end())
      {
      provider_iterator provider = algo->second.begin();

      while(provider != algo->second.end())
         {
         providers.push_back(provider->first);
         ++provider;
         }
      }

   return providers;
   }

/**
* Algorithm_Cache<T> Destructor
*/
template<typename T>
Algorithm_Cache<T>::~Algorithm_Cache()
   {
   algorithms_iterator algo = algorithms.begin();

   while(algo != algorithms.end())
      {
      provider_iterator provider = algo->second.begin();

      while(provider != algo->second.end())
         {
         delete provider->second;
         ++provider;
         }

      ++algo;
      }

   delete mutex;
   }

}

#endif