From 1896d36996ab48ed7271e855d7e32b4e61f64896 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 23 Apr 2012 16:48:00 +0200 Subject: Polymorphic inheritance support --- odb/cache-traits.hxx | 322 +++++++++++++++++++--------------- odb/database.ixx | 88 +++++++++- odb/database.txx | 162 +---------------- odb/exceptions.cxx | 12 ++ odb/exceptions.hxx | 17 ++ odb/forward.hxx | 14 ++ odb/no-id-object-result.hxx | 191 ++++++++++++++++++++ odb/no-id-object-result.txx | 28 +++ odb/object-result.hxx | 358 ++++---------------------------------- odb/object-result.txx | 112 ------------ odb/pointer-traits.hxx | 89 +++++++++- odb/polymorphic-info.hxx | 118 +++++++++++++ odb/polymorphic-map.hxx | 244 ++++++++++++++++++++++++++ odb/polymorphic-map.ixx | 20 +++ odb/polymorphic-map.txx | 72 ++++++++ odb/polymorphic-object-result.hxx | 233 +++++++++++++++++++++++++ odb/polymorphic-object-result.txx | 76 ++++++++ odb/query.hxx | 15 +- odb/result.hxx | 9 +- odb/session.txx | 2 +- odb/simple-object-result.hxx | 210 ++++++++++++++++++++++ odb/simple-object-result.txx | 65 +++++++ odb/tr1/pointer-traits.hxx | 16 +- odb/traits.hxx | 2 + odb/view-result.hxx | 1 + 25 files changed, 1725 insertions(+), 751 deletions(-) create mode 100644 odb/no-id-object-result.hxx create mode 100644 odb/no-id-object-result.txx delete mode 100644 odb/object-result.txx create mode 100644 odb/polymorphic-info.hxx create mode 100644 odb/polymorphic-map.hxx create mode 100644 odb/polymorphic-map.ixx create mode 100644 odb/polymorphic-map.txx create mode 100644 odb/polymorphic-object-result.hxx create mode 100644 odb/polymorphic-object-result.txx create mode 100644 odb/simple-object-result.hxx create mode 100644 odb/simple-object-result.txx diff --git a/odb/cache-traits.hxx b/odb/cache-traits.hxx index 6f5e14a..1e5ccdb 100644 --- a/odb/cache-traits.hxx +++ b/odb/cache-traits.hxx @@ -14,34 +14,154 @@ namespace odb { - // Caching traits for objects passed by pointer. + // pointer_cache_type // - template - struct pointer_cache_traits_impl; + // Used to convert an object pointer to the canonical form (non-const), + // suitable for insertion into the cache. + // + template ::element_type, + typename O = typename object_traits::object_type, + pointer_kind pk = pointer_traits

::kind> + struct pointer_cache_type + { + typedef typename object_traits::pointer_type pointer_type; + + static pointer_type + convert (const P& p) + { + return pointer_traits

::const_pointer_cast (p); + } + }; + + template + struct pointer_cache_type + { + // If element_type and object_type are the same, then it is already + // the canonical pointer. + // + static const P& + convert (const P& p) {return p;} + }; + + template + struct pointer_cache_type + { + // If the pointer is unique, then casting it can transfer ownership. + // So return null pointer, which will be ignored down the chain. + // + typedef typename object_traits::pointer_type pointer_type; + + static pointer_type + convert (const P&) {return pointer_type ();} + }; + + template + struct pointer_cache_type + { + typedef typename object_traits::pointer_type pointer_type; + + static pointer_type + convert (const P&) {return pointer_type ();} + }; + + // reference_cache_type + // + // Used to convert an object reference to the canonical form (non-const), + // suitable for insertion into the cache. + // + template ::object_type> + struct reference_cache_type + { + static O& + convert (T& r) + { + return const_cast (r); + } + }; + + template + struct reference_cache_type + { + // If the types are the same, then it is already the canonical form. + // + static T& + convert (T& r) {return r;} + }; + + // pointer_cache_traits + // + // Caching traits for objects passed by pointer. P should be the canonical + // pointer (non-const). + // + template + struct no_id_pointer_cache_traits + { + typedef P pointer_type; + struct position_type {}; + + static position_type + insert (odb::database&, const pointer_type&) + { + return position_type (); + } + }; template - struct pointer_cache_traits: pointer_cache_traits_impl< - P, - typename object_traits::element_type>::id_type, - pointer_traits

::kind> + struct no_op_pointer_cache_traits { + typedef P pointer_type; + typedef typename pointer_traits::element_type object_type; + typedef typename object_traits::id_type id_type; + struct position_type {}; + + struct insert_guard + { + insert_guard () {} + insert_guard (const position_type&) {} + + position_type + position () const {return position_type ();} + + void + release () {} + + void + reset (const position_type&) {} + }; + + static position_type + insert (odb::database&, const id_type&, const pointer_type&) + { + 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 ();} + + static void + erase (odb::database&, const id_type&) {} + + static void + erase (const position_type&) {} }; - template + template struct pointer_cache_traits_impl { typedef P pointer_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 typename pointer_traits::element_type object_type; + typedef typename object_traits::id_type id_type; typedef session::object_position position_type; struct insert_guard { + insert_guard () {} insert_guard (const position_type& pos): pos_ (pos) {} ~insert_guard () {erase (pos_);} @@ -51,6 +171,11 @@ namespace odb void release () {pos_.map_ = 0;} + // Note: doesn't call erase() on the old position (assumes not set). + // + void + reset (const position_type& pos) {pos_ = pos;} + private: position_type pos_; }; @@ -65,12 +190,7 @@ namespace odb 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)); - } + return session::current ().insert (db, id, p); else return position_type (); } @@ -109,102 +229,45 @@ 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_impl - { - typedef P pointer_type; - typedef typename pointer_traits::element_type element_type; - typedef typename object_traits::id_type id_type; - struct position_type {}; - - struct insert_guard - { - insert_guard (const position_type&) {} - - position_type - position () const {return position_type ();} - - void - release () {} - }; - - static position_type - insert (odb::database&, const id_type&, const pointer_type&) - { - 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 (); } - - static void - erase (odb::database&, const id_type&) {} - - static void - erase (const position_type&) {} - }; + template + struct pointer_cache_traits_impl: + no_op_pointer_cache_traits

{}; template - struct pointer_cache_traits_impl + struct pointer_cache_traits: + pointer_cache_traits_impl::kind> {}; + + // reference_cache_traits + // + // Caching traits for objects passed by reference. T should be the + // canonical object type (non-const). Only if the object pointer + // kind is raw do we add the object to the session. + // + template + struct no_id_reference_cache_traits { - typedef P pointer_type; + typedef T object_type; struct position_type {}; static position_type - insert (odb::database&, const pointer_type&) + insert (odb::database&, object_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 - 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> + struct no_op_reference_cache_traits { - }; - - template - struct reference_cache_traits_impl - { - typedef T element_type; - typedef typename object_traits::pointer_type pointer_type; - typedef typename object_traits::id_type id_type; - - typedef - typename pointer_cache_traits::position_type - position_type; + typedef T object_type; + typedef typename object_traits::id_type id_type; + struct position_type {}; struct insert_guard { + insert_guard () {} insert_guard (const position_type&) {} position_type @@ -212,76 +275,57 @@ namespace odb void release () {} + + void + reset () {} }; static position_type - insert (odb::database&, const id_type&, element_type&) + insert (odb::database&, const id_type&, object_type&) { return position_type (); } static position_type - insert (odb::database&, element_type&) + insert (odb::database&, object_type&) { return position_type (); } }; - 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: no_op_reference_cache_traits {}; - template - struct reference_cache_traits_impl + template + struct reference_cache_traits_impl { - typedef T element_type; - typedef typename object_traits::pointer_type pointer_type; - typedef typename object_traits::id_type id_type; - - typedef - typename pointer_cache_traits::position_type - position_type; + typedef T object_type; + typedef typename object_traits::pointer_type pointer_type; + typedef typename object_traits::id_type id_type; - typedef - typename pointer_cache_traits::insert_guard - insert_guard; + typedef pointer_cache_traits pointer_traits; + typedef typename pointer_traits::position_type position_type; + typedef typename pointer_traits::insert_guard insert_guard; static position_type - insert (odb::database& db, const id_type& id, element_type& obj) + insert (odb::database& db, const id_type& id, object_type& obj) { pointer_type p (&obj); - return pointer_cache_traits::insert (db, id, p); + return pointer_traits::insert (db, id, p); } static position_type - insert (odb::database& db, element_type& obj) + insert (odb::database& db, object_type& obj) { pointer_type p (&obj); - return pointer_cache_traits::insert (db, p); + return pointer_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 (); - } - }; + struct reference_cache_traits: + reference_cache_traits_impl< + T, pointer_traits::pointer_type>::kind> {}; } #include diff --git a/odb/database.ixx b/odb/database.ixx index d4869c1..4a00a74 100644 --- a/odb/database.ixx +++ b/odb/database.ixx @@ -2,7 +2,7 @@ // copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file -#include // std::string +#include // std::strlen() namespace odb { @@ -105,6 +105,28 @@ namespace odb } template + inline typename object_traits::pointer_type database:: + find (const typename object_traits::id_type& id) + { + // T is always object_type. + // + + // Compiler error pointing here? Perhaps the object doesn't have the + // default constructor? + // + return object_traits::find (*this, id); + } + + template + inline bool database:: + find (const typename object_traits::id_type& id, T& obj) + { + // T is always object_type. + // + return object_traits::find (*this, id, obj); + } + + template inline void database:: reload (T* p) { @@ -218,6 +240,41 @@ namespace odb template inline void database:: + update (T& obj) + { + // 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; + + // 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); + } + + template + inline void database:: + update_ (const typename object_traits::pointer_type& pobj) + { + // 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; + + typedef typename odb::object_traits::pointer_type pointer_type; + typedef odb::pointer_traits pointer_traits; + + T& obj (pointer_traits::get_ref (pobj)); + + // 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); + } + + template + inline void database:: erase (T* p) { typedef typename object_traits::pointer_type object_pointer; @@ -295,6 +352,26 @@ namespace odb } template + inline void database:: + erase (const typename object_traits::id_type& id) + { + // T is always object_type. + // + object_traits::erase (*this, id); + } + + template + inline void database:: + erase (T& obj) + { + // T can be const T while object_type will always be T. + // + typedef typename object_traits::object_type object_type; + + object_traits::erase (*this, obj); + } + + template inline unsigned long long database:: erase_query () { @@ -322,6 +399,15 @@ namespace odb } template + inline unsigned long long database:: + erase_query (const odb::query& q) + { + // T is always object_type. + // + return object_traits::erase_query (*this, q); + } + + template inline result database:: query (bool cache) { diff --git a/odb/database.txx b/odb/database.txx index dd0d995..abc6ba3 100644 --- a/odb/database.txx +++ b/odb/database.txx @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -20,14 +19,10 @@ namespace odb typedef typename odb::object_traits::object_type object_type; typedef odb::object_traits object_traits; - if (!transaction::has_current ()) - throw not_in_transaction (); - - object_traits::callback (*this, obj, callback_event::pre_persist); object_traits::persist (*this, obj); - object_traits::callback (*this, obj, callback_event::post_persist); - reference_cache_traits::insert (*this, obj); + object_traits::reference_cache_traits::insert ( + *this, reference_cache_type::convert (obj)); return object_traits::id (obj); } @@ -44,16 +39,13 @@ namespace odb typedef typename odb::object_traits::pointer_type pointer_type; typedef odb::pointer_traits pointer_traits; - if (!transaction::has_current ()) - throw not_in_transaction (); - T& obj (pointer_traits::get_ref (pobj)); - - object_traits::callback (*this, obj, callback_event::pre_persist); object_traits::persist (*this, obj); - object_traits::callback (*this, obj, callback_event::post_persist); - pointer_cache_traits::insert (*this, pobj); + // Get the canonical object pointer and insert it into object cache. + // + object_traits::pointer_cache_traits::insert ( + *this, pointer_cache_type::convert (pobj)); return object_traits::id (obj); } @@ -91,150 +83,14 @@ namespace odb // typedef odb::object_traits object_traits; + // We don't need to check for transaction here; + // object_traits::reload () does this. + if (!object_traits::reload (*this, obj)) throw object_not_persistent (); } template - typename object_traits::pointer_type database:: - find (const typename object_traits::id_type& id) - { - // T is always object_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. - // - { - pointer_type p ( - pointer_cache_traits::find (*this, id)); - - if (!pointer_traits::null_ptr (p)) - return p; - } - - if (!transaction::has_current ()) - throw not_in_transaction (); - - // Compiler error pointing here? Perhaps the object doesn't have the - // default constructor? - // - return pointer_type (object_traits::find (*this, id)); - } - - template - bool database:: - find (const typename object_traits::id_type& id, T& obj) - { - // T is always object_type. - // - if (!transaction::has_current ()) - throw not_in_transaction (); - - return object_traits::find (*this, id, obj); - } - - template - void database:: - update (T& obj) - { - // 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; - - if (!transaction::has_current ()) - throw not_in_transaction (); - - object_traits::callback (*this, obj,callback_event::pre_update); - - // 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); - - object_traits::callback (*this, obj, callback_event::post_update); - } - - template - void database:: - update_ (const typename object_traits::pointer_type& pobj) - { - // 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; - - typedef typename odb::object_traits::pointer_type pointer_type; - typedef odb::pointer_traits pointer_traits; - - if (!transaction::has_current ()) - throw not_in_transaction (); - - T& obj (pointer_traits::get_ref (pobj)); - - object_traits::callback (*this, obj, callback_event::pre_update); - - // 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); - - object_traits::callback (*this, obj, callback_event::post_update); - } - - template - void database:: - erase (const typename object_traits::id_type& id) - { - // T is always object_type. - // - typedef odb::object_traits object_traits; - typedef typename object_traits::pointer_type pointer_type; - - if (!transaction::has_current ()) - throw not_in_transaction (); - - object_traits::erase (*this, id); - pointer_cache_traits::erase (*this, id); - } - - template - void database:: - erase (T& obj) - { - // 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; - typedef typename object_traits::pointer_type pointer_type; - - if (!transaction::has_current ()) - throw not_in_transaction (); - - typename object_traits::id_type id (object_traits::id (obj)); - - object_traits::callback (*this, obj, callback_event::pre_erase); - object_traits::erase (*this, obj); - pointer_cache_traits::erase (*this, id); - object_traits::callback (*this, obj, callback_event::post_erase); - } - - template - unsigned long long database:: - erase_query (const odb::query& q) - { - // T is always object_type. - // - if (!transaction::has_current ()) - throw not_in_transaction (); - - return object_traits::erase_query (*this, q); - } - - template struct database::query_ { static result diff --git a/odb/exceptions.cxx b/odb/exceptions.cxx index b200843..d56711c 100644 --- a/odb/exceptions.cxx +++ b/odb/exceptions.cxx @@ -94,6 +94,18 @@ namespace odb return "query result is not cached"; } + const char* abstract_class:: + what () const throw () + { + return "database operation on instance of abstract class"; + } + + const char* no_type_info:: + what () const throw () + { + return "no type information"; + } + unknown_schema:: unknown_schema (const std::string& name) : name_ (name) diff --git a/odb/exceptions.hxx b/odb/exceptions.hxx index b55b2a4..9e37967 100644 --- a/odb/exceptions.hxx +++ b/odb/exceptions.hxx @@ -113,6 +113,20 @@ namespace odb { }; + // Polymorphism support exceptions. + // + struct LIBODB_EXPORT abstract_class: exception + { + virtual const char* + what () const throw (); + }; + + struct LIBODB_EXPORT no_type_info: exception + { + virtual const char* + what () const throw (); + }; + // Schema catalog exceptions. // struct LIBODB_EXPORT unknown_schema: exception @@ -156,6 +170,9 @@ namespace odb using odb::result_not_cached; using odb::database_exception; + using odb::abstract_class; + using odb::no_type_info; + using odb::unknown_schema; } } diff --git a/odb/forward.hxx b/odb/forward.hxx index 97bc7a8..4c5e4b9 100644 --- a/odb/forward.hxx +++ b/odb/forward.hxx @@ -73,6 +73,20 @@ namespace odb template struct view_traits; + // Cache traits. + // + template struct no_id_pointer_cache_traits; + template struct no_op_pointer_cache_traits; + template struct pointer_cache_traits; + template struct no_id_reference_cache_traits; + template struct no_op_reference_cache_traits; + template struct reference_cache_traits; + + // Polymorphism support. + // + template + struct polymorphic_map; + namespace details { template <> diff --git a/odb/no-id-object-result.hxx b/odb/no-id-object-result.hxx new file mode 100644 index 0000000..8893e7a --- /dev/null +++ b/odb/no-id-object-result.hxx @@ -0,0 +1,191 @@ +// file : odb/no-id-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_NO_ID_OBJECT_RESULT_HXX +#define ODB_NO_ID_OBJECT_RESULT_HXX + +#include + +#include // std::size_t +#include // std::move + +#include +#include +#include +#include +#include + +#include // ODB_CXX11 +#include + +namespace odb +{ + // Implementation for objects without object id (always non-polymorphic). + // + template + class no_id_object_result_impl: public details::shared_base + { + public: + virtual + ~no_id_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::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: + no_id_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 () + { + if (pointer_traits::null_ptr (current_) && !end_) + load (); + + return 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 void + next () = 0; + + virtual void + cache () = 0; + + virtual std::size_t + size () = 0; + + protected: +#ifdef ODB_CXX11 + void + current (pointer_type& p) + { + current_ = std::move (p); + guard_.reset (current_); + } + + void + current (pointer_type&& p) + { + current (p); + } +#else + void + current (pointer_type p) + { + current_ = p; + guard_.reset (current_); + } +#endif + + bool begin_; + bool end_; + + private: + void + load (); + + private: + database_type& db_; + pointer_type current_; + typename pointer_traits::guard guard_; + }; + + 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 no_id_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& obj) + { + // Objects without ids are not stored in session cache. + // + if (!res_->end ()) + res_->load (obj); + } + + protected: + result_impl_type* res_; + }; +} + +#include + +#include + +#endif // ODB_NO_ID_OBJECT_RESULT_HXX diff --git a/odb/no-id-object-result.txx b/odb/no-id-object-result.txx new file mode 100644 index 0000000..99bd80e --- /dev/null +++ b/odb/no-id-object-result.txx @@ -0,0 +1,28 @@ +// file : odb/no-id-object-result.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + // + // object_result_impl + // + + template + no_id_object_result_impl:: + ~no_id_object_result_impl () + { + } + + template + void no_id_object_result_impl:: + load () + { + // 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); + } +} diff --git a/odb/object-result.hxx b/odb/object-result.hxx index 759c9f5..f966018 100644 --- a/odb/object-result.hxx +++ b/odb/object-result.hxx @@ -7,363 +7,66 @@ #include -#include // std::ptrdiff_t, std::size_t +#include // std::ptrdiff_t #include // iterator categories -#include // std::move #include +#include #include #include -#include // ODB_CXX11 -#include - namespace odb { + // + // object_result_impl + // template class object_result_impl; template - class object_result_impl_no_id; + class polymorphic_object_result_impl; - template - class object_result_iterator; + template + class no_id_object_result_impl; + + // + // object_result_impl_selector + // + template ::id_type, + bool polymorphic = object_traits::polymorphic> + struct object_result_impl_selector; - template ::id_type> - struct object_result_impl_selector + template + struct object_result_impl_selector { typedef object_result_impl type; }; - template - struct object_result_impl_selector + template + struct object_result_impl_selector { - typedef object_result_impl_no_id type; + typedef polymorphic_object_result_impl type; }; - // Implementation for objects with object id. - // template - class object_result_impl: public details::shared_base + struct object_result_impl_selector { - public: - virtual - ~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: - // The fetch argument is a hint to the implementation. If it is - // false then it means load_id() was already called (and presumably - // fetched the data into the object image) and the object image - // is still valid (so the implementation doesn't need to fetch - // the data again). - // - virtual void - load (object_type&, bool fetch = true) = 0; - - virtual id_type - load_id () = 0; - - virtual void - next () = 0; - - virtual void - cache () = 0; - - virtual std::size_t - size () = 0; - - protected: -#ifdef ODB_CXX11 - void - current (pointer_type& p) - { - current_ = std::move (p); - guard_.reset (current_); - } - - void - current (pointer_type&& p) - { - current (p); - } -#else - void - current (pointer_type p) - { - current_ = p; - guard_.reset (current_); - } -#endif - - 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::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_no_id (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 void - next () = 0; - - virtual void - cache () = 0; - - virtual std::size_t - size () = 0; - - protected: -#ifdef ODB_CXX11 - void - current (pointer_type& p) - { - current_ = std::move (p); - guard_.reset (current_); - } - - void - current (pointer_type&& p) - { - current (p); - } -#else - void - current (pointer_type p) - { - current_ = p; - guard_.reset (current_); - } -#endif - - bool begin_; - bool end_; - - private: - database_type& db_; - pointer_type current_; - typename pointer_traits::guard guard_; + typedef no_id_object_result_impl type; }; // // 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&); - - id_type - id () - { - return res_->load_id (); - } - - protected: - result_impl_type* res_; - }; - - 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 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 object_result_iterator; template class result_iterator: public object_result_iterator< T, - typename object_traits::id_type> + typename object_traits::id_type, + object_traits::polymorphic> { public: typedef T value_type; @@ -375,8 +78,9 @@ namespace odb // T can be const T while object_type is always non-const. // typedef - object_result_iterator::id_type> - base_type; + object_result_iterator::id_type, + object_traits::polymorphic> base_type; public: explicit @@ -456,8 +160,6 @@ namespace odb }; } -#include - #include #endif // ODB_OBJECT_RESULT_HXX diff --git a/odb/object-result.txx b/odb/object-result.txx deleted file mode 100644 index 7972da1..0000000 --- a/odb/object-result.txx +++ /dev/null @@ -1,112 +0,0 @@ -// file : odb/object-result.txx -// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -#include -#include - -namespace odb -{ - // - // object_result_impl - // - - template - object_result_impl:: - ~object_result_impl () - { - } - - template - typename object_result_impl::pointer_type& - object_result_impl:: - current () - { - if (pointer_traits::null_ptr (current_) && !end_) - { - if (!session::has_current ()) - { - pointer_type p (object_traits::create ()); - object_type& obj (pointer_traits::get_ref (p)); - current (p); - load (obj); - } - else - { - // First check the session. - // - const id_type& id (load_id ()); - - pointer_type p ( - pointer_cache_traits::find (database (), id)); - - if (!pointer_traits::null_ptr (p)) - current (p); - else - { - pointer_type p (object_traits::create ()); - - typename pointer_cache_traits::insert_guard ig ( - pointer_cache_traits::insert (database (), id, p)); - - object_type& obj (pointer_traits::get_ref (p)); - current (p); - load (obj, false); - ig.release (); - } - } - } - - return current_; - } - - // - // object_result_impl_no_id - // - template - object_result_impl_no_id:: - ~object_result_impl_no_id () - { - } - - template - 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 ()) - return; - - if (!session::has_current ()) - res_->load (obj); - else - { - typename reference_cache_traits::insert_guard ig ( - reference_cache_traits::insert ( - res_->database (), res_->load_id (), obj)); - res_->load (obj, false); - ig.release (); - } - } -} diff --git a/odb/pointer-traits.hxx b/odb/pointer-traits.hxx index fbfa721..a24bf02 100644 --- a/odb/pointer-traits.hxx +++ b/odb/pointer-traits.hxx @@ -47,7 +47,7 @@ namespace odb release () {p_ = 0;} void - reset (P p) {delete p_; p_ = p;} + reset (P p = 0) {delete p_; p_ = p;} private: P p_; @@ -68,6 +68,9 @@ namespace odb release () {} void + reset () {} + + void reset (const P&) {} }; @@ -111,14 +114,28 @@ namespace odb return p == 0; } - // Cast away constness. + // Casts. // static unrestricted_pointer_type - cast (pointer_type p) + const_pointer_cast (pointer_type p) { return const_cast (p); } + template + static T1* + static_pointer_cast (pointer_type p) + { + return static_cast (p); + } + + template + static T1* + dynamic_pointer_cast (pointer_type p) + { + return dynamic_cast (p); + } + public: // Allocate memory for an element that will be managed by this // pointer. @@ -174,9 +191,32 @@ namespace odb return p.get () == 0; } - // cast() is not provided since it transfers the ownership. + // const_pointer_cast() is not provided. // + // Note: transfers ownership. + // + template + static std::auto_ptr + static_pointer_cast (pointer_type& p) + { + return std::auto_ptr (static_cast (p.release ())); + } + + // Note: transfers ownership if successful. + // + template + static std::auto_ptr + dynamic_pointer_cast (pointer_type& p) + { + T1* p1 (dynamic_cast (p.get ())); + + if (p1 != 0) + p.release (); + + return std::auto_ptr (p1); + } + public: static void* allocate (std::size_t n) @@ -225,8 +265,31 @@ namespace odb return !p; } - // cast() is not provided since it transfers the ownership. + // const_pointer_cast() is not provided. + // + + // Note: transfers ownership. // + template + static std::unique_ptr + static_pointer_cast (pointer_type& p) + { + return std::unique_ptr (static_cast (p.release ())); + } + + // Note: transfers ownership if successful. + // + template + static std::unique_ptr + dynamic_pointer_cast (pointer_type& p) + { + T1* p1 (dynamic_cast (p.get ())); + + if (p1 != 0) + p.release (); + + return std::unique_ptr (p1); + } public: static void* @@ -279,11 +342,25 @@ namespace odb } static unrestricted_pointer_type - cast (const pointer_type& p) + const_pointer_cast (const pointer_type& p) { return std::const_pointer_cast (p); } + template + static std::shared_ptr + static_pointer_cast (const pointer_type& p) + { + return std::static_pointer_cast (p); + } + + template + static std::shared_ptr + dynamic_pointer_cast (const pointer_type& p) + { + return std::dynamic_pointer_cast (p); + } + public: static void* allocate (std::size_t n) diff --git a/odb/polymorphic-info.hxx b/odb/polymorphic-info.hxx new file mode 100644 index 0000000..349f062 --- /dev/null +++ b/odb/polymorphic-info.hxx @@ -0,0 +1,118 @@ +// file : odb/polymorphic-info.hxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_POLYMORPHIC_INFO_HXX +#define ODB_POLYMORPHIC_INFO_HXX + +#include + +#include // database +#include + +namespace odb +{ + template + struct polymorphic_abstract_info + { + polymorphic_abstract_info (const std::type_info& t, + const polymorphic_abstract_info* b) + : type (t), base (b) {} + + bool + derived (const polymorphic_abstract_info& b) const + { + for (const polymorphic_abstract_info* p (base); p != 0; p = p->base) + if (&b == p) + return true; + + return false; + } + + public: + const std::type_info& type; + const polymorphic_abstract_info* base; + }; + + template + struct polymorphic_concrete_info: polymorphic_abstract_info + { + typedef R root_type; + typedef object_traits root_traits; + typedef typename root_traits::id_type id_type; + typedef typename root_traits::pointer_type pointer_type; + typedef typename root_traits::discriminator_type discriminator_type; + + enum call_type + { + call_callback, // arg points to callback event. + call_persist, // arg is not used. + call_update, // arg is not used. + call_find, // arg points to object id. + call_reload, // arg is not used. + call_load, // arg points to depth. + call_erase // arg points to object id. + }; + + typedef pointer_type (*create_function) (); + typedef bool (*dispatch_function) ( + call_type, database&, const root_type*, const void* arg); + typedef void (*delayed_loader_function) ( + database&, const id_type&, root_type&); + + public: + polymorphic_concrete_info (const std::type_info& t, + const polymorphic_abstract_info* b, + const discriminator_type& d, + create_function cf, + dispatch_function df, + delayed_loader_function dlf) + : polymorphic_abstract_info (t, b), + discriminator (d), + create (cf), dispatch (df), delayed_loader (dlf) + { + } + + public: + discriminator_type discriminator; + create_function create; + dispatch_function dispatch; + delayed_loader_function delayed_loader; + }; + + // Register concrete type T in the root's map. + // + template + struct polymorphic_entry + { + typedef T object_type; + typedef odb::object_traits object_traits; + + typedef typename object_traits::root_type root_type; + typedef odb::object_traits root_traits; + + polymorphic_entry (); + ~polymorphic_entry (); + }; + + // Helper functions that either return the concrete info or NULL + // depending on what kind of info we pass (used in query support). + // + template + inline const polymorphic_concrete_info* + polymorphic_info (const polymorphic_concrete_info& i) + { + return &i; + } + + template + inline const polymorphic_concrete_info* + polymorphic_info (const polymorphic_abstract_info&) + { + return 0; + } +} + +#include + +#endif // ODB_POLYMORPHIC_INFO_HXX diff --git a/odb/polymorphic-map.hxx b/odb/polymorphic-map.hxx new file mode 100644 index 0000000..9c18d33 --- /dev/null +++ b/odb/polymorphic-map.hxx @@ -0,0 +1,244 @@ +// file : odb/polymorphic-map.hxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_POLYMORPHIC_MAP_HXX +#define ODB_POLYMORPHIC_MAP_HXX + +#include + +#include +#include // std::move +#include // std::size_t +#include +#include + +#include + +#include // ODB_CXX11 +#include + +#include + +namespace odb +{ + template + struct polymorphic_map + { + typedef R root_type; + typedef polymorphic_concrete_info info_type; + typedef typename info_type::discriminator_type discriminator_type; + + polymorphic_map (): ref_count_ (1) {} + + const info_type& + find (const std::type_info& t) const; + + const info_type& + find (const discriminator_type& d) const; + + public: + typedef + std::map + type_map; + + struct discriminator_comparator + { + bool + operator() (const discriminator_type* x, + const discriminator_type* y) const + { + return *x < *y; + } + }; + + typedef + std::map + discriminator_map; + + public: + std::size_t ref_count_; + type_map type_map_; + discriminator_map discriminator_map_; + }; + + template + struct polymorphic_entry_impl + { + typedef R root_type; + typedef object_traits root_traits; + typedef polymorphic_concrete_info info_type; + + static void + insert (const info_type&); + + static void + erase (const info_type&); + }; + + template + typename object_traits::root_type>::pointer_type + create_impl () + { + typedef object_traits derived_traits; + typedef object_traits root_traits; + + typedef typename derived_traits::pointer_type derived_pointer_type; + typedef typename root_traits::pointer_type root_pointer_type; + + derived_pointer_type p ( + access::object_factory::create ()); + + // Implicit downcast. + // +#ifdef ODB_CXX11 + root_pointer_type r (std::move (p)); +#else + root_pointer_type r (p); +#endif + return r; + } + + template + struct dispatch_load + { + static void + call (database& db, T& obj, std::size_t d) + { + object_traits::load_ (db, obj, d); + } + }; + + template + struct dispatch_load + { + static void + call (database&, R&, std::size_t) + { + assert (false); + } + }; + + template + struct dispatch_persist + { + static void + call (database& db, const T& obj) + { + // Top-level call, no dynamic type checking. + // + object_traits::persist (db, obj, true, false); + } + }; + + template + struct dispatch_persist + { + static void + call (database& db, const T& obj) + { + // Top-level call, no dynamic type checking. + // + object_traits::persist (db, const_cast (obj), true, false); + } + }; + + template + bool dispatch_impl ( + typename polymorphic_concrete_info< + typename object_traits::root_type>::call_type c, + database& db, + const typename object_traits::root_type* pobj, + const void* arg) + { + typedef object_traits derived_traits; + typedef typename derived_traits::root_type root_type; + typedef object_traits root_traits; + typedef typename root_traits::id_type id_type; + typedef polymorphic_concrete_info info_type; + + bool r (false); + + switch (c) + { + case info_type::call_callback: + { + derived_traits::callback ( + db, + *const_cast (static_cast (pobj)), + *static_cast (arg)); + break; + } + case info_type::call_persist: + { + dispatch_persist::call ( + db, + *static_cast (pobj)); + break; + } + case info_type::call_update: + { + derived_traits::update ( + db, + *static_cast (pobj), + true, // Top-level call. + false); // No dynamic type checking. + break; + } + case info_type::call_find: + { + r = derived_traits::find ( + db, + *static_cast (arg), + *const_cast (static_cast (pobj)), + false); // No dynamic type checking. + break; + } + case info_type::call_reload: + { + r = derived_traits::reload ( + db, + *const_cast (static_cast (pobj)), + false); // No dynamic type checking. + break; + } + case info_type::call_load: + { + dispatch_load::call ( + db, + *const_cast (static_cast (pobj)), + *static_cast (arg)); + break; + } + case info_type::call_erase: + { + if (pobj != 0) + derived_traits::erase ( + db, + *static_cast (pobj), + true, // Top-level call. + false); // No dynamic type checking. + else + derived_traits::erase ( + db, + *static_cast (arg), + true, // Top-level call. + false); // No dynamic type checking. + break; + } + } + + return r; + } +} + +#include +#include + +#include + +#endif // ODB_POLYMORPHIC_MAP_HXX diff --git a/odb/polymorphic-map.ixx b/odb/polymorphic-map.ixx new file mode 100644 index 0000000..4dbd174 --- /dev/null +++ b/odb/polymorphic-map.ixx @@ -0,0 +1,20 @@ +// file : odb/polymorphic-map.ixx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + template + inline polymorphic_entry:: + polymorphic_entry () + { + polymorphic_entry_impl::insert (object_traits::info); + } + + template + inline polymorphic_entry:: + ~polymorphic_entry () + { + polymorphic_entry_impl::erase (object_traits::info); + } +} diff --git a/odb/polymorphic-map.txx b/odb/polymorphic-map.txx new file mode 100644 index 0000000..7b1b81a --- /dev/null +++ b/odb/polymorphic-map.txx @@ -0,0 +1,72 @@ +// file : odb/polymorphic-map.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include // no_type_info + +namespace odb +{ + // + // polymorphic_map + // + + template + const typename polymorphic_map::info_type& polymorphic_map:: + find (const std::type_info& t) const + { + typename type_map::const_iterator i (type_map_.find (&t)); + + if (i != type_map_.end ()) + return *i->second; + else + throw no_type_info (); + } + + template + const typename polymorphic_map::info_type& polymorphic_map:: + find (const discriminator_type& d) const + { + typename discriminator_map::const_iterator i ( + discriminator_map_.find (&d)); + + if (i != discriminator_map_.end ()) + return *i->second; + else + throw no_type_info (); + } + + // + // polymorphic_entry_impl + // + + template + void polymorphic_entry_impl:: + insert (const info_type& i) + { + polymorphic_map*& pm (root_traits::map); + + if (pm == 0) + pm = new polymorphic_map; + else + pm->ref_count_++; + + pm->type_map_[&i.type] = &i; + pm->discriminator_map_[&i.discriminator] = &i; + } + + template + void polymorphic_entry_impl:: + erase (const info_type& i) + { + polymorphic_map*& pm (root_traits::map); + + pm->discriminator_map_.erase (&i.discriminator); + pm->type_map_.erase (&i.type); + + if (--pm->ref_count_ == 0) + { + delete pm; + pm = 0; + } + } +} diff --git a/odb/polymorphic-object-result.hxx b/odb/polymorphic-object-result.hxx new file mode 100644 index 0000000..805fe96 --- /dev/null +++ b/odb/polymorphic-object-result.hxx @@ -0,0 +1,233 @@ +// file : odb/polymorphic-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_POLYMORPHIC_OBJECT_RESULT_HXX +#define ODB_POLYMORPHIC_OBJECT_RESULT_HXX + +#include + +#include // std::size_t +#include // std::move + +#include +#include +#include +#include +#include + +#include // ODB_CXX11 +#include + +namespace odb +{ + // Implementation for polymorphic objects with object id. + // + template + class polymorphic_object_result_impl: public details::shared_base + { + public: + virtual + ~polymorphic_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; + + typedef typename object_traits::root_type root_type; + typedef odb::object_traits root_traits; + typedef typename root_traits::discriminator_type discriminator_type; + + 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: + polymorphic_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 () + { + if (pointer_traits::null_ptr (current_) && !end_) + load (); + + return current_; + } + + void + release () + { + current_ = pointer_type (); + guard_.release (); + } + + void + begin () + { + if (begin_) + { + next (); + begin_ = false; + } + } + + bool + end () const + { + return end_; + } + + protected: + // The fetch argument is a hint to the implementation. If it is + // false then it means load_id() was already called (and presumably + // fetched the data into the object image) and the object image + // is still valid (so the implementation doesn't need to fetch + // the data again). + // + // The load() signature differs from the non-polymorphic cases in + // that we pass a pointer to object instead of a reference. The + // object is only passed if the user requests loading into an + // existing instance. Otherwise, we pass NULL an load() is + // responsible for creating the object of a correct dynamic + // type and managing the object cache insertion. + // + virtual void + load (object_type*, bool fetch = true) = 0; + + virtual id_type + load_id () = 0; + + virtual discriminator_type + load_discriminator () = 0; + + virtual void + next () = 0; + + virtual void + cache () = 0; + + virtual std::size_t + size () = 0; + + protected: +#ifdef ODB_CXX11 + void + current (pointer_type& p, bool guard = true) + { + current_ = std::move (p); + + if (guard) + guard_.reset (current_); + else + guard_.reset (); + } + + void + current (pointer_type&& p, bool guard = true) + { + current (p, guard); + } +#else + void + current (pointer_type p, bool guard = true) + { + current_ = p; + + if (guard) + guard_.reset (current_); + else + guard_.reset (); + } +#endif + + bool begin_; + bool end_; + + private: + void + load (); + + private: + database_type& db_; + pointer_type current_; + typename pointer_traits::guard guard_; + }; + + 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 typename object_traits::root_type root_type; + typedef typename object_traits::discriminator_type + discriminator_type; + + typedef polymorphic_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&); + + id_type + id () + { + return res_->load_id (); + } + + discriminator_type + discriminator () + { + return res_->load_discriminator (); + } + + protected: + result_impl_type* res_; + }; +} + +#include + +#include + +#endif // ODB_POLYMORPHIC_OBJECT_RESULT_HXX diff --git a/odb/polymorphic-object-result.txx b/odb/polymorphic-object-result.txx new file mode 100644 index 0000000..28331c6 --- /dev/null +++ b/odb/polymorphic-object-result.txx @@ -0,0 +1,76 @@ +// file : odb/polymorphic-object-result.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include +#include + +namespace odb +{ + // + // polymorphic_object_result_impl + // + + template + polymorphic_object_result_impl:: + ~polymorphic_object_result_impl () + { + } + + template + void polymorphic_object_result_impl:: + load () + { + typedef typename root_traits::pointer_type root_pointer_type; + typedef typename root_traits::pointer_traits root_pointer_traits; + + // First check the session. + // + const id_type& id (load_id ()); + + root_pointer_type rp ( + object_traits::pointer_cache_traits::find (database (), id)); + + if (!root_pointer_traits::null_ptr (rp)) + { + // Check if the types match. + // + pointer_type p ( + root_pointer_traits::template dynamic_pointer_cast< + object_type> (rp)); + + if (!pointer_traits::null_ptr (p)) + current (p, false); // Pointer from cache should not be guarded. + else + // We have an object in session that has a different type + // compared to the one in the database. + // + throw object_not_persistent (); // @@ type_mismatch? + } + else + // load() is responsible for creating the object of a correct + // dynamic type and for object cache insertion. + // + load (0, false); + } + + // + // object_result_iterator + // + + template + void object_result_iterator:: + load (object_type& obj) + { + if (res_->end ()) + return; + + typedef odb::object_traits object_traits; + + typename object_traits::reference_cache_traits::insert_guard ig ( + object_traits::reference_cache_traits::insert ( + res_->database (), res_->load_id (), obj)); + res_->load (&obj, false); + ig.release (); + } +} diff --git a/odb/query.hxx b/odb/query.hxx index 0c748d6..e654ade 100644 --- a/odb/query.hxx +++ b/odb/query.hxx @@ -11,15 +11,26 @@ namespace odb { + // Table alias for type T and alias tag Tag. The dummy third template + // argument is used to make the C++ compiler weed out duplicates. // + // The alias_traits interface consists of two things: the table_name + // static variable containing the name and, in case of a derived type + // in a polymorphic hierarchy, the base_traits typedef. Note that the + // same interface is exposed by object_traits, which is used when + // we need straight tables instead of aliases. // + // + template + struct alias_traits; + template struct query_columns_base; - template + template struct query_columns; - template + template struct pointer_query_columns; // Object pointer syntax wrapper. diff --git a/odb/result.hxx b/odb/result.hxx index 14f8c72..29c03df 100644 --- a/odb/result.hxx +++ b/odb/result.hxx @@ -9,7 +9,7 @@ #include // std::ptrdiff_t, std::size_t -#include // result +#include #include namespace odb @@ -190,10 +190,3 @@ namespace odb #include #endif // ODB_RESULT_HXX - -// Include result specializations so that the user code only needs -// to include this header. -// - -#include -#include diff --git a/odb/session.txx b/odb/session.txx index 553e51a..2a50005 100644 --- a/odb/session.txx +++ b/odb/session.txx @@ -28,7 +28,7 @@ namespace odb 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 + // For example, when the user loads the same object in two different // instances (i.e., load into a pre-allocated object). In this case // we should probably update our entries accordingly. // diff --git a/odb/simple-object-result.hxx b/odb/simple-object-result.hxx new file mode 100644 index 0000000..58d8958 --- /dev/null +++ b/odb/simple-object-result.hxx @@ -0,0 +1,210 @@ +// file : odb/simple-object-result.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SIMPLE_OBJECT_RESULT_HXX +#define ODB_SIMPLE_OBJECT_RESULT_HXX + +#include + +#include // std::size_t +#include // std::move + +#include +#include +#include +#include +#include + +#include // ODB_CXX11 +#include + +namespace odb +{ + // Implementation for non-polymorphic objects with object id. + // + template + class object_result_impl: public details::shared_base + { + public: + virtual + ~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 () + { + if (pointer_traits::null_ptr (current_) && !end_) + load (); + + return current_; + } + + void + release () + { + current_ = pointer_type (); + guard_.release (); + } + + void + begin () + { + if (begin_) + { + next (); + begin_ = false; + } + } + + bool + end () const + { + return end_; + } + + protected: + // The fetch argument is a hint to the implementation. If it is + // false then it means load_id() was already called (and presumably + // fetched the data into the object image) and the object image + // is still valid (so the implementation doesn't need to fetch + // the data again). + // + virtual void + load (object_type&, bool fetch = true) = 0; + + virtual id_type + load_id () = 0; + + virtual void + next () = 0; + + virtual void + cache () = 0; + + virtual std::size_t + size () = 0; + + protected: +#ifdef ODB_CXX11 + void + current (pointer_type& p, bool guard = true) + { + current_ = std::move (p); + + if (guard) + guard_.reset (current_); + else + guard_.reset (); + } + + void + current (pointer_type&& p, bool guard = true) + { + current (p, guard); + } +#else + void + current (pointer_type p, bool guard = true) + { + current_ = p; + + if (guard) + guard_.reset (current_); + else + guard_.reset (); + } +#endif + + bool begin_; + bool end_; + + private: + void + load (); + + private: + database_type& db_; + pointer_type current_; + typename pointer_traits::guard guard_; + }; + + 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&); + + id_type + id () + { + return res_->load_id (); + } + + protected: + result_impl_type* res_; + }; +} + +#include + +#include + +#endif // ODB_SIMPLE_OBJECT_RESULT_HXX diff --git a/odb/simple-object-result.txx b/odb/simple-object-result.txx new file mode 100644 index 0000000..832ff7f --- /dev/null +++ b/odb/simple-object-result.txx @@ -0,0 +1,65 @@ +// file : odb/simple-object-result.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +namespace odb +{ + // + // object_result_impl + // + + template + object_result_impl:: + ~object_result_impl () + { + } + + template + void object_result_impl:: + load () + { + // First check the session. + // + const id_type& id (load_id ()); + + pointer_type p ( + object_traits::pointer_cache_traits::find (database (), id)); + + if (!pointer_traits::null_ptr (p)) + current (p, false); // Pointer from cache should not be guarded. + else + { + p = object_traits::create (); + + typename object_traits::pointer_cache_traits::insert_guard ig ( + object_traits::pointer_cache_traits::insert (database (), id, p)); + + object_type& obj (pointer_traits::get_ref (p)); + current (p); + load (obj, false); + ig.release (); + } + } + + // + // object_result_iterator + // + + template + void object_result_iterator:: + load (object_type& obj) + { + if (res_->end ()) + return; + + typedef odb::object_traits object_traits; + + typename object_traits::reference_cache_traits::insert_guard ig ( + object_traits::reference_cache_traits::insert ( + res_->database (), res_->load_id (), obj)); + res_->load (obj, false); + ig.release (); + } +} diff --git a/odb/tr1/pointer-traits.hxx b/odb/tr1/pointer-traits.hxx index 12e1164..310c448 100644 --- a/odb/tr1/pointer-traits.hxx +++ b/odb/tr1/pointer-traits.hxx @@ -61,11 +61,25 @@ namespace odb } static unrestricted_pointer_type - cast (const pointer_type& p) + const_pointer_cast (const pointer_type& p) { return std::tr1::const_pointer_cast (p); } + template + static std::tr1::shared_ptr + static_pointer_cast (const pointer_type& p) + { + return std::tr1::static_pointer_cast (p); + } + + template + static std::tr1::shared_ptr + dynamic_pointer_cast (const pointer_type& p) + { + return std::tr1::dynamic_pointer_cast (p); + } + public: static void* allocate (std::size_t n) diff --git a/odb/traits.hxx b/odb/traits.hxx index 4c71f94..0743dba 100644 --- a/odb/traits.hxx +++ b/odb/traits.hxx @@ -138,6 +138,8 @@ namespace odb typedef typename access::object_traits::object_type object_type; typedef typename pointer_traits::const_pointer_type const_pointer_type; typedef const_pointer_type pointer_type; + + static const bool polymorphic = access::object_traits::polymorphic; }; // Specializations for pointer types to allow the C++ compiler to diff --git a/odb/view-result.hxx b/odb/view-result.hxx index dbe77a8..1fd30e0 100644 --- a/odb/view-result.hxx +++ b/odb/view-result.hxx @@ -12,6 +12,7 @@ #include // std::move #include +#include #include #include -- cgit v1.1