From 5adda85ed10d9196f4d68cc4b8fee12f6ba9cfec Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 9 Dec 2010 10:36:15 +0200 Subject: Add lazy pointer support Built-in support is provided for raw, auto, and tr1 shared/weak pointers. New test: common/lazy-ptr. --- odb/context.cxx | 11 +++- odb/context.hxx | 131 +++++++++++++++++++++++++------------- odb/mysql/common.cxx | 4 +- odb/mysql/schema.cxx | 2 +- odb/mysql/source.cxx | 87 +++++++++++++++++++------ odb/type-processor.cxx | 169 +++++++++++++++++++++++++++++++++++++++---------- 6 files changed, 302 insertions(+), 102 deletions(-) diff --git a/odb/context.cxx b/odb/context.cxx index ec8dec9..b606734 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -490,19 +490,24 @@ namespace bool context:: is_a (semantics::data_member& m, unsigned short f, - semantics::type&, + semantics::type& t, string const& kp) { bool r (false); if (f & test_pointer) { - r = r || object_pointer (m, kp); + r = r || object_pointer (t); } if (f & test_eager_pointer) { - r = r || object_pointer (m, kp); + r = r || (object_pointer (t) && !lazy_pointer (t)); + } + + if (f & test_lazy_pointer) + { + r = r || (object_pointer (t) && lazy_pointer (t)); } if (f & test_container) diff --git a/odb/context.hxx b/odb/context.hxx index 47375a3..6f5e89e 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -25,6 +25,16 @@ using std::cerr; class generation_failed {}; +// Keep this enum synchronized with the one in libodb/odb/pointer-traits.hxx. +// +enum pointer_kind +{ + pk_naked, + pk_unique, + pk_shared, + pk_weak +}; + // Keep this enum synchronized with the one in libodb/odb/container-traits.hxx. // enum container_kind @@ -43,6 +53,15 @@ public: typedef std::string string; typedef ::options options_type; +public: + static semantics::type& + member_type (semantics::data_member& m, string const& key_prefix) + { + return key_prefix.empty () + ? m.type () + : *m.type ().get ("tree-" + key_prefix + "-type"); + } + // Predicates. // public: @@ -78,50 +97,9 @@ public: } static semantics::class_* - object_pointer (semantics::data_member& m, - string const& key_prefix = string ()) + object_pointer (semantics::type& t) { - using semantics::class_; - - return key_prefix.empty () - ? m.get ("object-pointer", 0) - : m.get (key_prefix + "-object-pointer", 0); - } - - static bool - null_pointer (semantics::data_member& m) - { - return !(m.count ("not-null") || m.type ().count ("not-null")); - } - - static bool - null_pointer (semantics::data_member& m, string const& key_prefix) - { - if (key_prefix.empty ()) - return null_pointer (m); - - return !(m.count (key_prefix + "-not-null") || - m.type ().count ("not-null") || - m.type ().get ( - "tree-" + key_prefix +"-type")->count ("not-null")); - } - - static semantics::data_member* - inverse (semantics::data_member& m, string const& key_prefix = string ()) - { - using semantics::data_member; - - return object_pointer (m, key_prefix) - ? (key_prefix.empty () - ? m.get ("inverse", 0) - : m.get (key_prefix + "-inverse", 0)) - : 0; - } - - static bool - unordered (semantics::data_member& m) - { - return m.count ("unordered") || m.type ().count ("unordered"); + return t.get ("element-type", 0); } // Database names and types. @@ -187,6 +165,65 @@ public: semantics::data_member& id_member (semantics::class_&); + // Object pointer information. + // +public: + typedef ::pointer_kind pointer_kind_type; + + static pointer_kind_type + pointer_kind (semantics::type& p) + { + return p.get ("pointer-kind"); + } + + static bool + lazy_pointer (semantics::type& p) + { + return p.get ("pointer-lazy"); + } + + static bool + weak_pointer (semantics::type& p) + { + return pointer_kind (p) == pk_weak; + } + + static bool + null_pointer (semantics::data_member& m) + { + return !(m.count ("not-null") || m.type ().count ("not-null")); + } + + static bool + null_pointer (semantics::data_member& m, string const& key_prefix) + { + if (key_prefix.empty ()) + return null_pointer (m); + + return !(m.count (key_prefix + "-not-null") || + m.type ().count ("not-null") || + member_type (m, key_prefix).count ("not-null")); + } + + static semantics::data_member* + inverse (semantics::data_member& m) + { + return object_pointer (m.type ()) + ? m.get ("inverse", 0) + : 0; + } + + static semantics::data_member* + inverse (semantics::data_member& m, string const& key_prefix) + { + if (key_prefix.empty ()) + return inverse (m); + + return object_pointer (member_type (m, key_prefix)) + ? m.get (key_prefix + "-inverse", 0) + : 0; + } + // Container information. // public: @@ -216,10 +253,16 @@ public: return *c.get ("tree-key-type"); } + static bool + unordered (semantics::data_member& m) + { + return m.count ("unordered") || m.type ().count ("unordered"); + } + // The 'is a' and 'has a' tests. The has_a test currently does not // cross the container boundaries. // - +public: static unsigned short const test_pointer = 0x01; static unsigned short const test_eager_pointer = 0x02; static unsigned short const test_lazy_pointer = 0x04; diff --git a/odb/mysql/common.cxx b/odb/mysql/common.cxx index 3cec95c..830407d 100644 --- a/odb/mysql/common.cxx +++ b/odb/mysql/common.cxx @@ -55,7 +55,7 @@ namespace mysql { sql_type const& st (db_type (m, key_prefix_)); - if (semantics::class_* c = object_pointer (m, key_prefix_)) + if (semantics::class_* c = object_pointer (t)) { member_info mi (m, id_member (*c).type (), var, fq_type_override_); mi.st = &st; @@ -490,7 +490,7 @@ namespace mysql { string name (public_name (m)); - if (semantics::class_* c = object_pointer (m)) + if (semantics::class_* c = object_pointer (m.type ())) { // We cannot just typedef the query_type from the referenced // object for two reasons: (1) it may not be defined yet and diff --git a/odb/mysql/schema.cxx b/odb/mysql/schema.cxx index e02dde6..f99cf40 100644 --- a/odb/mysql/schema.cxx +++ b/odb/mysql/schema.cxx @@ -40,7 +40,7 @@ namespace mysql os << " PRIMARY KEY"; using semantics::class_; - if (class_* c = object_pointer (m, prefix_)) + if (class_* c = object_pointer (member_type (m, prefix_))) { os << " REFERENCES `" << table_name (*c) << "` (`" << column_name (id_member (*c)) << "`)"; diff --git a/odb/mysql/source.cxx b/odb/mysql/source.cxx index e09cbc3..3841208 100644 --- a/odb/mysql/source.cxx +++ b/odb/mysql/source.cxx @@ -65,7 +65,7 @@ namespace mysql // if (im != 0) { - semantics::class_* c (object_pointer (m)); + semantics::class_* c (object_pointer (m.type ())); if (container (im->type ())) { @@ -140,7 +140,7 @@ namespace mysql virtual bool column (semantics::data_member& m, string const& col_name, bool) { - semantics::class_* c (object_pointer (m)); + semantics::class_* c (object_pointer (m.type ())); if (c == 0) return true; @@ -758,7 +758,12 @@ namespace mysql traits = "composite_value_traits< " + mi.fq_type () + " >"; else { - if (semantics::class_* c = object_pointer (mi.m, key_prefix_)) + // When handling a pointer, mi.t is the id type of the referenced + // object. + // + semantics::type& mt (member_type (mi.m, key_prefix_)); + + if (semantics::class_* c = object_pointer (mt)) { type = "obj_traits::id_type"; image_type = member_image_type_.image_type (mi.m); @@ -768,15 +773,37 @@ namespace mysql // os << "{" << "typedef object_traits< " << c->fq_name () << - " > obj_traits;" - << "typedef pointer_traits< " << mi.fq_type () << + " > obj_traits;"; + + if (weak_pointer (mt)) + { + os << "typedef pointer_traits< " << mi.fq_type () << + " > wptr_traits;" + << "typedef pointer_traits< wptr_traits::" << + "strong_pointer_type > ptr_traits;" + << endl + << "wptr_traits::strong_pointer_type sp (" << + "wptr_traits::lock (" << member << "));"; + + member = "sp"; + } + else + os << "typedef pointer_traits< " << mi.fq_type () << " > ptr_traits;" - << endl - << "bool is_null (ptr_traits::null_ptr (" << member << "));" + << endl; + + os << "bool is_null (ptr_traits::null_ptr (" << member << "));" << "if (!is_null)" << "{" - << "const " << type << "& id (" << endl - << "obj_traits::id (ptr_traits::get_ref (" << member << ")));" + << "const " << type << "& id (" << endl; + + if (lazy_pointer (mt)) + os << "ptr_traits::object_id< ptr_traits::element_type > (" << + member << ")"; + else + os << "obj_traits::id (ptr_traits::get_ref (" << member << "))"; + + os << ");" << endl; member = "id"; @@ -805,7 +832,10 @@ namespace mysql { if (!comp_value (mi.t)) { - if (object_pointer (mi.m, key_prefix_)) + // When handling a pointer, mi.t is the id type of the referenced + // object. + // + if (object_pointer (member_type (mi.m, key_prefix_))) { os << "}"; @@ -1029,7 +1059,12 @@ namespace mysql traits = "composite_value_traits< " + mi.fq_type () + " >"; else { - if (semantics::class_* c = object_pointer (mi.m, key_prefix_)) + // When handling a pointer, mi.t is the id type of the referenced + // object. + // + semantics::type& mt (member_type (mi.m, key_prefix_)); + + if (semantics::class_* c = object_pointer (mt)) { type = "obj_traits::id_type"; image_type = member_image_type_.image_type (mi.m); @@ -1075,19 +1110,31 @@ namespace mysql virtual void post (member_info& mi) { - if (!comp_value (mi.t) && object_pointer (mi.m, key_prefix_)) + if (comp_value (mi.t)) + return; + + // When handling a pointer, mi.t is the id type of the referenced + // object. + // + semantics::type& mt (member_type (mi.m, key_prefix_)); + + if (object_pointer (mt)) { member = member_override_.empty () ? "o." + mi.m.name () : member_override_; - os << "// If a compiler error points to the line below, then" << endl - << "// it most likely means that a pointer used in a member" << endl - << "// cannot be initialized from an object pointer." << endl - << "//" << endl - << member << " = ptr_traits::pointer_type (" << endl - << "db.load< ptr_traits::element_type > (id));" - << "}" + if (lazy_pointer (mt)) + os << member << " = ptr_traits::pointer_type (db, id);"; + else + os << "// If a compiler error points to the line below, then" << endl + << "// it most likely means that a pointer used in a member" << endl + << "// cannot be initialized from an object pointer." << endl + << "//" << endl + << member << " = ptr_traits::pointer_type (" << endl + << "db.load< ptr_traits::element_type > (id));"; + + os << "}" << "}"; } } @@ -1316,7 +1363,7 @@ namespace mysql if (inverse) { - semantics::class_* c (object_pointer (m, "value")); + semantics::class_* c (object_pointer (vt)); string inv_table; // Other table name. string inv_id; // Other id column. diff --git a/odb/type-processor.cxx b/odb/type-processor.cxx index 381a4e4..e225d85 100644 --- a/odb/type-processor.cxx +++ b/odb/type-processor.cxx @@ -270,7 +270,6 @@ namespace size_t l (DECL_SOURCE_LINE (decl)); size_t c (DECL_SOURCE_COLUMN (decl)); - // Determine the container kind. // try @@ -313,7 +312,7 @@ namespace catch (generation_failed const&) { os << f << ":" << l << ":" << c << ": error: " - << "odb::container_traits specialization does not define the " + << "container_traits specialization does not define the " << "container kind constant" << endl; throw; @@ -339,7 +338,7 @@ namespace catch (generation_failed const&) { os << f << ":" << l << ":" << c << ": error: " - << "odb::container_traits specialization does not define the " + << "container_traits specialization does not define the " << "value_type type" << endl; throw; @@ -368,7 +367,7 @@ namespace catch (generation_failed const&) { os << f << ":" << l << ":" << c << ": error: " - << "odb::container_traits specialization does not define the " + << "container_traits specialization does not define the " << "index_type type" << endl; throw; @@ -397,7 +396,7 @@ namespace catch (generation_failed const&) { os << f << ":" << l << ":" << c << ": error: " - << "odb::container_traits specialization does not define the " + << "container_traits specialization does not define the " << "key_type type" << endl; throw; @@ -439,39 +438,145 @@ namespace using semantics::class_; using semantics::data_member; - tree inst (instantiate_template (pointer_traits_, t.tree_node ())); - - if (inst == 0) - return 0; + class_* c (0); - // Get the element type. - // - tree tn (0); - try + if (t.count ("element-type")) + c = t.get ("element-type"); + else { - tree decl ( - lookup_qualified_name ( - inst, get_identifier ("element_type"), true, false)); + tree inst (instantiate_template (pointer_traits_, t.tree_node ())); - if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) - throw generation_failed (); + if (inst == 0) + return 0; - tn = TYPE_MAIN_VARIANT (TREE_TYPE (decl)); - } - catch (generation_failed const&) - { - os << m.file () << ":" << m.line () << ":" << m.column () << ": " - << "error: odb::pointer_traits specialization does not define " - << "the element_type type" << endl; - throw; - } + // @@ This points to the primary template, not the specialization. + // + tree decl (TYPE_NAME (inst)); - class_* c (dynamic_cast (unit.find (tn))); + string fl (DECL_SOURCE_FILE (decl)); + size_t ln (DECL_SOURCE_LINE (decl)); + size_t cl (DECL_SOURCE_COLUMN (decl)); - if (c == 0 || !c->count ("object")) - return 0; + // Get the element type. + // + tree tn (0); + try + { + tree decl ( + lookup_qualified_name ( + inst, get_identifier ("element_type"), true, false)); + + if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL) + throw generation_failed (); + + tn = TYPE_MAIN_VARIANT (TREE_TYPE (decl)); + } + catch (generation_failed const&) + { + os << fl << ":" << ln << ":" << cl << ": error: pointer_traits " + << "specialization does not define the 'element_type' type" + << endl; + throw; + } + + c = dynamic_cast (unit.find (tn)); + + if (c == 0 || !c->count ("object")) + return 0; + + t.set ("element-type", c); + + // Determine the pointer kind. + // + try + { + tree kind ( + lookup_qualified_name ( + inst, get_identifier ("kind"), false, false)); + + if (kind == error_mark_node || TREE_CODE (kind) != VAR_DECL) + throw generation_failed (); + + // Instantiate this decalaration so that we can get its value. + // + if (DECL_TEMPLATE_INSTANTIATION (kind) && + !DECL_TEMPLATE_INSTANTIATED (kind) && + !DECL_EXPLICIT_INSTANTIATION (kind)) + instantiate_decl (kind, false, false); + + tree init (DECL_INITIAL (kind)); + + if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) + throw generation_failed (); + + unsigned long long e; + + { + HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init)); + HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init)); + + unsigned long long l (hwl); + unsigned long long h (hwh); + unsigned short width (HOST_BITS_PER_WIDE_INT); + + e = (h << width) + l; + } + + pointer_kind_type pk = static_cast (e); + t.set ("pointer-kind", pk); + } + catch (generation_failed const&) + { + os << fl << ":" << ln << ":" << cl << ": error: pointer_traits " + << "specialization does not define the 'kind' constant" << endl; + throw; + } + + // Get the lazy flag. + // + try + { + tree lazy ( + lookup_qualified_name ( + inst, get_identifier ("lazy"), false, false)); + + if (lazy == error_mark_node || TREE_CODE (lazy) != VAR_DECL) + throw generation_failed (); + + // Instantiate this decalaration so that we can get its value. + // + if (DECL_TEMPLATE_INSTANTIATION (lazy) && + !DECL_TEMPLATE_INSTANTIATED (lazy) && + !DECL_EXPLICIT_INSTANTIATION (lazy)) + instantiate_decl (lazy, false, false); + + tree init (DECL_INITIAL (lazy)); + + if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST) + throw generation_failed (); + + unsigned long long e; + + { + HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init)); + HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init)); - m.set (kp + (kp.empty () ? "": "-") + "object-pointer", c); + unsigned long long l (hwl); + unsigned long long h (hwh); + unsigned short width (HOST_BITS_PER_WIDE_INT); + + e = (h << width) + l; + } + + t.set ("pointer-lazy", static_cast (e)); + } + catch (generation_failed const&) + { + os << fl << ":" << ln << ":" << cl << ": error: pointer_traits " + << "specialization does not define the 'kind' constant" << endl; + throw; + } + } if (m.count ("not-null") && !kp.empty ()) { @@ -487,7 +592,7 @@ namespace string name (m.get ("inverse")); tree decl ( lookup_qualified_name ( - tn, get_identifier (name.c_str ()), false, false)); + c->tree_node (), get_identifier (name.c_str ()), false, false)); if (decl == error_mark_node || TREE_CODE (decl) != FIELD_DECL) { -- cgit v1.1