diff options
Diffstat (limited to 'odb/odb/inline.cxx')
-rw-r--r-- | odb/odb/inline.cxx | 506 |
1 files changed, 506 insertions, 0 deletions
diff --git a/odb/odb/inline.cxx b/odb/odb/inline.cxx new file mode 100644 index 0000000..15482aa --- /dev/null +++ b/odb/odb/inline.cxx @@ -0,0 +1,506 @@ +// file : odb/inline.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <odb/common.hxx> +#include <odb/context.hxx> +#include <odb/generate.hxx> +#include <odb/diagnostics.hxx> + +using namespace std; + +namespace inline_ +{ + // + // + struct callback_calls: traversal::class_, virtual context + { + callback_calls () + { + *this >> inherits_ >> *this; + } + + void + traverse (type& c, bool constant) + { + const_ = constant; + traverse (c); + } + + virtual void + traverse (type& c) + { + bool obj (object (c)); + + // Ignore transient bases. + // + if (!(obj || view (c))) + return; + + if (c.count ("callback")) + { + string name (c.get<string> ("callback")); + + // In case of the const instance, we only generate the call if + // there is a const callback. Note also that we cannot use + // object_type/view_type alias because it can be a base type. + // + string const& type (class_fq_name (c)); + + if (const_) + { + if (c.count ("callback-const")) + os << "static_cast<const " << type << "&> (x)." << name << + " (e, db);"; + } + else + os << "static_cast< " << type << "&> (x)." << name << " (e, db);"; + } + else if (obj) + inherits (c); + } + + protected: + bool const_; + traversal::inherits inherits_; + }; + + struct class_: traversal::class_, virtual context + { + class_ () + : typedefs_ (false) + { + *this >> defines_ >> *this; + *this >> typedefs_ >> *this; + } + + virtual void + traverse (type& c) + { + class_kind_type ck (class_kind (c)); + + if (ck == class_other || + (!options.at_once () && class_file (c) != unit.file ())) + return; + + names (c); + + switch (ck) + { + case class_object: traverse_object (c); break; + case class_view: traverse_view (c); break; + default: break; + } + } + + void + traverse_object (type&); + + void + traverse_view (type&); + + private: + traversal::defines defines_; + typedefs typedefs_; + + callback_calls callback_calls_; + }; +} + +void inline_::class_:: +traverse_object (type& c) +{ + using semantics::data_member; + + data_member_path* id (id_member (c)); + data_member* idf (id ? id->front () : 0); + bool auto_id (id && auto_ (*id)); + bool base_id (id && &idf->scope () != &c); // Comes from base. + + data_member* opt (context::optimistic (c)); + + // Base class that contains the object id. + // + type* base (base_id ? dynamic_cast<type*> (&idf->scope ()) : 0); + + bool poly (polymorphic (c)); + bool abst (abstract (c)); + bool reuse_abst (abst && !poly); + + user_sections& uss (c.get<user_sections> ("user-sections")); + + string const& type (class_fq_name (c)); + string traits ("access::object_traits< " + type + " >"); + + os << "// " << class_name (c) << endl + << "//" << endl + << endl; + + // id (object_type) + // + if (id != 0 || !reuse_abst) + { + os << "inline" << endl + << traits << "::id_type" << endl + << traits << "::" << endl + << "id (const object_type&" << (id != 0 ? " o" : "") << ")" + << "{"; + + if (id != 0) + { + if (base_id) + os << "return object_traits< " << class_fq_name (*base) << + " >::id (o);"; + else + { + // Get the id using the accessor expressions. + // + string r ("o"); + + for (data_member_path::const_iterator b (id->begin ()), i (b); + i != id->end (); + ++i) + { + member_access& ma ((*i)->get<member_access> ("get")); + + // If this is not a synthesized expression, then output its + // location for easier error tracking. + // + if (!ma.synthesized) + os << "// From " << location_string (ma.loc, true) << endl; + + r = ma.translate (r); + } + + os << "return " << r << ";"; + } + } + + os << "}"; + } + + if (opt != 0) + { + os << "inline" << endl + << traits << "::version_type" << endl + << traits << "::" << endl + << "version (const object_type& o)" + << "{"; + + if (base_id) + os << "return object_traits< " << class_fq_name (*base) << + " >::version (o);"; + else + { + // Get the id using the accessor expression. If this is not + // a synthesized expression, then output its location for + // easier error tracking. + // + member_access& ma (opt->get<member_access> ("get")); + + if (!ma.synthesized) + os << "// From " << location_string (ma.loc, true) << endl; + + os << "return " << ma.translate ("o") << ";"; + } + + os << "}"; + } + + // The rest does not apply to reuse-abstract objects. + // + if (reuse_abst) + return; + + // callback () + // + os << "inline" << endl + << "void " << traits << "::" << endl + << "callback (database& db, object_type& x, callback_event e)" + << endl + << "{" + << "ODB_POTENTIALLY_UNUSED (db);" + << "ODB_POTENTIALLY_UNUSED (x);" + << "ODB_POTENTIALLY_UNUSED (e);" + << endl; + callback_calls_.traverse (c, false); + os << "}"; + + os << "inline" << endl + << "void " << traits << "::" << endl + << "callback (database& db, const object_type& x, callback_event e)" + << "{" + << "ODB_POTENTIALLY_UNUSED (db);" + << "ODB_POTENTIALLY_UNUSED (x);" + << "ODB_POTENTIALLY_UNUSED (e);" + << endl; + callback_calls_.traverse (c, true); + os << "}"; + + // The rest only applies to dynamic milti-database support. + // + if (!multi_dynamic) + return; + + traits = "access::object_traits_impl< " + type + ", id_common >"; + + // + // Forwarding functions. + // + + // persist () + // + os << "inline" << endl + << "void " << traits << "::" << endl + << "persist (database& db, " << (auto_id ? "" : "const ") << + "object_type& o)" + << "{" + << "function_table[db.id ()]->persist (db, o" << + (poly ? ", true, true" : "") << ");" + << "}"; + + if (id != 0) + { + // find (id) + // + if (c.default_ctor ()) + { + os << "inline" << endl + << traits << "::pointer_type" << endl + << traits << "::" << endl + << "find (database& db, const id_type& id)" + << "{" + << "return function_table[db.id ()]->find1 (db, id);" + << "}"; + } + + // find (id, obj) + // + os << "inline" << endl + << "bool " << traits << "::" << endl + << "find (database& db, const id_type& id, object_type& o)" + << "{" + << "return function_table[db.id ()]->find2 (db, id, o" << + (poly ? ", true" : "") << ");" + << "}"; + + // reload () + // + os << "inline" << endl + << "bool " << traits << "::" << endl + << "reload (database& db, object_type& o)" + << "{" + << "return function_table[db.id ()]->reload (db, o" << + (poly ? ", true" : "") << ");" + << "}"; + + // update () + // + // In case of a polymorphic object, we generate update() even if it is + // readonly since the potentially-readwrite base will rely on it to + // initialize the id image. + // + // + if (!readonly (c) || poly) + { + os << "inline" << endl + << "void " << traits << "::" << endl + << "update (database& db, const object_type& o)" + << "{" + << "function_table[db.id ()]->update (db, o" << + (poly ? ", true, true" : "") << ");" + << "}"; + } + + // erase () + // + os << "inline" << endl + << "void " << traits << "::" << endl + << "erase (database& db, const id_type& id)" + << "{" + << "function_table[db.id ()]->erase1 (db, id" << + (poly ? ", true, true" : "") << ");" + << "}"; + + os << "inline" << endl + << "void " << traits << "::" << endl + << "erase (database& db, const object_type& o)" + << "{" + << "function_table[db.id ()]->erase2 (db, o" << + (poly ? ", true, true" : "") << ");" + << "}"; + + // Sections. + // + if (uss.count (user_sections::count_total | + user_sections::count_load | + (poly ? user_sections::count_load_empty : 0)) != 0) + os << "inline" << endl + << "bool " << traits << "::" << endl + << "load (connection& c, object_type& o, section& s)" + << "{" + << "return function_table[c.database ().id ()]->load_section (" << + "c, o, s" << (poly ? ", 0" : "") << ");" + << "}"; + + if (uss.count (user_sections::count_total | + user_sections::count_update | + (poly ? user_sections::count_update_empty : 0)) != 0) + os << "inline" << endl + << "bool " << traits << "::" << endl + << "update (connection& c, const object_type& o, const section& s)" + << "{" + << "return function_table[c.database ().id ()]->update_section (" << + "c, o, s" << (poly ? ", 0" : "") << ");" + << "}"; + } + + if (options.generate_query ()) + { + if (!options.omit_unprepared ()) + { + os << "inline" << endl + << "result< " << traits << "::object_type >" << endl + << traits << "::" << endl + << "query (database& db, const query_base_type& q)" + << "{" + << "return function_table[db.id ()]->query (db, q);" + << "}"; + } + + os << "inline" << endl + << "unsigned long long " << traits << "::" << endl + << "erase_query (database& db, const query_base_type& q)" + << "{" + << "return function_table[db.id ()]->erase_query (db, q);" + << "}"; + + if (options.generate_prepared ()) + { + os << "inline" << endl + << "odb::details::shared_ptr<prepared_query_impl>" << endl + << traits << "::" << endl + << "prepare_query (connection& c, const char* n, " << + "const query_base_type& q)" + << "{" + << "return function_table[c.database ().id ()]->prepare_query (" << + "c, n, q);" + << "}"; + + os << "inline" << endl + << "odb::details::shared_ptr<result_impl>" << endl + << traits << "::" << endl + << "execute_query (prepared_query_impl& pq)" + << "{" + << "return function_table[pq.conn.database ().id ()]->" << + "execute_query (pq);" + << "}"; + } + } +} + +void inline_::class_:: +traverse_view (type& c) +{ + string const& type (class_fq_name (c)); + string traits ("access::view_traits< " + type + " >"); + + os << "// " << class_name (c) << endl + << "//" << endl + << endl; + + // callback () + // + os << "inline" << endl + << "void " << traits << "::" << endl + << "callback (database& db, view_type& x, callback_event e)" + << endl + << "{" + << "ODB_POTENTIALLY_UNUSED (db);" + << "ODB_POTENTIALLY_UNUSED (x);" + << "ODB_POTENTIALLY_UNUSED (e);" + << endl; + callback_calls_.traverse (c, false); + os << "}"; + + // The rest only applies to dynamic milti-database support. + // + if (!multi_dynamic) + return; + + traits = "access::view_traits_impl< " + type + ", id_common >"; + + // + // Forwarding functions. + // + + if (!options.omit_unprepared ()) + { + os << "inline" << endl + << "result< " << traits << "::view_type >" << endl + << traits << "::" << endl + << "query (database& db, const query_base_type& q)" + << "{" + << "return function_table[db.id ()]->query (db, q);" + << "}"; + } + + if (options.generate_prepared ()) + { + os << "inline" << endl + << "odb::details::shared_ptr<prepared_query_impl>" << endl + << traits << "::" << endl + << "prepare_query (connection& c, const char* n, " << + "const query_base_type& q)" + << "{" + << "return function_table[c.database ().id ()]->prepare_query (" << + "c, n, q);" + << "}"; + + os << "inline" << endl + << "odb::details::shared_ptr<result_impl>" << endl + << traits << "::" << endl + << "execute_query (prepared_query_impl& pq)" + << "{" + << "return function_table[pq.conn.database ().id ()]->" << + "execute_query (pq);" + << "}"; + } +} + +namespace inline_ +{ + void + generate () + { + context ctx; + ostream& os (ctx.os); + + if (ctx.multi_dynamic) + os << "#include <odb/database.hxx>" << endl + << endl; + + traversal::unit unit; + traversal::defines unit_defines; + typedefs unit_typedefs (false); + traversal::namespace_ ns; + class_ c; + + unit >> unit_defines >> ns; + unit_defines >> c; + unit >> unit_typedefs >> c; + + traversal::defines ns_defines; + typedefs ns_typedefs (false); + + ns >> ns_defines >> ns; + ns_defines >> c; + ns >> ns_typedefs >> c; + + os << "namespace odb" + << "{"; + + unit.dispatch (ctx.unit); + + os << "}"; + } +} |