From 658a2f07b47ed80bd3ca35edd7380493c326daa3 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 27 Oct 2011 15:16:49 +0200 Subject: Add support for persistent classes without object ids New pragma id (object). New test: common/no-id. --- odb/cache-traits.hxx | 127 ++++++++++++++++++++++-- odb/database.txx | 20 ++-- odb/object-result.hxx | 262 +++++++++++++++++++++++++++++++++++++++++++------- odb/object-result.txx | 41 ++++++-- odb/result.hxx | 5 - odb/view-result.hxx | 10 +- odb/view-result.txx | 10 +- 7 files changed, 398 insertions(+), 77 deletions(-) diff --git a/odb/cache-traits.hxx b/odb/cache-traits.hxx index e4b2495..067812b 100644 --- a/odb/cache-traits.hxx +++ b/odb/cache-traits.hxx @@ -17,8 +17,19 @@ namespace odb { // Caching traits for objects passed by pointer. // - template ::kind> - struct pointer_cache_traits + template + struct pointer_cache_traits_impl; + + template + struct pointer_cache_traits: pointer_cache_traits_impl< + P, + typename object_traits::element_type>::id_type, + pointer_traits

::kind> + { + }; + + template + struct pointer_cache_traits_impl { typedef P pointer_type; typedef odb::pointer_traits pointer_traits; @@ -45,20 +56,36 @@ namespace odb position_type pos_; }; + // We need the insert() overload with explicit id to handle self- + // references. In such cases the object is not yet loaded and the + // id member does not contain the correct id. + // // Qualify the database type to resolve a phony ambiguity in VC 10. // static position_type insert (odb::database& db, const id_type& id, const pointer_type& p) { if (session::has_current ()) + { // Cast away constness if any. // return session::current ().insert ( db, id, pointer_traits::cast (p)); + } else return position_type (); } + static position_type + insert (odb::database& db, const pointer_type& p) + { + const id_type& id ( + object_traits::id ( + pointer_traits::get_ref (p))); + + return insert (db, id, p); + } + static pointer_type find (odb::database& db, const id_type& id) { @@ -83,10 +110,23 @@ namespace odb } }; + template + struct pointer_cache_traits_impl + { + typedef P pointer_type; + struct position_type {}; + + static position_type + insert (odb::database&, const pointer_type&) + { + return position_type (); + } + }; + // Unique pointers don't work with the object cache. // - template - struct pointer_cache_traits + template + struct pointer_cache_traits_impl { typedef P pointer_type; typedef typename pointer_traits::element_type element_type; @@ -110,6 +150,12 @@ namespace odb return position_type (); } + static position_type + insert (odb::database&, const pointer_type&) + { + return position_type (); + } + static pointer_type find (odb::database&, const id_type&) { return pointer_type (); } @@ -120,13 +166,35 @@ namespace odb erase (const position_type&) {} }; + template + struct pointer_cache_traits_impl + { + typedef P pointer_type; + struct position_type {}; + + static position_type + insert (odb::database&, const pointer_type&) + { + return position_type (); + } + }; + // Caching traits for objects passed by reference. Only if the object // pointer kind is raw do we add the object to the session. // - template ::pointer_type>::kind> - struct reference_cache_traits + template + struct reference_cache_traits_impl; + + template + struct reference_cache_traits: reference_cache_traits_impl< + T, + typename object_traits::id_type, + pointer_traits::pointer_type>::kind> + { + }; + + template + struct reference_cache_traits_impl { typedef T element_type; typedef typename object_traits::pointer_type pointer_type; @@ -152,10 +220,29 @@ namespace odb { return position_type (); } + + static position_type + insert (odb::database&, element_type&) + { + return position_type (); + } }; - template - struct reference_cache_traits + template + struct reference_cache_traits_impl + { + typedef T element_type; + struct position_type {}; + + static position_type + insert (odb::database&, element_type&) + { + return position_type (); + } + }; + + template + struct reference_cache_traits_impl { typedef T element_type; typedef typename object_traits::pointer_type pointer_type; @@ -175,6 +262,26 @@ namespace odb pointer_type p (&obj); return pointer_cache_traits::insert (db, id, p); } + + static position_type + insert (odb::database& db, element_type& obj) + { + pointer_type p (&obj); + return pointer_cache_traits::insert (db, p); + } + }; + + template + struct reference_cache_traits_impl + { + typedef T element_type; + struct position_type {}; + + static position_type + insert (odb::database&, element_type&) + { + return position_type (); + } }; } diff --git a/odb/database.txx b/odb/database.txx index c70697d..42643aa 100644 --- a/odb/database.txx +++ b/odb/database.txx @@ -28,9 +28,9 @@ namespace odb object_traits::persist (*this, obj); object_traits::callback (*this, obj, callback_event::post_persist); - const typename object_traits::id_type& id (object_traits::id (obj)); - reference_cache_traits::insert (*this, id, obj); - return id; + reference_cache_traits::insert (*this, obj); + + return object_traits::id (obj); } template @@ -54,9 +54,9 @@ namespace odb object_traits::persist (*this, obj); object_traits::callback (*this, obj, callback_event::post_persist); - const typename object_traits::id_type& id (object_traits::id (obj)); - pointer_cache_traits::insert (*this, id, pobj); - return id; + pointer_cache_traits::insert (*this, pobj); + + return object_traits::id (obj); } template @@ -139,8 +139,8 @@ namespace odb object_traits::callback (*this, obj,callback_event::pre_update); - // Compiler error pointing here? Perhaps the object is readonly and - // therefore does not provide the update() function? + // Compiler error pointing here? Perhaps the object is readonly or + // doesn't have an object id? Such objects cannot be updated. // object_traits::update (*this, obj); @@ -166,8 +166,8 @@ namespace odb object_traits::callback (*this, obj, callback_event::pre_update); - // Compiler error pointing here? Perhaps the object is readonly and - // therefore does not provide the update() function? + // Compiler error pointing here? Perhaps the object is readonly or + // doesn't have an object id? Such objects cannot be updated. // object_traits::update (*this, obj); diff --git a/odb/object-result.hxx b/odb/object-result.hxx index 4c25962..e4d28ee 100644 --- a/odb/object-result.hxx +++ b/odb/object-result.hxx @@ -20,30 +20,158 @@ namespace odb { template - class result_impl: public details::shared_base + class object_result_impl; + + template + class object_result_impl_no_id; + + template + class object_result_iterator; + + template ::id_type> + struct object_result_impl_selector + { + typedef object_result_impl type; + }; + + template + struct object_result_impl_selector + { + typedef object_result_impl_no_id type; + }; + + // Implementation for objects with object id. + // + template + class object_result_impl: public details::shared_base { public: virtual - ~result_impl (); + ~object_result_impl (); protected: + typedef odb::database database_type; + + // In result_impl, T is always non-const and the same as object_type. + // + typedef T object_type; + typedef odb::object_traits object_traits; + typedef typename object_traits::id_type id_type; + + typedef typename object_traits::pointer_type pointer_type; + typedef odb::pointer_traits pointer_traits; + friend class result; friend class result; friend class result_iterator; friend class result_iterator; + friend class object_result_iterator; + friend class object_result_iterator; + + protected: + object_result_impl (database_type& db) + : begin_ (true), end_ (false), db_ (db), current_ () + { + } + + database_type& + database () const + { + return db_; + } + + // To make this work with all kinds of pointers (raw, std::auto_ptr, + // shared), we need to make sure we don't make any copies of the + // pointer on the return path. + // + pointer_type& + current (); + + void + release () + { + current_ = pointer_type (); + guard_.release (); + } + + void + begin () + { + if (begin_) + { + next (); + begin_ = false; + } + } + + bool + end () const + { + return end_; + } + + protected: + virtual void + load (object_type&) = 0; + + virtual id_type + load_id () = 0; + + virtual void + next () = 0; + + virtual void + cache () = 0; + + virtual std::size_t + size () = 0; + + protected: + void + current (pointer_type p) + { + current_ = p; + guard_.reset (current_); + } + + bool begin_; + bool end_; + + private: + database_type& db_; + pointer_type current_; + typename pointer_traits::guard guard_; + }; + + // Implementation for objects without object id. + // + template + class object_result_impl_no_id: public details::shared_base + { + public: + virtual + ~object_result_impl_no_id (); + protected: typedef odb::database database_type; // In result_impl, T is always non-const and the same as object_type. // typedef T object_type; typedef odb::object_traits object_traits; - typedef typename object_traits::id_type id_type; typedef typename object_traits::pointer_type pointer_type; typedef odb::pointer_traits pointer_traits; - result_impl (database_type& db) + friend class result; + friend class result; + friend class result_iterator; + friend class result_iterator; + friend class object_result_iterator; + friend class object_result_iterator; + + protected: + object_result_impl_no_id (database_type& db) : begin_ (true), end_ (false), db_ (db), current_ () { } @@ -88,9 +216,6 @@ namespace odb virtual void load (object_type&) = 0; - virtual id_type - load_id () = 0; - virtual void next () = 0; @@ -117,8 +242,85 @@ namespace odb typename pointer_traits::guard guard_; }; + // + // result_iterator + // + + template + class object_result_iterator + { + public: + // T can be const T while object_type is always non-const. + // + typedef typename object_traits::object_type object_type; + typedef typename object_traits::id_type id_type; + + typedef object_result_impl result_impl_type; + + public: + object_result_iterator (result_impl_type* res) + : res_ (res) + { + } + + public: + typename object_traits::pointer_type + load () + { + typename object_traits::pointer_type r (res_->current ()); + res_->release (); + return r; + } + + void + load (object_type&); + + protected: + result_impl_type* res_; + }; + template - class result_iterator + class object_result_iterator + { + public: + // T can be const T while object_type is always non-const. + // + typedef typename object_traits::object_type object_type; + + typedef object_result_impl_no_id result_impl_type; + + public: + object_result_iterator (result_impl_type* res) + : res_ (res) + { + } + + public: + typename object_traits::pointer_type + load () + { + typename object_traits::pointer_type r (res_->current ()); + res_->release (); + return r; + } + + void + load (object_type& obj) + { + // Objects without ids are not stored in session cache. + // + if (!res_->end ()) + res_->load (obj); + } + + protected: + result_impl_type* res_; + }; + + template + class result_iterator: public object_result_iterator< + T, + typename object_traits::id_type> { public: typedef T value_type; @@ -129,15 +331,14 @@ namespace odb // T can be const T while object_type is always non-const. // - typedef typename object_traits::object_type object_type; - typedef typename object_traits::id_type id_type; - - typedef result_impl result_impl_type; + typedef + object_result_iterator::id_type> + base_type; public: explicit - result_iterator (result_impl_type* res = 0) - : res_ (res) + result_iterator (typename base_type::result_impl_type* res = 0) + : base_type (res) { } @@ -147,7 +348,7 @@ namespace odb reference operator* () const { - return pointer_traits::get_ref (res_->current ()); + return pointer_traits::get_ref (this->res_->current ()); } // Our value_type is already a pointer so return it instead of @@ -157,13 +358,13 @@ namespace odb pointer operator-> () const { - return pointer_traits::get_ptr (res_->current ()); + return pointer_traits::get_ptr (this->res_->current ()); } result_iterator& operator++ () { - res_->next (); + this->res_->next (); return *this; } @@ -172,27 +373,16 @@ namespace odb { // All non-end iterators for a result object move together. // - res_->next (); + this->res_->next (); return *this; } public: - typename object_traits::pointer_type - load () - { - typename object_traits::pointer_type r (res_->current ()); - res_->release (); - return r; - } - - void - load (object_type&); - - public: bool equal (result_iterator j) const { - return (res_ ? res_->end () : true) == (j.res_ ? j.res_->end () : true); + return (this->res_ ? this->res_->end () : true) == + (j.res_ ? j.res_->end () : true); } private: @@ -200,10 +390,10 @@ namespace odb // result_impl. // typedef - odb::pointer_traits::pointer_type> + odb::pointer_traits< + typename object_traits< + typename base_type::object_type>::pointer_type> pointer_traits; - - result_impl_type* res_; }; // @@ -217,7 +407,9 @@ namespace odb // T can be const T while object_type is always non-const. // typedef typename object_traits::object_type object_type; - typedef result_impl result_impl_type; + typedef + typename object_result_impl_selector::type + result_impl_type; }; } diff --git a/odb/object-result.txx b/odb/object-result.txx index c19e482..843ec59 100644 --- a/odb/object-result.txx +++ b/odb/object-result.txx @@ -9,18 +9,18 @@ namespace odb { // - // result_impl + // object_result_impl // template - result_impl:: - ~result_impl () + object_result_impl:: + ~object_result_impl () { } template - typename result_impl::pointer_type& - result_impl:: + typename object_result_impl::pointer_type& + object_result_impl:: current () { if (pointer_traits::null_ptr (current_) && !end_) @@ -62,11 +62,38 @@ namespace odb } // - // result_iterator + // object_result_impl_no_id // + template + object_result_impl_no_id:: + ~object_result_impl_no_id () + { + } template - void result_iterator:: + typename object_result_impl_no_id::pointer_type& + object_result_impl_no_id:: + current () + { + if (pointer_traits::null_ptr (current_) && !end_) + { + // Objects without ids are not stored in session cache. + // + pointer_type p (object_traits::create ()); + object_type& obj (pointer_traits::get_ref (p)); + current (p); + load (obj); + } + + return current_; + } + + // + // object_result_iterator + // + + template + void object_result_iterator:: load (object_type& obj) { if (res_->end ()) diff --git a/odb/result.hxx b/odb/result.hxx index 1d4a199..91c1a39 100644 --- a/odb/result.hxx +++ b/odb/result.hxx @@ -18,9 +18,6 @@ namespace odb template class result_base; - template - class result_impl; - template ::kind> class result_iterator; @@ -59,8 +56,6 @@ namespace odb typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - // T can be const T while result_impl's argument is always non-const. - // typedef typename base::result_impl_type result_impl_type; public: diff --git a/odb/view-result.hxx b/odb/view-result.hxx index a3cebf8..3f5a043 100644 --- a/odb/view-result.hxx +++ b/odb/view-result.hxx @@ -20,11 +20,11 @@ namespace odb { template - class result_impl: public details::shared_base + class view_result_impl: public details::shared_base { public: virtual - ~result_impl (); + ~view_result_impl (); protected: friend class result; @@ -42,7 +42,7 @@ namespace odb typedef typename view_traits::pointer_type pointer_type; typedef odb::pointer_traits pointer_traits; - result_impl (database_type& db) + view_result_impl (database_type& db) : begin_ (true), end_ (false), db_ (db), current_ () { } @@ -127,7 +127,7 @@ namespace odb // typedef typename view_traits::view_type view_type; - typedef result_impl result_impl_type; + typedef view_result_impl result_impl_type; public: explicit @@ -212,7 +212,7 @@ namespace odb // T can be const T while view_type is always non-const. // typedef typename view_traits::view_type view_type; - typedef result_impl result_impl_type; + typedef view_result_impl result_impl_type; }; } diff --git a/odb/view-result.txx b/odb/view-result.txx index 95f34e0..afc65b4 100644 --- a/odb/view-result.txx +++ b/odb/view-result.txx @@ -6,18 +6,18 @@ namespace odb { // - // result_impl + // view_result_impl // template - result_impl:: - ~result_impl () + view_result_impl:: + ~view_result_impl () { } template - typename result_impl::pointer_type& - result_impl:: + typename view_result_impl::pointer_type& + view_result_impl:: current () { if (pointer_traits::null_ptr (current_) && !end_) -- cgit v1.1