aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--odb/context.cxx254
-rw-r--r--odb/context.hxx29
-rw-r--r--odb/pragma.cxx1
-rw-r--r--odb/processor.cxx42
-rw-r--r--odb/relational/common.hxx3
-rw-r--r--odb/relational/common.txx12
-rw-r--r--odb/relational/source.hxx117
7 files changed, 376 insertions, 82 deletions
diff --git a/odb/context.cxx b/odb/context.cxx
index 1ff906f..5ce084a 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -22,6 +22,239 @@
using namespace std;
+static inline void
+add_space (string& s)
+{
+ string::size_type n (s.size ());
+ if (n != 0 && s[n - 1] != ' ')
+ s += ' ';
+}
+
+//
+// custom_cxx_type
+//
+string custom_cxx_type::
+translate (string const& val, const cxx_tokens& expr)
+{
+ // Similar to member_access::translate() and a few other places.
+ //
+ string r;
+
+ cxx_tokens_lexer l;
+ l.start (expr);
+
+ string tl;
+ for (cpp_ttype tt (l.next (tl)), ptt (CPP_EOF); tt != CPP_EOF;)
+ {
+ // Try to format the expression to resemble the style of the
+ // generated code.
+ //
+ switch (tt)
+ {
+ case CPP_NOT:
+ {
+ add_space (r);
+ r += '!';
+ break;
+ }
+ case CPP_COMMA:
+ {
+ r += ", ";
+ break;
+ }
+ case CPP_OPEN_PAREN:
+ {
+ if (ptt == CPP_NAME ||
+ ptt == CPP_KEYWORD)
+ add_space (r);
+
+ r += '(';
+ break;
+ }
+ case CPP_CLOSE_PAREN:
+ {
+ r += ')';
+ break;
+ }
+ case CPP_OPEN_SQUARE:
+ {
+ r += '[';
+ break;
+ }
+ case CPP_CLOSE_SQUARE:
+ {
+ r += ']';
+ break;
+ }
+ case CPP_OPEN_BRACE:
+ {
+ add_space (r);
+ r += "{ ";
+ break;
+ }
+ case CPP_CLOSE_BRACE:
+ {
+ add_space (r);
+ r += '}';
+ break;
+ }
+ case CPP_SEMICOLON:
+ {
+ r += ';';
+ break;
+ }
+ case CPP_ELLIPSIS:
+ {
+ add_space (r);
+ r += "...";
+ break;
+ }
+ case CPP_PLUS:
+ case CPP_MINUS:
+ {
+ bool unary (ptt != CPP_NAME &&
+ ptt != CPP_SCOPE &&
+ ptt != CPP_NUMBER &&
+ ptt != CPP_STRING &&
+ ptt != CPP_CLOSE_PAREN &&
+ ptt != CPP_PLUS_PLUS &&
+ ptt != CPP_MINUS_MINUS);
+
+ if (!unary)
+ add_space (r);
+
+ r += cxx_lexer::token_spelling[tt];
+
+ if (!unary)
+ r += ' ';
+ break;
+ }
+ case CPP_PLUS_PLUS:
+ case CPP_MINUS_MINUS:
+ {
+ if (ptt != CPP_NAME &&
+ ptt != CPP_CLOSE_PAREN &&
+ ptt != CPP_CLOSE_SQUARE)
+ add_space (r);
+
+ r += cxx_lexer::token_spelling[tt];
+ break;
+ }
+ case CPP_DEREF:
+ case CPP_DEREF_STAR:
+ case CPP_DOT:
+ case CPP_DOT_STAR:
+ {
+ r += cxx_lexer::token_spelling[tt];
+ break;
+ }
+ case CPP_STRING:
+ {
+ if (ptt == CPP_NAME ||
+ ptt == CPP_KEYWORD ||
+ ptt == CPP_STRING ||
+ ptt == CPP_NUMBER)
+ add_space (r);
+
+ r += context::strlit (tl);
+ break;
+ }
+ case CPP_NUMBER:
+ {
+ if (ptt == CPP_NAME ||
+ ptt == CPP_KEYWORD ||
+ ptt == CPP_STRING ||
+ ptt == CPP_NUMBER)
+ add_space (r);
+
+ r += tl;
+ break;
+ }
+ case CPP_SCOPE:
+ {
+ // Add space except for a few common cases.
+ //
+ if (ptt != CPP_NAME &&
+ ptt != CPP_OPEN_PAREN &&
+ ptt != CPP_OPEN_SQUARE)
+ add_space (r);
+
+ r += cxx_lexer::token_spelling[tt];
+ break;
+ }
+ case CPP_NAME:
+ {
+ // Start of a name.
+ //
+ if (ptt == CPP_NAME ||
+ ptt == CPP_KEYWORD ||
+ ptt == CPP_STRING ||
+ ptt == CPP_NUMBER)
+ add_space (r);
+
+ r += tl;
+ break;
+ }
+ case CPP_QUERY:
+ {
+ if (ptt == CPP_OPEN_PAREN)
+ {
+ // Get the next token and see if it is ')'.
+ //
+ ptt = tt;
+ tt = l.next (tl);
+
+ if (tt == CPP_CLOSE_PAREN)
+ r += val;
+ else
+ {
+ add_space (r);
+ r += "? ";
+ }
+ continue; // We have already gotten the next token.
+ }
+ // Fall through.
+ }
+ default:
+ {
+ // Handle CPP_KEYWORD here to avoid a warning (it is not
+ // part of the cpp_ttype enumeration).
+ //
+ if (tt == CPP_KEYWORD)
+ {
+ if (ptt == CPP_NAME ||
+ ptt == CPP_KEYWORD ||
+ ptt == CPP_STRING ||
+ ptt == CPP_NUMBER)
+ add_space (r);
+
+ r += tl;
+ }
+ else
+ {
+ // All the other operators.
+ //
+ add_space (r);
+ r += cxx_lexer::token_spelling[tt];
+ r += ' ';
+ }
+ break;
+ }
+ }
+
+ //
+ // Watch out for the continue statements above if you add any
+ // logic here.
+ //
+
+ ptt = tt;
+ tt = l.next (tl);
+ }
+
+ return r;
+}
+
+
//
// view_object
//
@@ -59,14 +292,6 @@ placeholder () const
return false;
}
-static inline void
-add_space (string& s)
-{
- string::size_type n (s.size ());
- if (n != 0 && s[n - 1] != ' ')
- s += ' ';
-}
-
string member_access::
translate (string const& obj, string const& val, string const& db) const
{
@@ -1163,7 +1388,10 @@ utype (semantics::type& t, semantics::names*& hint)
}
semantics::type& context::
-utype (semantics::data_member& m, semantics::names*& hint, string const& kp)
+utype (semantics::data_member& m,
+ semantics::names*& hint,
+ string const& kp,
+ const custom_cxx_type** translation)
{
semantics::type* t (0);
@@ -1200,6 +1428,9 @@ utype (semantics::data_member& m, semantics::names*& hint, string const& kp)
//
// @@ Need to cache the result on the member.
//
+ if (translation != 0)
+ *translation = 0;
+
for (semantics::scope* s (&m.scope ());; s = &s->scope_ ())
{
using semantics::namespace_;
@@ -1219,12 +1450,11 @@ utype (semantics::data_member& m, semantics::names*& hint, string const& kp)
if (i != m.end ())
{
- cerr << "mapping " << t->fq_name (hint) << " to ";
-
hint = i->second->as_hint;
t = i->second->as;
- cerr << t->fq_name (hint) << endl;
+ if (translation != 0)
+ *translation = i->second;
// Currently we only support one level of mapping, but I am
// sure someone will want multiple levels.
diff --git a/odb/context.hxx b/odb/context.hxx
index 6646e93..6e1d733 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -118,6 +118,12 @@ struct custom_cxx_type
{
custom_cxx_type (): type_node (0), as_node (0) {}
+ std::string
+ translate_to (std::string const& v) const {return translate (v, to);}
+
+ std::string
+ translate_from (std::string const& v) const {return translate (v, from);}
+
tree type_node;
std::string type_name;
semantics::type* type;
@@ -128,12 +134,18 @@ struct custom_cxx_type
semantics::type* as;
semantics::names* as_hint;
- // Empty expression means the values are implicitly convertible.
- //
cxx_tokens to;
+ bool to_move; // Single (?), so can move.
+
cxx_tokens from;
+ bool from_move; // Single (?), so can move.
location_t loc;
+ tree scope; // Scope for which this mapping is defined.
+
+private:
+ static std::string
+ translate (std::string const&, const cxx_tokens&);
};
typedef std::vector<custom_cxx_type> custom_cxx_types;
@@ -617,17 +629,19 @@ public:
// The same for a member's type but also do custom C++ type translation.
//
static semantics::type&
- utype (semantics::data_member& m)
+ utype (semantics::data_member& m, const custom_cxx_type** translation = 0)
{
semantics::names* hint (0);
- return utype (m, hint);
+ return utype (m, hint, string (), translation);
}
static semantics::type&
- utype (semantics::data_member& m, string const& key_prefix)
+ utype (semantics::data_member& m,
+ string const& key_prefix,
+ const custom_cxx_type** translation = 0)
{
semantics::names* hint (0);
- return utype (m, hint, key_prefix);
+ return utype (m, hint, key_prefix, translation);
}
// In addition to the unqualified type, this version also returns the
@@ -638,7 +652,8 @@ public:
static semantics::type&
utype (semantics::data_member&,
semantics::names*& hint,
- string const& key_prefix = string ());
+ string const& key_prefix = string (),
+ const custom_cxx_type** translation = 0);
// For arrays this function returns true if the (innermost) element
// type is const.
diff --git a/odb/pragma.cxx b/odb/pragma.cxx
index 733d19c..549a0f6 100644
--- a/odb/pragma.cxx
+++ b/odb/pragma.cxx
@@ -3117,6 +3117,7 @@ handle_pragma_qualifier (cxx_lexer& l, string p)
{
custom_cxx_type ct;
ct.loc = loc;
+ ct.scope = current_scope ();
val = ct;
name = "custom-cxx-types";
adder = &accumulate<custom_cxx_type>;
diff --git a/odb/processor.cxx b/odb/processor.cxx
index c281706..facbbb4 100644
--- a/odb/processor.cxx
+++ b/odb/processor.cxx
@@ -3002,12 +3002,12 @@ namespace
tree access_; // odb::access node.
};
- static void
+ static bool
check_to_from (const cxx_tokens& ex, const char* c, location_t l)
{
// Make sure we have one and only one placeholder (?).
//
- bool r (false);
+ bool r (false), m (true);
for (cxx_tokens::const_iterator i (ex.begin ()), e (ex.end ()); i != e;)
{
@@ -3018,11 +3018,7 @@ namespace
if (++i != e && i->type == CPP_CLOSE_PAREN)
{
if (r)
- {
- error (l) << "multiple '(?)' expressions in the '" << c << "' "
- << "clause of db pragma map" << endl;
- throw operation_failed ();
- }
+ m = false; // Multiple (?), can't move.
else
r = true;
}
@@ -3039,6 +3035,8 @@ namespace
throw operation_failed ();
}
+
+ return m;
}
}
@@ -3055,8 +3053,6 @@ process1 (semantics::unit& u)
u.set ("custom-cxx-types", custom_cxx_types ());
custom_cxx_types & cts (u.get<custom_cxx_types> ("custom-cxx-types"));
- custom_cxx_type_map& ctm (u.set ("custom-cxx-type-map",
- custom_cxx_type_map ()));
for (custom_cxx_types::iterator i (cts.begin ()); i != cts.end (); ++i)
{
@@ -3096,12 +3092,13 @@ process1 (semantics::unit& u)
e.push_back (cxx_token (0, CPP_OPEN_PAREN));
e.push_back (cxx_token (0, CPP_QUERY));
e.push_back (cxx_token (0, CPP_CLOSE_PAREN));
+ ct.to_move = true;
}
else
- check_to_from (e, "to", ct.loc);
+ ct.to_move = check_to_from (e, "to", ct.loc);
}
- // to
+ // from
//
{
cxx_tokens& e (ct.from);
@@ -3111,14 +3108,33 @@ process1 (semantics::unit& u)
e.push_back (cxx_token (0, CPP_OPEN_PAREN));
e.push_back (cxx_token (0, CPP_QUERY));
e.push_back (cxx_token (0, CPP_CLOSE_PAREN));
+ ct.from_move = true;
}
else
- check_to_from (e, "from", ct.loc);
+ ct.from_move = check_to_from (e, "from", ct.loc);
+ }
+
+ // Resolve mapping scope.
+ //
+ semantics::scope* s (dynamic_cast<semantics::scope*> (u.find (ct.scope)));
+ if (s == 0)
+ {
+ error (ct.loc) << "unable to resolve db pragma map scope" << endl;
+ throw operation_failed ();
+ }
+
+ if (semantics::namespace_* ns = dynamic_cast<semantics::namespace_*> (s))
+ {
+ if (ns->extension ())
+ s = &ns->original ();
}
// Enter into the map.
//
- ctm[ct.type] = &ct;
+ if (!s->count ("custom-cxx-type-map"))
+ s->set ("custom-cxx-type-map", custom_cxx_type_map ());
+
+ s->get<custom_cxx_type_map> ("custom-cxx-type-map")[ct.type] = &ct;
}
}
diff --git a/odb/relational/common.hxx b/odb/relational/common.hxx
index c117be5..bc7e034 100644
--- a/odb/relational/common.hxx
+++ b/odb/relational/common.hxx
@@ -78,6 +78,7 @@ namespace relational
semantics::data_member& m; // Member.
semantics::type& t; // Cvr-unqualified member C++ type, note
// that m.type () may not be the same as t.
+ const custom_cxx_type* ct; // Translation used for t, if any.
semantics::class_* ptr; // Pointed-to object if m is an object
// pointer. In this case t is the id type
// while fq_type_ is the pointer fq-type.
@@ -146,12 +147,14 @@ namespace relational
member_info (semantics::data_member& m_,
semantics::type& t_,
+ const custom_cxx_type* ct_,
semantics::type* wrapper_,
bool cq_,
string& var_,
string const& fq_type)
: m (m_),
t (t_),
+ ct (ct_),
ptr (0),
wrapper (wrapper_),
cq (cq_),
diff --git a/odb/relational/common.txx b/odb/relational/common.txx
index 7a3adad..893e16c 100644
--- a/odb/relational/common.txx
+++ b/odb/relational/common.txx
@@ -26,7 +26,10 @@ namespace relational
}
bool cq (type_override_ != 0 ? false : const_member (m));
- semantics::type& t (type_override_ != 0 ? *type_override_ : utype (m));
+ const custom_cxx_type* ct (0);
+ semantics::type& t (type_override_ != 0
+ ? *type_override_
+ : utype (m, &ct));
semantics::type* cont;
if (semantics::class_* c = object_pointer (t))
@@ -34,11 +37,12 @@ namespace relational
// A pointer in view might point to an object without id.
//
semantics::data_member* idm (id_member (*c));
- semantics::type& t (utype (idm != 0 ? *idm : m));
+ semantics::type& t (utype (idm != 0 ? *idm : m, &ct));
semantics::class_* comp (idm != 0 ? composite_wrapper (t) : 0);
member_info mi (m,
(comp != 0 ? *comp : t),
+ ct,
(comp != 0 && wrapper (t) ? &t : 0),
cq,
var,
@@ -64,6 +68,7 @@ namespace relational
//
member_info mi (m,
*c,
+ ct,
(wrapper (t) ? &t : 0),
cq,
var,
@@ -82,6 +87,7 @@ namespace relational
//
member_info mi (m,
*cont,
+ 0, // Cannot be mapped.
(wrapper (t) ? &t : 0),
cq,
var,
@@ -94,7 +100,7 @@ namespace relational
}
else
{
- member_info mi (m, t, 0, cq, var, fq_type_override_);
+ member_info mi (m, t, ct, 0, cq, var, fq_type_override_);
mi.st = &member_sql_type (m);
if (pre (mi))
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index a160672..81e182b 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -2154,6 +2154,19 @@ namespace relational
}
}
+ // Translate.
+ //
+ if (mi.ct != 0)
+ {
+ os << "// From " << location_string (mi.ct->loc, true) << endl
+ << type_ref_type (*mi.ct->as, mi.ct->as_hint, true, "vt") <<
+ " =" << endl
+ << " " << mi.ct->translate_to (member) << ";"
+ << endl;
+
+ member = "vt";
+ }
+
// 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
@@ -2181,7 +2194,11 @@ namespace relational
<< "{";
}
- member = "wrapper_traits< " + wt + " >::get_ref (" + member + ")";
+ os << "const" << mi.fq_type () << "& vw = " << endl
+ << " wrapper_traits< " + wt + " >::get_ref (" + member + ");"
+ << endl;
+
+ member = "vw";
}
if (discriminator (mi.m))
@@ -2553,7 +2570,7 @@ namespace relational
if (mi.ptr != 0 && view_member (mi.m))
return true; // That's enough for the object pointer in view.
- // Get the member using the accessor expression.
+ // Set the member using the modifier expression.
//
member_access& ma (mi.m.template get<member_access> ("set"));
@@ -2603,6 +2620,17 @@ namespace relational
member = "v";
}
+ // Translate.
+ //
+ if (mi.ct != 0)
+ {
+ os << type_val_type (*mi.ct->as, mi.ct->as_hint, false, "vt") << ";"
+ << endl;
+
+ translate_member = member;
+ member = "vt";
+ }
+
// 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
@@ -2625,10 +2653,16 @@ namespace relational
<< "i." << mi.var << "value" <<
(versioned (*comp) ? ", svm" : "") << "))" << endl
<< "wrapper_traits< " << wt << " >::set_null (" << member + ");"
- << "else" << endl;
+ << "else"
+ << "{";
}
- member = "wrapper_traits< " + wt + " >::set_ref (" + member + ")";
+ os << mi.fq_type () << "& vw =" << endl
+ << " wrapper_traits< " + wt + " >::set_ref (" + member + ");"
+ << endl;
+
+ wrap_member = member;
+ member = "vw";
}
if (mi.ptr != 0)
@@ -2739,6 +2773,30 @@ namespace relational
os << "}";
}
+ // Wrap back (so to speak).
+ //
+ if (mi.wrapper != 0 && composite (mi.t) != 0)
+ {
+ if (null (mi.m, key_prefix_) &&
+ mi.wrapper->template get<bool> ("wrapper-null-handler"))
+ os << "}";
+
+ member = wrap_member;
+ }
+
+ // Untranslate.
+ //
+ if (mi.ct != 0)
+ {
+ //@@ Use move() in C++11? Or not.
+ //
+ os << "// From " << location_string (mi.ct->loc, true) << endl
+ << translate_member << " = " <<
+ mi.ct->translate_from (member) << ";";
+
+ member = translate_member;
+ }
+
// Call the modifier if we are using a proper one.
//
if (member_override_.empty ())
@@ -2893,6 +2951,8 @@ namespace relational
string db_type_id;
string traits;
string member;
+ string translate_member; // Untranslated member.
+ string wrap_member; // Wrapped member.
instance<member_database_type_id> member_database_type_id_;
};
@@ -6118,11 +6178,6 @@ namespace relational
if (opt != 0) // Not load_opt, we do it in poly-derived as well.
{
- member_access& ma (opt->get<member_access> ("get"));
-
- if (!ma.synthesized)
- os << "// From " << location_string (ma.loc, true) << endl;
-
os << "if (";
if (poly_derived)
@@ -6137,7 +6192,8 @@ namespace relational
else
os << "version (im)";
- os << " != " << ma.translate ("obj") << ")" << endl
+ os << " != " << (poly_derived ? "root_traits::" : "") <<
+ "version (obj))" << endl
<< "throw object_changed ();"
<< endl;
}
@@ -6341,49 +6397,16 @@ namespace relational
//
if (s.optimistic ()) // Note: not update_opt.
{
- member_access& ma_get (opt->get<member_access> ("get"));
- member_access& ma_set (opt->get<member_access> ("set"));
-
// Object is passed as const reference so we need to cast away
// constness.
//
- string obj ("const_cast< object_type& > (obj)");
+ const char* obj ("const_cast<object_type&> (obj)");
string inc (optimistic_version_increment (*opt));
- if (!ma_set.synthesized)
- os << "// From " << location_string (ma_set.loc, true) << endl;
-
- if (ma_set.placeholder ())
- {
- if (!ma_get.synthesized)
- os << "// From " << location_string (ma_get.loc, true) << endl;
-
- if (inc == "1")
- os << ma_set.translate (
- obj, ma_get.translate ("obj") + " + 1") << ";";
- else
- os << ma_set.translate (obj, inc) << ";";
- }
+ if (inc == "1")
+ inc_member (*opt, obj, "obj", "version_type");
else
- {
- // If this member is const and we have a synthesized direct
- // access, then cast away constness. Otherwise, we assume
- // that the user-provided expression handles this.
- //
- bool cast (ma_set.direct () && const_member (*opt));
- if (cast)
- os << "const_cast< version_type& > (" << endl;
-
- os << ma_set.translate (obj);
-
- if (cast)
- os << ")";
-
- if (inc == "1")
- os << "++;";
- else
- os << " = " << inc << ";";
- }
+ set_member (*opt, obj, inc, "", "version_type");
}
os << "}";