From 89a3b6133ade1ccb3a8e9ab9c86eac6aaef5db69 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 15 Nov 2010 17:46:28 +0200 Subject: Add support for custom object pointers New option: --default-pointer. New object pragma specifier: pointer. --- odb/header.cxx | 3 + odb/mysql/header.cxx | 9 +- odb/mysql/source.cxx | 4 +- odb/odb.cxx | 28 ++++-- odb/options.cli | 23 +++++ odb/pragma.cxx | 234 ++++++++++++++++++++++++++++++++++++------------- odb/tracer/header.cxx | 9 +- odb/tracer/source.cxx | 4 +- odb/type-processor.cxx | 143 +++++++++++++++++++++++++++++- 9 files changed, 376 insertions(+), 81 deletions(-) diff --git a/odb/header.cxx b/odb/header.cxx index 9c816d8..35a95ab 100644 --- a/odb/header.cxx +++ b/odb/header.cxx @@ -80,6 +80,9 @@ namespace void generate_header (context& ctx) { + ctx.os << "#include " << endl + << endl; + ctx.os << "#include " << endl << "#include " << endl << endl; diff --git a/odb/mysql/header.cxx b/odb/mysql/header.cxx index 195263c..79b8d67 100644 --- a/odb/mysql/header.cxx +++ b/odb/mysql/header.cxx @@ -675,15 +675,14 @@ namespace mysql << "//" << endl; os << "template <>" << endl - << "class access::object_traits< " << type << " >: " << endl - << " public access::object_memory< " << type << " >," << endl - << " public access::object_factory< " << type << " >" + << "class access::object_traits< " << type << " >" << "{" << "public:" << endl; - // object_type + // object_type & pointer_type // - os << "typedef " << type << " object_type;"; + os << "typedef " << type << " object_type;" + << "typedef " << c.get ("object-pointer") << " pointer_type;"; // id_type // diff --git a/odb/mysql/source.cxx b/odb/mysql/source.cxx index 29495df..2e54a04 100644 --- a/odb/mysql/source.cxx +++ b/odb/mysql/source.cxx @@ -2174,8 +2174,8 @@ namespace mysql << "bool grew (false);" << "if (find (sts, id, grew))" << "{" - << "pointer_type p (access::object_factory< " << type << - " >::create ());" + << "pointer_type p (access::object_factory< object_type, " << + "pointer_type >::create ());" << "pointer_traits< pointer_type >::guard g (p);" << "object_type& obj (pointer_traits< pointer_type >::get_ref (p));" << "init (obj, sts.image ());"; diff --git a/odb/odb.cxx b/odb/odb.cxx index 1f1d45a..a1beccf 100644 --- a/odb/odb.cxx +++ b/odb/odb.cxx @@ -480,6 +480,10 @@ main (int argc, char* argv[]) pi.fd, ios_base::out | ios_base::binary); ostream os (&fb); + // Add the standard prologue. + // + // os << "#line 1 \"\"" << endl; + // Add custom prologue if any. // strings const& pro (ops.odb_prologue ()); @@ -501,11 +505,6 @@ main (int argc, char* argv[]) return 1; } - // Add the standard epilogue. - // - os << "#line 1 \"\"" << endl - << "#include " << endl; - // Add custom epilogue if any. // strings const& epi (ops.odb_epilogue ()); @@ -515,6 +514,25 @@ main (int argc, char* argv[]) << epi[i] << endl; } + + // Add the standard epilogue at the end so that we see all + // the declarations. + // + os << "#line 1 \"\"" << endl; + + // Includes for standard smart pointers. The Boost TR1 header + // may or may not delegate to the GCC implementation. In either + // case, the necessary declarations will be provided so we don't + // need to do anything. + // + os << "#include " << endl + << "#ifndef BOOST_TR1_MEMORY_HPP_INCLUDED" << endl + << "# include " << endl + << "#endif" << endl; + + // Standard containers traits. + // + os << "#include " << endl; } if (!wait_process (pi, argv[0])) diff --git a/odb/options.cli b/odb/options.cli index 8c9a965..ad8b97b 100644 --- a/odb/options.cli +++ b/odb/options.cli @@ -65,6 +65,29 @@ class options lost." }; + std::string --default-pointer = "*" + { + "", + "Use as the default pointer for persistent objects. Objects that + do not have a pointer assigned with the \cb{pointer} pragma specifier + will use this pointer by default. The value of this option can be \cb{*} + which denotes a 'naked' pointer and is the default, or a qualified name + of a smart pointer class template, for example, \cb{std::auto_ptr}. In + the latter case, the ODB compiler constructs the object pointer by adding + a single template argument of the object type to the qualified name, for + example \cb{std::auto_ptr}. The object pointer is used by the + ODB runtime to return dynamically allocated instances of the object + type. + + Except for the 'naked' pointer and the standard smart pointers defined + in the \cb{} header file, you are expected to include the + definition of the default pointer at the beginning of the generated + header file. There are two common ways to achieve this: you can either + include the necessary header in the file being compiled or you can use + the \cb{--hxx-prologue} option to add the necessary \cb{#include} + directive to the generated code." + }; + std::string --output-dir | -o { "", diff --git a/odb/pragma.cxx b/odb/pragma.cxx index 88c14a2..adcf06e 100644 --- a/odb/pragma.cxx +++ b/odb/pragma.cxx @@ -7,6 +7,16 @@ using namespace std; +// Token spelling. See cpplib.h for details. +// +#define OP(e, s) s , +#define TK(e, s) #e , +static char const* token_spelling[N_TTYPES] = { TTYPE_TABLE }; +#undef OP +#undef TK + +// Lists of pragmas. +// loc_pragmas loc_pragmas_; decl_pragmas decl_pragmas_; @@ -18,11 +28,13 @@ parse_scoped_name (tree& t, string const& prag) { tree scope, id; + bool first (true); if (tt == CPP_SCOPE) { name += "::"; scope = global_namespace; + first = false; tt = pragma_lex (&t); } else @@ -40,51 +52,66 @@ parse_scoped_name (tree& t, name += IDENTIFIER_POINTER (t); tt = pragma_lex (&t); - if (tt == CPP_SCOPE) + bool last (tt != CPP_SCOPE); + tree decl = lookup_qualified_name (scope, id, last && is_type, false); + + // If this is the first component in the name, then also search the + // outer scopes. + // + if (decl == error_mark_node && first && scope != global_namespace) { - scope = lookup_qualified_name (scope, id, false, false); + do + { + scope = TYPE_P (scope) + ? CP_TYPE_CONTEXT (scope) + : CP_DECL_CONTEXT (scope); + decl = lookup_qualified_name (scope, id, last && is_type, false); + } while (decl == error_mark_node && scope != global_namespace); + } - if (scope == error_mark_node) + if (decl == error_mark_node) + { + if (last) { error ((is_type ? "unable to resolve type name %qs in db pragma %qs" : "unable to resolve name %qs in db pragma %qs"), name.c_str (), prag.c_str ()); - return 0; + } + else + { + error ("unable to resolve name %qs in db pragma %qs", + name.c_str (), prag.c_str ()); } - if (TREE_CODE (scope) == TYPE_DECL) - scope = TREE_TYPE (scope); - - name += "::"; - tt = pragma_lex (&t); + return 0; } - else + + scope = decl; + + if (last) break; - } - tree decl (lookup_qualified_name (scope, id, is_type, false)); + first = false; - if (decl == error_mark_node) - { - error ((is_type - ? "unable to resolve type name %qs in db pragma %qs" - : "unable to resolve name %qs in db pragma %qs"), - name.c_str (), prag.c_str ()); - return 0; + if (TREE_CODE (scope) == TYPE_DECL) + scope = TREE_TYPE (scope); + + name += "::"; + tt = pragma_lex (&t); } // Get the actual type if this is a TYPE_DECL. // if (is_type) { - if (TREE_CODE (decl) == TYPE_DECL) - decl = TREE_TYPE (decl); + if (TREE_CODE (scope) == TYPE_DECL) + scope = TREE_TYPE (scope); - decl = TYPE_MAIN_VARIANT (decl); + scope = TYPE_MAIN_VARIANT (scope); } - return decl; + return scope; } bool @@ -110,7 +137,8 @@ check_decl_type (tree d, string const& name, string const& p, location_t l) return false; } } - else if (p == "object") + else if (p == "object" || + p == "pointer") { if (tc != RECORD_TYPE) { @@ -163,7 +191,10 @@ check_decl_type (tree d, string const& name, string const& p, location_t l) } static void -handle_pragma (string const& p, tree decl, string const& decl_name) +handle_pragma (cpp_reader* reader, + string const& p, + tree decl, + string const& decl_name) { tree t; cpp_ttype tt; @@ -206,6 +237,87 @@ handle_pragma (string const& p, tree decl, string const& decl_name) tt = pragma_lex (&t); } + else if (p == "pointer") + { + // pointer (qname) + // + + // Make sure we've got the correct declaration type. + // + if (decl != 0 && !check_decl_type (decl, decl_name, p, loc)) + return; + + if (pragma_lex (&t) != CPP_OPEN_PAREN) + { + error ("%qs expected after db pragma %qs", "(", pc); + return; + } + + size_t pb (0); + + for (tt = pragma_lex (&t); + tt != CPP_EOF && (tt != CPP_CLOSE_PAREN || pb != 0); + tt = pragma_lex (&t)) + { + if (tt == CPP_OPEN_PAREN) + pb++; + else if (tt == CPP_CLOSE_PAREN) + pb--; + + // @@ Need to handle literals, at least integer. + // + switch (tt) + { + case CPP_LESS: + { + val += "< "; + break; + } + case CPP_GREATER: + { + val += " >"; + break; + } + case CPP_COMMA: + { + val += ", "; + break; + } + case CPP_NAME: + { + val += IDENTIFIER_POINTER (t); + break; + } + default: + { + if (tt <= CPP_LAST_PUNCTUATOR) + val += token_spelling[tt]; + else + { + error ("unexpected token %qs in db pragma %qs", + token_spelling[tt], + pc); + return; + } + break; + } + } + } + + if (tt != CPP_CLOSE_PAREN) + { + error ("%qs expected at the end of db pragma %qs", ")", pc); + return; + } + + if (val.empty ()) + { + error ("expected pointer name in db pragma %qs", pc); + return; + } + + tt = pragma_lex (&t); + } else if (p == "id") { // id @@ -350,14 +462,14 @@ handle_pragma (string const& p, tree decl, string const& decl_name) // if (tt == CPP_NAME) { - handle_pragma (IDENTIFIER_POINTER (t), decl, decl_name); + handle_pragma (reader, IDENTIFIER_POINTER (t), decl, decl_name); } else if (tt != CPP_EOF) error ("unexpected text after %qs in db pragma", p.c_str ()); } static void -handle_pragma_qualifier (string const& p) +handle_pragma_qualifier (cpp_reader* reader, string const& p) { tree t; cpp_ttype tt; @@ -501,7 +613,7 @@ handle_pragma_qualifier (string const& p) p == "table" || p == "transient") { - handle_pragma (p, 0, ""); + handle_pragma (reader, p, 0, ""); return; } else @@ -530,106 +642,106 @@ handle_pragma_qualifier (string const& p) // if (tt == CPP_NAME) { - handle_pragma (IDENTIFIER_POINTER (t), decl, decl_name); + handle_pragma (reader, IDENTIFIER_POINTER (t), decl, decl_name); } else if (tt != CPP_EOF) error ("unexpected text after %qs in db pragma", p.c_str ()); } extern "C" void -handle_pragma_db_object (cpp_reader*) +handle_pragma_db_object (cpp_reader* reader) { - handle_pragma_qualifier ("object"); + handle_pragma_qualifier (reader, "object"); } extern "C" void -handle_pragma_db_value (cpp_reader*) +handle_pragma_db_value (cpp_reader* reader) { - handle_pragma_qualifier ("value"); + handle_pragma_qualifier (reader, "value"); } extern "C" void -handle_pragma_db_member (cpp_reader*) +handle_pragma_db_member (cpp_reader* reader) { - handle_pragma_qualifier ("member"); + handle_pragma_qualifier (reader, "member"); } extern "C" void -handle_pragma_db_id (cpp_reader*) +handle_pragma_db_id (cpp_reader* reader) { - handle_pragma_qualifier ("id"); + handle_pragma_qualifier (reader, "id"); } extern "C" void -handle_pragma_db_auto (cpp_reader*) +handle_pragma_db_auto (cpp_reader* reader) { - handle_pragma_qualifier ("auto"); + handle_pragma_qualifier (reader, "auto"); } extern "C" void -handle_pragma_db_column (cpp_reader*) +handle_pragma_db_column (cpp_reader* reader) { - handle_pragma_qualifier ("column"); + handle_pragma_qualifier (reader, "column"); } extern "C" void -handle_pragma_db_vcolumn (cpp_reader*) +handle_pragma_db_vcolumn (cpp_reader* reader) { - handle_pragma_qualifier ("value_column"); + handle_pragma_qualifier (reader, "value_column"); } extern "C" void -handle_pragma_db_icolumn (cpp_reader*) +handle_pragma_db_icolumn (cpp_reader* reader) { - handle_pragma_qualifier ("index_column"); + handle_pragma_qualifier (reader, "index_column"); } extern "C" void -handle_pragma_db_kcolumn (cpp_reader*) +handle_pragma_db_kcolumn (cpp_reader* reader) { - handle_pragma_qualifier ("key_column"); + handle_pragma_qualifier (reader, "key_column"); } extern "C" void -handle_pragma_db_idcolumn (cpp_reader*) +handle_pragma_db_idcolumn (cpp_reader* reader) { - handle_pragma_qualifier ("id_column"); + handle_pragma_qualifier (reader, "id_column"); } extern "C" void -handle_pragma_db_type (cpp_reader*) +handle_pragma_db_type (cpp_reader* reader) { - handle_pragma_qualifier ("type"); + handle_pragma_qualifier (reader, "type"); } extern "C" void -handle_pragma_db_vtype (cpp_reader*) +handle_pragma_db_vtype (cpp_reader* reader) { - handle_pragma_qualifier ("value_type"); + handle_pragma_qualifier (reader, "value_type"); } extern "C" void -handle_pragma_db_itype (cpp_reader*) +handle_pragma_db_itype (cpp_reader* reader) { - handle_pragma_qualifier ("index_type"); + handle_pragma_qualifier (reader, "index_type"); } extern "C" void -handle_pragma_db_ktype (cpp_reader*) +handle_pragma_db_ktype (cpp_reader* reader) { - handle_pragma_qualifier ("key_type"); + handle_pragma_qualifier (reader, "key_type"); } extern "C" void -handle_pragma_db_table (cpp_reader*) +handle_pragma_db_table (cpp_reader* reader) { - handle_pragma_qualifier ("table"); + handle_pragma_qualifier (reader, "table"); } extern "C" void -handle_pragma_db_transient (cpp_reader*) +handle_pragma_db_transient (cpp_reader* reader) { - handle_pragma_qualifier ("transient"); + handle_pragma_qualifier (reader, "transient"); } extern "C" void diff --git a/odb/tracer/header.cxx b/odb/tracer/header.cxx index eaa7546..a4dd368 100644 --- a/odb/tracer/header.cxx +++ b/odb/tracer/header.cxx @@ -35,15 +35,14 @@ namespace tracer << "//" << endl; os << "template <>" << endl - << "class access::object_traits< " << type << " >: " << endl - << " public access::object_memory< " << type << " >," << endl - << " public access::object_factory< " << type << " >" + << "class access::object_traits< " << type << " >" << "{" << "public:" << endl; - // object_type & shared_ptr + // object_type & pointer_type // - os << "typedef " << type << " object_type;"; + os << "typedef " << type << " object_type;" + << "typedef object_type* pointer_type;"; // id_type // diff --git a/odb/tracer/source.cxx b/odb/tracer/source.cxx index 338f2fb..8d1bd4f 100644 --- a/odb/tracer/source.cxx +++ b/odb/tracer/source.cxx @@ -93,8 +93,8 @@ namespace tracer << "if (id == id_type ())" << endl << "return pointer_type (0);" << endl - << "pointer_type r (access::object_factory< " << type << - " >::create ());" + << "pointer_type r (access::object_factory< object_type, " << + "pointer_type >::create ());" << "pointer_traits< pointer_type >::guard g (r);" << "r->" << id.name () << " = id;" << "g.release ();" diff --git a/odb/type-processor.cxx b/odb/type-processor.cxx index 5834e1f..b99cfb9 100644 --- a/odb/type-processor.cxx +++ b/odb/type-processor.cxx @@ -389,10 +389,151 @@ namespace virtual void traverse (type& c) { - if (!(c.count ("object") || comp_value (c))) + bool obj (c.count ("object")); + + if (!(obj || comp_value (c))) return; names (c); + + // Assign object pointer. + // + if (obj) + { + string ptr; + string const& name (c.fq_name ()); + + if (c.count ("pointer")) + { + string const& p (c.get ("pointer")); + + if (p == "*") + ptr = name + "*"; + else if (p[p.size () - 1] == '*') + ptr = p; + else if (p.find ('<') != string::npos) + ptr = p; + else + { + // This is not a template-id. Resolve it and see if it is a + // template or a type. + // + try + { + tree t (resolve_type (p, c.scope ())); + int tc (TREE_CODE (t)); + + if (tc == TYPE_DECL) + ptr = p; + else if (tc == TEMPLATE_DECL && DECL_CLASS_TEMPLATE_P (t)) + ptr = p + "< " + name + " >"; + else + { + cerr << c.file () << ":" << c.line () << ":" << c.column () + << ": error: name '" << p << "' specified with " + << "'#pragma object pointer' does not name a type " + << "or a template" << endl; + + throw generation_failed (); + } + } + catch (invalid_name const&) + { + cerr << c.file () << ":" << c.line () << ":" << c.column () + << ": error: type name '" << p << "' specified with " + << "'#pragma object pointer' is invalid" << endl; + + throw generation_failed (); + } + catch (unable_to_resolve const&) + { + cerr << c.file () << ":" << c.line () << ":" << c.column () + << ": error: unable to resolve type name '" << p + << "' specified with '#pragma object pointer'" << endl; + + throw generation_failed (); + } + } + } + else + { + // Use the default pointer. + // + string const& p (options.default_pointer ()); + + if (p == "*") + ptr = name + "*"; + else + ptr = p + "< " + name + " >"; + } + + c.set ("object-pointer", ptr); + } + } + + private: + struct invalid_name {}; + struct unable_to_resolve {}; + + tree + resolve_type (string const& qn, semantics::scope& ss) + { + tree scope (ss.tree_node ()); + + for (size_t b (0), e (qn.find (':')), size (qn.size ());; + e = qn.find (':', b)) + { + bool last (e == string::npos); + string n (qn, b, last ? string::npos : e - b); + + if (n.empty ()) + { + if (b == 0) + scope = global_namespace; + else + throw invalid_name (); + } + else + { + tree nid (get_identifier (n.c_str ())); + scope = lookup_qualified_name (scope, nid, last, false); + + // If this is the first component in the name, then also + // search the outer scopes. + // + if (scope == error_mark_node && b == 0 && !ss.global_scope ()) + { + semantics::scope* s (&ss); + do + { + s = &s->scope_ (); + scope = lookup_qualified_name ( + s->tree_node (), nid, last, false); + } while (scope == error_mark_node && !s->global_scope ()); + } + + if (scope == error_mark_node) + throw unable_to_resolve (); + + if (!last && TREE_CODE (scope) == TYPE_DECL) + scope = TREE_TYPE (scope); + } + + if (e == string::npos) + break; + + if (qn[++e] != ':') + throw invalid_name (); + + ++e; // Second ':'. + + if (e == size) + break; + + b = e; + } + + return scope; } private: -- cgit v1.1