summaryrefslogtreecommitdiff
path: root/odb
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-11-15 17:46:28 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-11-15 17:46:28 +0200
commit89a3b6133ade1ccb3a8e9ab9c86eac6aaef5db69 (patch)
tree394eb90c5acc9b55460bc7e4961cf791a60e397d /odb
parent61acf05c698a8b611c5ccf6aed8d3e654d5acf8e (diff)
Add support for custom object pointers
New option: --default-pointer. New object pragma specifier: pointer.
Diffstat (limited to 'odb')
-rw-r--r--odb/header.cxx3
-rw-r--r--odb/mysql/header.cxx9
-rw-r--r--odb/mysql/source.cxx4
-rw-r--r--odb/odb.cxx28
-rw-r--r--odb/options.cli23
-rw-r--r--odb/pragma.cxx234
-rw-r--r--odb/tracer/header.cxx9
-rw-r--r--odb/tracer/source.cxx4
-rw-r--r--odb/type-processor.cxx143
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 <memory>" << endl
+ << endl;
+
ctx.os << "#include <odb/core.hxx>" << endl
<< "#include <odb/traits.hxx>" << 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<string> ("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 \"<standard-odb-prologue>\"" << 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 \"<standard-odb-epilogue>\"" << endl
- << "#include <odb/container-traits.hxx>" << 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 \"<standard-odb-epilogue>\"" << 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 <memory>" << endl
+ << "#ifndef BOOST_TR1_MEMORY_HPP_INCLUDED" << endl
+ << "# include <tr1/memory>" << endl
+ << "#endif" << endl;
+
+ // Standard containers traits.
+ //
+ os << "#include <odb/container-traits.hxx>" << 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 = "*"
+ {
+ "<ptr>",
+ "Use <ptr> 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<object>}. 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{<memory>} 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
{
"<dir>",
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<string> ("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: