// file : odb/relational/inline.hxx // copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC // license : GNU GPL v3; see accompanying LICENSE file #ifndef ODB_RELATIONAL_INLINE_HXX #define ODB_RELATIONAL_INLINE_HXX #include #include #include namespace relational { namespace inline_ { // // get/set null (composite value only) // struct null_member: virtual member_base { typedef null_member base; null_member (bool get) : member_base (string (), 0, string (), string ()), get_ (get) { } protected: bool get_; }; template struct null_member_impl: null_member, virtual member_base_impl { typedef null_member_impl base_impl; null_member_impl (base const& x): base (x) {} typedef typename member_base_impl::member_info member_info; virtual bool pre (member_info& mi) { // If the member is soft- added or deleted, check the version. // unsigned long long av (added (mi.m)); unsigned long long dv (deleted (mi.m)); if (av != 0 || dv != 0) { os << "if ("; if (av != 0) os << "svm >= schema_version_migration (" << av << "ULL, true)"; if (av != 0 && dv != 0) os << " &&" << endl; if (dv != 0) os << "svm <= schema_version_migration (" << dv << "ULL, true)"; os << ")" << "{"; } // If the whole value type is readonly, then set will never be // called with sk == statement_update. // if (!get_ && !readonly (*context::top_object)) { semantics::class_* c; if (readonly (mi.m) || ((c = composite (mi.t)) && readonly (*c))) os << "if (sk == statement_insert)" << endl; } return true; } virtual void post (member_info& mi) { if (added (mi.m) || deleted (mi.m)) os << "}"; } virtual void traverse_composite (member_info& mi) { string traits ("composite_value_traits< " + mi.fq_type () + ", id_" + db.string () + " >"); if (get_) os << "r = r && " << traits << "::get_null (" << "i." << mi.var << "value"; else os << traits << "::set_null (i." << mi.var << "value, sk"; if (versioned (*composite (mi.t))) os << ", svm"; os << ");"; } }; struct null_base: traversal::class_, virtual context { typedef null_base base; null_base (bool get): get_ (get) {} virtual void traverse (type& c) { // Ignore transient bases. // if (!composite (c)) return; string traits ("composite_value_traits< " + class_fq_name (c) + ", id_" + db.string () + " >"); // If the derived value type is readonly, then set will never be // called with sk == statement_update. // if (!get_ && readonly (c) && !readonly (*context::top_object)) os << "if (sk == statement_insert)" << endl; if (get_) os << "r = r && " << traits << "::get_null (i"; else os << traits << "::set_null (i, sk"; if (versioned (c)) os << ", svm"; os << ");"; } protected: bool get_; }; // // struct class_: traversal::class_, virtual context { typedef class_ base; class_ () : typedefs_ (false), get_null_base_ (true), get_null_member_ (true), set_null_base_ (false), set_null_member_ (false) { init (); } class_ (class_ const&) : root_context (), //@@ -Wextra context (), typedefs_ (false), get_null_base_ (true), get_null_member_ (true), set_null_base_ (false), set_null_member_ (false) { init (); } void init () { *this >> defines_ >> *this; *this >> typedefs_ >> *this; get_null_base_inherits_ >> get_null_base_; get_null_member_names_ >> get_null_member_; set_null_base_inherits_ >> set_null_base_; set_null_member_names_ >> set_null_member_; } 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); context::top_object = context::cur_object = &c; switch (ck) { case class_object: traverse_object (c); break; case class_view: traverse_view (c); break; case class_composite: traverse_composite (c); break; default: break; } context::top_object = context::cur_object = 0; } virtual void object_extra (type&) { } virtual void traverse_object (type& c) { using semantics::data_member; data_member* id (id_member (c)); bool base_id (id && &id->scope () != &c); // Comes from base. data_member* optimistic (context::optimistic (c)); // Base class that contains the object id and version for optimistic // concurrency. // type* base ( id != 0 && base_id ? dynamic_cast (&id->scope ()) : 0); type* poly_root (context::polymorphic (c)); bool poly (poly_root != 0); bool poly_derived (poly && poly_root != &c); bool abst (abstract (c)); bool reuse_abst (abst && !poly); bool versioned (context::versioned (c)); string const& type (class_fq_name (c)); string traits ("access::object_traits_impl< " + type + ", id_" + db.string () + " >"); user_sections& uss (c.get ("user-sections")); os << "// " << class_name (c) << endl << "//" << endl << endl; object_extra (c); if (id != 0 && base_id) { if (!poly_derived) { // id (image_type) // if (options.generate_query ()) { os << "inline" << endl << traits << "::id_type" << endl << traits << "::" << endl << "id (const image_type& i)" << "{" << "return object_traits_impl< " << class_fq_name (*base) << ", id_" << db << " >::id (i);" << "}"; } // version (image_type) // if (optimistic != 0) { os << "inline" << endl << traits << "::version_type" << endl << traits << "::" << endl << "version (const image_type& i)" << "{" << "return object_traits_impl< " << class_fq_name (*base) << ", id_" << db << " >::version (i);" << "}"; } } // bind (id_image_type) // os << "inline" << endl << "void " << traits << "::" << endl << "bind (" << bind_vector << " b, id_image_type& i" << (optimistic != 0 ? ", bool bv" : "") << ")" << "{" << "object_traits_impl< " << class_fq_name (*base) << ", id_" << db << " >::bind (b, i" << (optimistic != 0 ? ", bv" : "") << ");" << "}"; os << "inline" << endl << "void " << traits << "::" << endl << "init (id_image_type& i, const id_type& id" << (optimistic != 0 ? ", const version_type* v" : "") << ")" << "{" << "object_traits_impl< " << class_fq_name (*base) << ", id_" << db << " >::init (i, id" << (optimistic != 0 ? ", v" : "") << ");" << "}"; } if (poly_derived) { size_t depth (polymorphic_depth (c)); // check_version // os << "inline" << endl << "bool " << traits << "::" << endl << "check_version (const std::size_t* v, const image_type& i)" << "{" << "return "; string image ("i."); for (size_t i (0); i < depth; ++i) { os << (i == 0 ? "" : " ||") << endl << " v[" << i << "UL] != " << image << "version"; image += "base->"; } os << ";" << "}"; // update_version // os << "inline" << endl << "void " << traits << "::" << endl << "update_version (std::size_t* v, const image_type& i, " << db << "::binding* b)" << "{"; image = "i."; for (size_t i (0); i < depth; ++i) { os << "v[" << i << "UL] = " << image << "version;"; image += "base->"; } // A poly-abstract class always has only one entry in the // bindings array. // if (abst) os << "b[0].version++;"; else for (size_t i (0); i < depth; ++i) os << "b[" << i << "UL].version++;"; os << "}"; } // The rest does not apply to reuse-abstract objects. // if (reuse_abst) return; // erase (object_type) // if (id != 0 && !poly && optimistic == 0 && !has_a (c, test_smart_container)) { os << "inline" << endl << "void " << traits << "::" << endl << "erase (database& db, const object_type& obj)" << "{" << "callback (db, obj, callback_event::pre_erase);" << "erase (db, id (obj));"; // Note that we don't reset sections since the object is now // transient and the state of a section in a transient object // is undefined. os << "callback (db, obj, callback_event::post_erase);" << "}"; } // load (section) [thunk version; poly_derived is true] // if (uss.count (user_sections::count_total | user_sections::count_load | (poly ? user_sections::count_load_empty : 0)) != 0 && uss.count (user_sections::count_new | user_sections::count_load | (poly ? user_sections::count_load_empty : 0)) == 0) { os << "inline" << endl << "bool " << traits << "::" << endl << "load (connection& conn, object_type& obj, section& s, " << "const info_type* pi)" << "{" << "return base_traits::load (conn, obj, s, pi);" << "}"; } // update (section) [thunk version; poly_derived is true] // if (uss.count (user_sections::count_total | user_sections::count_update | (poly ? user_sections::count_update_empty : 0)) != 0 && uss.count (user_sections::count_new | user_sections::count_update | (poly ? user_sections::count_update_empty : 0)) == 0) { os << "inline" << endl << "bool " << traits << "::" << endl << "update (connection& conn, const object_type& obj, " << "const section& s, const info_type* pi)" << "{" << "return base_traits::update (conn, obj, s, pi);" << "}"; } // load_() // if (id != 0 && !(poly_derived || has_a (c, test_container | include_eager_load, &main_section) || uss.count (user_sections::count_new | user_sections::count_load | (poly ? user_sections::count_load_empty : 0)) != 0)) { os << "inline" << endl << "void " << traits << "::" << endl << "load_ (statements_type& sts," << endl << "object_type& obj," << endl << "bool"; if (versioned) os << "," << endl << "const schema_version_migration& svm"; os << ")" << "{" << "ODB_POTENTIALLY_UNUSED (sts);" << "ODB_POTENTIALLY_UNUSED (obj);"; if (versioned) os << "ODB_POTENTIALLY_UNUSED (svm);"; os << endl; // Mark eager sections as loaded. // for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i) { // Skip special sections. // if (i->special == user_section::special_version) continue; data_member& m (*i->member); // If the section is soft- added or deleted, check the version. // We can only end up here if the object itself is versioned // (simple value section). // unsigned long long av (added (m)); unsigned long long dv (deleted (m)); if (av != 0 || dv != 0) { os << "if ("; if (av != 0) os << "svm >= schema_version_migration (" << av << "ULL, true)"; if (av != 0 && dv != 0) os << " &&" << endl; if (dv != 0) os << "svm <= schema_version_migration (" << dv << "ULL, true)"; os << ")" << endl; } // Section access is always by reference. // member_access& ma (m.get ("get")); if (!ma.synthesized) os << "// From " << location_string (ma.loc, true) << endl; os << ma.translate ("obj") << ".reset (true, false);" << endl; } os << "}"; } if (poly && need_image_clone && options.generate_query ()) { // root_image () // os << "inline" << endl << traits << "::root_traits::image_type&" << endl << traits << "::" << endl << "root_image (image_type& i)" << "{"; if (poly_derived) os << "return base_traits::root_image (*i.base);"; else os << "return i;"; os << "}"; // clone_image () // os << "inline" << endl << traits << "::image_type*" << endl << traits << "::" << endl << "clone_image (const image_type& i)" << "{"; if (poly_derived) os << "details::unique_ptr p (" << endl << "base_traits::clone_image (*i.base));" << "image_type* c (new image_type (i));" << "c->base = p.release ();" << "return c;"; else os << "return new image_type (i);"; os << "}"; // copy_image () // os << "inline" << endl << "void " << traits << "::" << endl << "copy_image (image_type& d, const image_type& s)" << "{"; if (poly_derived) os << "base_traits::image_type* b (d.base);" << "base_traits::copy_image (*b, *s.base);" << "d = s;" // Overwrites the base pointer. << "d.base = b;"; else os << "d = s;"; os << "}"; // free_image () // os << "inline" << endl << "void " << traits << "::" << endl << "free_image (image_type* i)" << "{"; if (poly_derived) os << "base_traits::free_image (i->base);"; os << "delete i;" << "}"; } } virtual void view_extra (type&) { } virtual void traverse_view (type& c) { string const& type (class_fq_name (c)); string traits ("access::view_traits_impl< " + type + ", id_" + db.string () + " >"); os << "// " << class_name (c) << endl << "//" << endl << endl; view_extra (c); } virtual void traverse_composite (type& c) { bool versioned (context::versioned (c)); string const& type (class_fq_name (c)); string traits ("access::composite_value_traits< " + type + ", id_" + db.string () + " >"); os << "// " << class_name (c) << endl << "//" << endl << endl; if (!has_a (c, test_container)) { // get_null (image) // os << "inline" << endl << "bool " << traits << "::" << endl << "get_null (const image_type& i"; if (versioned) os << "," << endl << "const schema_version_migration& svm"; os << ")" << "{"; if (versioned) os << "ODB_POTENTIALLY_UNUSED (svm);" << endl; os << "bool r (true);"; inherits (c, get_null_base_inherits_); names (c, get_null_member_names_); os << "return r;" << "}"; // set_null (image) // os << "inline" << endl << "void " << traits << "::" << endl << "set_null (image_type& i," << endl << db << "::statement_kind sk"; if (versioned) os << "," << endl << "const schema_version_migration& svm"; os << ")" << "{" << "ODB_POTENTIALLY_UNUSED (sk);"; if (versioned) os << "ODB_POTENTIALLY_UNUSED (svm);"; os << endl << "using namespace " << db << ";" << endl; inherits (c, set_null_base_inherits_); names (c, set_null_member_names_); os << "}"; } } private: traversal::defines defines_; typedefs typedefs_; instance get_null_base_; traversal::inherits get_null_base_inherits_; instance get_null_member_; traversal::names get_null_member_names_; instance set_null_base_; traversal::inherits set_null_base_inherits_; instance set_null_member_; traversal::names set_null_member_names_; }; struct include: virtual context { typedef include base; virtual void generate () { if (features.polymorphic_object && options.generate_query ()) os << "#include " << endl << endl; } }; } } #endif // ODB_RELATIONAL_INLINE_HXX