Botan
1.11.15
|
00001 /* 00002 * (C) 2014,2015 Jack Lloyd 00003 * 00004 * Botan is released under the Simplified BSD License (see license.txt) 00005 */ 00006 00007 #ifndef BOTAN_ALGO_REGISTRY_H__ 00008 #define BOTAN_ALGO_REGISTRY_H__ 00009 00010 #include <botan/types.h> 00011 #include <functional> 00012 #include <stdexcept> 00013 #include <mutex> 00014 #include <vector> 00015 #include <map> 00016 #include <string> 00017 #include <unordered_map> 00018 00019 namespace Botan { 00020 00021 template<typename T> 00022 class Algo_Registry 00023 { 00024 public: 00025 typedef typename T::Spec Spec; 00026 00027 typedef std::function<T* (const Spec&)> maker_fn; 00028 00029 static Algo_Registry<T>& global_registry() 00030 { 00031 static Algo_Registry<T> g_registry; 00032 return g_registry; 00033 } 00034 00035 void add(const std::string& name, const std::string& provider, maker_fn fn, byte pref) 00036 { 00037 std::unique_lock<std::mutex> lock(m_mutex); 00038 m_algo_info[name].add_provider(provider, fn, pref); 00039 } 00040 00041 std::vector<std::string> providers_of(const Spec& spec) 00042 { 00043 std::unique_lock<std::mutex> lock(m_mutex); 00044 auto i = m_algo_info.find(spec.algo_name()); 00045 if(i != m_algo_info.end()) 00046 return i->second.providers(); 00047 return std::vector<std::string>(); 00048 } 00049 00050 T* make(const Spec& spec, const std::string& provider = "") 00051 { 00052 maker_fn maker = find_maker(spec, provider); 00053 00054 try 00055 { 00056 return maker(spec); 00057 } 00058 catch(std::exception& e) 00059 { 00060 throw std::runtime_error("Creating '" + spec.as_string() + "' failed: " + e.what()); 00061 } 00062 } 00063 00064 class Add 00065 { 00066 public: 00067 Add(const std::string& basename, maker_fn fn, const std::string& provider, byte pref) 00068 { 00069 Algo_Registry<T>::global_registry().add(basename, provider, fn, pref); 00070 } 00071 00072 Add(bool cond, const std::string& basename, maker_fn fn, const std::string& provider, byte pref) 00073 { 00074 if(cond) 00075 Algo_Registry<T>::global_registry().add(basename, provider, fn, pref); 00076 } 00077 }; 00078 00079 private: 00080 Algo_Registry() {} 00081 00082 maker_fn find_maker(const Spec& spec, const std::string& provider) 00083 { 00084 std::unique_lock<std::mutex> lock(m_mutex); 00085 return m_algo_info[spec.algo_name()].get_maker(provider); 00086 } 00087 00088 struct Algo_Info 00089 { 00090 public: 00091 void add_provider(const std::string& provider, maker_fn fn, byte pref = 128) 00092 { 00093 if(m_maker_fns.count(provider) > 0) 00094 throw std::runtime_error("Duplicated registration of '" + provider + "'"); 00095 00096 m_maker_fns[provider] = std::make_pair(pref, fn); 00097 } 00098 00099 std::vector<std::string> providers() const 00100 { 00101 std::vector<std::string> v; 00102 for(auto&& k : m_maker_fns) 00103 v.push_back(k.first); 00104 return v; 00105 } 00106 00107 void set_pref(const std::string& provider, byte val) 00108 { 00109 m_maker_fns[provider].first = val; 00110 } 00111 00112 maker_fn get_maker(const std::string& req_provider) 00113 { 00114 maker_fn null_result = [](const Spec&) { return nullptr; }; 00115 00116 if(req_provider != "") 00117 { 00118 // find one explicit provider requested by user or fail 00119 auto i = m_maker_fns.find(req_provider); 00120 if(i != m_maker_fns.end()) 00121 return i->second.second; 00122 return null_result; 00123 } 00124 00125 size_t pref = 255; 00126 maker_fn result = null_result; 00127 00128 for(auto&& i : m_maker_fns) 00129 { 00130 if(i.second.first < pref) 00131 { 00132 pref = i.second.first; 00133 result = i.second.second; 00134 } 00135 } 00136 00137 return result; 00138 } 00139 private: 00140 std::unordered_map<std::string, std::pair<byte, maker_fn>> m_maker_fns; // provider -> (pref, creator fn) 00141 }; 00142 00143 std::mutex m_mutex; 00144 std::unordered_map<std::string, Algo_Info> m_algo_info; 00145 }; 00146 00147 template<typename T> T* 00148 make_a(const typename T::Spec& spec, const std::string provider = "") 00149 { 00150 return Algo_Registry<T>::global_registry().make(spec, provider); 00151 } 00152 00153 template<typename T> std::vector<std::string> providers_of(const typename T::Spec& spec) 00154 { 00155 return Algo_Registry<T>::global_registry().providers_of(spec); 00156 } 00157 00158 template<typename T> T* 00159 make_new_T(const typename Algo_Registry<T>::Spec&) { return new T; } 00160 00161 template<typename T, size_t DEF_VAL> T* 00162 make_new_T_1len(const typename Algo_Registry<T>::Spec& spec) 00163 { 00164 return new T(spec.arg_as_integer(0, DEF_VAL)); 00165 } 00166 00167 template<typename T, size_t DEF1, size_t DEF2> T* 00168 make_new_T_2len(const typename Algo_Registry<T>::Spec& spec) 00169 { 00170 return new T(spec.arg_as_integer(0, DEF1), spec.arg_as_integer(1, DEF2)); 00171 } 00172 00173 template<typename T> T* 00174 make_new_T_1str(const typename Algo_Registry<T>::Spec& spec, const std::string& def) 00175 { 00176 return new T(spec.arg(0, def)); 00177 } 00178 00179 template<typename T> T* 00180 make_new_T_1str_req(const typename Algo_Registry<T>::Spec& spec) 00181 { 00182 return new T(spec.arg(0)); 00183 } 00184 00185 template<typename T, typename X> T* 00186 make_new_T_1X(const typename Algo_Registry<T>::Spec& spec) 00187 { 00188 std::unique_ptr<X> x(Algo_Registry<X>::global_registry().make(spec.arg(0))); 00189 if(!x) 00190 throw std::runtime_error(spec.arg(0)); 00191 return new T(x.release()); 00192 } 00193 00194 #define BOTAN_REGISTER_TYPE(T, type, name, maker, provider, pref) \ 00195 namespace { Algo_Registry<T>::Add g_ ## type ## _reg(name, maker, provider, pref); } 00196 00197 #define BOTAN_REGISTER_TYPE_COND(cond, T, type, name, maker, provider, pref) \ 00198 namespace { Algo_Registry<T>::Add g_ ## type ## _reg(cond, name, maker, provider, pref); } 00199 00200 #define BOTAN_REGISTER_NAMED_T(T, name, type, maker) \ 00201 BOTAN_REGISTER_TYPE(T, type, name, maker, "builtin", 128) 00202 00203 #define BOTAN_REGISTER_T(T, type, maker) \ 00204 BOTAN_REGISTER_TYPE(T, type, #type, maker, "builtin", 128) 00205 00206 #define BOTAN_REGISTER_T_NOARGS(T, type) \ 00207 BOTAN_REGISTER_TYPE(T, type, #type, make_new_T<type>, "builtin", 128) 00208 #define BOTAN_REGISTER_T_1LEN(T, type, def) \ 00209 BOTAN_REGISTER_TYPE(T, type, #type, (make_new_T_1len<type,def>), "builtin", 128) 00210 00211 #define BOTAN_REGISTER_NAMED_T_NOARGS(T, type, name, provider) \ 00212 BOTAN_REGISTER_TYPE(T, type, name, make_new_T<type>, provider, 128) 00213 #define BOTAN_COND_REGISTER_NAMED_T_NOARGS(cond, T, type, name, provider, pref) \ 00214 BOTAN_REGISTER_TYPE_COND(cond, T, type, name, make_new_T<type>, provider, pref) 00215 00216 #define BOTAN_REGISTER_NAMED_T_2LEN(T, type, name, provider, len1, len2) \ 00217 BOTAN_REGISTER_TYPE(T, type, name, (make_new_T_2len<type,len1,len2>), provider, 128) 00218 00219 // TODO move elsewhere: 00220 #define BOTAN_REGISTER_TRANSFORM(name, maker) BOTAN_REGISTER_T(Transform, name, maker) 00221 #define BOTAN_REGISTER_TRANSFORM_NOARGS(name) BOTAN_REGISTER_T_NOARGS(Transform, name) 00222 00223 } 00224 00225 #endif