diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2012-04-23 16:48:00 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2012-04-23 16:48:00 +0200 |
commit | 1896d36996ab48ed7271e855d7e32b4e61f64896 (patch) | |
tree | 6d085eb0349d23bc26fe101b2451235939f17d40 | |
parent | c2be6303f97e470960ee77805128c46d3ea5c102 (diff) |
Polymorphic inheritance support
-rw-r--r-- | odb/cache-traits.hxx | 322 | ||||
-rw-r--r-- | odb/database.ixx | 88 | ||||
-rw-r--r-- | odb/database.txx | 162 | ||||
-rw-r--r-- | odb/exceptions.cxx | 12 | ||||
-rw-r--r-- | odb/exceptions.hxx | 17 | ||||
-rw-r--r-- | odb/forward.hxx | 14 | ||||
-rw-r--r-- | odb/no-id-object-result.hxx | 191 | ||||
-rw-r--r-- | odb/no-id-object-result.txx | 28 | ||||
-rw-r--r-- | odb/object-result.hxx | 358 | ||||
-rw-r--r-- | odb/object-result.txx | 112 | ||||
-rw-r--r-- | odb/pointer-traits.hxx | 89 | ||||
-rw-r--r-- | odb/polymorphic-info.hxx | 118 | ||||
-rw-r--r-- | odb/polymorphic-map.hxx | 244 | ||||
-rw-r--r-- | odb/polymorphic-map.ixx | 20 | ||||
-rw-r--r-- | odb/polymorphic-map.txx | 72 | ||||
-rw-r--r-- | odb/polymorphic-object-result.hxx | 233 | ||||
-rw-r--r-- | odb/polymorphic-object-result.txx | 76 | ||||
-rw-r--r-- | odb/query.hxx | 15 | ||||
-rw-r--r-- | odb/result.hxx | 9 | ||||
-rw-r--r-- | odb/session.txx | 2 | ||||
-rw-r--r-- | odb/simple-object-result.hxx | 210 | ||||
-rw-r--r-- | odb/simple-object-result.txx | 65 | ||||
-rw-r--r-- | odb/tr1/pointer-traits.hxx | 16 | ||||
-rw-r--r-- | odb/traits.hxx | 2 | ||||
-rw-r--r-- | odb/view-result.hxx | 1 |
25 files changed, 1725 insertions, 751 deletions
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 <typename P, typename ID, pointer_kind kind> - struct pointer_cache_traits_impl; + // Used to convert an object pointer to the canonical form (non-const), + // suitable for insertion into the cache. + // + template <typename P, + typename E = typename pointer_traits<P>::element_type, + typename O = typename object_traits<E>::object_type, + pointer_kind pk = pointer_traits<P>::kind> + struct pointer_cache_type + { + typedef typename object_traits<O>::pointer_type pointer_type; + + static pointer_type + convert (const P& p) + { + return pointer_traits<P>::const_pointer_cast (p); + } + }; + + template <typename P, typename T, pointer_kind pk> + struct pointer_cache_type<P, T, T, pk> + { + // 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 <typename P, typename E, typename O> + struct pointer_cache_type<P, E, O, pk_unique> + { + // 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<O>::pointer_type pointer_type; + + static pointer_type + convert (const P&) {return pointer_type ();} + }; + + template <typename P, typename T> + struct pointer_cache_type<P, T, T, pk_unique> + { + typedef typename object_traits<T>::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 <typename T, + typename O = typename object_traits<T>::object_type> + struct reference_cache_type + { + static O& + convert (T& r) + { + return const_cast<O&> (r); + } + }; + + template <typename T> + struct reference_cache_type<T, T> + { + // 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 <typename P> + 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 <typename P> - struct pointer_cache_traits: pointer_cache_traits_impl< - P, - typename object_traits<typename pointer_traits<P>::element_type>::id_type, - pointer_traits<P>::kind> + struct no_op_pointer_cache_traits { + typedef P pointer_type; + typedef typename pointer_traits<pointer_type>::element_type object_type; + typedef typename object_traits<object_type>::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 <typename P, typename ID, pointer_kind kind> + template <typename P, pointer_kind pk> struct pointer_cache_traits_impl { typedef P pointer_type; typedef odb::pointer_traits<pointer_type> 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<element_type>::object_type object_type; - typedef typename object_traits<element_type>::id_type id_type; + typedef typename pointer_traits::element_type object_type; + typedef typename object_traits<object_type>::id_type id_type; typedef session::object_position<object_type> 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<object_type> ( - db, id, pointer_traits::cast (p)); - } + return session::current ().insert<object_type> (db, id, p); else return position_type (); } @@ -109,102 +229,45 @@ namespace odb } }; - template <typename P, pointer_kind kind> - struct pointer_cache_traits_impl<P, void, kind> - { - 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 <typename P, typename ID> - struct pointer_cache_traits_impl<P, ID, pk_unique> - { - typedef P pointer_type; - typedef typename pointer_traits<pointer_type>::element_type element_type; - typedef typename object_traits<element_type>::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 <typename P> + struct pointer_cache_traits_impl<P, pk_unique>: + no_op_pointer_cache_traits<P> {}; template <typename P> - struct pointer_cache_traits_impl<P, void, pk_unique> + struct pointer_cache_traits: + pointer_cache_traits_impl<P, pointer_traits<P>::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 <typename T> + 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 <typename T, typename ID, pointer_kind kind> - struct reference_cache_traits_impl; - template <typename T> - struct reference_cache_traits: reference_cache_traits_impl< - T, - typename object_traits<T>::id_type, - pointer_traits<typename object_traits<T>::pointer_type>::kind> + struct no_op_reference_cache_traits { - }; - - template <typename T, typename ID, pointer_kind kind> - struct reference_cache_traits_impl - { - typedef T element_type; - typedef typename object_traits<element_type>::pointer_type pointer_type; - typedef typename object_traits<element_type>::id_type id_type; - - typedef - typename pointer_cache_traits<pointer_type>::position_type - position_type; + typedef T object_type; + typedef typename object_traits<object_type>::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 <typename T, pointer_kind kind> - struct reference_cache_traits_impl<T, void, kind> - { - typedef T element_type; - struct position_type {}; - - static position_type - insert (odb::database&, element_type&) - { - return position_type (); - } - }; + template <typename T, pointer_kind pk> + struct reference_cache_traits_impl: no_op_reference_cache_traits<T> {}; - template <typename T, typename ID> - struct reference_cache_traits_impl<T, ID, pk_raw> + template <typename T> + struct reference_cache_traits_impl<T, pk_raw> { - typedef T element_type; - typedef typename object_traits<element_type>::pointer_type pointer_type; - typedef typename object_traits<element_type>::id_type id_type; - - typedef - typename pointer_cache_traits<pointer_type>::position_type - position_type; + typedef T object_type; + typedef typename object_traits<object_type>::pointer_type pointer_type; + typedef typename object_traits<object_type>::id_type id_type; - typedef - typename pointer_cache_traits<pointer_type>::insert_guard - insert_guard; + typedef pointer_cache_traits<pointer_type> 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<pointer_type>::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<pointer_type>::insert (db, p); + return pointer_traits::insert (db, p); } }; template <typename T> - struct reference_cache_traits_impl<T, void, pk_raw> - { - 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<typename object_traits<T>::pointer_type>::kind> {}; } #include <odb/post.hxx> 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 <cstring> // std::string +#include <cstring> // std::strlen() namespace odb { @@ -105,6 +105,28 @@ namespace odb } template <typename T> + inline typename object_traits<T>::pointer_type database:: + find (const typename object_traits<T>::id_type& id) + { + // T is always object_type. + // + + // Compiler error pointing here? Perhaps the object doesn't have the + // default constructor? + // + return object_traits<T>::find (*this, id); + } + + template <typename T> + inline bool database:: + find (const typename object_traits<T>::id_type& id, T& obj) + { + // T is always object_type. + // + return object_traits<T>::find (*this, id, obj); + } + + template <typename T> inline void database:: reload (T* p) { @@ -218,6 +240,41 @@ namespace odb template <typename T> inline void database:: + update (T& obj) + { + // T can be const T while object_type will always be T. + // + typedef typename odb::object_traits<T>::object_type object_type; + typedef odb::object_traits<object_type> 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 <typename T> + inline void database:: + update_ (const typename object_traits<T>::pointer_type& pobj) + { + // T can be const T while object_type will always be T. + // + typedef typename odb::object_traits<T>::object_type object_type; + typedef odb::object_traits<object_type> object_traits; + + typedef typename odb::object_traits<T>::pointer_type pointer_type; + typedef odb::pointer_traits<pointer_type> 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 <typename T> + inline void database:: erase (T* p) { typedef typename object_traits<T>::pointer_type object_pointer; @@ -295,6 +352,26 @@ namespace odb } template <typename T> + inline void database:: + erase (const typename object_traits<T>::id_type& id) + { + // T is always object_type. + // + object_traits<T>::erase (*this, id); + } + + template <typename T> + inline void database:: + erase (T& obj) + { + // T can be const T while object_type will always be T. + // + typedef typename object_traits<T>::object_type object_type; + + object_traits<object_type>::erase (*this, obj); + } + + template <typename T> inline unsigned long long database:: erase_query () { @@ -322,6 +399,15 @@ namespace odb } template <typename T> + inline unsigned long long database:: + erase_query (const odb::query<T>& q) + { + // T is always object_type. + // + return object_traits<T>::erase_query (*this, q); + } + + template <typename T> inline result<T> 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 <odb/exceptions.hxx> #include <odb/transaction.hxx> #include <odb/session.hxx> -#include <odb/callback.hxx> #include <odb/cache-traits.hxx> #include <odb/pointer-traits.hxx> @@ -20,14 +19,10 @@ namespace odb typedef typename odb::object_traits<T>::object_type object_type; typedef odb::object_traits<object_type> 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<T>::insert (*this, obj); + object_traits::reference_cache_traits::insert ( + *this, reference_cache_type<T>::convert (obj)); return object_traits::id (obj); } @@ -44,16 +39,13 @@ namespace odb typedef typename odb::object_traits<T>::pointer_type pointer_type; typedef odb::pointer_traits<pointer_type> 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<pointer_type>::insert (*this, pobj); + // Get the canonical object pointer and insert it into object cache. + // + object_traits::pointer_cache_traits::insert ( + *this, pointer_cache_type<pointer_type>::convert (pobj)); return object_traits::id (obj); } @@ -91,150 +83,14 @@ namespace odb // typedef odb::object_traits<T> 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 T> - typename object_traits<T>::pointer_type database:: - find (const typename object_traits<T>::id_type& id) - { - // T is always object_type. - // - typedef odb::object_traits<T> object_traits; - typedef typename object_traits::pointer_type pointer_type; - typedef odb::pointer_traits<pointer_type> pointer_traits; - - // First check the session. - // - { - pointer_type p ( - pointer_cache_traits<pointer_type>::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 <typename T> - bool database:: - find (const typename object_traits<T>::id_type& id, T& obj) - { - // T is always object_type. - // - if (!transaction::has_current ()) - throw not_in_transaction (); - - return object_traits<T>::find (*this, id, obj); - } - - template <typename T> - void database:: - update (T& obj) - { - // T can be const T while object_type will always be T. - // - typedef typename odb::object_traits<T>::object_type object_type; - typedef odb::object_traits<object_type> 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 <typename T> - void database:: - update_ (const typename object_traits<T>::pointer_type& pobj) - { - // T can be const T while object_type will always be T. - // - typedef typename odb::object_traits<T>::object_type object_type; - typedef odb::object_traits<object_type> object_traits; - - typedef typename odb::object_traits<T>::pointer_type pointer_type; - typedef odb::pointer_traits<pointer_type> 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 <typename T> - void database:: - erase (const typename object_traits<T>::id_type& id) - { - // T is always object_type. - // - typedef odb::object_traits<T> 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<pointer_type>::erase (*this, id); - } - - template <typename T> - void database:: - erase (T& obj) - { - // T can be const T while object_type will always be T. - // - typedef typename odb::object_traits<T>::object_type object_type; - typedef odb::object_traits<object_type> 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<pointer_type>::erase (*this, id); - object_traits::callback (*this, obj, callback_event::post_erase); - } - - template <typename T> - unsigned long long database:: - erase_query (const odb::query<T>& q) - { - // T is always object_type. - // - if (!transaction::has_current ()) - throw not_in_transaction (); - - return object_traits<T>::erase_query (*this, q); - } - - template <typename T> struct database::query_<T, class_object> { static result<T> 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 <typename T> struct view_traits; + // Cache traits. + // + template <typename T> struct no_id_pointer_cache_traits; + template <typename T> struct no_op_pointer_cache_traits; + template <typename T> struct pointer_cache_traits; + template <typename T> struct no_id_reference_cache_traits; + template <typename T> struct no_op_reference_cache_traits; + template <typename T> struct reference_cache_traits; + + // Polymorphism support. + // + template <typename R> + 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 <odb/pre.hxx> + +#include <cstddef> // std::size_t +#include <utility> // std::move + +#include <odb/forward.hxx> +#include <odb/traits.hxx> +#include <odb/result.hxx> +#include <odb/object-result.hxx> +#include <odb/pointer-traits.hxx> + +#include <odb/details/config.hxx> // ODB_CXX11 +#include <odb/details/shared-ptr.hxx> + +namespace odb +{ + // Implementation for objects without object id (always non-polymorphic). + // + template <typename T> + 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_type> object_traits; + + typedef typename object_traits::pointer_type pointer_type; + typedef odb::pointer_traits<pointer_type> pointer_traits; + + friend class result<T>; + friend class result<const T>; + friend class result_iterator<T, class_object>; + friend class result_iterator<const T, class_object>; + friend class object_result_iterator<T, void, false>; + friend class object_result_iterator<const T, void, false>; + + 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 <typename T> + class object_result_iterator<T, void, false> + { + public: + // T can be const T while object_type is always non-const. + // + typedef typename object_traits<T>::object_type object_type; + + typedef no_id_object_result_impl<object_type> result_impl_type; + + public: + object_result_iterator (result_impl_type* res) + : res_ (res) + { + } + + public: + typename object_traits<T>::pointer_type + load () + { + typename object_traits<T>::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 <odb/no-id-object-result.txx> + +#include <odb/post.hxx> + +#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 <typename T> + no_id_object_result_impl<T>:: + ~no_id_object_result_impl () + { + } + + template <typename T> + void no_id_object_result_impl<T>:: + 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 <odb/pre.hxx> -#include <cstddef> // std::ptrdiff_t, std::size_t +#include <cstddef> // std::ptrdiff_t #include <iterator> // iterator categories -#include <utility> // std::move #include <odb/forward.hxx> +#include <odb/traits.hxx> #include <odb/result.hxx> #include <odb/pointer-traits.hxx> -#include <odb/details/config.hxx> // ODB_CXX11 -#include <odb/details/shared-ptr.hxx> - namespace odb { + // + // object_result_impl + // template <typename T> class object_result_impl; template <typename T> - class object_result_impl_no_id; + class polymorphic_object_result_impl; - template <typename T, typename ID> - class object_result_iterator; + template <typename T> + class no_id_object_result_impl; + + // + // object_result_impl_selector + // + template <typename T, + typename ID = typename object_traits<T>::id_type, + bool polymorphic = object_traits<T>::polymorphic> + struct object_result_impl_selector; - template <typename T, typename ID = typename object_traits<T>::id_type> - struct object_result_impl_selector + template <typename T, typename ID> + struct object_result_impl_selector<T, ID, false> { typedef object_result_impl<T> type; }; - template <typename T> - struct object_result_impl_selector<T, void> + template <typename T, typename ID> + struct object_result_impl_selector<T, ID, true> { - typedef object_result_impl_no_id<T> type; + typedef polymorphic_object_result_impl<T> type; }; - // Implementation for objects with object id. - // template <typename T> - class object_result_impl: public details::shared_base + struct object_result_impl_selector<T, void, false> { - 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_type> object_traits; - typedef typename object_traits::id_type id_type; - - typedef typename object_traits::pointer_type pointer_type; - typedef odb::pointer_traits<pointer_type> pointer_traits; - - friend class result<T>; - friend class result<const T>; - friend class result_iterator<T, class_object>; - friend class result_iterator<const T, class_object>; - friend class object_result_iterator<T, id_type>; - friend class object_result_iterator<const T, id_type>; - - 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 <typename T> - 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_type> object_traits; - - typedef typename object_traits::pointer_type pointer_type; - typedef odb::pointer_traits<pointer_type> pointer_traits; - - friend class result<T>; - friend class result<const T>; - friend class result_iterator<T, class_object>; - friend class result_iterator<const T, class_object>; - friend class object_result_iterator<T, void>; - friend class object_result_iterator<const T, void>; - - 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<T> type; }; // // result_iterator // - template <typename T, typename ID> - class object_result_iterator - { - public: - // T can be const T while object_type is always non-const. - // - typedef typename object_traits<T>::object_type object_type; - typedef typename object_traits<T>::id_type id_type; - - typedef object_result_impl<object_type> result_impl_type; - - public: - object_result_iterator (result_impl_type* res) - : res_ (res) - { - } - - public: - typename object_traits<T>::pointer_type - load () - { - typename object_traits<T>::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 <typename T> - class object_result_iterator<T, void> - { - public: - // T can be const T while object_type is always non-const. - // - typedef typename object_traits<T>::object_type object_type; - - typedef object_result_impl_no_id<object_type> result_impl_type; - - public: - object_result_iterator (result_impl_type* res) - : res_ (res) - { - } - - public: - typename object_traits<T>::pointer_type - load () - { - typename object_traits<T>::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 <typename T, typename ID, bool polymorphic> + class object_result_iterator; template <typename T> class result_iterator<T, class_object>: public object_result_iterator< T, - typename object_traits<T>::id_type> + typename object_traits<T>::id_type, + object_traits<T>::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<T, typename object_traits<T>::id_type> - base_type; + object_result_iterator<T, + typename object_traits<T>::id_type, + object_traits<T>::polymorphic> base_type; public: explicit @@ -456,8 +160,6 @@ namespace odb }; } -#include <odb/object-result.txx> - #include <odb/post.hxx> #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 <odb/session.hxx> -#include <odb/cache-traits.hxx> - -namespace odb -{ - // - // object_result_impl - // - - template <typename T> - object_result_impl<T>:: - ~object_result_impl () - { - } - - template <typename T> - typename object_result_impl<T>::pointer_type& - object_result_impl<T>:: - 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<pointer_type>::find (database (), id)); - - if (!pointer_traits::null_ptr (p)) - current (p); - else - { - pointer_type p (object_traits::create ()); - - typename pointer_cache_traits<pointer_type>::insert_guard ig ( - pointer_cache_traits<pointer_type>::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 <typename T> - object_result_impl_no_id<T>:: - ~object_result_impl_no_id () - { - } - - template <typename T> - typename object_result_impl_no_id<T>::pointer_type& - object_result_impl_no_id<T>:: - 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 <typename T, typename ID> - void object_result_iterator<T, ID>:: - load (object_type& obj) - { - if (res_->end ()) - return; - - if (!session::has_current ()) - res_->load (obj); - else - { - typename reference_cache_traits<object_type>::insert_guard ig ( - reference_cache_traits<object_type>::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<unrestricted_pointer_type> (p); } + template <typename T1> + static T1* + static_pointer_cast (pointer_type p) + { + return static_cast<T1*> (p); + } + + template <typename T1> + static T1* + dynamic_pointer_cast (pointer_type p) + { + return dynamic_cast<T1*> (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 <typename T1> + static std::auto_ptr<T1> + static_pointer_cast (pointer_type& p) + { + return std::auto_ptr<T1> (static_cast<T1*> (p.release ())); + } + + // Note: transfers ownership if successful. + // + template <typename T1> + static std::auto_ptr<T1> + dynamic_pointer_cast (pointer_type& p) + { + T1* p1 (dynamic_cast<T1*> (p.get ())); + + if (p1 != 0) + p.release (); + + return std::auto_ptr<T1> (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 <typename T1> + static std::unique_ptr<T1> + static_pointer_cast (pointer_type& p) + { + return std::unique_ptr<T1> (static_cast<T1*> (p.release ())); + } + + // Note: transfers ownership if successful. + // + template <typename T1> + static std::unique_ptr<T1> + dynamic_pointer_cast (pointer_type& p) + { + T1* p1 (dynamic_cast<T1*> (p.get ())); + + if (p1 != 0) + p.release (); + + return std::unique_ptr<T1> (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<unrestricted_element_type> (p); } + template <typename T1> + static std::shared_ptr<T1> + static_pointer_cast (const pointer_type& p) + { + return std::static_pointer_cast<T1> (p); + } + + template <typename T1> + static std::shared_ptr<T1> + dynamic_pointer_cast (const pointer_type& p) + { + return std::dynamic_pointer_cast<T1> (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 <odb/pre.hxx> + +#include <odb/forward.hxx> // database +#include <odb/traits.hxx> + +namespace odb +{ + template <typename R> + 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 <typename R> + struct polymorphic_concrete_info: polymorphic_abstract_info<R> + { + typedef R root_type; + typedef object_traits<root_type> 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<R>* b, + const discriminator_type& d, + create_function cf, + dispatch_function df, + delayed_loader_function dlf) + : polymorphic_abstract_info<R> (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 <typename T> + struct polymorphic_entry + { + typedef T object_type; + typedef odb::object_traits<object_type> object_traits; + + typedef typename object_traits::root_type root_type; + typedef odb::object_traits<root_type> 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 <typename R> + inline const polymorphic_concrete_info<R>* + polymorphic_info (const polymorphic_concrete_info<R>& i) + { + return &i; + } + + template <typename R> + inline const polymorphic_concrete_info<R>* + polymorphic_info (const polymorphic_abstract_info<R>&) + { + return 0; + } +} + +#include <odb/post.hxx> + +#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 <odb/pre.hxx> + +#include <map> +#include <utility> // std::move +#include <cstddef> // std::size_t +#include <cassert> +#include <typeinfo> + +#include <odb/callback.hxx> + +#include <odb/details/config.hxx> // ODB_CXX11 +#include <odb/details/type-info.hxx> + +#include <odb/polymorphic-info.hxx> + +namespace odb +{ + template <typename R> + struct polymorphic_map + { + typedef R root_type; + typedef polymorphic_concrete_info<root_type> 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<const std::type_info*, + const info_type*, + details::type_info_comparator> + type_map; + + struct discriminator_comparator + { + bool + operator() (const discriminator_type* x, + const discriminator_type* y) const + { + return *x < *y; + } + }; + + typedef + std::map<const discriminator_type*, + const info_type*, + discriminator_comparator> + discriminator_map; + + public: + std::size_t ref_count_; + type_map type_map_; + discriminator_map discriminator_map_; + }; + + template <typename R> + struct polymorphic_entry_impl + { + typedef R root_type; + typedef object_traits<root_type> root_traits; + typedef polymorphic_concrete_info<root_type> info_type; + + static void + insert (const info_type&); + + static void + erase (const info_type&); + }; + + template <typename T> + typename object_traits<typename object_traits<T>::root_type>::pointer_type + create_impl () + { + typedef object_traits<T> derived_traits; + typedef object_traits<typename derived_traits::root_type> 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<T, derived_pointer_type>::create ()); + + // Implicit downcast. + // +#ifdef ODB_CXX11 + root_pointer_type r (std::move (p)); +#else + root_pointer_type r (p); +#endif + return r; + } + + template <typename T, typename R> + struct dispatch_load + { + static void + call (database& db, T& obj, std::size_t d) + { + object_traits<T>::load_ (db, obj, d); + } + }; + + template <typename R> + struct dispatch_load<R, R> + { + static void + call (database&, R&, std::size_t) + { + assert (false); + } + }; + + template <typename T, bool auto_id> + struct dispatch_persist + { + static void + call (database& db, const T& obj) + { + // Top-level call, no dynamic type checking. + // + object_traits<T>::persist (db, obj, true, false); + } + }; + + template <typename T> + struct dispatch_persist<T, true> + { + static void + call (database& db, const T& obj) + { + // Top-level call, no dynamic type checking. + // + object_traits<T>::persist (db, const_cast<T&> (obj), true, false); + } + }; + + template <typename T> + bool dispatch_impl ( + typename polymorphic_concrete_info< + typename object_traits<T>::root_type>::call_type c, + database& db, + const typename object_traits<T>::root_type* pobj, + const void* arg) + { + typedef object_traits<T> derived_traits; + typedef typename derived_traits::root_type root_type; + typedef object_traits<root_type> root_traits; + typedef typename root_traits::id_type id_type; + typedef polymorphic_concrete_info<root_type> info_type; + + bool r (false); + + switch (c) + { + case info_type::call_callback: + { + derived_traits::callback ( + db, + *const_cast<T*> (static_cast<const T*> (pobj)), + *static_cast<const callback_event*> (arg)); + break; + } + case info_type::call_persist: + { + dispatch_persist<T, root_traits::auto_id>::call ( + db, + *static_cast<const T*> (pobj)); + break; + } + case info_type::call_update: + { + derived_traits::update ( + db, + *static_cast<const T*> (pobj), + true, // Top-level call. + false); // No dynamic type checking. + break; + } + case info_type::call_find: + { + r = derived_traits::find ( + db, + *static_cast<const id_type*> (arg), + *const_cast<T*> (static_cast<const T*> (pobj)), + false); // No dynamic type checking. + break; + } + case info_type::call_reload: + { + r = derived_traits::reload ( + db, + *const_cast<T*> (static_cast<const T*> (pobj)), + false); // No dynamic type checking. + break; + } + case info_type::call_load: + { + dispatch_load<T, root_type>::call ( + db, + *const_cast<T*> (static_cast<const T*> (pobj)), + *static_cast<const std::size_t*> (arg)); + break; + } + case info_type::call_erase: + { + if (pobj != 0) + derived_traits::erase ( + db, + *static_cast<const T*> (pobj), + true, // Top-level call. + false); // No dynamic type checking. + else + derived_traits::erase ( + db, + *static_cast<const id_type*> (arg), + true, // Top-level call. + false); // No dynamic type checking. + break; + } + } + + return r; + } +} + +#include <odb/polymorphic-map.ixx> +#include <odb/polymorphic-map.txx> + +#include <odb/post.hxx> + +#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 <typename T> + inline polymorphic_entry<T>:: + polymorphic_entry () + { + polymorphic_entry_impl<root_type>::insert (object_traits::info); + } + + template <typename T> + inline polymorphic_entry<T>:: + ~polymorphic_entry () + { + polymorphic_entry_impl<root_type>::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 <odb/exceptions.hxx> // no_type_info + +namespace odb +{ + // + // polymorphic_map + // + + template <typename R> + const typename polymorphic_map<R>::info_type& polymorphic_map<R>:: + 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 <typename R> + const typename polymorphic_map<R>::info_type& polymorphic_map<R>:: + 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 <typename R> + void polymorphic_entry_impl<R>:: + insert (const info_type& i) + { + polymorphic_map<root_type>*& pm (root_traits::map); + + if (pm == 0) + pm = new polymorphic_map<root_type>; + else + pm->ref_count_++; + + pm->type_map_[&i.type] = &i; + pm->discriminator_map_[&i.discriminator] = &i; + } + + template <typename R> + void polymorphic_entry_impl<R>:: + erase (const info_type& i) + { + polymorphic_map<root_type>*& 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 <odb/pre.hxx> + +#include <cstddef> // std::size_t +#include <utility> // std::move + +#include <odb/forward.hxx> +#include <odb/traits.hxx> +#include <odb/result.hxx> +#include <odb/object-result.hxx> +#include <odb/pointer-traits.hxx> + +#include <odb/details/config.hxx> // ODB_CXX11 +#include <odb/details/shared-ptr.hxx> + +namespace odb +{ + // Implementation for polymorphic objects with object id. + // + template <typename T> + 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_type> object_traits; + typedef typename object_traits::id_type id_type; + + typedef typename object_traits::pointer_type pointer_type; + typedef odb::pointer_traits<pointer_type> pointer_traits; + + typedef typename object_traits::root_type root_type; + typedef odb::object_traits<root_type> root_traits; + typedef typename root_traits::discriminator_type discriminator_type; + + friend class result<T>; + friend class result<const T>; + friend class result_iterator<T, class_object>; + friend class result_iterator<const T, class_object>; + friend class object_result_iterator<T, id_type, true>; + friend class object_result_iterator<const T, id_type, true>; + + 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 <typename T, typename ID> + class object_result_iterator<T, ID, true> + { + public: + // T can be const T while object_type is always non-const. + // + typedef typename object_traits<T>::object_type object_type; + typedef typename object_traits<T>::id_type id_type; + typedef typename object_traits<T>::root_type root_type; + typedef typename object_traits<root_type>::discriminator_type + discriminator_type; + + typedef polymorphic_object_result_impl<object_type> result_impl_type; + + public: + object_result_iterator (result_impl_type* res) + : res_ (res) + { + } + + public: + typename object_traits<T>::pointer_type + load () + { + typename object_traits<T>::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 <odb/polymorphic-object-result.txx> + +#include <odb/post.hxx> + +#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 <odb/cache-traits.hxx> +#include <odb/exceptions.hxx> + +namespace odb +{ + // + // polymorphic_object_result_impl + // + + template <typename T> + polymorphic_object_result_impl<T>:: + ~polymorphic_object_result_impl () + { + } + + template <typename T> + void polymorphic_object_result_impl<T>:: + 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 <typename T, typename ID> + void object_result_iterator<T, ID, true>:: + load (object_type& obj) + { + if (res_->end ()) + return; + + typedef odb::object_traits<object_type> 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 <typename T, typename Tag, bool dummy = true> + struct alias_traits; + template <typename T> struct query_columns_base; - template <typename T, const char* table> + template <typename T, typename Alias> struct query_columns; - template <typename T, const char* table> + template <typename T, typename Alias> 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 <cstddef> // std::ptrdiff_t, std::size_t -#include <odb/forward.hxx> // result +#include <odb/forward.hxx> #include <odb/traits.hxx> namespace odb @@ -190,10 +190,3 @@ namespace odb #include <odb/post.hxx> #endif // ODB_RESULT_HXX - -// Include result specializations so that the user code only needs -// to include this header. -// - -#include <odb/object-result.hxx> -#include <odb/view-result.hxx> 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<typename object_map<T>::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 <odb/pre.hxx> + +#include <cstddef> // std::size_t +#include <utility> // std::move + +#include <odb/forward.hxx> +#include <odb/traits.hxx> +#include <odb/result.hxx> +#include <odb/object-result.hxx> +#include <odb/pointer-traits.hxx> + +#include <odb/details/config.hxx> // ODB_CXX11 +#include <odb/details/shared-ptr.hxx> + +namespace odb +{ + // Implementation for non-polymorphic objects with object id. + // + template <typename T> + 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_type> object_traits; + typedef typename object_traits::id_type id_type; + + typedef typename object_traits::pointer_type pointer_type; + typedef odb::pointer_traits<pointer_type> pointer_traits; + + friend class result<T>; + friend class result<const T>; + friend class result_iterator<T, class_object>; + friend class result_iterator<const T, class_object>; + friend class object_result_iterator<T, id_type, false>; + friend class object_result_iterator<const T, id_type, false>; + + 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 <typename T, typename ID> + class object_result_iterator<T, ID, false> + { + public: + // T can be const T while object_type is always non-const. + // + typedef typename object_traits<T>::object_type object_type; + typedef typename object_traits<T>::id_type id_type; + + typedef object_result_impl<object_type> result_impl_type; + + public: + object_result_iterator (result_impl_type* res) + : res_ (res) + { + } + + public: + typename object_traits<T>::pointer_type + load () + { + typename object_traits<T>::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 <odb/simple-object-result.txx> + +#include <odb/post.hxx> + +#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 <odb/cache-traits.hxx> + +namespace odb +{ + // + // object_result_impl + // + + template <typename T> + object_result_impl<T>:: + ~object_result_impl () + { + } + + template <typename T> + void object_result_impl<T>:: + 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 <typename T, typename ID> + void object_result_iterator<T, ID, false>:: + load (object_type& obj) + { + if (res_->end ()) + return; + + typedef odb::object_traits<object_type> 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<unrestricted_element_type> (p); } + template <typename T1> + static std::tr1::shared_ptr<T1> + static_pointer_cast (const pointer_type& p) + { + return std::tr1::static_pointer_cast<T1> (p); + } + + template <typename T1> + static std::tr1::shared_ptr<T1> + dynamic_pointer_cast (const pointer_type& p) + { + return std::tr1::dynamic_pointer_cast<T1> (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<T>::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<T>::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 <utility> // std::move #include <odb/forward.hxx> +#include <odb/traits.hxx> #include <odb/result.hxx> #include <odb/pointer-traits.hxx> |