From a28444da4ca6adb016f719e032174ccb54e1692e Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 21 Sep 2011 13:00:33 +0200 Subject: Rework const object handling Now objects are always loaded as non-const and the object cache in session treats all objects as non-const. --- odb/cache-traits.hxx | 20 +++++++++++----- odb/database.hxx | 6 ++--- odb/database.ixx | 36 +++++++--------------------- odb/database.txx | 57 ++++++++++++++++---------------------------- odb/exceptions.cxx | 6 ----- odb/exceptions.hxx | 7 ------ odb/object-result.hxx | 59 +++++++++++++++++++++++++++++++++++++++------- odb/object-result.txx | 21 +++++++---------- odb/pointer-traits.hxx | 15 ++++++++++++ odb/session.hxx | 30 +++-------------------- odb/session.ixx | 47 ------------------------------------ odb/session.txx | 49 ++++++++++++-------------------------- odb/tr1/pointer-traits.hxx | 11 +++++++++ odb/traits.hxx | 20 ++++++++++++++++ odb/view-result.hxx | 57 +++++++++++++++++++++++++++++++++++++------- odb/view-result.txx | 2 -- 16 files changed, 216 insertions(+), 227 deletions(-) diff --git a/odb/cache-traits.hxx b/odb/cache-traits.hxx index 596ee35..e4b2495 100644 --- a/odb/cache-traits.hxx +++ b/odb/cache-traits.hxx @@ -21,9 +21,14 @@ namespace odb struct pointer_cache_traits { typedef P pointer_type; - typedef typename pointer_traits::element_type element_type; + typedef odb::pointer_traits pointer_traits; + typedef typename pointer_traits::element_type element_type; + + // element_type can be const while object_type is always non-const. + // + typedef typename object_traits::object_type object_type; typedef typename object_traits::id_type id_type; - typedef session::object_position position_type; + typedef session::object_position position_type; struct insert_guard { @@ -46,7 +51,10 @@ namespace odb insert (odb::database& db, const id_type& id, const pointer_type& p) { if (session::has_current ()) - return session::current ().insert (db, id, p); + // Cast away constness if any. + // + return session::current ().insert ( + db, id, pointer_traits::cast (p)); else return position_type (); } @@ -55,7 +63,7 @@ namespace odb find (odb::database& db, const id_type& id) { if (session::has_current ()) - return session::current ().find (db, id); + return session::current ().find (db, id); else return pointer_type (); } @@ -64,14 +72,14 @@ namespace odb erase (odb::database& db, const id_type& id) { if (session::has_current ()) - session::current ().erase (db, id); + session::current ().erase (db, id); } static void erase (const position_type& p) { if (p.map_ != 0) - session::current ().erase (p); + session::current ().erase (p); } }; diff --git a/odb/database.hxx b/odb/database.hxx index f24e0fa..7e29ddf 100644 --- a/odb/database.hxx +++ b/odb/database.hxx @@ -19,7 +19,6 @@ #include #include -#include namespace odb { @@ -142,7 +141,7 @@ namespace odb template unsigned long long - erase_query (const odb::query::object_type>&); + erase_query (const odb::query&); // Query API. // @@ -160,8 +159,7 @@ namespace odb template result - query (const odb::query::result>&, - bool cache = true); + query (const odb::query&, bool cache = true); // Native database statement execution. // diff --git a/odb/database.ixx b/odb/database.ixx index c4b3c77..7bc6520 100644 --- a/odb/database.ixx +++ b/odb/database.ixx @@ -167,66 +167,48 @@ namespace odb inline unsigned long long database:: erase_query () { - // T can be const T while object_type will always be T. + // T is always object_type. // - typedef typename odb::object_traits::object_type object_type; - - return erase_query (odb::query ()); + return erase_query (odb::query ()); } template inline unsigned long long database:: erase_query (const char* q) { - // T can be const T while object_type will always be T. + // T is always object_type. // - typedef typename odb::object_traits::object_type object_type; - - return erase_query (odb::query (q)); + return erase_query (odb::query (q)); } template inline unsigned long long database:: erase_query (const std::string& q) { - // T can be const T while object_type will always be T. + // T is always object_type. // - typedef typename odb::object_traits::object_type object_type; - - return erase_query (odb::query (q)); + return erase_query (odb::query (q)); } template inline result database:: query (bool cache) { - // T can be const T. - // - typedef typename details::meta::remove_const::result type; - - return query (odb::query (), cache); + return query (odb::query (), cache); } template inline result database:: query (const char* q, bool cache) { - // T can be const T. - // - typedef typename details::meta::remove_const::result type; - - return query (odb::query (q), cache); + return query (odb::query (q), cache); } template inline result database:: query (const std::string& q, bool cache) { - // T can be const T. - // - typedef typename details::meta::remove_const::result type; - - return query (odb::query (q), cache); + return query (odb::query (q), cache); } inline unsigned long long database:: diff --git a/odb/database.txx b/odb/database.txx index 8117997..82afd64 100644 --- a/odb/database.txx +++ b/odb/database.txx @@ -63,6 +63,8 @@ namespace odb typename object_traits::pointer_type database:: load (const typename object_traits::id_type& id) { + // T is always object_type. + // typedef typename object_traits::pointer_type pointer_type; typedef odb::pointer_traits pointer_traits; @@ -86,12 +88,10 @@ namespace odb typename object_traits::pointer_type database:: find (const typename object_traits::id_type& id) { - // T can be const T while object_type will always be T. + // T is always object_type. // - typedef typename odb::object_traits::object_type object_type; - typedef odb::object_traits object_traits; - - typedef typename odb::object_traits::pointer_type pointer_type; + typedef odb::object_traits object_traits; + typedef typename object_traits::pointer_type pointer_type; typedef odb::pointer_traits pointer_traits; // First check the session. @@ -117,15 +117,12 @@ namespace odb bool database:: find (const typename object_traits::id_type& id, T& obj) { - // T can be const T while object_type will always be T. + // T is always object_type. // - typedef typename odb::object_traits::object_type object_type; - typedef odb::object_traits object_traits; - if (!transaction::has_current ()) throw not_in_transaction (); - return object_traits::find (*this, id, obj); + return object_traits::find (*this, id, obj); } template @@ -171,12 +168,10 @@ namespace odb void database:: erase (const typename object_traits::id_type& id) { - // T can be const T while object_type will always be T. + // T is always object_type. // - typedef typename odb::object_traits::object_type object_type; - typedef odb::object_traits object_traits; - - typedef typename odb::object_traits::pointer_type pointer_type; + typedef odb::object_traits object_traits; + typedef typename object_traits::pointer_type pointer_type; if (!transaction::has_current ()) throw not_in_transaction (); @@ -193,8 +188,7 @@ namespace odb // typedef typename odb::object_traits::object_type object_type; typedef odb::object_traits object_traits; - - typedef typename odb::object_traits::pointer_type pointer_type; + typedef typename object_traits::pointer_type pointer_type; if (!transaction::has_current ()) throw not_in_transaction (); @@ -209,53 +203,42 @@ namespace odb template unsigned long long database:: - erase_query (const odb::query::object_type>& q) + erase_query (const odb::query& q) { - // T can be const T while object_type will always be T. + // T is always object_type. // - typedef typename odb::object_traits::object_type object_type; - typedef odb::object_traits object_traits; - if (!transaction::has_current ()) throw not_in_transaction (); - return object_traits::erase_query (*this, q); + return object_traits::erase_query (*this, q); } template struct database::query_ { - // T can be const T while object_type will always be T. - // - typedef typename odb::object_traits::object_type object_type; - typedef odb::object_traits object_traits; - static result - call (database& db, const odb::query& q) + call (database& db, const odb::query& q) { - return object_traits::template query (db, q); + return object_traits::query (db, q); } }; template struct database::query_ { - // Const views are not supported. - // - typedef odb::view_traits view_traits; - static result call (database& db, const odb::query& q) { - return view_traits::query (db, q); + return view_traits::query (db, q); } }; template result database:: - query (const odb::query::result>& q, - bool cache) + query (const odb::query& q, bool cache) { + // T is always object_type. + // if (!transaction::has_current ()) throw not_in_transaction (); diff --git a/odb/exceptions.cxx b/odb/exceptions.cxx index b79f189..bc4b509 100644 --- a/odb/exceptions.cxx +++ b/odb/exceptions.cxx @@ -47,12 +47,6 @@ namespace odb return "session not in effect in this thread"; } - const char* const_object:: - what () const throw () - { - return "object cached in session is const"; - } - const char* deadlock:: what () const throw () { diff --git a/odb/exceptions.hxx b/odb/exceptions.hxx index b1e4711..698baee 100644 --- a/odb/exceptions.hxx +++ b/odb/exceptions.hxx @@ -56,12 +56,6 @@ namespace odb what () const throw (); }; - struct LIBODB_EXPORT const_object: exception - { - virtual const char* - what () const throw (); - }; - // Database operations exceptions. // struct LIBODB_EXPORT recoverable: exception @@ -139,7 +133,6 @@ namespace odb using odb::already_in_session; using odb::not_in_session; - using odb::const_object; using odb::recoverable; using odb::deadlock; diff --git a/odb/object-result.hxx b/odb/object-result.hxx index fcee125..235b682 100644 --- a/odb/object-result.hxx +++ b/odb/object-result.hxx @@ -28,16 +28,20 @@ namespace odb protected: friend class result; + friend class result; friend class result_iterator; + friend class result_iterator; typedef odb::database database_type; - typedef typename odb::object_traits::pointer_type pointer_type; - typedef odb::pointer_traits pointer_traits; - - typedef typename odb::object_traits::object_type object_type; - typedef typename odb::object_traits::id_type id_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) : begin_ (true), end_ (false), db_ (db), current_ () @@ -123,12 +127,12 @@ namespace odb typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; - // T might be const T, but object_type is always T. + // 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 result_impl result_impl_type; public: explicit @@ -192,8 +196,11 @@ namespace odb } private: + // Use unrestricted pointer traits since that's what is returned by + // result_impl. + // typedef - odb::pointer_traits::pointer_type> + odb::pointer_traits::pointer_type> pointer_traits; result_impl_type* res_; @@ -234,7 +241,10 @@ namespace odb typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef result_impl result_impl_type; + // 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; public: result () @@ -267,6 +277,35 @@ namespace odb return *this; } + // Conversion from result to result. + // + template + result (const result& r) + // + // If you get a compiler error pointing to the line below saying + // that the impl_ member is inaccessible, then you are most likely + // trying to perform an illegal result conversion, for example, + // from result to result. + // + : impl_ (r.impl_) + { + } + + template + result& + operator= (const result& r) + { + // If you get a compiler error pointing to the line below saying + // that the impl_ member is inaccessible, then you are most likely + // trying to perform an illegal result conversion, for example, + // from result to result. + // + if (impl_ != r.impl_) + impl_ = r.impl_; + + return *this; + } + void swap (result& r) { @@ -325,6 +364,8 @@ namespace odb } private: + friend class result; + details::shared_ptr impl_; }; } diff --git a/odb/object-result.txx b/odb/object-result.txx index bd4e95e..c19e482 100644 --- a/odb/object-result.txx +++ b/odb/object-result.txx @@ -23,16 +23,13 @@ namespace odb result_impl:: current () { - typedef typename object_traits::pointer_type unrestricted_pointer_type; - typedef typename object_traits::pointer_traits unrestricted_pointer_traits; - if (pointer_traits::null_ptr (current_) && !end_) { if (!session::has_current ()) { - unrestricted_pointer_type up (object_traits::create ()); - object_type& obj (unrestricted_pointer_traits::get_ref (up)); - current (pointer_type (up)); + pointer_type p (object_traits::create ()); + object_type& obj (pointer_traits::get_ref (p)); + current (p); load (obj); } else @@ -48,15 +45,13 @@ namespace odb current (p); else { - unrestricted_pointer_type up (object_traits::create ()); + pointer_type p (object_traits::create ()); - typename - pointer_cache_traits::insert_guard ig ( - pointer_cache_traits::insert ( - database (), id, up)); + typename pointer_cache_traits::insert_guard ig ( + pointer_cache_traits::insert (database (), id, p)); - object_type& obj (unrestricted_pointer_traits::get_ref (up)); - current (pointer_type (up)); + object_type& obj (pointer_traits::get_ref (p)); + current (p); load (obj); ig.release (); } diff --git a/odb/pointer-traits.hxx b/odb/pointer-traits.hxx index 8882309..f8eed3a 100644 --- a/odb/pointer-traits.hxx +++ b/odb/pointer-traits.hxx @@ -12,6 +12,8 @@ #include // std::auto_ptr #include // std::size_t +#include + namespace odb { enum pointer_kind @@ -81,6 +83,8 @@ namespace odb typedef T element_type; typedef T* pointer_type; typedef const T* const_pointer_type; + typedef typename details::meta::remove_const::result* + unrestricted_pointer_type; typedef raw_ptr_guard guard; // Return raw pointer to the pointed-to element, including NULL. @@ -107,6 +111,14 @@ namespace odb return p == 0; } + // Cast away constness. + // + static unrestricted_pointer_type + cast (pointer_type p) + { + return const_cast (p); + } + public: // Allocate memory for an element that will be managed by this // pointer. @@ -162,6 +174,9 @@ namespace odb return p.get () == 0; } + // cast() is not provided since it transfers the ownership. + // + public: static void* allocate (std::size_t n) diff --git a/odb/session.hxx b/odb/session.hxx index d1b61a2..65d0987 100644 --- a/odb/session.hxx +++ b/odb/session.hxx @@ -67,31 +67,6 @@ namespace odb session& operator= (const session&); protected: - template - struct object_pointers - { - typedef typename object_traits::pointer_type pointer_type; - typedef typename object_traits::const_pointer_type const_pointer_type; - - object_pointers (); - - void - set (const pointer_type&); - - void - set (const const_pointer_type&); - - void - get (pointer_type& p) const; - - void - get (const_pointer_type& cp) const; - - private: - pointer_type p_; - const_pointer_type cp_; - }; - struct LIBODB_EXPORT object_map_base: details::shared_base { virtual @@ -101,7 +76,8 @@ namespace odb template struct object_map: object_map_base, - std::map< typename object_traits::id_type, object_pointers > + std::map::id_type, + typename object_traits::pointer_type> { }; @@ -111,7 +87,7 @@ namespace odb template struct object_position { - typedef typename object_traits::object_type object_type; + typedef T object_type; typedef object_map map; typedef typename map::iterator iterator; diff --git a/odb/session.ixx b/odb/session.ixx index c6708b7..573deb2 100644 --- a/odb/session.ixx +++ b/odb/session.ixx @@ -15,51 +15,4 @@ namespace odb // p.map_->erase (p.pos_); } - - // - // object_pointers - // - template - inline session::object_pointers:: - object_pointers () : p_ (), cp_ () {} - - template - inline void session::object_pointers:: - set (const pointer_type& p) - { - p_ = p; - cp_ = const_pointer_type (); - } - - template - inline void session::object_pointers:: - set (const const_pointer_type& cp) - { - p_ = pointer_type (); - cp_ = cp; - } - - template - inline void session::object_pointers:: - get (pointer_type& p) const - { - if (!pointer_traits::null_ptr (p_)) - p = p_; - else if (!pointer_traits::null_ptr (cp_)) - throw const_object (); - else - p = pointer_type (); - } - - template - inline void session::object_pointers:: - get (const_pointer_type& cp) const - { - if (!pointer_traits::null_ptr (p_)) - cp = const_pointer_type (p_); - else if (!pointer_traits::null_ptr (cp_)) - cp = cp_; - else - cp = const_pointer_type (); - } } diff --git a/odb/session.txx b/odb/session.txx index e2d7734..31814f8 100644 --- a/odb/session.txx +++ b/odb/session.txx @@ -13,28 +13,20 @@ namespace odb const typename object_traits::id_type& id, const typename object_traits::pointer_type& obj) { - // T can be const T while object_type will always be T. - // - typedef typename object_traits::object_type object_type; - typedef odb::object_traits object_traits; - - typedef typename odb::object_traits::pointer_type pointer_type; + typedef odb::object_traits object_traits; + typedef typename object_traits::pointer_type pointer_type; typedef odb::pointer_traits pointer_traits; type_map& tm (db_map_[&db]); - details::shared_ptr& pom (tm[&typeid (object_type)]); + details::shared_ptr& pom (tm[&typeid (T)]); if (!pom) - pom.reset (new (details::shared) object_map); + pom.reset (new (details::shared) object_map); - object_map& om ( - static_cast&> (*pom)); + object_map& om (static_cast&> (*pom)); - typename object_map::value_type vt ( - id, object_pointers ()); - vt.second.set (obj); - std::pair::iterator, bool> r ( - om.insert (vt)); + typename object_map::value_type vt (id, obj); + std::pair::iterator, bool> r (om.insert (vt)); // In what situation may we possibly attempt to reinsert the object? // For example, when the user loads the same object in to different @@ -42,7 +34,7 @@ namespace odb // we should probably update our entries accordingly. // if (!r.second) - r.first->second.set (obj); + r.first->second = obj; return object_position (om, r.first); } @@ -51,9 +43,6 @@ namespace odb typename object_traits::pointer_type session:: find (database_type& db, const typename object_traits::id_type& id) const { - // T can be const T while object_type will always be T. - // - typedef typename object_traits::object_type object_type; typedef typename object_traits::pointer_type pointer_type; database_map::const_iterator di (db_map_.find (&db)); @@ -62,45 +51,37 @@ namespace odb return pointer_type (); const type_map& tm (di->second); - type_map::const_iterator ti (tm.find (&typeid (object_type))); + type_map::const_iterator ti (tm.find (&typeid (T))); if (ti == tm.end ()) return pointer_type (); - const object_map& om ( - static_cast&> (*ti->second)); - typename object_map::const_iterator oi (om.find (id)); + const object_map& om (static_cast&> (*ti->second)); + typename object_map::const_iterator oi (om.find (id)); if (oi == om.end ()) return pointer_type (); - pointer_type r; - oi->second.get (r); - return r; + return oi->second; } template void session:: erase (database_type& db, const typename object_traits::id_type& id) { - // T can be const T while object_type will always be T. - // - typedef typename object_traits::object_type object_type; - database_map::iterator di (db_map_.find (&db)); if (di == db_map_.end ()) return; type_map& tm (di->second); - type_map::iterator ti (tm.find (&typeid (object_type))); + type_map::iterator ti (tm.find (&typeid (T))); if (ti == tm.end ()) return; - object_map& om ( - static_cast&> (*ti->second)); - typename object_map::iterator oi (om.find (id)); + object_map& om (static_cast&> (*ti->second)); + typename object_map::iterator oi (om.find (id)); if (oi == om.end ()) return; diff --git a/odb/tr1/pointer-traits.hxx b/odb/tr1/pointer-traits.hxx index 80f6419..b6ef5ae 100644 --- a/odb/tr1/pointer-traits.hxx +++ b/odb/tr1/pointer-traits.hxx @@ -14,6 +14,7 @@ // #include +#include namespace odb { @@ -29,6 +30,10 @@ namespace odb typedef T element_type; typedef std::tr1::shared_ptr pointer_type; typedef std::tr1::shared_ptr const_pointer_type; + typedef typename details::meta::remove_const::result + unrestricted_element_type; + typedef std::tr1::shared_ptr + unrestricted_pointer_type; typedef smart_ptr_guard guard; static element_type* @@ -49,6 +54,12 @@ namespace odb return !p; } + static unrestricted_pointer_type + cast (const pointer_type& p) + { + return std::tr1::const_pointer_cast (p); + } + public: static void* allocate (std::size_t n) diff --git a/odb/traits.hxx b/odb/traits.hxx index 3f400cb..4d136af 100644 --- a/odb/traits.hxx +++ b/odb/traits.hxx @@ -194,6 +194,26 @@ namespace odb typedef typename access::view_traits::pointer_type pointer_type; }; + // Specialization for const views. It only defines the view, pointer, + // and const_pointer types with pointer and const_pointer being the + // same. Similar to objects, the idea is to only use this specialization + // in the interfaces, with the implementations detecting this situation + // and using the non-const view_traits version. + // + template + struct view_traits + { + private: + typedef + odb::pointer_traits::pointer_type> + pointer_traits; + + public: + typedef typename access::view_traits::view_type view_type; + typedef typename pointer_traits::const_pointer_type const_pointer_type; + typedef const_pointer_type pointer_type; + }; + // // composite_value_traits // diff --git a/odb/view-result.hxx b/odb/view-result.hxx index 088969a..ef9ffd8 100644 --- a/odb/view-result.hxx +++ b/odb/view-result.hxx @@ -28,16 +28,20 @@ namespace odb protected: friend class result; + friend class result; friend class result_iterator; + friend class result_iterator; typedef odb::database database_type; - typedef typename odb::view_traits::pointer_type pointer_type; - typedef odb::pointer_traits pointer_traits; - - typedef typename odb::view_traits::view_type view_type; + // In result_impl, T is always non-const and the same as view_type. + // + typedef T view_type; typedef odb::view_traits view_traits; + typedef typename view_traits::pointer_type pointer_type; + typedef odb::pointer_traits pointer_traits; + result_impl (database_type& db) : begin_ (true), end_ (false), db_ (db), current_ () { @@ -119,11 +123,11 @@ namespace odb typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; - // Const views are not supported, so this should be the same as T. + // 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 result_impl result_impl_type; public: explicit @@ -187,8 +191,11 @@ namespace odb } private: + // Use unrestricted pointer traits since that's what is returned by + // result_impl. + // typedef - odb::pointer_traits::pointer_type> + odb::pointer_traits::pointer_type> pointer_traits; result_impl_type* res_; @@ -229,7 +236,10 @@ namespace odb typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef result_impl result_impl_type; + // 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; public: result () @@ -262,6 +272,35 @@ namespace odb return *this; } + // Conversion from result to result. + // + template + result (const result& r) + // + // If you get a compiler error pointing to the line below saying + // that the impl_ member is inaccessible, then you are most likely + // trying to perform an illegal result conversion, for example, + // from result to result. + // + : impl_ (r.impl_) + { + } + + template + result& + operator= (const result& r) + { + // If you get a compiler error pointing to the line below saying + // that the impl_ member is inaccessible, then you are most likely + // trying to perform an illegal result conversion, for example, + // from result to result. + // + if (impl_ != r.impl_) + impl_ = r.impl_; + + return *this; + } + void swap (result& r) { @@ -320,6 +359,8 @@ namespace odb } private: + friend class result; + details::shared_ptr impl_; }; } diff --git a/odb/view-result.txx b/odb/view-result.txx index 52d478e..95f34e0 100644 --- a/odb/view-result.txx +++ b/odb/view-result.txx @@ -22,8 +22,6 @@ namespace odb { if (pointer_traits::null_ptr (current_) && !end_) { - // For views, pointer_type is unrestricted_pointer_type. - // pointer_type p (view_traits::create ()); view_type& view (pointer_traits::get_ref (p)); current (p); -- cgit v1.1