aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/algo_base/algo_registry.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/algo_base/algo_registry.h')
-rw-r--r--src/lib/algo_base/algo_registry.h146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/lib/algo_base/algo_registry.h b/src/lib/algo_base/algo_registry.h
new file mode 100644
index 000000000..d40e9fc67
--- /dev/null
+++ b/src/lib/algo_base/algo_registry.h
@@ -0,0 +1,146 @@
+/*
+* (C) 2014,2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ALGO_REGISTRY_H__
+#define BOTAN_ALGO_REGISTRY_H__
+
+#include <botan/types.h>
+#include <functional>
+#include <stdexcept>
+#include <mutex>
+#include <map>
+
+namespace Botan {
+
+size_t static_provider_weight(const std::string& prov_name);
+
+template<typename T>
+class Algo_Registry
+ {
+ public:
+ typedef typename T::Spec Spec;
+
+ typedef std::function<T* (const Spec&)> maker_fn;
+
+ static Algo_Registry<T>& global_registry()
+ {
+ static Algo_Registry<T> g_registry;
+ return g_registry;
+ }
+
+ void add(const std::string& name, const std::string& provider, maker_fn fn)
+ {
+ std::unique_lock<std::mutex> lock(m_mutex);
+ // TODO: check for duplicated registrations
+ m_maker_fns[name][provider] = fn;
+ }
+
+ T* make(const Spec& spec, const std::string& provider = "")
+ {
+ maker_fn maker = find_maker(spec, provider);
+
+ try
+ {
+ return maker(spec);
+ }
+ catch(std::exception& e)
+ {
+ throw std::runtime_error("Creating '" + spec.as_string() + "' failed: " + e.what());
+ }
+ }
+
+ class Add
+ {
+ public:
+ Add(const std::string& basename, maker_fn fn, const std::string& provider = "builtin")
+ {
+ Algo_Registry<T>::global_registry().add(basename, provider, fn);
+ }
+
+ Add(bool cond, const std::string& basename, maker_fn fn, const std::string& provider)
+ {
+ if(cond)
+ Algo_Registry<T>::global_registry().add(basename, provider, fn);
+ }
+ };
+
+ private:
+ Algo_Registry() {}
+
+ maker_fn find_maker(const Spec& spec, const std::string& provider)
+ {
+ const std::string basename = spec.algo_name();
+
+ std::unique_lock<std::mutex> lock(m_mutex);
+ auto providers = m_maker_fns.find(basename);
+
+ if(providers != m_maker_fns.end() && !providers->second.empty())
+ {
+ const std::map<std::string, maker_fn>& prov = providers->second;
+
+ if(provider != "")
+ {
+ // find one explicit provider requested by user, or fail
+ auto i = prov.find(provider);
+ if(i != prov.end())
+ return i->second;
+ }
+ else
+ {
+ if(prov.size() == 1)
+ {
+ return prov.begin()->second;
+ }
+ else if(prov.size() > 1)
+ {
+ // TODO choose best of available options (how?)
+ //throw std::runtime_error("multiple choice not implemented");
+ return prov.begin()->second;
+ }
+ }
+ }
+ // Default result is a function producing a null pointer
+ return [](const Spec&) { return nullptr; };
+ }
+
+ std::mutex m_mutex;
+ std::map<std::string, std::map<std::string, maker_fn>> m_maker_fns;
+ };
+
+template<typename T> T*
+make_new_T(const typename Algo_Registry<T>::Spec&) { return new T; }
+
+template<typename T, size_t DEF_VAL> T*
+make_new_T_1len(const typename Algo_Registry<T>::Spec& spec)
+ {
+ return new T(spec.arg_as_integer(0, DEF_VAL));
+ }
+
+template<typename T> T*
+make_new_T_1str(const typename Algo_Registry<T>::Spec& spec, const std::string& def)
+ {
+ return new T(spec.arg(0, def));
+ }
+
+#define BOTAN_REGISTER_NAMED_T(T, namestr, type, maker) \
+ namespace { Algo_Registry<T>::Add g_ ## type ## _reg(namestr, maker); }
+#define BOTAN_REGISTER_T(T, name, maker) \
+ namespace { Algo_Registry<T>::Add g_ ## name ## _reg(#name, maker); }
+#define BOTAN_REGISTER_T_NOARGS(T, name) \
+ namespace { Algo_Registry<T>::Add g_ ## name ## _reg(#name, make_new_T<name>); }
+#define BOTAN_REGISTER_T_1LEN(T, name, def) \
+ namespace { Algo_Registry<T>::Add g_ ## name ## _reg(#name, make_new_T_1len<name, def>); }
+
+#define BOTAN_COND_REGISTER_NAMED_T_NOARGS(cond, T, type, name, provider) \
+ namespace { Algo_Registry<T>::Add g_ ## type ## _reg(cond, name, make_new_T<type>, provider); }
+
+// TODO move elsewhere:
+#define BOTAN_REGISTER_TRANSFORM(name, maker) BOTAN_REGISTER_T(Transform, name, maker)
+#define BOTAN_REGISTER_TRANSFORM_NOARGS(name) BOTAN_REGISTER_T_NOARGS(Transform, name)
+
+}
+
+#endif