aboutsummaryrefslogtreecommitdiff
path: root/odb/type-processor.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-11-06 18:05:19 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-11-06 18:05:19 +0200
commitce696c26d2c9dd5a5813fd865082ab19ac49bcfa (patch)
treec44331b2a6e6fa1d9d518ddff63e711ce5d308c4 /odb/type-processor.cxx
parent727a83dc82fa094aa91630d165d230a9a2dabe60 (diff)
Add support for container persistence
Diffstat (limited to 'odb/type-processor.cxx')
-rw-r--r--odb/type-processor.cxx357
1 files changed, 349 insertions, 8 deletions
diff --git a/odb/type-processor.cxx b/odb/type-processor.cxx
index c8e58a1..ff799b2 100644
--- a/odb/type-processor.cxx
+++ b/odb/type-processor.cxx
@@ -3,6 +3,8 @@
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v3; see accompanying LICENSE file
+#include <odb/gcc.hxx>
+
#include <odb/type-processor.hxx>
namespace
@@ -12,10 +14,63 @@ namespace
data_member (context& c)
: context (c)
{
+ // Find the odb namespace.
+ //
+ tree odb = lookup_qualified_name (
+ global_namespace, get_identifier ("odb"), false, false);
+
+ if (odb == error_mark_node)
+ {
+ //@@ tmp
+ container_traits_ = 0;
+ return;
+
+ os << unit.file () << ": error: unable to resolve odb namespace"
+ << endl;
+
+ throw generation_failed ();
+ }
+
+ // Find the access class.
+ //
+ tree access = lookup_qualified_name (
+ odb, get_identifier ("access"), true, false);
+
+ if (access == error_mark_node)
+ {
+ //@@ tmp
+ container_traits_ = 0;
+ return;
+
+ os << unit.file () << ": error: unable to resolve access class"
+ << "in the odb namespace" << endl;
+
+ throw generation_failed ();
+ }
+
+ access = TREE_TYPE (access);
+
+ // Find container_traits.
+ //
+ container_traits_ = lookup_qualified_name (
+ access, get_identifier ("container_traits"), true, false);
+
+ if (container_traits_ == error_mark_node ||
+ !DECL_CLASS_TEMPLATE_P (container_traits_))
+ {
+ //@@ tmp
+ container_traits_ = 0;
+ return;
+
+ os << unit.file () << ": error: unable to resolve container_traits "
+ << "in the odb namespace" << endl;
+
+ throw generation_failed ();
+ }
}
virtual void
- traverse (type& m)
+ traverse (semantics::data_member& m)
{
if (m.count ("transient"))
return;
@@ -27,7 +82,15 @@ namespace
if (comp_value (t))
return;
- string const& type (column_type_impl (m));
+ string type;
+
+ if (m.count ("type"))
+ type = m.get<string> ("type");
+
+ if (type.empty () && t.count ("type"))
+ type = t.get<string> ("type");
+
+ type = column_type_impl (t, type, &m);
if (!type.empty ())
{
@@ -37,21 +100,299 @@ namespace
// See if this is a container type.
//
+ if (process_container (m))
+ return;
// If it is none of the above then we have an error.
//
string const& fq_type (t.fq_name (m.belongs ().hint ()));
- cerr << m.file () << ":" << m.line () << ":" << m.column () << ":"
- << " error: unable to map C++ type '" << fq_type << "' used in "
- << "data member '" << m.name () << "' to a database type" << endl;
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: unable to map C++ type '" << fq_type << "' used in "
+ << "data member '" << m.name () << "' to a database type" << endl;
- cerr << m.file () << ":" << m.line () << ":" << m.column () << ":"
- << " info: use '#pragma db type' to specify the database type"
- << endl;
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " info: use '#pragma db type' to specify the database type"
+ << endl;
+
+ throw generation_failed ();
+ }
+
+ void
+ process_container_value (semantics::type& t,
+ string const& prefix,
+ semantics::data_member& m)
+ {
+ if (comp_value (t))
+ return;
+
+ string type;
+
+ // Custom mapping can come from these places (listed in the order
+ // of priority): member, container type, value type.
+ //
+ if (m.count (prefix + "-type"))
+ type = m.get<string> (prefix + "-type");
+
+ semantics::type& ct (m.type ());
+
+ if (type.empty () && ct.count (prefix + "-type"))
+ type = ct.get<string> (prefix + "-type");
+
+ if (type.empty () && t.count ("type"))
+ type = t.get<string> ("type");
+
+ type = column_type_impl (t, type, 0);
+
+ if (!type.empty ())
+ {
+ m.set (prefix + "-column-type", type);
+ return;
+ }
+
+ // We do not support nested containers so skip that test.
+ //
+
+ // If it is none of the above then we have an error.
+ //
+ string fq_type (t.fq_anonymous () ? "<anonymous>" : t.fq_name ());
+
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " error: unable to map C++ type '" << fq_type << "' used in "
+ << "data member '" << m.name () << "' to a database type" << endl;
+
+ os << m.file () << ":" << m.line () << ":" << m.column () << ":"
+ << " info: use '#pragma db " << prefix << "_type' to specify the "
+ << "database type" << endl;
throw generation_failed ();
}
+
+ bool
+ process_container (semantics::data_member& m)
+ {
+ // @@ tmp
+ //
+ if (container_traits_ == 0)
+ return false;
+
+ // The overall idea is as follows: try to instantiate the container
+ // traits class template. If we are successeful, then this is a
+ // container type and we can extract the various information from
+ // the instantiation. Otherwise, this is not a container.
+ //
+
+ semantics::type& t (m.type ());
+
+ container_kind_type ck;
+ semantics::type* vt (0);
+ semantics::type* it (0);
+ semantics::type* kt (0);
+
+ if (t.count ("container"))
+ {
+ ck = t.get<container_kind_type> ("container-kind");
+ vt = t.get<semantics::type*> ("tree-value-type");
+
+ if (ck == ck_ordered)
+ it = t.get<semantics::type*> ("tree-index-type");
+
+ if (ck == ck_map || ck == ck_multimap)
+ kt = t.get<semantics::type*> ("tree-key-type");
+ }
+ else
+ {
+ tree args (make_tree_vec (1));
+ TREE_VEC_ELT (args, 0) = t.tree_node ();
+
+ // This step should succeed regardles of whether there is a
+ // container traits specialization for this type.
+ //
+ tree inst (
+ lookup_template_class (
+ container_traits_, args, 0, 0, 0, tf_warning_or_error));
+
+ if (inst == error_mark_node)
+ {
+ // Diagnostics has already been issued by lookup_template_class.
+ //
+ throw generation_failed ();
+ }
+
+ inst = TYPE_MAIN_VARIANT (inst);
+
+ // The instantiation may already be complete if it matches a
+ // (complete) specialization.
+ //
+ if (!COMPLETE_TYPE_P (inst))
+ inst = instantiate_class_template (inst);
+
+ // If we cannot instantiate this type, assume there is no suitable
+ // container traits specialization for it.
+ //
+ if (inst == error_mark_node || !COMPLETE_TYPE_P (inst))
+ return false;
+
+ // @@ This points to the primary template, not the specialization.
+ //
+ tree decl (TYPE_NAME (inst));
+
+ string f (DECL_SOURCE_FILE (decl));
+ size_t l (DECL_SOURCE_LINE (decl));
+ size_t c (DECL_SOURCE_COLUMN (decl));
+
+
+ // Determine the container kind.
+ //
+ try
+ {
+ tree kind (
+ lookup_qualified_name (
+ inst, get_identifier ("kind"), false, false));
+
+ if (kind == error_mark_node || TREE_CODE (kind) != VAR_DECL)
+ throw generation_failed ();
+
+
+ // Instantiate this decalaration so that we can get its value.
+ //
+ if (DECL_TEMPLATE_INSTANTIATION (kind) &&
+ !DECL_TEMPLATE_INSTANTIATED (kind) &&
+ !DECL_EXPLICIT_INSTANTIATION (kind))
+ instantiate_decl (kind, false, false);
+
+ tree init (DECL_INITIAL (kind));
+
+ if (init == error_mark_node || TREE_CODE (init) != INTEGER_CST)
+ throw generation_failed ();
+
+ unsigned long long e;
+
+ {
+ HOST_WIDE_INT hwl (TREE_INT_CST_LOW (init));
+ HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (init));
+
+ unsigned long long l (hwl);
+ unsigned long long h (hwh);
+ unsigned short width (HOST_BITS_PER_WIDE_INT);
+
+ e = (h << width) + l;
+ }
+
+ ck = static_cast<container_kind_type> (e);
+ }
+ catch (generation_failed const&)
+ {
+ os << f << ":" << l << ":" << c << ": error: "
+ << "odb::container_traits specialization does not define the "
+ << "container kind constant" << endl;
+
+ throw;
+ }
+
+ t.set ("container-kind", ck);
+
+ // Get the value type.
+ //
+ try
+ {
+ tree decl (
+ lookup_qualified_name (
+ inst, get_identifier ("value_type"), true, false));
+
+ if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL)
+ throw generation_failed ();
+
+ tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
+
+ vt = &dynamic_cast<semantics::type&> (*unit.find (type));
+ }
+ catch (generation_failed const&)
+ {
+ os << f << ":" << l << ":" << c << ": error: "
+ << "odb::container_traits specialization does not define the "
+ << "value_type type" << endl;
+
+ throw;
+ }
+
+ t.set ("tree-value-type", vt);
+
+
+ // Get the index type for ordered containers.
+ //
+ if (ck == ck_ordered)
+ {
+ try
+ {
+ tree decl (
+ lookup_qualified_name (
+ inst, get_identifier ("index_type"), true, false));
+
+ if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL)
+ throw generation_failed ();
+
+ tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
+
+ it = &dynamic_cast<semantics::type&> (*unit.find (type));
+ }
+ catch (generation_failed const&)
+ {
+ os << f << ":" << l << ":" << c << ": error: "
+ << "odb::container_traits specialization does not define the "
+ << "index_type type" << endl;
+
+ throw;
+ }
+
+ t.set ("tree-index-type", it);
+ }
+
+ // Get the key type for maps.
+ //
+ if (ck == ck_map || ck == ck_multimap)
+ {
+ try
+ {
+ tree decl (
+ lookup_qualified_name (
+ inst, get_identifier ("key_type"), true, false));
+
+ if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL)
+ throw generation_failed ();
+
+ tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
+
+ kt = &dynamic_cast<semantics::type&> (*unit.find (type));
+ }
+ catch (generation_failed const&)
+ {
+ os << f << ":" << l << ":" << c << ": error: "
+ << "odb::container_traits specialization does not define the "
+ << "key_type type" << endl;
+
+ throw;
+ }
+
+ t.set ("tree-key-type", kt);
+ }
+ }
+
+ // Process member data.
+ //
+ process_container_value (*vt, "value", m);
+
+ if (it != 0)
+ process_container_value (*it, "index", m);
+
+ if (kt != 0)
+ process_container_value (*kt, "key", m);
+
+ return true;
+ }
+
+ private:
+ tree container_traits_;
};
struct class_: traversal::class_, context