aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-08-04 13:29:43 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-08-04 13:29:43 +0200
commit14392d7ca625facaf509b354f19ece627b81a4b0 (patch)
treee422c02227501f2e7e29a20f69dcac4b8d82ba40
parentc7a98034ccc3425090dddade05fd09d54d1f940f (diff)
Add support for value wrappers
Wrapper is a class that wraps another type. Examples of wrappers are various smart pointers, holders, etc. A wrapper can be transparent or it can handle the NULL semantics. The new odb::nullable class template is a NULL wrapper that helps to add the NULL semantics to a value type. New test: common/wrapper.
-rw-r--r--odb/context.cxx127
-rw-r--r--odb/header.cxx5
-rw-r--r--odb/odb.cxx5
-rw-r--r--odb/relational/type-processor.cxx218
4 files changed, 336 insertions, 19 deletions
diff --git a/odb/context.cxx b/odb/context.cxx
index 3b684ea..0280c28 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -150,17 +150,60 @@ null (semantics::data_member& m)
{
semantics::type& t (m.type ());
- // By default pointers can be null.
- //
if (object_pointer (t))
- return m.count ("null") ||
- (!m.count ("not-null") &&
- (t.count ("null") || !t.count ("not-null")));
+ {
+ // By default pointers can be null.
+ //
+ if (m.count ("null"))
+ return true;
+
+ if (!m.count ("not-null"))
+ {
+ if (t.count ("null"))
+ return true;
+
+ if (!t.count ("not-null"))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
else
+ {
// Everything else by default is not null.
//
- return m.count ("null") ||
- (!m.count ("not-null") && t.count ("null"));
+ if (m.count ("null"))
+ return true;
+
+ if (!m.count ("not-null"))
+ {
+ if (t.count ("null"))
+ return true;
+
+ if (!t.count ("not-null"))
+ {
+ // Check if this type is a wrapper.
+ //
+ if (t.get<bool> ("wrapper"))
+ {
+ // First see if it is null by default.
+ //
+ if (t.get<bool> ("wrapper-null-handler") &&
+ t.get<bool> ("wrapper-null-default"))
+ return true;
+
+ // Otherwise, check the wrapped type.
+ //
+ if (t.get<semantics::type*> ("wrapper-type")->count ("null"))
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
}
bool context::
@@ -173,17 +216,67 @@ null (semantics::data_member& m, string const& kp)
semantics::type& t (member_type (m, kp));
if (object_pointer (t))
- return m.count (kp + "-null") ||
- (!m.count (kp + "-not-null") &&
- (c.count (kp + "-null") ||
- (!c.count (kp + "-not-null") &&
- (t.count ("null") || !t.count ("not-null")))));
+ {
+ if (m.count (kp + "-null"))
+ return true;
+
+ if (!m.count (kp + "-not-null"))
+ {
+ if (c.count (kp + "-null"))
+ return true;
+
+ if (!c.count (kp + "-not-null"))
+ {
+ if (t.count ("null"))
+ return true;
+
+ if (!t.count ("not-null"))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
else
- return m.count (kp + "-null") ||
- (!m.count (kp + "-not-null") &&
- (c.count (kp + "-null") ||
- (!c.count (kp + "-not-null") &&
- t.count ("null"))));
+ {
+ if (m.count (kp + "-null"))
+ return true;
+
+ if (!m.count (kp + "-not-null"))
+ {
+ if (c.count (kp + "-null"))
+ return true;
+
+ if (!c.count (kp + "-not-null"))
+ {
+ if (t.count ("null"))
+ return true;
+
+ if (!t.count ("not-null"))
+ {
+ // Check if this type is a wrapper.
+ //
+ if (t.get<bool> ("wrapper"))
+ {
+ // First see if it is null by default.
+ //
+ if (t.get<bool> ("wrapper-null-handler") &&
+ t.get<bool> ("wrapper-null-default"))
+ return true;
+
+ // Otherwise, check the wrapped type.
+ //
+ if (t.get<semantics::type*> ("wrapper-type")->count ("null"))
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
}
string context::
diff --git a/odb/header.cxx b/odb/header.cxx
index 62902f6..a17b111 100644
--- a/odb/header.cxx
+++ b/odb/header.cxx
@@ -89,6 +89,7 @@ namespace header
os << "#include <odb/core.hxx>" << endl
<< "#include <odb/traits.hxx>" << endl
<< "#include <odb/callback.hxx>" << endl
+ << "#include <odb/wrapper-traits.hxx>" << endl
<< "#include <odb/pointer-traits.hxx>" << endl;
// In case of a boost TR1 implementation, we cannot distinguish
@@ -99,12 +100,14 @@ namespace header
if (ctx.unit.count ("tr1-pointer-used") &&
ctx.unit.get<bool> ("tr1-pointer-used"))
{
- os << "#include <odb/tr1/pointer-traits.hxx>" << endl;
+ os << "#include <odb/tr1/wrapper-traits.hxx>" << endl
+ << "#include <odb/tr1/pointer-traits.hxx>" << endl;
}
else if (ctx.unit.count ("boost-pointer-used") &&
ctx.unit.get<bool> ("boost-pointer-used"))
{
os << "#ifdef BOOST_TR1_MEMORY_HPP_INCLUDED" << endl
+ << "# include <odb/tr1/wrapper-traits.hxx>" << endl
<< "# include <odb/tr1/pointer-traits.hxx>" << endl
<< "#endif" << endl;
}
diff --git a/odb/odb.cxx b/odb/odb.cxx
index 2a14eb9..a4376b5 100644
--- a/odb/odb.cxx
+++ b/odb/odb.cxx
@@ -746,6 +746,11 @@ main (int argc, char* argv[])
<< "# include <tr1/memory>" << endl
<< "#endif" << endl;
+ // Standard wrapper traits.
+ //
+ os << "#include <odb/wrapper-traits.hxx>" << endl
+ << "#include <odb/tr1/wrapper-traits.hxx>" << endl;
+
// Standard pointer traits.
//
os << "#include <odb/pointer-traits.hxx>" << endl
diff --git a/odb/relational/type-processor.cxx b/odb/relational/type-processor.cxx
index 0f1c1d2..5aa8830 100644
--- a/odb/relational/type-processor.cxx
+++ b/odb/relational/type-processor.cxx
@@ -51,12 +51,26 @@ namespace relational
throw generation_failed ();
}
+ // Find wrapper traits.
+ //
+ wrapper_traits_ = lookup_qualified_name (
+ odb, get_identifier ("wrapper_traits"), true, false);
+
+ if (wrapper_traits_ == error_mark_node ||
+ !DECL_CLASS_TEMPLATE_P (wrapper_traits_))
+ {
+ os << unit.file () << ": error: unable to resolve wrapper_traits "
+ << "in the odb namespace" << endl;
+
+ throw generation_failed ();
+ }
+
// Find pointer traits.
//
pointer_traits_ = lookup_qualified_name (
odb, get_identifier ("pointer_traits"), true, false);
- if (container_traits_ == error_mark_node ||
+ if (pointer_traits_ == error_mark_node ||
!DECL_CLASS_TEMPLATE_P (pointer_traits_))
{
os << unit.file () << ": error: unable to resolve pointer_traits "
@@ -103,6 +117,14 @@ namespace relational
semantics::type& t (m.type ());
+ semantics::type* wt (0);
+ semantics::names* wh (0);
+ if (process_wrapper (t))
+ {
+ wt = t.get<semantics::type*> ("wrapper-type");
+ wh = t.get<semantics::names*> ("wrapper-hint");
+ }
+
// Nothing to do if this is a composite value type.
//
if (comp_value (t))
@@ -138,11 +160,21 @@ namespace relational
if (type.empty () && m.count ("id") && t.count ("id-type"))
type = t.get<string> ("id-type");
+ if (type.empty () && wt != 0 && m.count ("id") &&
+ wt->count ("id-type"))
+ type = wt->get<string> ("id-type");
+
if (type.empty () && t.count ("type"))
type = t.get<string> ("type");
+ if (type.empty () && wt != 0 && wt->count ("type"))
+ type = wt->get<string> ("type");
+
if (type.empty ())
type = database_type (t, m.belongs ().hint (), m.count ("id"));
+
+ if (type.empty () && wt != 0)
+ type = database_type (*wt, wh, m.count ("id"));
}
if (!type.empty ())
@@ -188,6 +220,14 @@ namespace relational
string const& prefix,
bool obj_ptr)
{
+ semantics::type* wt (0);
+ semantics::names* wh (0);
+ if (process_wrapper (t))
+ {
+ wt = t.get<semantics::type*> ("wrapper-type");
+ wh = t.get<semantics::names*> ("wrapper-hint");
+ }
+
if (comp_value (t))
return;
@@ -231,8 +271,14 @@ namespace relational
if (type.empty () && t.count ("type"))
type = t.get<string> ("type");
+ if (type.empty () && wt != 0 && wt->count ("type"))
+ type = wt->get<string> ("type");
+
if (type.empty ())
type = database_type (t, hint, false);
+
+ if (type.empty () && wt != 0)
+ type = database_type (*wt, wh, false);
}
if (!type.empty ())
@@ -821,6 +867,175 @@ namespace relational
return c;
}
+ bool
+ process_wrapper (semantics::type& t)
+ {
+ if (t.count ("wrapper"))
+ return t.get<bool> ("wrapper");
+
+ // Check this type with wrapper_traits.
+ //
+ tree inst (instantiate_template (wrapper_traits_, t.tree_node ()));
+
+ if (inst == 0)
+ {
+ t.set ("wrapper", false);
+ 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));
+
+ // Get the wrapped type.
+ //
+ try
+ {
+ tree decl (
+ lookup_qualified_name (
+ inst, get_identifier ("wrapped_type"), true, false));
+
+ if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL)
+ throw generation_failed ();
+
+ tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
+ semantics::type& wt (
+ dynamic_cast<semantics::type&> (*unit.find (type)));
+
+ // Find the hint.
+ //
+ semantics::names* wh (0);
+
+ for (tree ot (DECL_ORIGINAL_TYPE (decl));
+ ot != 0;
+ ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0)
+ {
+ if ((wh = unit.find_hint (ot)))
+ break;
+
+ decl = TYPE_NAME (ot);
+ }
+
+ t.set ("wrapper-type", &wt);
+ t.set ("wrapper-hint", wh);
+ }
+ catch (generation_failed const&)
+ {
+ os << f << ":" << l << ":" << c << ": error: "
+ << "wrapper_traits specialization does not define the "
+ << "wrapped_type type" << endl;
+
+ throw;
+ }
+
+ // Get the null_handler flag.
+ //
+ bool null_handler (false);
+
+ try
+ {
+ tree nh (
+ lookup_qualified_name (
+ inst, get_identifier ("null_handler"), false, false));
+
+ if (nh == error_mark_node || TREE_CODE (nh) != VAR_DECL)
+ throw generation_failed ();
+
+ // Instantiate this decalaration so that we can get its value.
+ //
+ if (DECL_TEMPLATE_INSTANTIATION (nh) &&
+ !DECL_TEMPLATE_INSTANTIATED (nh) &&
+ !DECL_EXPLICIT_INSTANTIATION (nh))
+ instantiate_decl (nh, false, false);
+
+ tree init (DECL_INITIAL (nh));
+
+ 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;
+ }
+
+ null_handler = static_cast<bool> (e);
+ t.set ("wrapper-null-handler", null_handler);
+ }
+ catch (generation_failed const&)
+ {
+ os << f << ":" << l << ":" << c << ": error: "
+ << "wrapper_traits specialization does not define the "
+ << "null_handler constant" << endl;
+
+ throw;
+ }
+
+ // Get the null_default flag.
+ //
+ if (null_handler)
+ {
+ try
+ {
+ tree nh (
+ lookup_qualified_name (
+ inst, get_identifier ("null_default"), false, false));
+
+ if (nh == error_mark_node || TREE_CODE (nh) != VAR_DECL)
+ throw generation_failed ();
+
+ // Instantiate this decalaration so that we can get its value.
+ //
+ if (DECL_TEMPLATE_INSTANTIATION (nh) &&
+ !DECL_TEMPLATE_INSTANTIATED (nh) &&
+ !DECL_EXPLICIT_INSTANTIATION (nh))
+ instantiate_decl (nh, false, false);
+
+ tree init (DECL_INITIAL (nh));
+
+ 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;
+ }
+
+ t.set ("wrapper-null-default", static_cast<bool> (e));
+ }
+ catch (generation_failed const&)
+ {
+ os << f << ":" << l << ":" << c << ": error: "
+ << "wrapper_traits specialization does not define the "
+ << "null_default constant" << endl;
+
+ throw;
+ }
+ }
+
+ t.set ("wrapper", true);
+ return true;
+ }
+
tree
instantiate_template (tree t, tree arg)
{
@@ -858,6 +1073,7 @@ namespace relational
}
private:
+ tree wrapper_traits_;
tree pointer_traits_;
tree container_traits_;
};