From 14392d7ca625facaf509b354f19ece627b81a4b0 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 4 Aug 2011 13:29:43 +0200 Subject: 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. --- odb/context.cxx | 127 +++++++++++++++++++--- odb/header.cxx | 5 +- odb/odb.cxx | 5 + odb/relational/type-processor.cxx | 218 +++++++++++++++++++++++++++++++++++++- 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 ("wrapper")) + { + // First see if it is null by default. + // + if (t.get ("wrapper-null-handler") && + t.get ("wrapper-null-default")) + return true; + + // Otherwise, check the wrapped type. + // + if (t.get ("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 ("wrapper")) + { + // First see if it is null by default. + // + if (t.get ("wrapper-null-handler") && + t.get ("wrapper-null-default")) + return true; + + // Otherwise, check the wrapped type. + // + if (t.get ("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 " << endl << "#include " << endl << "#include " << endl + << "#include " << endl << "#include " << 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 ("tr1-pointer-used")) { - os << "#include " << endl; + os << "#include " << endl + << "#include " << endl; } else if (ctx.unit.count ("boost-pointer-used") && ctx.unit.get ("boost-pointer-used")) { os << "#ifdef BOOST_TR1_MEMORY_HPP_INCLUDED" << endl + << "# include " << endl << "# include " << 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 " << endl << "#endif" << endl; + // Standard wrapper traits. + // + os << "#include " << endl + << "#include " << endl; + // Standard pointer traits. // os << "#include " << 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 ("wrapper-type"); + wh = t.get ("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 ("id-type"); + if (type.empty () && wt != 0 && m.count ("id") && + wt->count ("id-type")) + type = wt->get ("id-type"); + if (type.empty () && t.count ("type")) type = t.get ("type"); + if (type.empty () && wt != 0 && wt->count ("type")) + type = wt->get ("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 ("wrapper-type"); + wh = t.get ("wrapper-hint"); + } + if (comp_value (t)) return; @@ -231,8 +271,14 @@ namespace relational if (type.empty () && t.count ("type")) type = t.get ("type"); + if (type.empty () && wt != 0 && wt->count ("type")) + type = wt->get ("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 ("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 (*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 (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 (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_; }; -- cgit v1.1