aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-12-09 10:36:15 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-12-09 10:36:15 +0200
commit5adda85ed10d9196f4d68cc4b8fee12f6ba9cfec (patch)
tree8a97d998dd8de5a4c2dbda8a171fabbf54af6c4e
parent5789a4f7c5cee94df29e37fd1c2f7c1d9e883002 (diff)
Add lazy pointer support
Built-in support is provided for raw, auto, and tr1 shared/weak pointers. New test: common/lazy-ptr.
-rw-r--r--odb/context.cxx11
-rw-r--r--odb/context.hxx131
-rw-r--r--odb/mysql/common.cxx4
-rw-r--r--odb/mysql/schema.cxx2
-rw-r--r--odb/mysql/source.cxx87
-rw-r--r--odb/type-processor.cxx169
6 files changed, 302 insertions, 102 deletions
diff --git a/odb/context.cxx b/odb/context.cxx
index ec8dec9..b606734 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -490,19 +490,24 @@ namespace
bool context::
is_a (semantics::data_member& m,
unsigned short f,
- semantics::type&,
+ semantics::type& t,
string const& kp)
{
bool r (false);
if (f & test_pointer)
{
- r = r || object_pointer (m, kp);
+ r = r || object_pointer (t);
}
if (f & test_eager_pointer)
{
- r = r || object_pointer (m, kp);
+ r = r || (object_pointer (t) && !lazy_pointer (t));
+ }
+
+ if (f & test_lazy_pointer)
+ {
+ r = r || (object_pointer (t) && lazy_pointer (t));
}
if (f & test_container)
diff --git a/odb/context.hxx b/odb/context.hxx
index 47375a3..6f5e89e 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -25,6 +25,16 @@ using std::cerr;
class generation_failed {};
+// Keep this enum synchronized with the one in libodb/odb/pointer-traits.hxx.
+//
+enum pointer_kind
+{
+ pk_naked,
+ pk_unique,
+ pk_shared,
+ pk_weak
+};
+
// Keep this enum synchronized with the one in libodb/odb/container-traits.hxx.
//
enum container_kind
@@ -43,6 +53,15 @@ public:
typedef std::string string;
typedef ::options options_type;
+public:
+ static semantics::type&
+ member_type (semantics::data_member& m, string const& key_prefix)
+ {
+ return key_prefix.empty ()
+ ? m.type ()
+ : *m.type ().get<semantics::type*> ("tree-" + key_prefix + "-type");
+ }
+
// Predicates.
//
public:
@@ -78,50 +97,9 @@ public:
}
static semantics::class_*
- object_pointer (semantics::data_member& m,
- string const& key_prefix = string ())
+ object_pointer (semantics::type& t)
{
- using semantics::class_;
-
- return key_prefix.empty ()
- ? m.get<class_*> ("object-pointer", 0)
- : m.get<class_*> (key_prefix + "-object-pointer", 0);
- }
-
- static bool
- null_pointer (semantics::data_member& m)
- {
- return !(m.count ("not-null") || m.type ().count ("not-null"));
- }
-
- static bool
- null_pointer (semantics::data_member& m, string const& key_prefix)
- {
- if (key_prefix.empty ())
- return null_pointer (m);
-
- return !(m.count (key_prefix + "-not-null") ||
- m.type ().count ("not-null") ||
- m.type ().get<semantics::type*> (
- "tree-" + key_prefix +"-type")->count ("not-null"));
- }
-
- static semantics::data_member*
- inverse (semantics::data_member& m, string const& key_prefix = string ())
- {
- using semantics::data_member;
-
- return object_pointer (m, key_prefix)
- ? (key_prefix.empty ()
- ? m.get<data_member*> ("inverse", 0)
- : m.get<data_member*> (key_prefix + "-inverse", 0))
- : 0;
- }
-
- static bool
- unordered (semantics::data_member& m)
- {
- return m.count ("unordered") || m.type ().count ("unordered");
+ return t.get<semantics::class_*> ("element-type", 0);
}
// Database names and types.
@@ -187,6 +165,65 @@ public:
semantics::data_member&
id_member (semantics::class_&);
+ // Object pointer information.
+ //
+public:
+ typedef ::pointer_kind pointer_kind_type;
+
+ static pointer_kind_type
+ pointer_kind (semantics::type& p)
+ {
+ return p.get<pointer_kind_type> ("pointer-kind");
+ }
+
+ static bool
+ lazy_pointer (semantics::type& p)
+ {
+ return p.get<bool> ("pointer-lazy");
+ }
+
+ static bool
+ weak_pointer (semantics::type& p)
+ {
+ return pointer_kind (p) == pk_weak;
+ }
+
+ static bool
+ null_pointer (semantics::data_member& m)
+ {
+ return !(m.count ("not-null") || m.type ().count ("not-null"));
+ }
+
+ static bool
+ null_pointer (semantics::data_member& m, string const& key_prefix)
+ {
+ if (key_prefix.empty ())
+ return null_pointer (m);
+
+ return !(m.count (key_prefix + "-not-null") ||
+ m.type ().count ("not-null") ||
+ member_type (m, key_prefix).count ("not-null"));
+ }
+
+ static semantics::data_member*
+ inverse (semantics::data_member& m)
+ {
+ return object_pointer (m.type ())
+ ? m.get<semantics::data_member*> ("inverse", 0)
+ : 0;
+ }
+
+ static semantics::data_member*
+ inverse (semantics::data_member& m, string const& key_prefix)
+ {
+ if (key_prefix.empty ())
+ return inverse (m);
+
+ return object_pointer (member_type (m, key_prefix))
+ ? m.get<semantics::data_member*> (key_prefix + "-inverse", 0)
+ : 0;
+ }
+
// Container information.
//
public:
@@ -216,10 +253,16 @@ public:
return *c.get<semantics::type*> ("tree-key-type");
}
+ static bool
+ unordered (semantics::data_member& m)
+ {
+ return m.count ("unordered") || m.type ().count ("unordered");
+ }
+
// The 'is a' and 'has a' tests. The has_a test currently does not
// cross the container boundaries.
//
-
+public:
static unsigned short const test_pointer = 0x01;
static unsigned short const test_eager_pointer = 0x02;
static unsigned short const test_lazy_pointer = 0x04;
diff --git a/odb/mysql/common.cxx b/odb/mysql/common.cxx
index 3cec95c..830407d 100644
--- a/odb/mysql/common.cxx
+++ b/odb/mysql/common.cxx
@@ -55,7 +55,7 @@ namespace mysql
{
sql_type const& st (db_type (m, key_prefix_));
- if (semantics::class_* c = object_pointer (m, key_prefix_))
+ if (semantics::class_* c = object_pointer (t))
{
member_info mi (m, id_member (*c).type (), var, fq_type_override_);
mi.st = &st;
@@ -490,7 +490,7 @@ namespace mysql
{
string name (public_name (m));
- if (semantics::class_* c = object_pointer (m))
+ if (semantics::class_* c = object_pointer (m.type ()))
{
// We cannot just typedef the query_type from the referenced
// object for two reasons: (1) it may not be defined yet and
diff --git a/odb/mysql/schema.cxx b/odb/mysql/schema.cxx
index e02dde6..f99cf40 100644
--- a/odb/mysql/schema.cxx
+++ b/odb/mysql/schema.cxx
@@ -40,7 +40,7 @@ namespace mysql
os << " PRIMARY KEY";
using semantics::class_;
- if (class_* c = object_pointer (m, prefix_))
+ if (class_* c = object_pointer (member_type (m, prefix_)))
{
os << " REFERENCES `" << table_name (*c) << "` (`" <<
column_name (id_member (*c)) << "`)";
diff --git a/odb/mysql/source.cxx b/odb/mysql/source.cxx
index e09cbc3..3841208 100644
--- a/odb/mysql/source.cxx
+++ b/odb/mysql/source.cxx
@@ -65,7 +65,7 @@ namespace mysql
//
if (im != 0)
{
- semantics::class_* c (object_pointer (m));
+ semantics::class_* c (object_pointer (m.type ()));
if (container (im->type ()))
{
@@ -140,7 +140,7 @@ namespace mysql
virtual bool
column (semantics::data_member& m, string const& col_name, bool)
{
- semantics::class_* c (object_pointer (m));
+ semantics::class_* c (object_pointer (m.type ()));
if (c == 0)
return true;
@@ -758,7 +758,12 @@ namespace mysql
traits = "composite_value_traits< " + mi.fq_type () + " >";
else
{
- if (semantics::class_* c = object_pointer (mi.m, key_prefix_))
+ // When handling a pointer, mi.t is the id type of the referenced
+ // object.
+ //
+ semantics::type& mt (member_type (mi.m, key_prefix_));
+
+ if (semantics::class_* c = object_pointer (mt))
{
type = "obj_traits::id_type";
image_type = member_image_type_.image_type (mi.m);
@@ -768,15 +773,37 @@ namespace mysql
//
os << "{"
<< "typedef object_traits< " << c->fq_name () <<
- " > obj_traits;"
- << "typedef pointer_traits< " << mi.fq_type () <<
+ " > obj_traits;";
+
+ if (weak_pointer (mt))
+ {
+ os << "typedef pointer_traits< " << mi.fq_type () <<
+ " > wptr_traits;"
+ << "typedef pointer_traits< wptr_traits::" <<
+ "strong_pointer_type > ptr_traits;"
+ << endl
+ << "wptr_traits::strong_pointer_type sp (" <<
+ "wptr_traits::lock (" << member << "));";
+
+ member = "sp";
+ }
+ else
+ os << "typedef pointer_traits< " << mi.fq_type () <<
" > ptr_traits;"
- << endl
- << "bool is_null (ptr_traits::null_ptr (" << member << "));"
+ << endl;
+
+ os << "bool is_null (ptr_traits::null_ptr (" << member << "));"
<< "if (!is_null)"
<< "{"
- << "const " << type << "& id (" << endl
- << "obj_traits::id (ptr_traits::get_ref (" << member << ")));"
+ << "const " << type << "& id (" << endl;
+
+ if (lazy_pointer (mt))
+ os << "ptr_traits::object_id< ptr_traits::element_type > (" <<
+ member << ")";
+ else
+ os << "obj_traits::id (ptr_traits::get_ref (" << member << "))";
+
+ os << ");"
<< endl;
member = "id";
@@ -805,7 +832,10 @@ namespace mysql
{
if (!comp_value (mi.t))
{
- if (object_pointer (mi.m, key_prefix_))
+ // When handling a pointer, mi.t is the id type of the referenced
+ // object.
+ //
+ if (object_pointer (member_type (mi.m, key_prefix_)))
{
os << "}";
@@ -1029,7 +1059,12 @@ namespace mysql
traits = "composite_value_traits< " + mi.fq_type () + " >";
else
{
- if (semantics::class_* c = object_pointer (mi.m, key_prefix_))
+ // When handling a pointer, mi.t is the id type of the referenced
+ // object.
+ //
+ semantics::type& mt (member_type (mi.m, key_prefix_));
+
+ if (semantics::class_* c = object_pointer (mt))
{
type = "obj_traits::id_type";
image_type = member_image_type_.image_type (mi.m);
@@ -1075,19 +1110,31 @@ namespace mysql
virtual void
post (member_info& mi)
{
- if (!comp_value (mi.t) && object_pointer (mi.m, key_prefix_))
+ if (comp_value (mi.t))
+ return;
+
+ // When handling a pointer, mi.t is the id type of the referenced
+ // object.
+ //
+ semantics::type& mt (member_type (mi.m, key_prefix_));
+
+ if (object_pointer (mt))
{
member = member_override_.empty ()
? "o." + mi.m.name ()
: member_override_;
- os << "// If a compiler error points to the line below, then" << endl
- << "// it most likely means that a pointer used in a member" << endl
- << "// cannot be initialized from an object pointer." << endl
- << "//" << endl
- << member << " = ptr_traits::pointer_type (" << endl
- << "db.load< ptr_traits::element_type > (id));"
- << "}"
+ if (lazy_pointer (mt))
+ os << member << " = ptr_traits::pointer_type (db, id);";
+ else
+ os << "// If a compiler error points to the line below, then" << endl
+ << "// it most likely means that a pointer used in a member" << endl
+ << "// cannot be initialized from an object pointer." << endl
+ << "//" << endl
+ << member << " = ptr_traits::pointer_type (" << endl
+ << "db.load< ptr_traits::element_type > (id));";
+
+ os << "}"
<< "}";
}
}
@@ -1316,7 +1363,7 @@ namespace mysql
if (inverse)
{
- semantics::class_* c (object_pointer (m, "value"));
+ semantics::class_* c (object_pointer (vt));
string inv_table; // Other table name.
string inv_id; // Other id column.
diff --git a/odb/type-processor.cxx b/odb/type-processor.cxx
index 381a4e4..e225d85 100644
--- a/odb/type-processor.cxx
+++ b/odb/type-processor.cxx
@@ -270,7 +270,6 @@ namespace
size_t l (DECL_SOURCE_LINE (decl));
size_t c (DECL_SOURCE_COLUMN (decl));
-
// Determine the container kind.
//
try
@@ -313,7 +312,7 @@ namespace
catch (generation_failed const&)
{
os << f << ":" << l << ":" << c << ": error: "
- << "odb::container_traits specialization does not define the "
+ << "container_traits specialization does not define the "
<< "container kind constant" << endl;
throw;
@@ -339,7 +338,7 @@ namespace
catch (generation_failed const&)
{
os << f << ":" << l << ":" << c << ": error: "
- << "odb::container_traits specialization does not define the "
+ << "container_traits specialization does not define the "
<< "value_type type" << endl;
throw;
@@ -368,7 +367,7 @@ namespace
catch (generation_failed const&)
{
os << f << ":" << l << ":" << c << ": error: "
- << "odb::container_traits specialization does not define the "
+ << "container_traits specialization does not define the "
<< "index_type type" << endl;
throw;
@@ -397,7 +396,7 @@ namespace
catch (generation_failed const&)
{
os << f << ":" << l << ":" << c << ": error: "
- << "odb::container_traits specialization does not define the "
+ << "container_traits specialization does not define the "
<< "key_type type" << endl;
throw;
@@ -439,39 +438,145 @@ namespace
using semantics::class_;
using semantics::data_member;
- tree inst (instantiate_template (pointer_traits_, t.tree_node ()));
-
- if (inst == 0)
- return 0;
+ class_* c (0);
- // Get the element type.
- //
- tree tn (0);
- try
+ if (t.count ("element-type"))
+ c = t.get<class_*> ("element-type");
+ else
{
- tree decl (
- lookup_qualified_name (
- inst, get_identifier ("element_type"), true, false));
+ tree inst (instantiate_template (pointer_traits_, t.tree_node ()));
- if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL)
- throw generation_failed ();
+ if (inst == 0)
+ return 0;
- tn = TYPE_MAIN_VARIANT (TREE_TYPE (decl));
- }
- catch (generation_failed const&)
- {
- os << m.file () << ":" << m.line () << ":" << m.column () << ": "
- << "error: odb::pointer_traits specialization does not define "
- << "the element_type type" << endl;
- throw;
- }
+ // @@ This points to the primary template, not the specialization.
+ //
+ tree decl (TYPE_NAME (inst));
- class_* c (dynamic_cast<class_*> (unit.find (tn)));
+ string fl (DECL_SOURCE_FILE (decl));
+ size_t ln (DECL_SOURCE_LINE (decl));
+ size_t cl (DECL_SOURCE_COLUMN (decl));
- if (c == 0 || !c->count ("object"))
- return 0;
+ // Get the element type.
+ //
+ tree tn (0);
+ try
+ {
+ tree decl (
+ lookup_qualified_name (
+ inst, get_identifier ("element_type"), true, false));
+
+ if (decl == error_mark_node || TREE_CODE (decl) != TYPE_DECL)
+ throw generation_failed ();
+
+ tn = TYPE_MAIN_VARIANT (TREE_TYPE (decl));
+ }
+ catch (generation_failed const&)
+ {
+ os << fl << ":" << ln << ":" << cl << ": error: pointer_traits "
+ << "specialization does not define the 'element_type' type"
+ << endl;
+ throw;
+ }
+
+ c = dynamic_cast<class_*> (unit.find (tn));
+
+ if (c == 0 || !c->count ("object"))
+ return 0;
+
+ t.set ("element-type", c);
+
+ // Determine the pointer 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;
+ }
+
+ pointer_kind_type pk = static_cast<pointer_kind_type> (e);
+ t.set ("pointer-kind", pk);
+ }
+ catch (generation_failed const&)
+ {
+ os << fl << ":" << ln << ":" << cl << ": error: pointer_traits "
+ << "specialization does not define the 'kind' constant" << endl;
+ throw;
+ }
+
+ // Get the lazy flag.
+ //
+ try
+ {
+ tree lazy (
+ lookup_qualified_name (
+ inst, get_identifier ("lazy"), false, false));
+
+ if (lazy == error_mark_node || TREE_CODE (lazy) != VAR_DECL)
+ throw generation_failed ();
+
+ // Instantiate this decalaration so that we can get its value.
+ //
+ if (DECL_TEMPLATE_INSTANTIATION (lazy) &&
+ !DECL_TEMPLATE_INSTANTIATED (lazy) &&
+ !DECL_EXPLICIT_INSTANTIATION (lazy))
+ instantiate_decl (lazy, false, false);
+
+ tree init (DECL_INITIAL (lazy));
+
+ 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));
- m.set (kp + (kp.empty () ? "": "-") + "object-pointer", c);
+ unsigned long long l (hwl);
+ unsigned long long h (hwh);
+ unsigned short width (HOST_BITS_PER_WIDE_INT);
+
+ e = (h << width) + l;
+ }
+
+ t.set ("pointer-lazy", static_cast<bool> (e));
+ }
+ catch (generation_failed const&)
+ {
+ os << fl << ":" << ln << ":" << cl << ": error: pointer_traits "
+ << "specialization does not define the 'kind' constant" << endl;
+ throw;
+ }
+ }
if (m.count ("not-null") && !kp.empty ())
{
@@ -487,7 +592,7 @@ namespace
string name (m.get<string> ("inverse"));
tree decl (
lookup_qualified_name (
- tn, get_identifier (name.c_str ()), false, false));
+ c->tree_node (), get_identifier (name.c_str ()), false, false));
if (decl == error_mark_node || TREE_CODE (decl) != FIELD_DECL)
{