diff options
Diffstat (limited to 'odb/instance.hxx')
-rw-r--r-- | odb/instance.hxx | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/odb/instance.hxx b/odb/instance.hxx new file mode 100644 index 0000000..76e72c3 --- /dev/null +++ b/odb/instance.hxx @@ -0,0 +1,279 @@ +// file : odb/instance.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_INSTANCE_HXX +#define ODB_INSTANCE_HXX + +#include <map> +#include <string> +#include <cstddef> // std::size_t +#include <typeinfo> + +#include <odb/option-types.hxx> +#include <odb/context.hxx> + +#include <odb/traversal/elements.hxx> +#include <odb/traversal/relational/elements.hxx> + +// +// Dynamic traversal instantiation support. +// + +template <typename B> +struct factory +{ + static B* + create (B const& prototype) + { + std::string kind, name; + database db (context::current ().options.database ()[0]); + + switch (db) + { + case database::common: + { + name = "common"; + break; + } + case database::mssql: + case database::mysql: + case database::oracle: + case database::pgsql: + case database::sqlite: + { + kind = "relational"; + name = kind + "::" + db.string (); + break; + } + } + + if (map_ != 0) + { + typename map::const_iterator i; + + if (!name.empty ()) + i = map_->find (name); + + if (i == map_->end ()) + i = map_->find (kind); + + if (i != map_->end ()) + return i->second (prototype); + } + + return new B (prototype); + } + +private: + template <typename> + friend struct entry; + + static void + init () + { + if (factory<B>::count_++ == 0) + factory<B>::map_ = new typename factory<B>::map; + } + + static void + term () + { + if (--factory<B>::count_ == 0) + delete factory<B>::map_; + } + + typedef B* (*create_func) (B const&); + typedef std::map<std::string, create_func> map; + static map* map_; + static std::size_t count_; +}; + +template <typename B> +typename factory<B>::map* factory<B>::map_; + +template <typename B> +std::size_t factory<B>::count_; + +struct entry_base +{ + static std::string + name (std::type_info const&); +}; + +template <typename D> +struct entry: entry_base +{ + typedef typename D::base base; + + entry () + { + factory<base>::init (); + (*factory<base>::map_)[name (typeid (D))] = &create; + } + + ~entry () + { + factory<base>::term (); + } + + static base* + create (base const& prototype) + { + return new D (prototype); + } +}; + +template <typename B> +struct instance +{ + typedef typename B::base base_type; + typedef ::factory<base_type> factory_type; + + ~instance () + { + delete x_; + } + + instance () + { + base_type prototype; + x_ = factory_type::create (prototype); + } + + template <typename A1> + instance (A1& a1) + { + base_type prototype (a1); + x_ = factory_type::create (prototype); + } + + template <typename A1> + instance (A1 const& a1) + { + base_type prototype (a1); + x_ = factory_type::create (prototype); + } + + template <typename A1, typename A2> + instance (A1& a1, A2& a2) + { + base_type prototype (a1, a2); + x_ = factory_type::create (prototype); + } + + template <typename A1, typename A2> + instance (A1 const& a1, A2 const& a2) + { + base_type prototype (a1, a2); + x_ = factory_type::create (prototype); + } + + template <typename A1, typename A2, typename A3> + instance (A1& a1, A2& a2, A3& a3) + { + base_type prototype (a1, a2, a3); + x_ = factory_type::create (prototype); + } + + template <typename A1, typename A2, typename A3> + instance (A1 const& a1, A2 const& a2, A3 const& a3) + { + base_type prototype (a1, a2, a3); + x_ = factory_type::create (prototype); + } + + template <typename A1, typename A2, typename A3, typename A4> + instance (A1& a1, A2& a2, A3& a3, A4& a4) + { + base_type prototype (a1, a2, a3, a4); + x_ = factory_type::create (prototype); + } + + template <typename A1, typename A2, typename A3, typename A4> + instance (A1 const& a1, A2 const& a2, A3 const& a3, A4 const& a4) + { + base_type prototype (a1, a2, a3, a4); + x_ = factory_type::create (prototype); + } + + template <typename A1, typename A2, typename A3, typename A4, typename A5> + instance (A1& a1, A2& a2, A3& a3, A4& a4, A5& a5) + { + base_type prototype (a1, a2, a3, a4, a5); + x_ = factory_type::create (prototype); + } + + template <typename A1, typename A2, typename A3, typename A4, typename A5> + instance (A1 const& a1, A2 const& a2, A3 const& a3, A4 const& a4, + A5 const& a5) + { + base_type prototype (a1, a2, a3, a4, a5); + x_ = factory_type::create (prototype); + } + + instance (instance const& i) + { + // This is tricky: use the other instance as a prototype. + // + x_ = factory_type::create (*i.x_); + } + + base_type* + operator-> () const + { + return x_; + } + + base_type& + operator* () const + { + return *x_; + } + + base_type* + get () const + { + return x_; + } + +private: + instance& operator= (instance const&); + +private: + base_type* x_; +}; + +template <typename T> +inline traversal::edge_base& +operator>> (instance<T>& n, traversal::edge_base& e) +{ + n->edge_traverser (e); + return e; +} + +template <typename T> +inline traversal::relational::edge_base& +operator>> (instance<T>& n, traversal::relational::edge_base& e) +{ + n->edge_traverser (e); + return e; +} + +template <typename T> +inline traversal::node_base& +operator>> (traversal::edge_base& e, instance<T>& n) +{ + e.node_traverser (*n); + return *n; +} + +template <typename T> +inline traversal::relational::node_base& +operator>> (traversal::relational::edge_base& e, instance<T>& n) +{ + e.node_traverser (*n); + return *n; +} + +#endif // ODB_INSTANCE_HXX |