Botan  1.11.15
src/lib/base/algo_registry.h
Go to the documentation of this file.
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