From eacf52a9a4f3832274fdefc909ab23c13413e128 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 15 Aug 2012 11:46:00 +0200 Subject: Add support for member accessors/modifiers New pragmas: get, set, access. New test: common/access. --- odb/relational/source.hxx | 379 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 283 insertions(+), 96 deletions(-) (limited to 'odb/relational/source.hxx') diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index a1f1190..38bb80f 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -1127,6 +1127,9 @@ namespace relational virtual void set_null (member_info&) = 0; + virtual void + check_accessor (member_info&, member_access&) {} + virtual bool pre (member_info& mi) { @@ -1142,8 +1145,13 @@ namespace relational if (mi.ptr != 0 && mi.m.count ("polymorphic-ref")) return false; + bool comp (composite (mi.t)); + if (!member_override_.empty ()) + { member = member_override_; + os << "{"; + } else { // If we are generating standard init() and this member @@ -1158,9 +1166,7 @@ namespace relational if (!insert_send_auto_id && id (mi.m) && auto_ (mi.m)) return false; - string const& name (mi.m.name ()); - - os << "// " << name << endl + os << "// " << mi.m.name () << endl << "//" << endl; // If the whole class is readonly, then we will never be @@ -1176,13 +1182,37 @@ namespace relational os << "if (sk == statement_insert)"; } + os << "{"; + if (discriminator (mi.m)) member = "di.discriminator"; else - member = "o." + name; - } + { + // Get the member using the accessor expression. + // + member_access& ma (mi.m.template get ("get")); - bool comp (composite (mi.t)); + // Make sure this kind of member can be accessed with this + // kind of accessor (database-specific, e.g., streaming). + // + if (!comp) + check_accessor (mi, ma); + + // If this is not a synthesized expression, then output + // its location for easier error tracking. + // + if (ma.loc != 0) + os << "// From " << location_string (ma.loc, true) << endl; + + // Use the original type to form the const reference. + // + os << member_ref_type (mi.m, true, "v") << " (" << endl + << ma.translate ("o") << ");" + << endl; + + member = "v"; + } + } // If this is a wrapped composite value, then we need to "unwrap" // it. If this is a NULL wrapper, then we also need to handle that. @@ -1205,14 +1235,13 @@ namespace relational member << "))" << endl << "composite_value_traits< " + mi.fq_type () + " >::" << "set_null (i." << mi.var << "value, sk);" - << "else"; + << "else" + << "{"; } member = "wrapper_traits< " + wt + " >::get_ref (" + member + ")"; } - os << "{"; - if (discriminator (mi.m)) os << "const info_type& di (map->find (typeid (o)));" << endl; @@ -1301,6 +1330,13 @@ namespace relational set_null (mi); } + if (mi.wrapper != 0 && composite (mi.t)) + { + if (null (mi.m, key_prefix_) && + mi.wrapper->template get ("wrapper-null-handler")) + os << "}"; + } + os << "}"; } @@ -1430,6 +1466,9 @@ namespace relational virtual void get_null (member_info&) = 0; + virtual void + check_modifier (member_info&, member_access&) {} + virtual bool pre (member_info& mi) { @@ -1447,25 +1486,66 @@ namespace relational if (ignore_implicit_discriminator_ && discriminator (mi.m)) return false; + bool comp (composite (mi.t)); + if (!member_override_.empty ()) + { + os << "{"; member = member_override_; + } else { - string const& name (mi.m.name ()); - member = "o." + name; + os << "// " << mi.m.name () << endl + << "//" << endl + << "{"; + + // Get the member using the accessor expression. + // + member_access& ma (mi.m.template get ("set")); + + // Make sure this kind of member can be modified with this + // kind of accessor (database-specific, e.g., streaming). + // + if (!comp) + check_modifier (mi, ma); - if (mi.cq) + // If this is not a synthesized expression, then output + // its location for easier error tracking. + // + if (ma.loc != 0) + os << "// From " << location_string (ma.loc, true) << endl; + + // See if we are modifying via a reference or proper modifier. + // + if (ma.placeholder ()) + os << member_val_type (mi.m, false, "v") << ";" + << endl; + else { - string t (mi.ptr == 0 ? mi.fq_type (false) : mi.ptr_fq_type ()); - member = "const_cast< " + t + "& > (" + member + ")"; + // Use the original type to form the reference. + // + os << member_ref_type (mi.m, false, "v") << " (" << endl; + + // If this member is const and we have a synthesized access, + // then cast away constness. Otherwise, we assume that the + // user-provided expression handles this. + // + if (mi.cq && ma.loc == 0) + os << "const_cast< " << member_ref_type (mi.m, false) << + " > (" << endl; + + os << ma.translate ("o"); + + if (mi.cq && ma.loc == 0) + os << ")"; + + os << ");" + << endl; } - os << "// " << name << endl - << "//" << endl; + member = "v"; } - bool comp (composite (mi.t)); - // If this is a wrapped composite value, then we need to "unwrap" it. // If this is a NULL wrapper, then we also need to handle that. For // simple values this is taken care of by the value_traits @@ -1498,8 +1578,7 @@ namespace relational // Handle NULL pointers and extract the id. // - os << "{" - << "typedef object_traits< " << class_fq_name (*mi.ptr) << + os << "typedef object_traits< " << class_fq_name (*mi.ptr) << " > obj_traits;" << "typedef odb::pointer_traits< " << mi.ptr_fq_type () << " > ptr_traits;" @@ -1548,16 +1627,9 @@ namespace relational { if (mi.ptr != 0) { - if (!member_override_.empty ()) - member = member_override_; - else - { - member = "o." + mi.m.name (); - - if (mi.cq) - member = "const_cast< " + mi.ptr_fq_type () + - "& > (" + member + ")"; - } + // Restore the member variable name. + // + member = member_override_.empty () ? "v" : member_override_; // When handling a pointer, mi.t is the id type of the referenced // object. @@ -1592,9 +1664,28 @@ namespace relational } } - os << "}" - << "}"; + os << "}"; + } + + // Call the modifier if we are using a proper one. + // + if (member_override_.empty ()) + { + member_access& ma (mi.m.template get ("set")); + + if (ma.placeholder ()) + { + // If this is not a synthesized expression, then output its + // location for easier error tracking. + // + if (ma.loc != 0) + os << "// From " << location_string (ma.loc, true) << endl; + + os << ma.translate ("o", "v") << ";"; + } } + + os << "}"; } virtual void @@ -2867,9 +2958,10 @@ namespace relational }; container_calls (call_type call) - : object_members_base (true, false, false), + : object_members_base (true, false, true), call_ (call), - obj_prefix_ ("obj.") + obj_prefix_ ("obj"), + modifier_ (0) { } @@ -2878,17 +2970,56 @@ namespace relational semantics::class_& c, semantics::type* w) { - if (m == 0) + if (m == 0 || call_ == erase_call || modifier_ != 0) { object_members_base::traverse_composite (m, c); return; } - string old (obj_prefix_); - obj_prefix_ += m->name (); + // Get this member using the accessor expression. + // + member_access& ma ( + m->get (call_ == load_call ? "set" : "get")); + + // We don't support by-value modifiers for composite values + // with containers. However, at this point we don't know + // whether this composite value has any containers. So we + // are just going to set a flag that can be checked in + // traverse_container() below. + // + if (ma.placeholder ()) + { + modifier_ = &ma; + object_members_base::traverse_composite (m, c); + modifier_ = 0; + return; + } + + string old_op (obj_prefix_); + string old_f (from_); + obj_prefix_.clear (); - // If this is a wrapped composite value, then we need to - // "unwrap" it. + // If this member is const and we have a synthesized access, + // then cast away constness. Otherwise, we assume that the + // user-provided expression handles this. + // + if (call_ == load_call && ma.loc == 0 && const_type (m->type ())) + obj_prefix_ = "const_cast< " + member_ref_type (*m, false) + + " > (\n"; + + obj_prefix_ += ma.translate (old_op); + + if (call_ == load_call && ma.loc == 0 && const_type (m->type ())) + obj_prefix_ += ")"; + + // If this is not a synthesized expression, then store its + // location which we will output later for easier error + // tracking. + // + if (ma.loc != 0) + from_ += "// From " + location_string (ma.loc, true) + "\n"; + + // If this is a wrapped composite value, then we need to "unwrap" it. // if (w != 0) { @@ -2900,26 +3031,14 @@ namespace relational // assert (&t == w); - string const& type (t.fq_name (hint)); - - if (call_ == load_call && const_type (m->type ())) - obj_prefix_ = "const_cast< " + type + "& > (\n" + - obj_prefix_ + ")"; - - obj_prefix_ = "wrapper_traits< " + type + " >::" + + obj_prefix_ = "wrapper_traits< " + t.fq_name (hint) + " >::" + (call_ == load_call ? "set_ref" : "get_ref") + " (\n" + obj_prefix_ + ")"; } - else if (call_ == load_call && const_type (m->type ())) - { - obj_prefix_ = "const_cast< " + class_fq_name (c) + "& > (\n" + - obj_prefix_ + ")"; - } - - obj_prefix_ += '.'; object_members_base::traverse_composite (m, c); - obj_prefix_ = old; + from_ = old_f; + obj_prefix_ = old_op; } virtual void @@ -2929,87 +3048,155 @@ namespace relational bool inverse (context::inverse (m, "value")); + // In certain cases we don't need to do anything. + // + if ((call_ != load_call && inverse) || + (call_ == update_call && readonly (member_path_, member_scope_))) + return; + string const& name (m.name ()); - string obj_name (obj_prefix_ + name); string sts_name (flat_prefix_ + name); string traits (flat_prefix_ + public_name (m) + "_traits"); - if (call_ == load_call && const_type (m.type ())) - { - - } + os << "// " << member_prefix_ << m.name () << endl + << "//" << endl; - semantics::names* hint; - semantics::type& t (utype (m, hint)); + // Get this member using the accessor expression. + // + string var; + member_access& ma ( + m.get (call_ == load_call ? "set" : "get")); - // If this is a wrapped container, then we need to "unwrap" it. + // We don't support by-value modifiers for composite values + // with containers. // - if (wrapper (t)) + if (call_ == load_call && modifier_ != 0) + { + error (modifier_->loc) << "by-value modification of a composite " + << "value with container is not supported" + << endl; + info (m.location ()) << "container member is defined here" << endl; + throw operation_failed (); + } + + if (call_ != erase_call) { - string const& type (t.fq_name (hint)); + os << "{"; - // We cannot use traits::container_type here. + // Output stored locations, if any. // - if (call_ == load_call && const_type (m.type ())) - obj_name = "const_cast< " + type + "& > (\n" + obj_name + ")"; + if (!ma.placeholder ()) + os << from_; - obj_name = "wrapper_traits< " + type + " >::" + - (call_ == load_call ? "set_ref" : "get_ref") + - " (\n" + obj_name + ")"; - } - else if (call_ == load_call && const_type (m.type ())) - { - obj_name = "const_cast< " + traits + "::container_type& > (\n" + - obj_name + ")"; - } + // If this is not a synthesized expression, then output its + // location for easier error tracking. + // + if (ma.loc != 0) + os << "// From " << location_string (ma.loc, true) << endl; + // See if we are modifying via a reference or proper modifier. + // + if (ma.placeholder ()) + os << member_val_type (m, false, "v") << ";" + << endl; + else + { + os << member_ref_type (m, call_ != load_call, "v") << " (" << endl; + + // If this member is const and we have a synthesized access, + // then cast away constness. Otherwise, we assume that the + // user-provided expression handles this. + // + if (call_ == load_call && ma.loc == 0 && const_type (m.type ())) + os << "const_cast< " << member_ref_type (m, false) << + " > (" << endl; + + os << ma.translate (obj_prefix_); + + if (call_ == load_call && ma.loc == 0 && const_type (m.type ())) + os << ")"; + + os << ");" + << endl; + } + + var = "v"; + + semantics::names* hint; + semantics::type& t (utype (m, hint)); + + // If this is a wrapped container, then we need to "unwrap" it. + // + if (wrapper (t)) + { + var = "wrapper_traits< " + t.fq_name (hint) + " >::" + + (call_ == load_call ? "set_ref" : "get_ref") + " (" + var + ")"; + } + } switch (call_) { case persist_call: { - if (!inverse) - os << traits << "::persist (" << endl - << obj_name << "," << endl - << "idb," << endl - << "sts.container_statment_cache ()." << sts_name << ");" - << endl; + os << traits << "::persist (" << endl + << var << "," << endl + << "idb," << endl + << "sts.container_statment_cache ()." << sts_name << ");"; break; } case load_call: { os << traits << "::load (" << endl - << obj_name << "," << endl + << var << "," << endl << "idb," << endl - << "sts.container_statment_cache ()." << sts_name << ");" - << endl; + << "sts.container_statment_cache ()." << sts_name << ");"; break; } case update_call: { - if (!(inverse || readonly (member_path_, member_scope_))) - os << traits << "::update (" << endl - << obj_name << "," << endl - << "idb," << endl - << "sts.container_statment_cache ()." << sts_name << ");" - << endl; + os << traits << "::update (" << endl + << var << "," << endl + << "idb," << endl + << "sts.container_statment_cache ()." << sts_name << ");"; break; } case erase_call: { - if (!inverse) - os << traits << "::erase (" << endl - << "idb," << endl - << "sts.container_statment_cache ()." << sts_name << ");" - << endl; + os << traits << "::erase (" << endl + << "idb," << endl + << "sts.container_statment_cache ()." << sts_name << ");" + << endl; break; } } + + if (call_ != erase_call) + { + // Call the modifier if we are using a proper one. + // + if (ma.placeholder ()) + { + os << endl + << from_; + + // If this is not a synthesized expression, then output its + // location for easier error tracking. + // + if (ma.loc != 0) + os << "// From " << location_string (ma.loc, true) << endl; + + os << ma.translate (obj_prefix_, "v") << ";"; + } + + os << "}"; + } } protected: call_type call_; string obj_prefix_; + string from_; + member_access* modifier_; }; // Output a list of parameters for the persist statement. -- cgit v1.1