From 531c792dd4eecd246cc1ccebac812d6888464a78 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 22 Nov 2010 12:03:11 +0200 Subject: Add session, database operations on pointers and const objects Currently, session is just an object cache. The persist, update, and erase database operations are overloaded to also work on object pointers. All the database operations and the query facility now support const objects. New session-related exceptions: not_in_session, already_in_session, const_object. --- odb/cache-traits.hxx | 152 +++++++++++++++++++++++++++++++++++++++++++ odb/database.hxx | 70 ++++++++++++++++++-- odb/database.ixx | 177 +++++++++++++++++++++++++++++++++++++++++++++++++-- odb/database.txx | 115 +++++++++++++++++++++++++++------ odb/exceptions.cxx | 18 ++++++ odb/exceptions.hxx | 24 +++++++ odb/makefile | 1 + odb/result.hxx | 43 ++++++++++--- odb/result.txx | 72 ++++++++++++++++++++- odb/session.cxx | 72 +++++++++++++++++++++ odb/session.hxx | 159 +++++++++++++++++++++++++++++++++++++++++++++ odb/session.ixx | 65 +++++++++++++++++++ odb/session.txx | 116 +++++++++++++++++++++++++++++++++ odb/traits.hxx | 61 +++++++++++++++++- 14 files changed, 1103 insertions(+), 42 deletions(-) create mode 100644 odb/cache-traits.hxx create mode 100644 odb/session.cxx create mode 100644 odb/session.hxx create mode 100644 odb/session.ixx create mode 100644 odb/session.txx diff --git a/odb/cache-traits.hxx b/odb/cache-traits.hxx new file mode 100644 index 0000000..5d32624 --- /dev/null +++ b/odb/cache-traits.hxx @@ -0,0 +1,152 @@ +// file : odb/cache-traits.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_CACHE_TRAITS_HXX +#define ODB_CACHE_TRAITS_HXX + +#include + +#include +#include +#include + +namespace odb +{ + // Caching traits for objects passed by pointer. + // + template ::kind> + struct pointer_cache_traits + { + typedef P pointer_type; + typedef typename pointer_traits::element_type element_type; + typedef typename object_traits::id_type id_type; + typedef session::object_position position_type; + + struct insert_guard + { + insert_guard (const position_type& pos): pos_ (pos) {} + + ~insert_guard () + { + if (pos_.map_ != 0) + session::current ().erase (pos_); + } + + void + release () {pos_.map_ = 0;} + + private: + position_type pos_; + }; + + static position_type + insert (database& db, const id_type& id, const pointer_type& p) + { + if (session::has_current ()) + return session::current ().insert (db, id, p); + else + return position_type (); + } + + static pointer_type + find (database& db, const id_type& id) + { + if (session::has_current ()) + return session::current ().find (db, id); + else + return pointer_type (); + } + + static void + erase (database& db, const id_type& id) + { + if (session::has_current ()) + session::current ().erase (db, id); + } + }; + + // Unique pointers don't work with the object cache. + // + template + struct pointer_cache_traits + { + 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&) {} + void release () {} + }; + + static position_type + insert (database&, const id_type&, const pointer_type&) + { + return position_type (); + } + + static pointer_type + find (database&, const id_type&) { return pointer_type (); } + + static void + erase (database&, const id_type&) {} + }; + + // Caching traits for objects passed by reference. Only if the object + // pointer kind is naked do we add the object to the session. + // + template ::pointer_type>::kind> + struct reference_cache_traits + { + typedef T element_type; + typedef typename object_traits::pointer_type pointer_type; + typedef typename object_traits::id_type id_type; + + struct position_type {}; + + struct insert_guard + { + insert_guard (const position_type&) {} + void release () {} + }; + + static position_type + insert (database&, const id_type&, element_type&) + { + return position_type (); + } + }; + + template + struct reference_cache_traits + { + 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 + typename pointer_cache_traits::insert_guard + insert_guard; + + static position_type + insert (database& db, const id_type& id, element_type& obj) + { + pointer_type p (&obj); + return pointer_cache_traits::insert (db, id, p); + } + }; +} + +#include + +#endif // ODB_CACHE_TRAITS_HXX diff --git a/odb/database.hxx b/odb/database.hxx index 7db04c8..e7ea91a 100644 --- a/odb/database.hxx +++ b/odb/database.hxx @@ -36,11 +36,23 @@ namespace odb // template typename object_traits::id_type - persist (const T& object); + persist (T& object); template typename object_traits::id_type - persist (T& object); + persist (T* obj_ptr); + + template class P> + typename object_traits::id_type + persist (const P& obj_ptr); + + template class P> + typename object_traits::id_type + persist (P& obj_ptr); + + template + typename object_traits::id_type + persist (const typename object_traits::pointer_type& obj_ptr); // Throw object_not_persistent if not found. // @@ -66,18 +78,50 @@ namespace odb // template void - update (const T& object); + update (T& object); + + template + void + update (T* obj_ptr); + + template class P> + void + update (const P& obj_ptr); + + template class P> + void + update (P& obj_ptr); + + template + void + update (const typename object_traits::pointer_type& obj_ptr); // Make the object transient. Throw object_not_persistent if not // found. // template void - erase (const T& object); + erase (const typename object_traits::id_type& id); template void - erase (const typename object_traits::id_type& id); + erase (T& object); + + template + void + erase (T* obj_ptr); + + template class P> + void + erase (const P& obj_ptr); + + template class P> + void + erase (P& obj_ptr); + + template + void + erase (const typename object_traits::pointer_type& obj_ptr); // Query API. // @@ -95,7 +139,8 @@ namespace odb template result - query (const odb::query&, bool cache = true); + query (const odb::query::object_type>&, + bool cache = true); // Transaction API. // @@ -106,6 +151,19 @@ namespace odb protected: database (); + protected: + template + typename object_traits::id_type + persist_ (const typename object_traits::pointer_type&); + + template + void + update_ (const typename object_traits::pointer_type&); + + template + void + erase_ (const typename object_traits::pointer_type&); + private: database (const database&); database& operator= (const database&); diff --git a/odb/database.ixx b/odb/database.ixx index 8085210..86ccd15 100644 --- a/odb/database.ixx +++ b/odb/database.ixx @@ -11,30 +11,197 @@ namespace odb } template + inline typename object_traits::id_type database:: + persist (T* p) + { + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + return persist_ (pobj); + } + + template class P> + inline typename object_traits::id_type database:: + persist (const P& p) + { + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + return persist_ (pobj); + } + + template class P> + inline typename object_traits::id_type database:: + persist (P& p) + { + const P& cr (p); + return persist (cr); + } + + template + inline typename object_traits::id_type database:: + persist (const typename object_traits::pointer_type& pobj) + { + return persist_ (pobj); + } + + template inline void database:: - erase (const T& obj) + update (T* p) { - erase (object_traits::id (obj)); + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + update_ (pobj); + } + + template class P> + inline void database:: + update (const P& p) + { + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + update_ (pobj); + } + + template class P> + inline void database:: + update (P& p) + { + const P& cr (p); + update (cr); + } + + template + inline void database:: + update (const typename object_traits::pointer_type& pobj) + { + update_ (pobj); + } + + template + inline 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; + + erase (object_traits::id (obj)); + } + + template + inline void database:: + erase (T* p) + { + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + erase_ (pobj); + } + + template class P> + inline void database:: + erase (const P& p) + { + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + erase_ (pobj); + } + + template class P> + inline void database:: + erase (P& p) + { + const P& cr (p); + erase (cr); + } + + template + inline void database:: + erase (const typename object_traits::pointer_type& pobj) + { + erase_ (pobj); + } + + template + inline void database:: + erase_ (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; + + erase (object_traits::id (pointer_traits::get_ref (pobj))); } template inline result database:: query (bool cache) { - return query (odb::query (), cache); + // T can be const T while object_type will always be T. + // + typedef typename odb::object_traits::object_type object_type; + + return query (odb::query (), cache); } template inline result database:: query (const char* q, bool cache) { - return query (odb::query (q), cache); + // T can be const T while object_type will always be T. + // + typedef typename odb::object_traits::object_type object_type; + + return query (odb::query (q), cache); } template inline result database:: query (const std::string& q, bool cache) { - return query (odb::query (q), cache); + // T can be const T while object_type will always be T. + // + typedef typename odb::object_traits::object_type object_type; + + return query (odb::query (q), cache); } } diff --git a/odb/database.txx b/odb/database.txx index 31e9153..d98028d 100644 --- a/odb/database.txx +++ b/odb/database.txx @@ -5,43 +5,62 @@ #include #include +#include +#include +#include namespace odb { template typename object_traits::id_type database:: - persist (const T& obj) + persist (T& obj) { - typedef object_traits traits; + // 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 (); - traits::persist (*this, obj); - return traits::id (obj); + object_traits::persist (*this, obj); + const typename object_traits::id_type& id (object_traits::id (obj)); + reference_cache_traits::insert (*this, id, obj); + return id; } template typename object_traits::id_type database:: - persist (T& obj) + persist_ (const typename object_traits::pointer_type& pobj) { - typedef object_traits traits; + // 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 (); - traits::persist (*this, obj); - return traits::id (obj); + T& obj (pointer_traits::get_ref (pobj)); + object_traits::persist (*this, obj); + const typename object_traits::id_type& id (object_traits::id (obj)); + pointer_cache_traits::insert (*this, id, pobj); + return id; } template typename object_traits::pointer_type database:: load (const typename object_traits::id_type& id) { - typedef object_traits traits; - typename traits::pointer_type r (find (id)); + typedef typename object_traits::pointer_type pointer_type; + typedef odb::pointer_traits pointer_traits; + + pointer_type r (find (id)); - if (traits::pointer_traits::null_ptr (r)) + if (pointer_traits::null_ptr (r)) throw object_not_persistent (); return r; @@ -59,53 +78,113 @@ namespace odb typename object_traits::pointer_type database:: find (const typename object_traits::id_type& id) { + // T can be const T while object_type will always be T. + // + 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; + + // 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 object_traits::find (*this, id); + return pointer_type (object_traits::find (*this, id)); } template bool database:: find (const typename object_traits::id_type& id, 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 (); + + 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 (); - return object_traits::find (*this, id, obj); + object_traits::update (*this, obj); } template void database:: - update (const T& obj) + 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 (); - object_traits::update (*this, obj); + object_traits::update (*this, pointer_traits::get_ref (pobj)); } template void database:: erase (const typename object_traits::id_type& id) { + // 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; + if (!transaction::has_current ()) throw not_in_transaction (); - object_traits::erase (*this, id); + object_traits::erase (*this, id); + pointer_cache_traits::erase (*this, id); } template result database:: - query (const odb::query& q, bool cache) + query (const odb::query::object_type>& q, + bool cache) { + // 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 (); - result r (object_traits::query (*this, q)); + result r (object_traits::template query (*this, q)); if (cache) r.cache (); diff --git a/odb/exceptions.cxx b/odb/exceptions.cxx index c480125..a41f719 100644 --- a/odb/exceptions.cxx +++ b/odb/exceptions.cxx @@ -25,6 +25,24 @@ namespace odb return "transaction already committed or rolled back"; } + const char* already_in_session:: + what () const throw () + { + return "session already in effect in this thread"; + } + + const char* not_in_session:: + what () const throw () + { + return "session not in effect in this thread"; + } + + const char* const_object:: + what () const throw () + { + return "object cached in session is const"; + } + const char* deadlock:: what () const throw () { diff --git a/odb/exceptions.hxx b/odb/exceptions.hxx index 91fa5ab..26550cb 100644 --- a/odb/exceptions.hxx +++ b/odb/exceptions.hxx @@ -14,6 +14,8 @@ namespace odb { + // Transaction exceptions. + // struct LIBODB_EXPORT already_in_transaction: odb::exception { virtual const char* @@ -32,6 +34,28 @@ namespace odb what () const throw (); }; + // Session exceptions. + // + struct LIBODB_EXPORT already_in_session: odb::exception + { + virtual const char* + what () const throw (); + }; + + struct LIBODB_EXPORT not_in_session: odb::exception + { + virtual const char* + what () const throw (); + }; + + struct LIBODB_EXPORT const_object: odb::exception + { + virtual const char* + what () const throw (); + }; + + // Database operations exceptions. + // struct LIBODB_EXPORT deadlock: odb::exception { virtual const char* diff --git a/odb/makefile b/odb/makefile index 6e8790f..2569de5 100644 --- a/odb/makefile +++ b/odb/makefile @@ -8,6 +8,7 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make cxx := \ exceptions.cxx \ database.cxx \ +session.cxx \ transaction.cxx # Implementation details. diff --git a/odb/result.hxx b/odb/result.hxx index 42acb0e..e87374e 100644 --- a/odb/result.hxx +++ b/odb/result.hxx @@ -30,15 +30,30 @@ namespace odb public: virtual ~result_impl (); - result_impl () : end_ (false), current_ () {} protected: friend class result; friend class result_iterator; - typedef object_traits traits; - typedef typename traits::pointer_type pointer_type; - typedef typename traits::pointer_traits pointer_traits; + typedef odb::database database_type; + + typedef typename odb::object_traits::pointer_type pointer_type; + typedef odb::pointer_traits pointer_traits; + + typedef typename odb::object_traits::object_type object_type; + typedef typename odb::object_traits::id_type id_type; + typedef odb::object_traits object_traits; + + result_impl (database_type& db) + : end_ (false), db_ (db), current_ () + { + } + + database_type& + database () const + { + return db_; + } // To make this work with all kinds of pointers (naked, std::auto_ptr, // shared), we need to make sure we don't make any copies of the @@ -62,7 +77,10 @@ namespace odb protected: virtual void - current (T&) = 0; + current (object_type&) = 0; + + virtual id_type + current_id () = 0; virtual void next () = 0; @@ -84,6 +102,7 @@ namespace odb bool end_; private: + database_type& db_; pointer_type current_; typename pointer_traits::guard_type guard_; }; @@ -98,6 +117,11 @@ namespace odb typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; + // T might be const T, but object_type is always T. + // + typedef typename object_traits::object_type object_type; + typedef typename object_traits::id_type id_type; + public: explicit result_iterator (result_impl* res = 0) @@ -150,10 +174,7 @@ namespace odb } void - load (T& x) - { - res_->current (x); - } + load (object_type&); public: bool @@ -163,7 +184,9 @@ namespace odb } private: - typedef typename object_traits::pointer_traits pointer_traits; + typedef + odb::pointer_traits::pointer_type> + pointer_traits; result_impl* res_; }; diff --git a/odb/result.txx b/odb/result.txx index 3068890..603ee54 100644 --- a/odb/result.txx +++ b/odb/result.txx @@ -3,6 +3,9 @@ // copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file +#include +#include + namespace odb { template @@ -15,12 +18,77 @@ namespace odb typename result_impl::pointer_type& result_impl:: current () { + typedef typename object_traits::pointer_type unrestricted_pointer_type; + typedef typename object_traits::pointer_traits unrestricted_pointer_traits; + if (pointer_traits::null_ptr (current_) && !end_) { - current (traits::create ()); - current (pointer_traits::get_ref (current_)); + if (!session::has_current ()) + { + // Non-const pointer. + // + unrestricted_pointer_type p (object_traits::create ()); + object_type& r (unrestricted_pointer_traits::get_ref (p)); + + current (pointer_type (p)); + current (r); + } + else + { + const id_type& id (current_id ()); + + // First check the session. + // + pointer_type p ( + pointer_cache_traits::find (database (), id)); + + if (!pointer_traits::null_ptr (p)) + current (p); + else + { + unrestricted_pointer_type up (object_traits::create ()); + + typename + pointer_cache_traits::insert_guard ig ( + pointer_cache_traits::insert ( + database (), id, up)); + + object_type& r (unrestricted_pointer_traits::get_ref (up)); + + current (pointer_type (up)); + current (r); + + ig.release (); + } + } } return current_; } + + // + // result_iterator + // + + template + void result_iterator:: + load (object_type& x) + { + if (res_->end ()) + return; + + if (!session::has_current ()) + res_->current (x); + else + { + const id_type& id (res_->current_id ()); + + typename reference_cache_traits::insert_guard ig ( + reference_cache_traits::insert ( + res_->database (), id, x)); + + res_->current (x); + ig.release (); + } + } } diff --git a/odb/session.cxx b/odb/session.cxx new file mode 100644 index 0000000..b34c1d7 --- /dev/null +++ b/odb/session.cxx @@ -0,0 +1,72 @@ +// file : odb/session.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include +#include + +#include + +namespace odb +{ + using namespace details; + + static ODB_TLS_POINTER (session) current_session; + + session:: + session () + { + if (has_current ()) + throw already_in_session (); + + current (*this); + } + + session:: + ~session () + { + // If we are the current thread's session, reset it. + // + if (has_current () && ¤t () == this) + reset_current (); + } + + bool session:: + has_current () + { + return tls_get (current_session) != 0; + } + + session& session:: + current () + { + session* cur (tls_get (current_session)); + + if (cur == 0) + throw not_in_session (); + + return *cur; + } + + void session:: + current (session& s) + { + tls_set (current_session, &s); + } + + void session:: + reset_current () + { + session* s (0); + tls_set (current_session, s); + } + + // + // object_map_base + // + session::object_map_base:: + ~object_map_base () + { + } +} diff --git a/odb/session.hxx b/odb/session.hxx new file mode 100644 index 0000000..033934a --- /dev/null +++ b/odb/session.hxx @@ -0,0 +1,159 @@ +// file : odb/session.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SESSION_HXX +#define ODB_SESSION_HXX + +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +namespace odb +{ + class LIBODB_EXPORT session + { + public: + typedef odb::database database_type; + + // Set the current thread's session to this session. If another + // session is already in effect, throw the already_in_session + // exception. + // + session (); + + // Reset the current thread's session if it is this session. + // + ~session (); + + // Current session. + // + public: + // Return true if there is a session in effect in the current + // thread. + // + static bool + has_current (); + + // Get current thread's session. Throw if no session is in effect. + // + static session& + current (); + + // Set current thread's session. + // + static void + current (session&); + + // Revert to the no session in effect state for the current thread. + // + static void + reset_current (); + + // Copying or assignment of sessions is not supported. + // + private: + session (const session&); + session& operator= (const session&); + + protected: + template + struct object_pointers + { + typedef typename object_traits::pointer_type pointer_type; + typedef typename object_traits::const_pointer_type const_pointer_type; + + object_pointers (); + + void + set (const pointer_type&); + + void + set (const const_pointer_type&); + + void + get (pointer_type& p) const; + + void + get (const_pointer_type& cp) const; + + private: + pointer_type p_; + const_pointer_type cp_; + }; + + struct LIBODB_EXPORT object_map_base: details::shared_base + { + virtual + ~object_map_base (); + }; + + template + struct object_map: + object_map_base, + std::map< typename object_traits::id_type, object_pointers > + { + }; + + // Object cache. + // + public: + template + struct object_position + { + typedef typename object_traits::object_type object_type; + typedef object_map map; + typedef typename map::iterator iterator; + + object_position (): map_ (0) {} + object_position (map& m, const iterator& p): map_ (&m), pos_ (p) {} + + map* map_; + iterator pos_; + }; + + template + object_position + insert (database_type&, + const typename object_traits::id_type&, + const typename object_traits::pointer_type&); + + template + typename object_traits::pointer_type + find (database_type&, const typename object_traits::id_type&) const; + + template + void + erase (database_type&, const typename object_traits::id_type&); + + template + void + erase (const object_position&); + + protected: + typedef std::map, + details::type_info_comparator> type_map; + + typedef std::map database_map; + + database_map db_map_; + }; +} + +#include +#include + +#include + +#endif // ODB_SESSION_HXX diff --git a/odb/session.ixx b/odb/session.ixx new file mode 100644 index 0000000..0be6bfa --- /dev/null +++ b/odb/session.ixx @@ -0,0 +1,65 @@ +// file : odb/session.ixx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +namespace odb +{ + template + inline void session:: + erase (const object_position& p) + { + // @@ Empty maps are not cleaned up by this version of erase. + // + p.map_->erase (p.pos_); + } + + // + // object_pointers + // + template + inline session::object_pointers:: + object_pointers () : p_ (), cp_ () {} + + template + inline void session::object_pointers:: + set (const pointer_type& p) + { + p_ = p; + cp_ = const_pointer_type (); + } + + template + inline void session::object_pointers:: + set (const const_pointer_type& cp) + { + p_ = pointer_type (); + cp_ = cp; + } + + template + inline void session::object_pointers:: + get (pointer_type& p) const + { + if (!pointer_traits::null_ptr (p_)) + p = p_; + else if (!pointer_traits::null_ptr (cp_)) + throw const_object (); + else + p = pointer_type (); + } + + template + inline void session::object_pointers:: + get (const_pointer_type& cp) const + { + if (!pointer_traits::null_ptr (p_)) + cp = const_pointer_type (p_); + else if (!pointer_traits::null_ptr (cp_)) + cp = cp_; + else + cp = const_pointer_type (); + } +} diff --git a/odb/session.txx b/odb/session.txx new file mode 100644 index 0000000..1e3ba96 --- /dev/null +++ b/odb/session.txx @@ -0,0 +1,116 @@ +// file : odb/session.txx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +namespace odb +{ + template + typename session::object_position session:: + insert (database_type& db, + const typename object_traits::id_type& id, + const typename object_traits::pointer_type& obj) + { + // T can be const T while object_type will always be T. + // + typedef typename object_traits::object_type object_type; + typedef odb::object_traits object_traits; + + typedef typename odb::object_traits::pointer_type pointer_type; + typedef odb::pointer_traits pointer_traits; + + type_map& tm (db_map_[&db]); + details::shared_ptr& pom (tm[&typeid (object_type)]); + + if (!pom) + pom.reset (new (details::shared) object_map); + + object_map& om ( + static_cast&> (*pom)); + + typename object_map::value_type vt ( + id, object_pointers ()); + vt.second.set (obj); + std::pair::iterator, bool> r ( + om.insert (vt)); + + // In what situation may we possibly attempt to reinsert the object? + // For example, when the user loads the same object in to different + // instances (i.e., load into a pre-allocated object). In this case + // we should probably update our entries accordingly. + // + if (!r.second) + r.first->second.set (obj); + + return object_position (om, r.first); + } + + template + typename object_traits::pointer_type session:: + find (database_type& db, const typename object_traits::id_type& id) const + { + // T can be const T while object_type will always be T. + // + typedef typename object_traits::object_type object_type; + typedef typename object_traits::pointer_type pointer_type; + + database_map::const_iterator di (db_map_.find (&db)); + + if (di == db_map_.end ()) + return pointer_type (); + + const type_map& tm (di->second); + type_map::const_iterator ti (tm.find (&typeid (object_type))); + + if (ti == tm.end ()) + return pointer_type (); + + const object_map& om ( + static_cast&> (*ti->second)); + typename object_map::const_iterator oi (om.find (id)); + + if (oi == om.end ()) + return pointer_type (); + + pointer_type r; + oi->second.get (r); + return r; + } + + template + void session:: + erase (database_type& db, const typename object_traits::id_type& id) + { + // T can be const T while object_type will always be T. + // + typedef typename object_traits::object_type object_type; + + database_map::iterator di (db_map_.find (&db)); + + if (di == db_map_.end ()) + return; + + type_map& tm (di->second); + type_map::iterator ti (tm.find (&typeid (object_type))); + + if (ti == tm.end ()) + return; + + object_map& om ( + static_cast&> (*ti->second)); + typename object_map::iterator oi (om.find (id)); + + if (oi == om.end ()) + return; + + om.erase (oi); + + if (om.empty ()) + tm.erase (ti); + + if (tm.empty ()) + db_map_.erase (di); + } +} diff --git a/odb/traits.hxx b/odb/traits.hxx index bc25dcb..87fcec5 100644 --- a/odb/traits.hxx +++ b/odb/traits.hxx @@ -72,15 +72,74 @@ namespace odb }; template - struct object_traits: access::object_traits, + struct object_traits: + access::object_traits, access::object_factory::pointer_type> { + // + // If a C++ compiler issues an error pointing to this struct and + // saying that it is incomplete, then you are most likely trying to + // perform a database operation on a C++ type that is not a persistent + // object. Or you forgot to include the corresponding -odb.hxx file. + // + + typedef + odb::pointer_traits::pointer_type> + pointer_traits; + typedef typename access::object_traits::object_type object_type; typedef typename access::object_traits::pointer_type pointer_type; + typedef typename pointer_traits::const_pointer_type const_pointer_type; + }; + // Specialization for const objects. It only defines the id, object, + // pointer, and const_pointer types with pointer and const_pointer + // being the same. The idea is to only use this specialization in the + // interfaces, with the implementations detecting this situation and + // using the non-const object_traits version. + // + template + struct object_traits + { + private: typedef odb::pointer_traits::pointer_type> pointer_traits; + + public: + typedef typename access::object_traits::id_type id_type; + 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; + }; + + // Specializations for pointer types to allow the C++ compiler to + // instantiate persist(), etc., signatures in class database. The + // overloads that use these specializations would never actually + // be selected by the compiler. + // + template + struct object_traits + { + struct id_type {}; + }; + + template + struct object_traits + { + struct id_type {}; + }; + + template class P> + struct object_traits< P > + { + struct id_type {}; + }; + + template class P> + struct object_traits< const P > + { + struct id_type {}; }; template -- cgit v1.1