// file : odb/header.cxx // copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC // license : GNU GPL v3; see accompanying LICENSE file #include #include #include 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_; instance pointer_query_columns_type_; }; } void header::class1:: traverse_object (type& c) { using semantics::data_member; data_member* id (id_member (c)); bool auto_id (id && auto_ (*id)); bool base_id (id && &id->scope () != &c); // Comes from base. data_member* optimistic (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")); 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 ("object-pointer") << " pointer_type;" << "typedef odb::pointer_traits 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::discriminator_type " << "discriminator_type;" << "typedef polymorphic_concrete_info info_type;"; if (abst) os << "typedef polymorphic_abstract_info " << "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 map_type;" << "typedef polymorphic_concrete_info info_type;"; if (abst) os << "typedef polymorphic_abstract_info " << "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 (id->scope ())); string const& type (class_fq_name (b)); os << "typedef object_traits< " << type << " >::id_type id_type;"; if (optimistic != 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 (optimistic != 0) { semantics::names* hint; semantics::type& t (utype (*optimistic, 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; } // 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" << endl << "pointer_cache_traits;" << endl << "typedef" << endl << "no_id_reference_cache_traits" << endl << "reference_cache_traits;" << endl; } else { char const* obj (poly_derived ? "root_type" : "object_type"); char const* ptr (poly_derived ? "object_traits::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_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 (*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 " << "(*prepare_query) (connection&, const char*, const query_base_type&);"; os << "odb::details::shared_ptr (*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" << 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" << endl << "prepare_query (connection&, const char*, const query_base_type&);" << endl; os << "static odb::details::shared_ptr" << 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 ("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 ("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 (*query) (database&, const query_base_type&);" << endl; if (options.generate_prepared ()) { os << "odb::details::shared_ptr " << "(*prepare_query) (connection&, const char*, const query_base_type&);" << endl; os << "odb::details::shared_ptr (*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" << endl << "query (database&, const query_base_type&);" << endl; if (options.generate_prepared ()) { os << "static odb::details::shared_ptr" << endl << "prepare_query (connection&, const char*, const query_base_type&);" << endl; os << "static odb::details::shared_ptr" << 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_; instance query_columns_type_inst_; instance 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 ("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 " << endl << "#include " << endl; // std::size_t if (ctx.features.polymorphic_object) os << "#include " << endl; // For discriminator. os << endl; os << "#include " << endl << "#include " << endl << "#include " << endl << "#include " << endl << "#include " << endl; // 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 " << endl << "#include " << endl; } else if (ctx.features.boost_pointer) { os << "#ifdef BOOST_TR1_MEMORY_HPP_INCLUDED" << endl << "# include " << endl << "# include " << endl << "#endif" << endl; } os << "#include " << endl; if (ctx.features.session_object) { if (ctx.options.session_type () == "odb::session") os << "#include " << endl; os << "#include " << endl; } else os << "#include " << endl; if (ctx.features.polymorphic_object) os << "#include " << endl; if (ctx.options.generate_query ()) { if (ctx.multi_dynamic) os << "#include " << endl; if (ctx.options.generate_prepared ()) os << "#include " << endl; os << "#include " << endl; if (ctx.features.simple_object) os << "#include " << endl; if (ctx.features.polymorphic_object) os << "#include " << endl; if (ctx.features.no_id_object) os << "#include " << endl; if (ctx.features.view) os << "#include " << endl; } os << endl << "#include " << endl; if (ctx.options.generate_query ()) os << "#include " << 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 << "}"; } }