diff options
Diffstat (limited to 'odb/odb/header.cxx')
-rw-r--r-- | odb/odb/header.cxx | 902 |
1 files changed, 902 insertions, 0 deletions
diff --git a/odb/odb/header.cxx b/odb/odb/header.cxx new file mode 100644 index 0000000..dacdd1d --- /dev/null +++ b/odb/odb/header.cxx @@ -0,0 +1,902 @@ +// file : odb/header.cxx +// license : GNU GPL v3; see accompanying LICENSE file + +#include <odb/common.hxx> +#include <odb/context.hxx> +#include <odb/generate.hxx> + +using namespace std; + +namespace header +{ + struct class1: traversal::class_, virtual context + { + class1 () + : typedefs_ (false), + query_columns_type_ (false, true, false), + pointer_query_columns_type_ (true, true, 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_; + + instance<query_columns_type> query_columns_type_; + instance<query_columns_type> pointer_query_columns_type_; + }; +} + +void header::class1:: +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)); + + type* poly_root (polymorphic (c)); + bool poly (poly_root != 0); + bool poly_derived (poly && poly_root != &c); + type* poly_base (poly_derived ? &polymorphic_base (c) : 0); + data_member* discriminator (poly ? context::discriminator (*poly_root) : 0); + + 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)); + + os << "// " << class_name (c) << endl + << "//" << endl; + + // class_traits + // + os << "template <>" << endl + << "struct class_traits< " << type << " >" + << "{" + << "static const class_kind kind = class_object;" + << "};"; + + // object_traits + // + os << "template <>" << endl + << "class " << exp << "access::object_traits< " << type << " >" + << "{" + << "public:" << endl; + + // object_type & pointer_type + // + os << "typedef " << type << " object_type;" + << "typedef " << c.get<string> ("object-pointer") << " pointer_type;" + << "typedef odb::pointer_traits<pointer_type> pointer_traits;" + << endl; + + // polymorphic, root_type, base_type, etc. + // + os << "static const bool polymorphic = " << poly << ";" + << endl; + + if (poly) + { + os << "typedef " << class_fq_name (*poly_root) << " root_type;"; + + if (poly_derived) + { + os << "typedef " << class_fq_name (*poly_base) << " base_type;" + << "typedef object_traits<root_type>::discriminator_type " << + "discriminator_type;" + << "typedef polymorphic_concrete_info<root_type> info_type;"; + + if (abst) + os << "typedef polymorphic_abstract_info<root_type> " << + "abstract_info_type;"; + + // Calculate our hierarchy depth (number of classes). + // + size_t depth (polymorphic_depth (c)); + + os << endl + << "static const std::size_t depth = " << depth << "UL;"; + } + else + { + semantics::names* hint; + semantics::type& t (utype (*discriminator, hint)); + + os << "typedef " << t.fq_name (hint) << " discriminator_type;" + << "typedef polymorphic_map<object_type> map_type;" + << "typedef polymorphic_concrete_info<object_type> info_type;"; + + if (abst) + os << "typedef polymorphic_abstract_info<object_type> " << + "abstract_info_type;"; + + os << endl + << "static const std::size_t depth = 1UL;"; + } + + os << endl; + } + + // id_type, version_type, etc. + // + if (id != 0) + { + if (base_id) + { + semantics::class_& b (dynamic_cast<semantics::class_&> (idf->scope ())); + string const& type (class_fq_name (b)); + + os << "typedef object_traits< " << type << " >::id_type id_type;"; + + if (opt != 0) + os << "typedef object_traits< " << type << " >::version_type " << + "version_type;"; + + os << endl; + + if (poly_derived) + os << "static const bool auto_id = false;"; + else + os << "static const bool auto_id = object_traits< " << type << + " >::auto_id;"; + } + else + { + { + semantics::names* hint; + semantics::type& t (utype (*id, hint)); + os << "typedef " << t.fq_name (hint) << " id_type;"; + } + + if (opt != 0) + { + semantics::names* hint; + semantics::type& t (utype (*opt, hint)); + os << "typedef " << t.fq_name (hint) << " version_type;"; + } + + os << endl + << "static const bool auto_id = " << auto_id << ";"; + } + + os << endl; + } + else if (!reuse_abst) + { + // Object without id. + // + os << "typedef void id_type;" + << endl + << "static const bool auto_id = false;" + << endl; + } + + // abstract + // + os << "static const bool abstract = " << abst << ";" + << endl; + + // id() + // + if (id != 0 || !reuse_abst) + { + // We want to generate a dummy void id() accessor even if this + // object has no id to help us in the runtime. This way we can + // write generic code that will work for both void and non-void + // ids. + // + os << "static id_type" << endl + << "id (const object_type&);" + << endl; + } + + // version() + // + if (opt != 0) + { + os << "static version_type" << endl + << "version (const object_type&);" + << endl; + } + + // Query. + // + if (options.generate_query ()) + { + // Generate object pointer tags here if we are generating dynamic + // multi-database support. + // + if (multi_dynamic && has_a (c, test_pointer | exclude_base)) + { + query_tags t; + t.traverse (c); + } + } + + // The rest does not apply to reuse-abstract objects. + // + if (!reuse_abst) + { + // Cache traits typedefs. + // + if (id == 0) + { + os << "typedef" << endl + << "no_id_pointer_cache_traits<pointer_type>" << endl + << "pointer_cache_traits;" + << endl + << "typedef" << endl + << "no_id_reference_cache_traits<object_type>" << endl + << "reference_cache_traits;" + << endl; + } + else + { + char const* obj (poly_derived ? "root_type" : "object_type"); + char const* ptr (poly_derived + ? "object_traits<root_type>::pointer_type" + : "pointer_type"); + if (session (c)) + { + string const& s (options.session_type ()); + + os << "typedef" << endl + << "odb::pointer_cache_traits<" << endl + << " " << ptr << "," << endl + << " " << s << " >" << endl + << "pointer_cache_traits;" + << endl + << "typedef" << endl + << "odb::reference_cache_traits<" << endl + << " " << obj << "," << endl + << " " << s << " >" << endl + << "reference_cache_traits;" + << endl; + } + else + { + os << "typedef" << endl + << "no_op_pointer_cache_traits<" << ptr << ">" << endl + << "pointer_cache_traits;" + << endl + << "typedef" << endl + << "no_op_reference_cache_traits<" << obj << ">" << endl + << "reference_cache_traits;" + << endl; + } + } + + // callback () + // + os << "static void" << endl + << "callback (database&, object_type&, callback_event);" + << endl; + + os << "static void" << endl + << "callback (database&, const object_type&, callback_event);" + << endl; + } + + os << "};"; + + // The rest only applies to dynamic milti-database support. + // + if (!multi_dynamic) + return; + + // pointer_query_columns & query_columns + // + if (options.generate_query ()) + { + // If we don't have object pointers, then also generate + // query_columns (in this case pointer_query_columns and + // query_columns are the same and the former inherits from + // the latter). Otherwise we have to postpone query_columns + // generation until the second pass to deal with forward- + // declared objects. + // + if (!has_a (c, test_pointer | include_base)) + query_columns_type_->traverse (c); + + pointer_query_columns_type_->traverse (c); + } + + // object_traits_impl + // + os << "template <>" << endl + << "class " << exp << "access::object_traits_impl< " << type << ", " << + "id_common >:" << endl + << " public access::object_traits< " << type << " >" + << "{"; + + // We don't need to generate anything else for reuse-abstract objects. + // + if (reuse_abst) + { + os << "};"; + return; + } + + os << "public:" << endl; + + if (options.generate_query ()) + { + // base_traits is needed for query support. + // + if (poly_derived) + os << "typedef object_traits_impl<base_type, id_common> base_traits;" + << endl; + + // query_base_type + // + os << "typedef odb::query_base query_base_type;" + << endl; + } + + // function_table_type + // + os << "struct function_table_type" + << "{"; + + // persist () + // + os << "void (*persist) (database&, " << (auto_id ? "" : "const ") << + "object_type&" << (poly ? ", bool, bool" : "") << ");"; + + if (id != 0) + { + // find (id) + // + if (c.default_ctor ()) + os << "pointer_type (*find1) (database&, const id_type&);"; + + // find (id, obj) + // + os << "bool (*find2) (database&, const id_type&, object_type&" << + (poly ? ", bool" : "") << ");"; + + // reload () + // + os << "bool (*reload) (database&, object_type&" << + (poly ? ", bool" : "") << ");"; + + // update () + // + if (!readonly (c) || poly) + { + os << "void (*update) (database&, const object_type&" << + (poly ? ", bool, bool" : "") << ");"; + } + + // erase () + // + os << "void (*erase1) (database&, const id_type&" << + (poly ? ", bool, bool" : "") << ");"; + + os << "void (*erase2) (database&, const object_type&" << + (poly ? ", bool, bool" : "") << ");"; + + // Sections. + // + if (uss.count (user_sections::count_total | + user_sections::count_load | + (poly ? user_sections::count_load_empty : 0)) != 0) + os << "bool (*load_section) (connection&, object_type&, section&" << + (poly ? ", const info_type*" : "") << ");"; + + if (uss.count (user_sections::count_total | + user_sections::count_update | + (poly ? user_sections::count_update_empty : 0)) != 0) + os << "bool (*update_section) (connection&, const object_type&, " << + "const section&" << (poly ? ", const info_type*" : "") << ");"; + } + + if (options.generate_query ()) + { + if (!options.omit_unprepared ()) + os << "result<object_type> (*query) (database&, const query_base_type&);"; + + os << "unsigned long long (*erase_query) (database&, " << + "const query_base_type&);"; + + if (options.generate_prepared ()) + { + os << "odb::details::shared_ptr<prepared_query_impl> " << + "(*prepare_query) (connection&, const char*, const query_base_type&);"; + + os << "odb::details::shared_ptr<result_impl> (*execute_query) (" + "prepared_query_impl&);"; + } + } + + os << "};" // function_table_type + << "static const function_table_type* function_table[database_count];" + << endl; + + // + // Forwarding functions. + // + + // persist () + // + os << "static void" << endl + << "persist (database&, " << (auto_id ? "" : "const ") << "object_type&);" + << endl; + + if (id != 0) + { + // find (id) + // + if (c.default_ctor ()) + os << "static pointer_type" << endl + << "find (database&, const id_type&);" + << endl; + + // find (id, obj) + // + os << "static bool" << endl + << "find (database&, const id_type&, object_type&);" + << endl; + + // reload () + // + os << "static bool" << endl + << "reload (database&, object_type&);" + << endl; + + // update () + // + if (!readonly (c) || poly) + { + os << "static void" << endl + << "update (database&, const object_type&);" + << endl; + } + + // erase () + // + os << "static void" << endl + << "erase (database&, const id_type&);" + << endl; + + os << "static void" << endl + << "erase (database&, const object_type&);" + << endl; + + // Sections. + // + if (uss.count (user_sections::count_total | + user_sections::count_load | + (poly ? user_sections::count_load_empty : 0)) != 0) + os << "static bool" << endl + << "load (connection&, object_type&, section&);" + << endl; + + if (uss.count (user_sections::count_total | + user_sections::count_update | + (poly ? user_sections::count_update_empty : 0)) != 0) + os << "static bool" << endl + << "update (connection&, const object_type&, const section&);" + << endl; + } + + if (options.generate_query ()) + { + if (!options.omit_unprepared ()) + { + os << "static result<object_type>" << endl + << "query (database&, const query_base_type&);" + << endl; + } + + os << "static unsigned long long" << endl + << "erase_query (database&, const query_base_type&);" + << endl; + + if (options.generate_prepared ()) + { + os << "static odb::details::shared_ptr<prepared_query_impl>" << endl + << "prepare_query (connection&, const char*, const query_base_type&);" + << endl; + + os << "static odb::details::shared_ptr<result_impl>" << endl + << "execute_query (prepared_query_impl&);" + << endl; + } + } + + os << "};"; // object_traits_impl +} + +void header::class1:: +traverse_view (type& c) +{ + string const& type (class_fq_name (c)); + + os << "// " << class_name (c) << endl + << "//" << endl; + + // class_traits + // + os << "template <>" << endl + << "struct class_traits< " << type << " >" + << "{" + << "static const class_kind kind = class_view;" + << "};"; + + // view_traits + // + os << "template <>" << endl + << "class " << exp << "access::view_traits< " << type << " >" + << "{" + << "public:" << endl; + + // view_type & pointer_type + // + os << "typedef " << type << " view_type;" + << "typedef " << c.get<string> ("object-pointer") << " pointer_type;" + << endl; + + // Generate associated object tags here if we are generating dynamic + // multi-database support. + // + if (multi_dynamic) + { + query_tags t; + t.traverse (c); + } + + // callback () + // + os << "static void" << endl + << "callback (database&, view_type&, callback_event);" + << endl; + + os << "};"; + + // The rest only applies to dynamic milti-database support. + // + if (!multi_dynamic) + return; + + size_t obj_count (c.get<size_t> ("object-count")); + + // view_traits_impl + // + os << "template <>" << endl + << "class " << exp << "access::view_traits_impl< " << type << ", " << + "id_common >:" << endl + << " public access::view_traits< " << type << " >" + << "{" + << "public:" << endl; + + // query_base_type and query_columns (definition generated by class2). + // + os << "typedef odb::query_base query_base_type;" + << "struct query_columns"; + + if (obj_count == 0) + os << "{" + << "};"; + else + os << ";" + << endl; + + // function_table_type + // + os << "struct function_table_type" + << "{"; + + if (!options.omit_unprepared ()) + os << "result<view_type> (*query) (database&, const query_base_type&);" + << endl; + + if (options.generate_prepared ()) + { + os << "odb::details::shared_ptr<prepared_query_impl> " << + "(*prepare_query) (connection&, const char*, const query_base_type&);" + << endl; + + os << "odb::details::shared_ptr<result_impl> (*execute_query) (" + "prepared_query_impl&);" + << endl; + } + + os << "};" // function_table_type + << "static const function_table_type* function_table[database_count];" + << endl; + + // + // Forwarding functions. + // + + if (!options.omit_unprepared ()) + os << "static result<view_type>" << endl + << "query (database&, const query_base_type&);" + << endl; + + if (options.generate_prepared ()) + { + os << "static odb::details::shared_ptr<prepared_query_impl>" << endl + << "prepare_query (connection&, const char*, const query_base_type&);" + << endl; + + os << "static odb::details::shared_ptr<result_impl>" << endl + << "execute_query (prepared_query_impl&);" + << endl; + } + + os << "};"; +} + +namespace header +{ + struct class2: traversal::class_, virtual context + { + class2 () + : typedefs_ (false), + query_columns_type_ (false, true, false), + query_columns_type_inst_ (false, false, true), + view_query_columns_type_ (true) + { + *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_; + + instance<query_columns_type> query_columns_type_; + instance<query_columns_type> query_columns_type_inst_; + instance<view_query_columns_type> view_query_columns_type_; + }; +} + +void header::class2:: +traverse_object (type& c) +{ + if (options.generate_query ()) + { + os << "// " << class_name (c) << endl + << "//" << endl; + + // query_columns + // + // If we don't have any pointers, then query_columns is generated + // in pass 1 (see the comment in class1 for details). + // + if (has_a (c, test_pointer | include_base)) + query_columns_type_->traverse (c); + + // Generate extern template declarations. + // + query_columns_type_inst_->traverse (c); + } + + // Move header comment out of if-block if adding any code here. +} + +void header::class2:: +traverse_view (type& c) +{ + // query_columns + // + if (c.get<size_t> ("object-count") != 0) + { + os << "// " << class_name (c) << endl + << "//" << endl; + + view_query_columns_type_->traverse (c); + } + + // Move header comment out of if-block if adding any code here. +} + +namespace header +{ + void + generate () + { + context ctx; + ostream& os (ctx.os); + + os << "#include <memory>" << endl + << "#include <cstddef>" << endl; // std::size_t + + if (ctx.features.polymorphic_object) + os << "#include <string>" << endl; // For discriminator. + + if (ctx.options.std () >= cxx_version::cxx11) + os << "#include <utility>" << endl; // move() + + os << endl; + + os << "#include <odb/core.hxx>" << endl + << "#include <odb/traits.hxx>" << endl + << "#include <odb/callback.hxx>" << endl + << "#include <odb/wrapper-traits.hxx>" << endl + << "#include <odb/pointer-traits.hxx>" << endl; + + // @@ TMP: drop after 2.5.0. + // +#if 0 + if (ctx.options.std () == cxx_version::cxx98) + { + // In case of a boost TR1 implementation, we cannot distinguish + // between the boost::shared_ptr and std::tr1::shared_ptr usage since + // the latter is just a using-declaration for the former. To resolve + // this we will include TR1 traits if the Boost TR1 header is included. + // + if (ctx.features.tr1_pointer) + { + os << "#include <odb/tr1/wrapper-traits.hxx>" << endl + << "#include <odb/tr1/pointer-traits.hxx>" << endl; + } + else if (ctx.features.boost_pointer) + { + os << "#ifdef BOOST_TR1_MEMORY_HPP_INCLUDED" << endl + << "# include <odb/tr1/wrapper-traits.hxx>" << endl + << "# include <odb/tr1/pointer-traits.hxx>" << endl + << "#endif" << endl; + } + } +#endif + + os << "#include <odb/container-traits.hxx>" << endl; + + if (ctx.features.session_object) + { + if (ctx.options.session_type () == "odb::session") + os << "#include <odb/session.hxx>" << endl; + + os << "#include <odb/cache-traits.hxx>" << endl; + } + else + os << "#include <odb/no-op-cache-traits.hxx>" << endl; + + if (ctx.features.polymorphic_object) + os << "#include <odb/polymorphic-info.hxx>" << endl; + + if (ctx.options.generate_query ()) + { + if (ctx.multi_dynamic) + os << "#include <odb/query-dynamic.hxx>" << endl; + + if (ctx.options.generate_prepared ()) + os << "#include <odb/prepared-query.hxx>" << endl; + + os << "#include <odb/result.hxx>" << endl; + + if (ctx.features.simple_object) + os << "#include <odb/simple-object-result.hxx>" << endl; + + if (ctx.features.polymorphic_object) + os << "#include <odb/polymorphic-object-result.hxx>" << endl; + + if (ctx.features.no_id_object) + os << "#include <odb/no-id-object-result.hxx>" << endl; + + if (ctx.features.view) + os << "#include <odb/view-image.hxx>" << endl + << "#include <odb/view-result.hxx>" << endl; + } + + os << endl + << "#include <odb/details/unused.hxx>" << endl; + + if (ctx.options.generate_query ()) + os << "#include <odb/details/shared-ptr.hxx>" << endl; + + os << endl; + + os << "namespace odb" + << "{"; + + // Generate common code. + // + { + traversal::unit unit; + traversal::defines unit_defines; + typedefs unit_typedefs (false); + traversal::namespace_ ns; + class1 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; + + unit.dispatch (ctx.unit); + } + + if (ctx.multi_dynamic) + { + traversal::unit unit; + traversal::defines unit_defines; + typedefs unit_typedefs (false); + traversal::namespace_ ns; + class2 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; + + unit.dispatch (ctx.unit); + } + + os << "}"; + } +} |