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/inline.hxx | 18 +- odb/relational/mssql/source.cxx | 35 ++++ odb/relational/oracle/source.cxx | 39 ++++ odb/relational/processor.cxx | 432 ++++++++++++++++++++++++++++++--------- odb/relational/source.cxx | 339 +++++++++++++++++++++--------- odb/relational/source.hxx | 379 +++++++++++++++++++++++++--------- 6 files changed, 939 insertions(+), 303 deletions(-) (limited to 'odb/relational') diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx index 39801cb..2642809 100644 --- a/odb/relational/inline.hxx +++ b/odb/relational/inline.hxx @@ -5,6 +5,7 @@ #ifndef ODB_RELATIONAL_INLINE_HXX #define ODB_RELATIONAL_INLINE_HXX +#include #include #include @@ -258,16 +259,27 @@ namespace relational os << "inline" << endl << traits << "::id_type" << endl << traits << "::" << endl - << "id (const object_type&" << (id != 0 ? " obj" : "") << ")" + << "id (const object_type&" << (id != 0 ? " o" : "") << ")" << "{"; if (id != 0) { if (base_id) os << "return object_traits< " << class_fq_name (*base) << - " >::id (obj);"; + " >::id (o);"; else - os << "return obj." << id->name () << ";"; + { + // Get the id using the accessor expression. If this is not + // a synthesized expression, then output its location for + // easier error tracking. + // + member_access& ma (id->get ("get")); + + if (ma.loc != 0) + os << "// From " << location_string (ma.loc, true) << endl; + + os << "return " << ma.translate ("o") << ";"; + } } os << "}"; diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx index 1201c87..7fce155 100644 --- a/odb/relational/mssql/source.cxx +++ b/odb/relational/mssql/source.cxx @@ -307,6 +307,24 @@ namespace relational } virtual void + check_accessor (member_info& mi, member_access& ma) + { + // We cannot use accessors that return by-value for long data + // members. + // + if (long_data (*mi.st) && ma.by_value) + { + error (ma.loc) << "accessor returning a value cannot be used " + << "for a data member of SQL Server long data " + << "type" << endl; + info (ma.loc) << "accessor returning a const reference is required" + << endl; + info (mi.m.location ()) << "data member is defined here" << endl; + throw operation_failed (); + } + } + + virtual void traverse_integer (member_info& mi) { os << traits << "::set_image (" << endl @@ -541,6 +559,23 @@ namespace relational } virtual void + check_modifier (member_info& mi, member_access& ma) + { + // We cannot use by-value modifier for long data members. + // + if (long_data (*mi.st) && ma.placeholder ()) + { + error (ma.loc) << "modifier accepting a value cannot be used " + << "for a data member of SQL Server long data " + << "type" << endl; + info (ma.loc) << "modifier returning a non-const reference is " + << "required" << endl; + info (mi.m.location ()) << "data member is defined here" << endl; + throw operation_failed (); + } + } + + virtual void traverse_integer (member_info& mi) { os << traits << "::set_value (" << endl diff --git a/odb/relational/oracle/source.cxx b/odb/relational/oracle/source.cxx index 780dc06..85be6cc 100644 --- a/odb/relational/oracle/source.cxx +++ b/odb/relational/oracle/source.cxx @@ -217,6 +217,26 @@ namespace relational } virtual void + check_accessor (member_info& mi, member_access& ma) + { + // We cannot use accessors that return by-value for LOB + // members. + // + if ((mi.st->type == sql_type::BLOB || + mi.st->type == sql_type::CLOB || + mi.st->type == sql_type::NCLOB) && + ma.by_value) + { + error (ma.loc) << "accessor returning a value cannot be used " + << "for a data member of Oracle LOB type" << endl; + info (ma.loc) << "accessor returning a const reference is required" + << endl; + info (mi.m.location ()) << "data member is defined here" << endl; + throw operation_failed (); + } + } + + virtual void set_null (member_info& mi) { os << "i." << mi.var << "indicator = -1;"; @@ -363,6 +383,25 @@ namespace relational } virtual void + check_modifier (member_info& mi, member_access& ma) + { + // We cannot use by-value modifier for LOB members. + // + if ((mi.st->type == sql_type::BLOB || + mi.st->type == sql_type::CLOB || + mi.st->type == sql_type::NCLOB) && + ma.placeholder ()) + { + error (ma.loc) << "modifier accepting a value cannot be used " + << "for a data member of Oracle LOB type" << endl; + info (ma.loc) << "modifier returning a non-const reference is " + << "required" << endl; + info (mi.m.location ()) << "data member is defined here" << endl; + throw operation_failed (); + } + } + + virtual void traverse_int32 (member_info& mi) { os << traits << "::set_value (" << endl diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx index 64987a2..7e2bf53 100644 --- a/odb/relational/processor.cxx +++ b/odb/relational/processor.cxx @@ -120,8 +120,6 @@ namespace relational if (transient (m)) return; - process_index (m); - semantics::names* hint; semantics::type& t (utype (m, hint)); @@ -151,146 +149,378 @@ namespace relational m.set ("readonly", true); } - // Nothing to do if this is a composite value type. + // Determine the member kind. // - if (composite_wrapper (t)) - return; - - string type, id_type; + enum {simple, composite, container, unknown} kind (unknown); - if (m.count ("id-type")) - id_type = m.get ("id-type"); + // See if this is a composite value type. + // + if (composite_wrapper (t)) + kind = composite; - if (m.count ("type")) + // If not, see if it is a simple value. + // + if (kind == unknown) { - type = m.get ("type"); + string type, id_type; - if (id_type.empty ()) - id_type = type; - } + if (m.count ("id-type")) + id_type = m.get ("id-type"); - if (semantics::class_* c = process_object_pointer (m, t)) - { - // This is an object pointer. The column type is the pointed-to - // object id type. - // - semantics::data_member& id (*id_member (*c)); + if (m.count ("type")) + { + type = m.get ("type"); - semantics::names* idhint; - semantics::type& idt (utype (id, idhint)); + if (id_type.empty ()) + id_type = type; + } - semantics::type* wt (0); - semantics::names* whint (0); - if (process_wrapper (idt)) + if (semantics::class_* c = process_object_pointer (m, t)) { - whint = idt.get ("wrapper-hint"); - wt = &utype (*idt.get ("wrapper-type"), whint); + // This is an object pointer. The column type is the pointed-to + // object id type. + // + semantics::data_member& id (*id_member (*c)); + + semantics::names* idhint; + semantics::type& idt (utype (id, idhint)); + + semantics::type* wt (0); + semantics::names* whint (0); + if (process_wrapper (idt)) + { + whint = idt.get ("wrapper-hint"); + wt = &utype (*idt.get ("wrapper-type"), whint); + } + + // The id type can be a composite value type. + // + if (composite_wrapper (idt)) + kind = composite; + else + { + if (type.empty () && id.count ("id-type")) + type = id.get ("id-type"); + + if (type.empty () && id.count ("type")) + type = id.get ("type"); + + // The rest should be identical to the code for the id_type in + // the else block. + // + if (type.empty () && idt.count ("id-type")) + type = idt.get ("id-type"); + + if (type.empty () && wt != 0 && wt->count ("id-type")) + type = wt->get ("id-type"); + + if (type.empty () && idt.count ("type")) + type = idt.get ("type"); + + if (type.empty () && wt != 0 && wt->count ("type")) + type = wt->get ("type"); + + if (type.empty ()) + type = database_type (idt, idhint, true); + + if (type.empty () && wt != 0) + type = database_type (*wt, whint, true); + + id_type = type; + } } + else + { + if (id_type.empty () && t.count ("id-type")) + id_type = t.get ("id-type"); - // Nothing to do if this is a composite value type. - // - if (composite_wrapper (idt)) - return; + if (id_type.empty () && wt != 0 && wt->count ("id-type")) + id_type = wt->get ("id-type"); - if (type.empty () && id.count ("id-type")) - type = id.get ("id-type"); + if (type.empty () && t.count ("type")) + type = t.get ("type"); - if (type.empty () && id.count ("type")) - type = id.get ("type"); + if (type.empty () && wt != 0 && wt->count ("type")) + type = wt->get ("type"); - // The rest should be identical to the code for the id_type in - // the else block. - // - if (type.empty () && idt.count ("id-type")) - type = idt.get ("id-type"); + if (id_type.empty ()) + id_type = type; - if (type.empty () && wt != 0 && wt->count ("id-type")) - type = wt->get ("id-type"); + if (id_type.empty ()) + id_type = database_type (t, hint, true); - if (type.empty () && idt.count ("type")) - type = idt.get ("type"); + if (type.empty ()) + type = database_type (t, hint, false); - if (type.empty () && wt != 0 && wt->count ("type")) - type = wt->get ("type"); + if (id_type.empty () && wt != 0) + id_type = database_type (*wt, whint, true); - if (type.empty ()) - type = database_type (idt, idhint, true); + if (type.empty () && wt != 0) + type = database_type (*wt, whint, false); - if (type.empty () && wt != 0) - type = database_type (*wt, whint, true); + // Use id mapping for discriminators. + // + if (id (m) || discriminator (m)) + type = id_type; + } + + if (kind == unknown && !type.empty ()) + { + m.set ("column-type", type); + m.set ("column-id-type", id_type); + + // Issue a warning if we are relaxing null-ness. + // + if (m.count ("null") && t.count ("not-null")) + { + os << m.file () << ":" << m.line () << ":" << m.column () << ":" + << " warning: data member declared null while its type is " + << "declared not null" << endl; + } - id_type = type; + kind = simple; + } } - else + + // If not a simple value, see if this is a container. + // + if (kind == unknown && + (process_container (m, t) || + (wt != 0 && process_container (m, *wt)))) + kind = container; + + // If it is none of the above then we have an error. + // + if (kind == unknown) { - if (id_type.empty () && t.count ("id-type")) - id_type = t.get ("id-type"); + os << m.file () << ":" << m.line () << ":" << m.column () << ":" + << " error: unable to map C++ type '" << t.fq_name (hint) + << "' used in data member '" << m.name () << "' to a " + << "database type" << endl; - if (id_type.empty () && wt != 0 && wt->count ("id-type")) - id_type = wt->get ("id-type"); + os << m.file () << ":" << m.line () << ":" << m.column () << ":" + << " info: use '#pragma db type' to specify the database type" + << endl; - if (type.empty () && t.count ("type")) - type = t.get ("type"); + throw operation_failed (); + } - if (type.empty () && wt != 0 && wt->count ("type")) - type = wt->get ("type"); + process_access (m, "get"); + process_access (m, "set"); + process_index (m); + } - if (id_type.empty ()) - id_type = type; + // Process member access expressions. + // + void + process_access (semantics::data_member& m, std::string const& k) + { + // If we don't have an access expression, synthesize one which + // goes directly for the member. Zero location indicates it is + // a synthesized one. + // + if (!m.count (k)) + { + member_access& ma (m.set (k, member_access (0))); + ma.expr.push_back (cxx_token (0, CPP_KEYWORD, "this")); + ma.expr.push_back (cxx_token (0, CPP_DOT)); + ma.expr.push_back (cxx_token (0, CPP_NAME, m.name ())); + return; + } - if (id_type.empty ()) - id_type = database_type (t, hint, true); + semantics::type& t (utype (m)); + member_access& ma (m.get (k)); + cxx_tokens& e (ma.expr); - if (type.empty ()) - type = database_type (t, hint, false); + // If it is just a name, resolve it and convert to an + // appropriate expression. + // + if (e.size () == 1 && e.back ().type == CPP_NAME) + { + string n (e.back ().literal); + e.clear (); - if (id_type.empty () && wt != 0) - id_type = database_type (*wt, whint, true); + tree decl ( + lookup_qualified_name ( + m.scope ().tree_node (), + get_identifier (n.c_str ()), + false, + false)); - if (type.empty () && wt != 0) - type = database_type (*wt, whint, false); + if (decl == error_mark_node) + { + error (ma.loc) << "unable to resolve data member or function " + << "name '" << n << "'" << endl; + throw operation_failed (); + } - // Use id mapping for discriminators. - // - if (id (m) || discriminator (m)) - type = id_type; + switch (TREE_CODE (decl)) + { + case FIELD_DECL: + { + e.push_back (cxx_token (0, CPP_KEYWORD, "this")); + e.push_back (cxx_token (0, CPP_DOT)); + e.push_back (cxx_token (0, CPP_NAME, n)); + break; + } + case BASELINK: + { + // OVL_* macros work for both FUNCTION_DECL and OVERLOAD. + // + for (tree o (BASELINK_FUNCTIONS (decl)); + o != 0; + o = OVL_NEXT (o)) + { + tree f (OVL_CURRENT (o)); + + // We are only interested in non-static member functions. + // + if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (f)) + continue; + + // Note that we have to use TREE_TYPE(TREE_TYPE()) and + // not DECL_RESULT, as suggested by the documentation. + // + tree r (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (f)))); + tree a (DECL_ARGUMENTS (f)); + a = DECL_CHAIN (a); // Skip this. + + if (k == "get") + { + // For an accessor, look for a function with a non-void + // return value and no arguments (other than 'this'). + // + if (r != void_type_node && a == NULL_TREE) + { + e.push_back (cxx_token (0, CPP_KEYWORD, "this")); + e.push_back (cxx_token (0, CPP_DOT)); + e.push_back (cxx_token (0, CPP_NAME, n)); + e.push_back (cxx_token (0, CPP_OPEN_PAREN, n)); + e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n)); + + // See if it returns by value. + // + int tc (TREE_CODE (r)); + ma.by_value = (tc != REFERENCE_TYPE && tc != POINTER_TYPE); + break; + } + } + else + { + // For a modifier, it can either be a function that + // returns a non-const reference (or non-const pointer, + // in case the member is an array) or a proper modifier + // that sets a new value. If both are available, we + // prefer the former for efficiency. + // + semantics::array* ar (dynamic_cast (&t)); + int tc (TREE_CODE (r)); + + if (a == NULL_TREE && + ((ar == 0 && tc == REFERENCE_TYPE) || + (ar != 0 && tc == POINTER_TYPE))) + { + tree bt (TREE_TYPE (r)); // Base type. + tree bt_mv (TYPE_MAIN_VARIANT (bt)); + + if (!CP_TYPE_CONST_P (bt) && + ((ar == 0 && bt_mv == t.tree_node ()) || + (ar != 0 && bt_mv == ar->base_type ().tree_node ()))) + { + e.clear (); // Could contain proper modifier. + e.push_back (cxx_token (0, CPP_KEYWORD, "this")); + e.push_back (cxx_token (0, CPP_DOT)); + e.push_back (cxx_token (0, CPP_NAME, n)); + e.push_back (cxx_token (0, CPP_OPEN_PAREN, n)); + e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n)); + break; + } + } + + // Any function with a single argument works for us. + // And we don't care what it returns. + // + if (a != NULL_TREE && DECL_CHAIN (a) == NULL_TREE) + { + if (e.empty ()) + { + e.push_back (cxx_token (0, CPP_KEYWORD, "this")); + e.push_back (cxx_token (0, CPP_DOT)); + e.push_back (cxx_token (0, CPP_NAME, n)); + e.push_back (cxx_token (0, CPP_OPEN_PAREN, n)); + e.push_back (cxx_token (0, CPP_QUERY)); + e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n)); + } + + // Continue searching in case there is version that + // returns a non-const reference (which we prefer). + } + } + } + + if (e.empty ()) + { + error (ma.loc) << "unable to find suitable " + << (k == "get" ? "accessor" : "modifier") + << " function '" << n << "'" << endl; + throw operation_failed (); + } + break; + } + default: + { + error (ma.loc) << "name '" << n << "' does not refer to a data " + << "member or function" << endl; + throw operation_failed (); + } + } } - if (!type.empty ()) + // If there is no 'this' keyword, then add it as a prefix. + // { - m.set ("column-type", type); - m.set ("column-id-type", id_type); - - // Issue a warning if we are relaxing null-ness. - // - if (m.count ("null") && t.count ("not-null")) + bool t (false); + for (cxx_tokens::iterator i (e.begin ()); i != e.end (); ++i) { - os << m.file () << ":" << m.line () << ":" << m.column () << ":" - << " warning: data member declared null while its type is " - << "declared not null" << endl; + if (i->type == CPP_KEYWORD && i->literal == "this") + { + t = true; + break; + } } - return; + if (!t) + { + e.insert (e.begin (), cxx_token (0, CPP_DOT)); + e.insert (e.begin (), cxx_token (0, CPP_KEYWORD, "this")); + } } - // See if this is a container type. + // Check that there is no placeholder in the accessor expression. // - if (process_container (m, t) || - (wt != 0 && process_container (m, *wt))) - return; + if (k == "get" && ma.placeholder ()) + { + error (ma.loc) << "(?) placeholder in the accessor expression" + << endl; + throw operation_failed (); + } - // If it is none of the above then we have an error. + // Check that the member type is default-constructible if we + // have a placeholder in the modifier. // - os << m.file () << ":" << m.line () << ":" << m.column () << ":" - << " error: unable to map C++ type '" << t.fq_name (hint) - << "' used in data member '" << m.name () << "' to a " - << "database type" << endl; - - os << m.file () << ":" << m.line () << ":" << m.column () << ":" - << " info: use '#pragma db type' to specify the database type" - << endl; + if (k == "set" && ma.placeholder ()) + { + // Assume all other types are default-constructible. + // + semantics::class_* c (dynamic_cast (&t)); - throw operation_failed (); + if (c != 0 && !c->default_ctor ()) + { + error (ma.loc) << "modifier expression requires member type " + << "to be default-constructible" << endl; + throw operation_failed (); + } + } } // Convert index/unique specifiers to the index entry in the object. @@ -2480,9 +2710,7 @@ namespace relational tt != CPP_EOF; tt = lex_.next (t)) { - cxx_token ct (lex_.location (), tt); - ct.literal = t; - i->cond.push_back (ct); + i->cond.push_back (cxx_token (lex_.location (), tt, t)); } } } diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx index a338b09..e525089 100644 --- a/odb/relational/source.cxx +++ b/odb/relational/source.cxx @@ -20,10 +20,13 @@ traverse_object (type& c) data_member* id (id_member (c)); bool auto_id (id ? id->count ("auto") : false); bool base_id (id ? &id->scope () != &c : false); // Comes from base. + member_access* id_ma (id ? &id->get ("get") : 0); bool has_ptr (has_a (c, test_pointer)); - data_member* optimistic (context::optimistic (c)); + data_member* opt (optimistic (c)); + member_access* opt_ma_get (opt ? &opt->get ("get") : 0); + member_access* opt_ma_set (opt ? &opt->get ("set") : 0); type* poly_root (polymorphic (c)); bool poly (poly_root != 0); @@ -42,7 +45,7 @@ traverse_object (type& c) { grow = context::grow (c); grow_id = (id ? context::grow (*id) : false) || - (optimistic ? context::grow (*optimistic) : false); + (opt ? context::grow (*opt) : false); } string const& type (class_fq_name (c)); @@ -105,6 +108,8 @@ traverse_object (type& c) // if (!poly_derived && id != 0 && !base_id) { + // id (image) + // if (options.generate_query ()) { os << traits << "::id_type" << endl @@ -120,14 +125,16 @@ traverse_object (type& c) << "}"; } - if (optimistic != 0) + // version (image) + // + if (opt != 0) { os << traits << "::version_type" << endl << traits << "::" << endl << "version (const image_type& i)" << "{" << "version_type v;"; - init_version_value_member_->traverse (*optimistic); + init_version_value_member_->traverse (*opt); os << "return v;" << "}"; } @@ -277,7 +284,7 @@ traverse_object (type& c) { os << "void " << traits << "::" << endl << "bind (" << bind_vector << " b, id_image_type& i" << - (optimistic != 0 ? ", bool bv" : "") << ")" + (opt != 0 ? ", bool bv" : "") << ")" << "{" << "std::size_t n (0);"; @@ -286,14 +293,14 @@ traverse_object (type& c) bind_id_member_->traverse (*id); - if (optimistic != 0) + if (opt != 0) { os << "if (bv)" << "{" << "n += " << column_count (c).id << ";" << endl; - bind_version_member_->traverse (*optimistic); + bind_version_member_->traverse (*opt); os << "}"; } @@ -370,7 +377,7 @@ traverse_object (type& c) { os << "void " << traits << "::" << endl << "init (id_image_type& i, const id_type& id" << - (optimistic != 0 ? ", const version_type* v" : "") << ")" + (opt != 0 ? ", const version_type* v" : "") << ")" << "{"; if (grow_id) @@ -381,13 +388,13 @@ traverse_object (type& c) init_id_image_member_->traverse (*id); - if (optimistic != 0) + if (opt != 0) { // Here we rely on the fact that init_image_member // always wraps the statements in a block. // os << "if (v != 0)"; - init_version_image_member_->traverse (*optimistic); + init_version_image_member_->traverse (*opt); } if (grow_id) @@ -625,8 +632,8 @@ traverse_object (type& c) instance t (qtable, sk, sc); t->traverse (*discriminator); - if (optimistic != 0) - t->traverse (*optimistic); + if (opt != 0) + t->traverse (*opt); process_statement_columns (sc, statement_select); } @@ -696,10 +703,10 @@ traverse_object (type& c) convert_to (qp->next (), i->type, *i->member)); } - if (optimistic != 0 && !poly_derived) + if (opt != 0 && !poly_derived) os << endl - << strlit (" AND " + column_qname (*optimistic) + "=" + - convert_to (qp->next (), *optimistic)); + << strlit (" AND " + column_qname (*opt) + "=" + + convert_to (qp->next (), *opt)); os << ";" << endl; } @@ -725,7 +732,7 @@ traverse_object (type& c) << endl; } - if (optimistic != 0 && !poly_derived) + if (opt != 0 && !poly_derived) { instance qp (table); @@ -743,8 +750,8 @@ traverse_object (type& c) } os << endl - << strlit (" AND " + column_qname (*optimistic) + "=" + - convert_to (qp->next (), *optimistic)) << ";" + << strlit (" AND " + column_qname (*opt) + "=" + + convert_to (qp->next (), *opt)) << ";" << endl; } } @@ -936,26 +943,66 @@ traverse_object (type& c) if (!poly_derived && auto_id) { - if (const_type (id->type ())) - os << "const_cast< id_type& > (obj." << id->name () << ")"; + member_access& ma (id->get ("set")); + + if (ma.loc != 0) + os << "// From " << location_string (ma.loc, true) << endl; + + if (ma.placeholder ()) + os << ma.translate ("obj", "static_cast< id_type > (st.id ())") << ";" + << endl; else - os << "obj." << id->name (); + { + // 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. + // + bool cast (ma.loc == 0 && const_type (id->type ())); + if (cast) + os << "const_cast< id_type& > (" << endl; - os << " = static_cast< id_type > (st.id ());" - << endl; + os << ma.translate ("obj"); + + if (cast) + os << ")"; + + os << " = static_cast< id_type > (st.id ());" + << endl; + } } - if (optimistic != 0 && !poly_derived) + // Set the optimistic concurrency version in the object member. + // + if (opt != 0 && !poly_derived) { - // Set the version in the object member. + // If we don't have auto id, then obj is a const reference. // - if (!auto_id || const_type (optimistic->type ())) - os << "const_cast< version_type& > (obj." << optimistic->name () << - ") = 1;"; + string obj (auto_id ? "obj" : "const_cast< object_type& > (obj)"); + + if (opt_ma_set->loc != 0) + os << "// From " << location_string (opt_ma_set->loc, true) << endl; + + if (opt_ma_set->placeholder ()) + os << opt_ma_set->translate (obj, "1") << ";" + << endl; else - os << "obj." << optimistic->name () << " = 1;"; + { + // 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. + // + bool cast (opt_ma_set->loc == 0 && const_type (opt->type ())); + if (cast) + os << "const_cast< version_type& > (" << endl; - os << endl; + os << opt_ma_set->translate (obj); + + if (cast) + os << ")"; + + os << " = 1;" + << endl; + } } // Initialize id_image and binding if we are a root of a polymorphic @@ -971,8 +1018,12 @@ traverse_object (type& c) os << "if (!top)" << "{"; - os << "id_image_type& i (sts.id_image ());" - << "init (i, obj." << id->name () << ");" + os << "id_image_type& i (sts.id_image ());"; + + if (id_ma->loc != 0) + os << "// From " << location_string (id_ma->loc, true) << endl; + + os << "init (i, " << id_ma->translate ("obj") << ");" << endl << "binding& idb (sts.id_image_binding ());" << "if (i.version != sts.id_image_version () || idb.version == 0)" @@ -1100,8 +1151,12 @@ traverse_object (type& c) os << "if (!top)"; os << "{" - << "id_image_type& i (sts.id_image ());" - << "init (i, obj." << id->name () << ");" + << "id_image_type& i (sts.id_image ());"; + + if (id_ma->loc != 0) + os << "// From " << location_string (id_ma->loc, true) << endl; + + os << "init (i, " << id_ma->translate ("obj") << ");" << endl; os << "binding& idb (sts.id_image_binding ());" @@ -1161,9 +1216,11 @@ traverse_object (type& c) // exists in the database. Use the discriminator_() call for // that. // - os << "root_traits::discriminator_ (sts.root_statements (), obj." << - id->name () << ", 0);" - << endl; + if (id_ma->loc != 0) + os << "// From " << location_string (id_ma->loc, true) << endl; + + os << "root_traits::discriminator_ (sts.root_statements (), " << + id_ma->translate ("obj") << ", 0);" << endl; } // Otherwise, nothing else to do here if we don't have any columns // to update. @@ -1179,15 +1236,27 @@ traverse_object (type& c) // Initialize object and id images. // + if (opt != 0) + { + if (opt_ma_get->loc != 0) + os << "// From " << location_string (opt_ma_get->loc, true) << endl; + + os << "const version_type& v (" << endl + << opt_ma_get->translate ("obj") << ");"; + } + os << "id_image_type& i (sts.id_image ());"; - if (optimistic == 0) - os << "init (i, obj." << id->name () << ");"; - else - os << "init (i, obj." << id->name () << ", &obj." << - optimistic->name () << ");"; + if (id_ma->loc != 0) + os << "// From " << location_string (id_ma->loc, true) << endl; - os << endl + os << "init (i, " << id_ma->translate ("obj"); + + if (opt != 0) + os << ", &v"; + + os << ");" + << endl << "image_type& im (sts.image ());"; if (generate_grow) @@ -1245,7 +1314,7 @@ traverse_object (type& c) os << "if (sts.update_statement ().execute () == 0)" << endl; - if (optimistic == 0) + if (opt == 0) os << "throw object_not_persistent ();"; else os << "throw object_changed ();"; @@ -1265,21 +1334,29 @@ traverse_object (type& c) << "conn.statement_cache ().find_object ());" << endl; + if (id_ma->loc != 0) + os << "// From " << location_string (id_ma->loc, true) << endl; + + os << "const id_type& id (" << endl + << id_ma->translate ("obj") << ");" + << endl; + if (poly) { // In case of a polymorphic root, use discriminator_(), which // is faster. And initialize the id image, unless this is a // top-level call. // - os << "discriminator_ (sts, obj." << id->name () << ", 0);" + os << "discriminator_ (sts, id, 0);" << endl; if (!abst) os << "if (!top)"; os << "{" - << "id_image_type& i (sts.id_image ());" - << "init (i, obj." << id->name () << ");" + << "id_image_type& i (sts.id_image ());"; + + os << "init (i, id);" << endl; os << "binding& idb (sts.id_image_binding ());" @@ -1293,7 +1370,7 @@ traverse_object (type& c) } else { - os << "if (!find_ (sts, &obj." << id->name () << "))" << endl + os << "if (!find_ (sts, &id))" << endl << "throw object_not_persistent ();" << endl; @@ -1312,11 +1389,46 @@ traverse_object (type& c) t->traverse (c); } - if (optimistic != 0 && !poly_derived) + // Update the optimistic concurrency version in the object member. + // + if (opt != 0 && !poly_derived) { - // Update version in the object member. + // Object is passed as const reference so we need to cast away + // constness. // - os << "const_cast (obj." << optimistic->name () << ")++;"; + string obj ("const_cast< object_type& > (obj)"); + + if (opt_ma_set->loc != 0) + os << "// From " << location_string (opt_ma_set->loc, true) << endl; + + if (opt_ma_set->placeholder ()) + { + if (opt_ma_get->loc != 0) + os << "// From " << location_string (opt_ma_get->loc, true) << + endl; + + os << opt_ma_set->translate ( + obj, opt_ma_get->translate ("obj") + " + 1") << ";" + << endl; + } + else + { + // 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. + // + bool cast (opt_ma_set->loc == 0 && const_type (opt->type ())); + if (cast) + os << "const_cast< version_type& > (" << endl; + + os << opt_ma_set->translate (obj); + + if (cast) + os << ")"; + + os << "++;" + << endl; + } } // Call callback (post_update). @@ -1457,7 +1569,7 @@ traverse_object (type& c) // erase (object) // - if (id != 0 && (poly || optimistic != 0)) + if (id != 0 && (poly || opt != 0)) { os << "void " << traits << "::" << endl << "erase (database& db, const object_type& obj"; @@ -1497,7 +1609,7 @@ traverse_object (type& c) // Determine the dynamic type of this object. // - if (optimistic == 0) + if (opt == 0) { os << "callback (db, obj, callback_event::pre_erase);" << "erase (db, id (obj), true, false);" @@ -1530,6 +1642,16 @@ traverse_object (type& c) << endl; } + if (!abst || straight_containers) + { + if (id_ma->loc != 0) + os << "// From " << location_string (id_ma->loc, true) << endl; + + os << "const id_type& id (" << endl + << id_ma->translate ("obj") << ");" + << endl; + } + // Initialize id + managed column image. // os << "binding& idb (" << rsts << ".id_image_binding ());" @@ -1541,9 +1663,13 @@ traverse_object (type& c) os << "if (top)" << "{"; - os << "id_image_type& i (" << rsts << ".id_image ());" - << "init (i, obj." << id->name () << ", &obj." << - optimistic->name () << ");" + if (opt_ma_get->loc != 0) + os << "// From " << location_string (opt_ma_get->loc, true) << endl; + + os << "const version_type& v (" << endl + << opt_ma_get->translate ("obj") << ");" + << "id_image_type& i (" << rsts << ".id_image ());" + << "init (i, id, &v);" << endl; // To update the id part of the optimistic id binding we have @@ -1592,10 +1718,13 @@ traverse_object (type& c) os << "if (top)" << "{" << "version_type v;" - << "root_traits::discriminator_ (" << rsts << ", obj." << - id->name () << ", 0, &v);" - << endl - << "if (v != obj." << optimistic->name () << ")" << endl + << "root_traits::discriminator_ (" << rsts << ", id, 0, &v);" + << endl; + + if (opt_ma_get->loc != 0) + os << "// From " << location_string (opt_ma_get->loc, true) << endl; + + os << "if (v != " << opt_ma_get->translate ("obj") << ")" << endl << "throw object_changed ();" << "}"; } @@ -1618,15 +1747,19 @@ traverse_object (type& c) // have been more efficient but it would complicated and bloat // things significantly. // - os << "if (!find_ (sts, &obj." << id->name () << "))" << endl + os << "if (!find_ (sts, &id))" << endl << "throw object_changed ();" << endl; if (delay_freeing_statement_result) - os << "sts.find_statement ().free_result ();"; + os << "sts.find_statement ().free_result ();" + << endl; + + if (opt_ma_get->loc != 0) + os << "// From " << location_string (opt_ma_get->loc, true) << endl; - os << "if (version (sts.image ()) != obj." << - optimistic->name () << ")" << endl + os << "if (version (sts.image ()) != " << + opt_ma_get->translate ("obj") << ")" << endl << "throw object_changed ();" << endl; } @@ -1666,7 +1799,7 @@ traverse_object (type& c) // Remove from the object cache. // - os << "pointer_cache_traits::erase (db, obj." << id->name () << ");"; + os << "pointer_cache_traits::erase (db, id);"; // Call callback (post_erase). // @@ -2015,7 +2148,14 @@ traverse_object (type& c) << "statements_type::auto_lock l (" << rsts << ");" << endl; - os << "if (!find_ (sts, &obj." << id->name () << "))" << endl + if (id_ma->loc != 0) + os << "// From " << location_string (id_ma->loc, true) << endl; + + os << "const id_type& id (" << endl + << id_ma->translate ("obj") << ");" + << endl; + + os << "if (!find_ (sts, &id))" << endl << "return false;" << endl; @@ -2028,10 +2168,14 @@ traverse_object (type& c) os << "auto_result ar (st);" << endl; - if (optimistic != 0) + if (opt != 0) { + if (opt_ma_get->loc != 0) + os << "// From " << location_string (opt_ma_get->loc, true) << endl; + os << "if (" << (poly_derived ? "root_traits::" : "") << "version (" << - rsts << ".image ()) == obj." << optimistic->name () << ")" << endl + rsts << ".image ()) == " << opt_ma_get->translate ("obj") << + ")" << endl << "return true;" << endl; } @@ -2272,7 +2416,7 @@ traverse_object (type& c) << "const id_type& id," << endl << "discriminator_type* pd"; - if (optimistic != 0) + if (opt != 0) os << "," << endl << "version_type* pv"; @@ -2291,7 +2435,7 @@ traverse_object (type& c) << "if (idi.version != sts.discriminator_id_image_version () ||" << endl << "idb.version == 0)" << "{" - << "bind (idb.bind, idi" << (optimistic != 0 ? ", false" : "") << ");" + << "bind (idb.bind, idi" << (opt != 0 ? ", false" : "") << ");" << "sts.discriminator_id_image_version (idi.version);" << "idb.version++;" << "}"; @@ -2313,11 +2457,11 @@ traverse_object (type& c) bind_discriminator_member_->traverse (*discriminator); os << "}"; - if (optimistic != 0) + if (opt != 0) { os << "n++;" // For now discriminator is a simple value. << "{"; - bind_version_member_->traverse (*optimistic); + bind_version_member_->traverse (*opt); os << "}"; } @@ -2334,7 +2478,7 @@ traverse_object (type& c) << "if (r == select_statement::no_data)" << "{"; - if (optimistic != 0) + if (opt != 0) os << "if (pv != 0)" << endl << "throw object_changed ();" << "else" << endl; @@ -2342,9 +2486,9 @@ traverse_object (type& c) os << "throw object_not_persistent ();" << "}"; - if (generate_grow && ( - context::grow (*discriminator) || - (optimistic != 0 && context::grow (*optimistic)))) + if (generate_grow && + (context::grow (*discriminator) || + (opt != 0 && context::grow (*opt)))) { os << "else if (r == select_statement::truncated)" << "{"; @@ -2358,8 +2502,8 @@ traverse_object (type& c) index_ = 0; grow_discriminator_member_->traverse (*discriminator); - if (optimistic != 0) - grow_version_member_->traverse (*optimistic); + if (opt != 0) + grow_version_member_->traverse (*opt); os << "if (grew)" << endl << "i.version++;" @@ -2375,11 +2519,11 @@ traverse_object (type& c) bind_discriminator_member_->traverse (*discriminator); os << "}"; - if (optimistic != 0) + if (opt != 0) { os << "n++;" // For now discriminator is a simple value. << "{"; - bind_version_member_->traverse (*optimistic); + bind_version_member_->traverse (*opt); os << "}"; } @@ -2404,12 +2548,12 @@ traverse_object (type& c) init_named_discriminator_value_member_->traverse (*discriminator); os << "}"; - if (optimistic != 0) + if (opt != 0) { os << "if (pv != 0)" << "{" << "version_type& v (*pv);"; - init_named_version_value_member_->traverse (*optimistic); + init_named_version_value_member_->traverse (*opt); os << "}"; } @@ -2618,10 +2762,7 @@ traverse_view (type& c) else // Output the pragma location for easier error tracking. // - os << "// From " << - location_file (vq.loc).leaf () << ":" << - location_line (vq.loc) << ":" << - location_column (vq.loc) << endl + os << "// From " << location_string (vq.loc, true) << endl << translate_expression ( c, vq.expr, vq.scope, vq.loc, "query", &ph).value; @@ -2707,13 +2848,10 @@ traverse_view (type& c) l += " ON"; + // Output the pragma location for easier error tracking. + // os << "r += " << strlit (l) << ";" - // Output the pragma location for easier error tracking. - // - << "// From " << - location_file (i->loc).leaf () << ":" << - location_line (i->loc) << ":" << - location_column (i->loc) << endl + << "// From " << location_string (i->loc, true) << endl << "r += " << e.value << ";" << endl; @@ -2775,13 +2913,10 @@ traverse_view (type& c) l += " ON"; + // Output the pragma location for easier error tracking. + // os << "r += " << strlit (l) << ";" - // Output the pragma location for easier error tracking. - // - << "// From " << - location_file (i->loc).leaf () << ":" << - location_line (i->loc) << ":" << - location_column (i->loc) << endl + << "// From " << location_string (i->loc, true) << endl << "r += " << e.value << ";"; if (poly_depth != 1) @@ -3210,10 +3345,7 @@ traverse_view (type& c) { // Output the pragma location for easier error tracking. // - os << "// From " << - location_file (vq.loc).leaf () << ":" << - location_line (vq.loc) << ":" << - location_column (vq.loc) << endl + os << "// From " << location_string (vq.loc, true) << endl << translate_expression ( c, vq.expr, vq.scope, vq.loc, "query", &ph).value; @@ -3596,6 +3728,9 @@ namespace relational string const& prag, bool* placeholder) { + // This code is similar to translate() from context.cxx. + // + // The overall idea is as folows: read in tokens and add them // to the string. If a token starts a name, try to resolve it // to an object member (taking into account aliases). If this 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