From 6f0d40508286afc8cdd72a0b5f807d5c2a589cfc Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 4 Jun 2010 16:33:08 +0200 Subject: Initial implementation --- odb/core.hxx | 7 +- odb/database.cxx | 14 ++ odb/database.hxx | 71 ++++++++++ odb/database.ixx | 12 ++ odb/database.txx | 73 +++++++++++ odb/exception.cxx | 17 +++ odb/exception.hxx | 22 ++++ odb/exceptions.cxx | 10 ++ odb/exceptions.hxx | 52 ++++++++ odb/forward.hxx | 38 ++++++ odb/makefile | 60 +++++++++ odb/meta/answer.hxx | 25 ++++ odb/meta/class-p.hxx | 28 ++++ odb/meta/polymorphic-p.hxx | 51 ++++++++ odb/meta/remove-c.hxx | 27 ++++ odb/meta/remove-cv.hxx | 24 ++++ odb/meta/remove-p.hxx | 27 ++++ odb/meta/remove-v.hxx | 27 ++++ odb/session.cxx | 120 +++++++++++++++++ odb/session.hxx | 190 +++++++++++++++++++++++++++ odb/session.txx | 320 +++++++++++++++++++++++++++++++++++++++++++++ odb/shared-ptr-traits.hxx | 119 +++++++++++++++++ odb/shared-ptr.hxx | 145 ++++++++++++++++++++ odb/shared-ptr/base.cxx | 63 +++++++++ odb/shared-ptr/base.hxx | 91 +++++++++++++ odb/shared-ptr/base.ixx | 79 +++++++++++ odb/shared-ptr/base.txx | 183 ++++++++++++++++++++++++++ odb/traits.hxx | 93 +++++++++++++ odb/transaction.cxx | 93 +++++++++++++ odb/transaction.hxx | 139 ++++++++++++++++++++ odb/transaction.ixx | 25 ++++ 31 files changed, 2239 insertions(+), 6 deletions(-) create mode 100644 odb/database.cxx create mode 100644 odb/database.hxx create mode 100644 odb/database.ixx create mode 100644 odb/database.txx create mode 100644 odb/exception.cxx create mode 100644 odb/exception.hxx create mode 100644 odb/exceptions.cxx create mode 100644 odb/exceptions.hxx create mode 100644 odb/forward.hxx create mode 100644 odb/makefile create mode 100644 odb/meta/answer.hxx create mode 100644 odb/meta/class-p.hxx create mode 100644 odb/meta/polymorphic-p.hxx create mode 100644 odb/meta/remove-c.hxx create mode 100644 odb/meta/remove-cv.hxx create mode 100644 odb/meta/remove-p.hxx create mode 100644 odb/meta/remove-v.hxx create mode 100644 odb/session.cxx create mode 100644 odb/session.hxx create mode 100644 odb/session.txx create mode 100644 odb/shared-ptr-traits.hxx create mode 100644 odb/shared-ptr.hxx create mode 100644 odb/shared-ptr/base.cxx create mode 100644 odb/shared-ptr/base.hxx create mode 100644 odb/shared-ptr/base.ixx create mode 100644 odb/shared-ptr/base.txx create mode 100644 odb/traits.hxx create mode 100644 odb/transaction.cxx create mode 100644 odb/transaction.hxx create mode 100644 odb/transaction.ixx (limited to 'odb') diff --git a/odb/core.hxx b/odb/core.hxx index 227dea7..ea0ed05 100644 --- a/odb/core.hxx +++ b/odb/core.hxx @@ -13,11 +13,6 @@ # define PRAGMA_ODB(x) #endif -namespace odb -{ - class image - { - }; -} +#include #endif // ODB_CORE_HXX diff --git a/odb/database.cxx b/odb/database.cxx new file mode 100644 index 0000000..aa75dae --- /dev/null +++ b/odb/database.cxx @@ -0,0 +1,14 @@ +// file : odb/database.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +namespace odb +{ + database:: + ~database () + { + } +} diff --git a/odb/database.hxx b/odb/database.hxx new file mode 100644 index 0000000..2a904a4 --- /dev/null +++ b/odb/database.hxx @@ -0,0 +1,71 @@ +// file : odb/database.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_DATABASE_HXX +#define ODB_DATABASE_HXX + +#include +#include + +namespace odb +{ + class transaction_impl; + + class database + { + public: + virtual + ~database (); + + template class P> + typename object_traits::id_type + persist (P obj); + + template + typename object_traits::shared_ptr + load (typename object_traits::id_type const&); + + template + typename object_traits::shared_ptr + find (typename object_traits::id_type const&); + + template class P> + void + erase (P obj); + + template class P> + void + modified (P obj); + + // Transaction API. + // + public: + // Start a transaction. If an existing session can be obtained via + // session::current(), the transaction is run as part of that session. + // Otherwise a new session is created and will be automatically flushed + // and destroyed when transaction ends. + // + virtual transaction_impl* + begin_transaction () = 0; + + // Start a transaction as part of an existing session. The session + // is not automatically flushed or destroyed when transaction ends. + // + virtual transaction_impl* + begin_transaction (session&) = 0; + + protected: + database (); + + private: + database (const database&); + database& operator= (const database&); + }; +} + +#include +#include + +#endif // ODB_DATABASE_HXX diff --git a/odb/database.ixx b/odb/database.ixx new file mode 100644 index 0000000..c8fe08c --- /dev/null +++ b/odb/database.ixx @@ -0,0 +1,12 @@ +// file : odb/database.ixx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + inline database:: + database () + { + } +} diff --git a/odb/database.txx b/odb/database.txx new file mode 100644 index 0000000..c507030 --- /dev/null +++ b/odb/database.txx @@ -0,0 +1,73 @@ +// file : odb/database.txx +// 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 +{ + // @@ Should I make these inline? + // + + template class P> + typename object_traits::id_type database:: + persist (P p) + { + // P should be the same or convertible to + // object_traits::shared_ptr. + // + const typename object_traits::shared_ptr& obj (p); + + session& s (transaction::current ().session ()); + return s.persist (*this, obj); + } + + template + typename object_traits::shared_ptr database:: + load (typename object_traits::id_type const& id) + { + typename object_traits::shared_ptr r (find (id)); + + if (object_traits::shared_ops::null_ptr (r)) + throw object_not_persistent (); + + return r; + } + + template + typename object_traits::shared_ptr database:: + find (typename object_traits::id_type const& id) + { + session& s (transaction::current ().session ()); + return s.find (*this, id); + } + + template class P> + void database:: + erase (P p) + { + // P should be the same or convertible to + // object_traits::shared_ptr. + // + const typename object_traits::shared_ptr& obj (p); + + session& s (transaction::current ().session ()); + return s.erase (*this, obj); + } + + template class P> + void database:: + modified (P p) + { + // P should be the same or convertible to + // object_traits::shared_ptr. + // + const typename object_traits::shared_ptr& obj (p); + + session& s (transaction::current ().session ()); + return s.modified (obj); + } +} diff --git a/odb/exception.cxx b/odb/exception.cxx new file mode 100644 index 0000000..52d8370 --- /dev/null +++ b/odb/exception.cxx @@ -0,0 +1,17 @@ +// file : odb/exception.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +#include + +namespace odb +{ + char const* exception:: + what () const throw () + { + return typeid (*this).name (); + } +} diff --git a/odb/exception.hxx b/odb/exception.hxx new file mode 100644 index 0000000..ff3fc63 --- /dev/null +++ b/odb/exception.hxx @@ -0,0 +1,22 @@ +// file : odb/exception.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_EXCEPTION_HXX +#define ODB_EXCEPTION_HXX + +#include + +namespace odb +{ + struct exception: std::exception + { + // By default return the exception type name ( typeid (*this).name () ). + // + virtual char const* + what () const throw (); + }; +} + +#endif // ODB_EXCEPTION_HXX diff --git a/odb/exceptions.cxx b/odb/exceptions.cxx new file mode 100644 index 0000000..d86657c --- /dev/null +++ b/odb/exceptions.cxx @@ -0,0 +1,10 @@ +// file : odb/exceptions.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +namespace odb +{ +} diff --git a/odb/exceptions.hxx b/odb/exceptions.hxx new file mode 100644 index 0000000..4b5909b --- /dev/null +++ b/odb/exceptions.hxx @@ -0,0 +1,52 @@ +// file : odb/exceptions.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_EXCEPTIONS_HXX +#define ODB_EXCEPTIONS_HXX + +#include + +namespace odb +{ + // nested_transaction + // + struct already_in_transaction: odb::exception + { + }; + + // no_transaction + // + struct not_in_transaction: odb::exception + { + }; + + // finilized_transaction + // + struct transaction_already_finilized: odb::exception + { + }; + + struct already_in_session: odb::exception + { + }; + + struct not_in_session: odb::exception + { + }; + + struct object_not_persistent: odb::exception + { + }; + + struct object_already_persistent: odb::exception + { + }; + + struct database_exception: odb::exception + { + }; +} + +#endif // ODB_EXCEPTIONS_HXX diff --git a/odb/forward.hxx b/odb/forward.hxx new file mode 100644 index 0000000..b59034f --- /dev/null +++ b/odb/forward.hxx @@ -0,0 +1,38 @@ +// file : odb/forward.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_FORWARD_HXX +#define ODB_FORWARD_HXX + +namespace odb +{ + class session; + class database; + class transaction; + + template + class shared_ptr; + + class access + { + public: + template + class value_traits; + + template + class object_traits; + + template + class object_memory; + + template + class object_factory; + + template + class shared_factory; + }; +} + +#endif // ODB_FORWARD_HXX diff --git a/odb/makefile b/odb/makefile new file mode 100644 index 0000000..71c719a --- /dev/null +++ b/odb/makefile @@ -0,0 +1,60 @@ +# file : odb/makefile +# author : Boris Kolpackov +# copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +# license : GNU GPL v2; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make + +cxx_tun := \ +exception.cxx \ +exceptions.cxx \ +shared-ptr/base.cxx \ +session.cxx \ +database.cxx \ +transaction.cxx + +cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o)) +cxx_od := $(cxx_obj:.o=.o.d) + +odb.l := $(out_base)/odb.l +odb.l.cpp-options := $(out_base)/odb.l.cpp-options + +default := $(out_base)/ +install := $(out_base)/.install +clean := $(out_base)/.clean + + +# Build. +# +$(odb.l): $(cxx_obj) + +$(cxx_obj) $(cxx_od): $(odb.l.cpp-options) +$(odb.l.cpp-options): value := -I$(src_root) + +$(call include-dep,$(cxx_od)) + + +# Convenience alias for default target. +# +$(out_base)/: $(odb.l) + +# Install. +# +$(install): $(odb.l) + $(call install-lib,$<,$(install_lib_dir)/$(ld_lib_prefix)odb$(ld_lib_suffix)) + $(call install-dir,$(src_base),$(install_inc_dir)/odb,\ +'(' -name '*.hxx' -o -name '*.ixx' -o -name '*.txx' ')') + +# Clean. +# +$(clean): $(odb.l).o.clean \ + $(odb.l.cpp-options).clean \ + $(addsuffix .cxx.clean,$(cxx_obj)) \ + $(addsuffix .cxx.clean,$(cxx_od)) + + +# How to. +# +$(call include,$(bld_root)/cxx/o-l.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) diff --git a/odb/meta/answer.hxx b/odb/meta/answer.hxx new file mode 100644 index 0000000..80a25e0 --- /dev/null +++ b/odb/meta/answer.hxx @@ -0,0 +1,25 @@ +// file : odb/meta/answer.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_META_ANSWER_HXX +#define ODB_META_ANSWER_HXX + +namespace odb +{ + namespace meta + { + struct yes + { + char filling; + }; + + struct no + { + char filling[2]; + }; + } +} + +#endif // ODB_META_ANSWER_HXX diff --git a/odb/meta/class-p.hxx b/odb/meta/class-p.hxx new file mode 100644 index 0000000..e3d15c9 --- /dev/null +++ b/odb/meta/class-p.hxx @@ -0,0 +1,28 @@ +// file : odb/meta/class-p.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_META_CLASS_HXX +#define ODB_META_CLASS_HXX + +#include + +namespace odb +{ + namespace meta + { + // g++ cannot have these inside class_p. + // + template no class_p_test (...); + template yes class_p_test (void (Y::*) ()); + + template + struct class_p + { + static bool const r = sizeof (class_p_test (0)) == sizeof (yes); + }; + } +} + +#endif // ODB_META_CLASS_HXX diff --git a/odb/meta/polymorphic-p.hxx b/odb/meta/polymorphic-p.hxx new file mode 100644 index 0000000..571ef52 --- /dev/null +++ b/odb/meta/polymorphic-p.hxx @@ -0,0 +1,51 @@ +// file : odb/meta/polymorphic-p.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_META_POLYMORPHIC_HXX +#define ODB_META_POLYMORPHIC_HXX + +#include +#include + +namespace odb +{ + namespace meta + { + template + struct polymorphic_p + { + typedef typename remove_cv::r X; + + template + struct impl + { + static const bool r = false; + }; + + template + struct impl + { + struct t1: Y + { + t1 (); + }; + + struct t2: Y + { + t2 (); + + virtual + ~t2 () throw (); + }; + + static const bool r = sizeof (t1) == sizeof (t2); + }; + + static const bool r = impl::r>::r; + }; + } +} + +#endif // ODB_META_POLYMORPHIC_HXX diff --git a/odb/meta/remove-c.hxx b/odb/meta/remove-c.hxx new file mode 100644 index 0000000..db724b3 --- /dev/null +++ b/odb/meta/remove-c.hxx @@ -0,0 +1,27 @@ +// file : odb/meta/remove-c.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_META_REMOVE_C_HXX +#define ODB_META_REMOVE_C_HXX + +namespace odb +{ + namespace meta + { + template + struct remove_c + { + typedef X r; + }; + + template + struct remove_c + { + typedef X r; + }; + } +} + +#endif // ODB_META_REMOVE_C_HXX diff --git a/odb/meta/remove-cv.hxx b/odb/meta/remove-cv.hxx new file mode 100644 index 0000000..0805a9d --- /dev/null +++ b/odb/meta/remove-cv.hxx @@ -0,0 +1,24 @@ +// file : odb/meta/remove-cv.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_META_REMOVE_CV_HXX +#define ODB_META_REMOVE_CV_HXX + +#include +#include + +namespace odb +{ + namespace meta + { + template + struct remove_cv + { + typedef typename remove_v::r>::r r; + }; + } +} + +#endif // ODB_META_REMOVE_CV_HXX diff --git a/odb/meta/remove-p.hxx b/odb/meta/remove-p.hxx new file mode 100644 index 0000000..053c860 --- /dev/null +++ b/odb/meta/remove-p.hxx @@ -0,0 +1,27 @@ +// file : odb/meta/remove-p.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_META_REMOVE_P_HXX +#define ODB_META_REMOVE_P_HXX + +namespace odb +{ + namespace meta + { + template + struct remove_p + { + typedef X r; + }; + + template + struct remove_p + { + typedef X r; + }; + } +} + +#endif // ODB_META_REMOVE_P_HXX diff --git a/odb/meta/remove-v.hxx b/odb/meta/remove-v.hxx new file mode 100644 index 0000000..9e37a6c --- /dev/null +++ b/odb/meta/remove-v.hxx @@ -0,0 +1,27 @@ +// file : odb/meta/remove-v.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_META_REMOVE_V_HXX +#define ODB_META_REMOVE_V_HXX + +namespace odb +{ + namespace meta + { + template + struct remove_v + { + typedef X r; + }; + + template + struct remove_v + { + typedef X r; + }; + } +} + +#endif // ODB_META_REMOVE_V_HXX diff --git a/odb/session.cxx b/odb/session.cxx new file mode 100644 index 0000000..9ee0104 --- /dev/null +++ b/odb/session.cxx @@ -0,0 +1,120 @@ +// 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 // std::make_pair + +#include +#include + +namespace odb +{ + session::type_map:: + ~type_map () + { + } + + session::object_proxy:: + ~object_proxy () + { + } + + // + // session + // + + static session* current_session = 0; + + session:: + session () + { + if (current_session != 0) + throw already_in_session (); + + current_session = this; + } + + bool session:: + has_current () + { + return current_session != 0; + } + + session& session:: + current () + { + if (current_session == 0) + throw not_in_session (); + + return *current_session; + } + + void session:: + current (session& s) + { + current_session = &s; + } + + void session:: + reset_current () + { + current_session = 0; + } + + void session:: + flush () + { + if (!transaction::has_current ()) + throw not_in_transaction (); + + // @@ Order of insertion and deletion can be important (triggers, + // id assignment, constraints etc). + // + + for (object_map::iterator i (object_map_.begin ()), + e (object_map_.end ()); i != e;) + { + object_proxy& pxy (*i->second); + + switch (pxy.state_) + { + case object_proxy::transient: + { + pxy.persist (); + + // If the id is auto-assigned, then we only get it now, so + // register with the id map. + // + if (pxy.id_source_ != ids_assigned) + pxy.register_id (id_map_, i); + + pxy.state_ = object_proxy::clean; + ++i; + break; + } + case object_proxy::dirty: + { + pxy.update (); + pxy.state_ = object_proxy::clean; + ++i; + break; + } + case object_proxy::erased: + { + pxy.erase (); + pxy.unregister_id (id_map_); + object_map_.erase (i++); + break; + } + case object_proxy::clean: + { + // Nothing to do for this case. + // + ++i; + break; + } + } + } + } +} diff --git a/odb/session.hxx b/odb/session.hxx new file mode 100644 index 0000000..90df00d --- /dev/null +++ b/odb/session.hxx @@ -0,0 +1,190 @@ +// 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 + +namespace odb +{ + class session + { + public: + session (); + ~session () + { + reset_current (); + } + + private: + session (const session&); + session& operator= (const session&); + + public: + template class P> + typename object_traits::id_type + persist (database&, P obj); + + template + typename object_traits::shared_ptr + find (database&, typename object_traits::id_type const&); + + template class P> + void + erase (database&, P obj); + + template class P> + void + modified (P obj); + + void + flush (); + + public: + // Return true if there is a session in effect. + // + static bool + has_current (); + + // Get current thread's session. Throw if no session in effect. + // + static session& + current (); + + // Set current thread's session. + // + static void + current (session&); + + // Revert to the no session in effect state. + // + static void + reset_current (); + + private: + struct object_proxy; + typedef std::map< void*, shared_ptr > object_map; + + struct type_map + { + virtual + ~type_map () = 0; + }; + + template + struct type_map_impl: + type_map, + std::map::id_type, object_map::iterator> + { + }; + + struct type_info_comparator + { + bool + operator() (const std::type_info* x, const std::type_info* y) const + { + // XL C++ on AIX has buggy type_info::before() in that + // it returns true for two different type_info objects + // that happened to be for the same type. + // +#if defined(__xlC__) && defined(_AIX) + return *x != *y && x->before (*y); +#else + return x->before (*y); +#endif + } + }; + + typedef + std::map, type_info_comparator> + id_map; + + // + // + struct object_proxy + { + virtual + ~object_proxy () = 0; + + object_proxy (database& db, id_source is) + : id_source_ (is), db_ (db) + { + } + + enum state + { + transient, /* Persisted out of transaction. */ + clean, + dirty, /* To be updated on flush. */ + erased /* To be deleted on flush. */ + }; + + public: + virtual void + persist () = 0; + + virtual void + update () = 0; + + virtual void + erase () = 0; + + virtual void + register_id (id_map&, object_map::iterator) = 0; + + virtual void + unregister_id (id_map&) = 0; + + public: + state state_; + id_source id_source_; + database& db_; + }; + + template + struct object_proxy_impl: object_proxy + { + typedef object_traits traits; + typedef typename traits::shared_ptr obj_ptr; + typedef typename traits::shared_ops ptr_ops; + + object_proxy_impl (database& db, obj_ptr obj) + : object_proxy (db, traits::id_source), obj_ (obj) + { + } + + public: + virtual void + persist (); + + virtual void + update (); + + virtual void + erase (); + + virtual void + register_id (id_map&, object_map::iterator); + + virtual void + unregister_id (id_map&); + + public: + obj_ptr obj_; + }; + + object_map object_map_; + id_map id_map_; + }; +} + +#include + +#endif // ODB_SESSION_HXX diff --git a/odb/session.txx b/odb/session.txx new file mode 100644 index 0000000..55155f7 --- /dev/null +++ b/odb/session.txx @@ -0,0 +1,320 @@ +// 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 // std::make_pair + +#include +#include + +#include // @@ tmp + +namespace odb +{ + // + // session::object_proxy_impl + // + + template + void session::object_proxy_impl:: + persist () + { + traits::insert (db_, ptr_ops::get_ref (obj_)); + } + + template + void session::object_proxy_impl:: + update () + { + traits::update (db_, ptr_ops::get_ref (obj_)); + } + + template + void session::object_proxy_impl:: + erase () + { + traits::erase (db_, traits::id (ptr_ops::get_ref (obj_))); + } + + template + void session::object_proxy_impl:: + register_id (id_map& idm, object_map::iterator i) + { + // For polymorphic types we should use the root of the hierarchy + // (presumably defined in traits) as a type id so that all types + // in this hierarchy end up in the same map. See also other places. + // + shared_ptr& m (idm[&typeid (T)]); + + if (!m) + m.reset (new (shared) type_map_impl); + + type_map_impl& mi (static_cast&> (*m)); + + std::pair::iterator, bool> r ( + mi.insert (std::make_pair (traits::id (ptr_ops::get_ref (obj_)), i))); + + if (!r.second) + throw object_already_persistent (); + } + + template + void session::object_proxy_impl:: + unregister_id (id_map& idm) + { + shared_ptr& m (idm[&typeid (T)]); + + if (m) + { + type_map_impl& mi (static_cast&> (*m)); + mi.erase (traits::id (ptr_ops::get_ref (obj_))); + } + } + + // + // session + // + + template class P> + typename object_traits::id_type session:: + persist (database& db, P p) + { + typedef object_traits traits; + typedef typename traits::shared_ops ops; + + // P should be the same or convertible to + // object_traits::shared_ptr. + // + const typename traits::shared_ptr& obj (p); + + // For polymorphic types we need to cast the pointer to the + // root of the hierarchy. + // + void* ptr (ops::get_ptr (obj)); + T& ref (ops::get_ref (obj)); + + // @@ What if the object that's already in the map is in the + // erased state? + // + if (object_map_.find (ptr) != object_map_.end ()) + throw object_already_persistent (); + + shared_ptr pxy (new (shared) object_proxy_impl (db, obj)); + + // If we are in a transaction, save this object immediately. This + // helps with two things: (1) assignment of auto-generated ids and + // (2) detection of duplicate objects. + // + if (transaction::has_current ()) + { + // @@ What if the manually-assigned id is already in use by + // an object waiting to be deleted? + // + traits::insert (db, ref); + pxy->state_ = object_proxy::clean; + } + else + pxy->state_ = object_proxy::transient; + + object_map::iterator i ( + object_map_.insert (std::make_pair (ptr, pxy)).first); + + // If this object has auto-assigned id and we haven't hit the db + // yet, then the id is "NULL" and we cannot insert this object + // into the id map. + // + if (pxy->state_ != object_proxy::transient || + traits::id_source == ids_assigned) + { + try + { + pxy->register_id (id_map_, i); + } + catch (...) + { + object_map_.erase (i); + throw; + } + } + + return traits::id (ref); + } + + template + typename object_traits::shared_ptr session:: + find (database& db, typename object_traits::id_type const& id) + { + typedef object_traits traits; + typedef typename traits::shared_ops ops; + typedef typename traits::shared_ptr obj_ptr; + + // First see if we have this object in the maps. + // + shared_ptr& m (id_map_[&typeid (T)]); + + if (m) + { + typedef type_map_impl map_impl; + map_impl& mi (static_cast (*m)); + typename map_impl::iterator i (mi.find (id)); + + if (i != mi.end ()) + { + const object_map::iterator& j (i->second); + + if (j->second->state_ != object_proxy::erased) + { + object_proxy_impl& pxy ( + static_cast&> (*j->second)); + return pxy.obj_; + } + else + return obj_ptr (); + } + } + + // If we are in transaction then hit the database. Otherwise, the + // object is not found. + // + if (!transaction::has_current ()) + return obj_ptr (); + + obj_ptr obj (traits::find (db, id)); + + if (ops::null_ptr (obj)) + return obj; + + // Add this object to our maps. + // + void* ptr (ops::get_ptr (obj)); + shared_ptr pxy (new (shared) object_proxy_impl (db, obj)); + pxy->state_ = object_proxy::clean; + + object_map::iterator i ( + object_map_.insert ( + std::make_pair (ptr, pxy)).first); + + try + { + if (!m) + m.reset (new (shared) type_map_impl); + + type_map_impl& mi (static_cast&> (*m)); + mi.insert (std::make_pair (id, i)); + } + catch (...) + { + object_map_.erase (i); + throw; + } + + return obj; + } + + template class P> + void session:: + erase (database& db, P p) + { + typedef object_traits traits; + typedef typename traits::shared_ops ops; + + // P should be the same or convertible to + // object_traits::shared_ptr. + // + const typename traits::shared_ptr& obj (p); + + // For polymorphic types we need to cast the pointer to the + // root of the hierarchy. + // + void* ptr (ops::get_ptr (obj)); + T& ref (ops::get_ref (obj)); + + object_map::iterator i (object_map_.find (ptr)); + + if (object_map_.find (ptr) == object_map_.end ()) + throw object_not_persistent (); + + object_proxy& pxy (*i->second); + + switch (pxy.state_) + { + case object_proxy::transient: + { + // If this object is still transient then all we need to do is + // purge it from the maps. + // + + // See if we are registered in the id map. + // + if (traits::id_source == ids_assigned) + pxy.unregister_id (id_map_); + + object_map_.erase (i); + break; + } + case object_proxy::clean: + case object_proxy::dirty: + { + // Ideally we would need to store the object id as well as the + // version (optimistic concurrency) since the user is free to + // modify the object state. + // + pxy.state_ = object_proxy::erased; + break; + } + case object_proxy::erased: + { + // Already erased. Throw to be consistent with the transient + // case. + // + throw object_not_persistent (); + } + } + } + + template class P> + void session:: + modified (P p) + { + typedef object_traits traits; + typedef typename traits::shared_ops ops; + + // P should be the same or convertible to + // object_traits::shared_ptr. + // + const typename traits::shared_ptr& obj (p); + + // For polymorphic types we need to cast the pointer to the + // root of the hierarchy. + // + void* ptr (ops::get_ptr (obj)); + + object_map::iterator i (object_map_.find (ptr)); + + if (object_map_.find (ptr) == object_map_.end ()) + throw object_not_persistent (); + + object_proxy& pxy (*i->second); + + switch (pxy.state_) + { + case object_proxy::transient: + case object_proxy::dirty: + { + // Nothing to do here. + // + break; + } + case object_proxy::clean: + { + pxy.state_ = object_proxy::dirty; + break; + } + case object_proxy::erased: + { + throw object_not_persistent (); + } + } + } +} diff --git a/odb/shared-ptr-traits.hxx b/odb/shared-ptr-traits.hxx new file mode 100644 index 0000000..a1d5146 --- /dev/null +++ b/odb/shared-ptr-traits.hxx @@ -0,0 +1,119 @@ +// file : odb/shared-ptr-traits.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SHARED_PTR_TRAITS_HXX +#define ODB_SHARED_PTR_TRAITS_HXX + +#include // operators new/delete +#include // std::size_t + +#include + +namespace odb +{ + template + class shared_ptr_traits; + + // Default implementation that should work for any sensible smart + // pointer with one template argument (object type). The only + // assumptions that we make are the availability of operator-> and + // operator*, and that the former does not throw if the pointer is + // NULL. + // + template class P> + class shared_ptr_traits< P > + { + public: + typedef T type; + typedef P shared_ptr; + + // Return underlying pointer, including NULL. + // + static type* + get_ptr (const shared_ptr& p) + { + return p.operator-> (); + } + + // Return reference to the pointed-to object. + // + static type& + get_ref (const shared_ptr& p) + { + return *p; + } + + // Return true if the pointer is NULL. + // + static bool + null_ptr (const shared_ptr& p) + { + return get_ptr () == 0; + } + + public: + // Allocate memory for a shared object. + // + static void* + allocate (std::size_t n) + { + return operator new (n); + } + + // Free memory allocated for a shared object. This functions is + // only called if the constructor of the object being created + // fails. Otherwise, shared_ptr is used to delete the object + // and free the memory. This behavior is identical to the one + // used by operator delete overloading. + // + static void + free (void* p) + { + operator delete (p); + } + }; + + // Specialization for odb::shared_ptr. + // + template + class shared_ptr_traits< shared_ptr > + { + public: + typedef T type; + typedef odb::shared_ptr shared_ptr; + + static type* + get_ptr (const shared_ptr& p) + { + return p.get (); + } + + static type& + get_ref (const shared_ptr& p) + { + return *p; + } + + static bool + null_ptr (const shared_ptr& p) + { + return !p; + } + + static void* + allocate (std::size_t n) + { + return operator new (n, shared); + } + + static void + free (void* p) + { + operator delete (p, shared); + } + }; +} + +#endif // ODB_SHARED_PTR_TRAITS_HXX diff --git a/odb/shared-ptr.hxx b/odb/shared-ptr.hxx new file mode 100644 index 0000000..ee56792 --- /dev/null +++ b/odb/shared-ptr.hxx @@ -0,0 +1,145 @@ +// file : odb/shared-ptr.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SHARED_PTR_HXX +#define ODB_SHARED_PTR_HXX + +#include + +namespace odb +{ + template + class shared_ptr: bits::counter_ops::r, X> + { + typedef bits::counter_ops::r, X> base; + + public: + ~shared_ptr () + { + if (x_ != 0) + base::dec (x_); + } + + explicit + shared_ptr (X* x = 0) + : base (x), x_ (x) + { + } + + shared_ptr (shared_ptr const& x) + : base (x), x_ (x.x_) + { + if (x_ != 0) + base::inc (x_); + } + + template + shared_ptr (shared_ptr const& x) + : base (x), x_ (x.x_) + { + if (x_ != 0) + base::inc (x_); + } + + shared_ptr& + operator= (shared_ptr const& x) + { + if (x_ != x.x_) + { + if (x_ != 0) + base::dec (x_); + + static_cast (*this) = x; + x_ = x.x_; + + if (x_ != 0) + base::inc (x_); + } + + return *this; + } + + template + shared_ptr& + operator= (shared_ptr const& x) + { + if (x_ != x.x_) + { + if (x_ != 0) + base::dec (x_); + + static_cast (*this) = x; + x_ = x.x_; + + if (x_ != 0) + base::inc (x_); + } + + return *this; + } + + public: + X* + operator-> () const + { + return x_; + } + + X& + operator* () const + { + return *x_; + } + + // Conversion to bool. + // + typedef void (shared_ptr::*boolean_convertible)(); + void true_value () {}; + + operator boolean_convertible () const + { + return x_ ? &shared_ptr::true_value : 0; + } + + public: + X* + get () const + { + return x_; + } + + X* + release () + { + X* r (x_); + x_ = 0; + return r; + } + + void + reset (X* x) + { + if (x_ != 0) + base::dec (x_); + + base::reset (x); + x_ = x; + } + + std::size_t + count () const + { + return x_ != 0 ? base::count (x_) : 0; + } + + private: + template + friend class shared_ptr; + + X* x_; + }; +} + +#endif // ODB_SHARED_PTR_HXX diff --git a/odb/shared-ptr/base.cxx b/odb/shared-ptr/base.cxx new file mode 100644 index 0000000..11fa1c2 --- /dev/null +++ b/odb/shared-ptr/base.cxx @@ -0,0 +1,63 @@ +// file : odb/shared-ptr/base.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +using std::size_t; + +// +// +odb::share shared = odb::share (1); +odb::share exclusive = odb::share (2); + +// +// +namespace odb +{ + char const* not_shared:: + what () const throw () + { + return "object is not shared"; + } +} + +// +// +void* +operator new (size_t n, odb::share s) throw (std::bad_alloc) +{ + if (s == shared) + { + // Here we need to make sure we don't break the alignment of the + // returned block. For that we need to know the maximum alignment + // of this platform. Twice the pointer size is a good guess for + // most platforms. + // + size_t* p = static_cast (operator new (n + 2 * sizeof (size_t))); + *p++ = 1; // Initial count. + *p++ = 0xDEADBEEF; // Signature. + return p; + } + else + return operator new (n); + +} + +void +operator delete (void* p, odb::share s) throw () +{ + // This version of operator delete is only called when the c-tor + // fails. In this case there is no object and we can just free the + // memory. + // + if (s == shared) + { + size_t* sp = static_cast (p); + sp -= 2; + operator delete (sp); + } + else + operator delete (p); +} diff --git a/odb/shared-ptr/base.hxx b/odb/shared-ptr/base.hxx new file mode 100644 index 0000000..8c1b62b --- /dev/null +++ b/odb/shared-ptr/base.hxx @@ -0,0 +1,91 @@ +// file : odb/shared-ptr/base.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SHARED_PTR_BASE_HXX +#define ODB_SHARED_PTR_BASE_HXX + +#include +#include // std::size_t + +#include + +namespace odb +{ + struct share + { + explicit + share (char id); + + bool + operator== (share) const; + + private: + char id_; + }; +} + +extern odb::share shared; +extern odb::share exclusive; + +void* +operator new (std::size_t, odb::share) throw (std::bad_alloc); + +void +operator delete (void*, odb::share) throw (); + +namespace odb +{ + struct not_shared: exception + { + virtual char const* + what () const throw (); + }; + + struct shared_base + { + shared_base (); + shared_base (shared_base const&); + shared_base& + operator= (shared_base const&); + + void + _inc_ref (); + + bool + _dec_ref (); + + std::size_t + _ref_count () const; + + void* + operator new (std::size_t, share) throw (std::bad_alloc); + + void + operator delete (void*, share) throw (); + + void + operator delete (void*) throw (); + + protected: + std::size_t counter_; + }; + + template + inline X* + inc_ref (X*); + + template + inline void + dec_ref (X*); + + template + inline std::size_t + ref_count (X const*); +} + +#include +#include + +#endif // ODB_SHARED_PTR_BASE_HXX diff --git a/odb/shared-ptr/base.ixx b/odb/shared-ptr/base.ixx new file mode 100644 index 0000000..992e156 --- /dev/null +++ b/odb/shared-ptr/base.ixx @@ -0,0 +1,79 @@ +// file : odb/shared-ptr/base.ixx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + // share + // + + inline share:: + share (char id) + : id_ (id) + { + } + + inline bool share:: + operator== (share x) const + { + return id_ == x.id_; + } + + // shared_base + // + + inline shared_base:: + shared_base () + : counter_ (1) + { + } + + inline shared_base:: + shared_base (shared_base const&) + : counter_ (1) + { + } + + inline shared_base& shared_base:: + operator= (shared_base const&) + { + return *this; + } + + inline void shared_base:: + _inc_ref () + { + counter_++; + } + + inline bool shared_base:: + _dec_ref () + { + return --counter_ == 0; + } + + inline std::size_t shared_base:: + _ref_count () const + { + return counter_; + } + + inline void* shared_base:: + operator new (std::size_t n, share) throw (std::bad_alloc) + { + return ::operator new (n); + } + + inline void shared_base:: + operator delete (void* p, share) throw () + { + ::operator delete (p); + } + + inline void shared_base:: + operator delete (void* p) throw () + { + ::operator delete (p); + } +} diff --git a/odb/shared-ptr/base.txx b/odb/shared-ptr/base.txx new file mode 100644 index 0000000..a8d5f26 --- /dev/null +++ b/odb/shared-ptr/base.txx @@ -0,0 +1,183 @@ +// file : odb/shared-ptr/base.txx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include +#include + +namespace odb +{ + namespace bits + { + // Support for locating the counter in the memory block. + // + template ::r> + struct locator; + + template + struct locator + { + static std::size_t* + counter (X* x) + { + std::size_t* p (reinterpret_cast (x)); + + if (*(--p) != 0xDEADBEEF) + throw not_shared (); + + return --p; + } + }; + + template + struct locator + { + static std::size_t* + counter (X* x) + { + std::size_t* p ( + static_cast ( + dynamic_cast (x))); + + if (*(--p) != 0xDEADBEEF) + throw not_shared (); + + return --p; + } + }; + + template + std::size_t* + counter (X const* p) + { + return bits::locator::counter (const_cast (p)); + } + + // Counter type and operations. + // + meta::no test (...); + meta::yes test (shared_base*); + + template (0)))> + struct counter_type; + + template + struct counter_type + { + typedef X r; + }; + + template + struct counter_type + { + typedef shared_base r; + }; + + template + struct counter_ops; + + template + struct counter_ops + { + counter_ops (X const* p) : counter_ (p ? bits::counter (p) : 0) {} + counter_ops (counter_ops const& x) : counter_ (x.counter_) {} + + template + counter_ops (counter_ops const& x) : counter_ (x.counter_) {} + + counter_ops& + operator= (counter_ops const& x) + { + counter_ = x.counter_; + return *this; + } + + template + counter_ops& + operator= (counter_ops const& x) + { + counter_ = x.counter_; + return *this; + } + + void + reset (X const* p) + { + counter_ = p ? bits::counter (p) : 0; + } + + void + inc (X*) + { + (*counter_)++; + } + + void + dec (X* p) + { + if (--(*counter_) == 0) + { + p->~X (); + operator delete (counter_); // Counter is the top of the memory block. + } + } + + std::size_t + count (X const*) const + { + return *counter_; + } + + std::size_t* counter_; + }; + + template + struct counter_ops + { + counter_ops (Y const*) {} + + void + reset (Y const*) {} + + void + inc (shared_base* p) {p->_inc_ref ();} + + void + dec (Y* p) + { + if (static_cast (p)->_dec_ref ()) + delete p; + } + + std::size_t + count (shared_base const* p) const {return p->_ref_count ();} + }; + } + + template + inline X* + inc_ref (X* p) + { + bits::counter_ops::r, X> c (p); + c.inc (p); + return p; + } + + template + inline void + dec_ref (X* p) + { + bits::counter_ops::r, X> c (p); + c.dec (p); + } + + template + inline std::size_t + ref_count (X const* p) + { + bits::counter_ops::r, X> c (p); + return c.count (p); + } +} diff --git a/odb/traits.hxx b/odb/traits.hxx new file mode 100644 index 0000000..e8e109c --- /dev/null +++ b/odb/traits.hxx @@ -0,0 +1,93 @@ +// file : odb/traits.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_TRAITS_HXX +#define ODB_TRAITS_HXX + +#include // std::auto_ptr + +#include +#include +#include + +namespace odb +{ + enum id_source + { + ids_assigned /* Assigned by the application. */ + }; + + // Specializations should defined the following members: + // + // id_type - object id (primary key) type + // id_source - object id (primary key) source + // id_type id (const T&) - get object id + // + // void insert (database&, const T&) + // void update (database&, const T&) + // void erase (database&, const id_type&) + // memory_traits::shared_ptr find (database&, const id_type&) + // + // And inherit from object_memory and object_factory. + // + // template + // class access::object_traits; + + template + class access::object_memory + { + public: + typedef odb::shared_ptr shared_ptr; + typedef std::auto_ptr unique_ptr; + }; + + template + class access::object_factory + { + public: + static typename object_memory::shared_ptr + create () + { + // By default use shared_ptr-specific construction. + // + return shared_factory::shared_ptr>::create (); + } + }; + + template + class access::shared_factory + { + public: + typedef typename shared_ptr_traits

::type object_type; + + static P + create () + { + void* v (shared_ptr_traits

::allocate (sizeof (object_type))); + guard g (v); + P p (new (v) object_type); + g.release (); + return p; + } + private: + struct guard + { + guard (void* p): p_ (p) {} + ~guard () {if (p_) shared_ptr_traits

::free (p_);} + void release () {p_ = 0;} + void* p_; + }; + }; + + template + struct object_traits: access::object_traits + { + typedef + shared_ptr_traits::shared_ptr> + shared_ops; + }; +} + +#endif // ODB_TRAITS_HXX diff --git a/odb/transaction.cxx b/odb/transaction.cxx new file mode 100644 index 0000000..7b28ea2 --- /dev/null +++ b/odb/transaction.cxx @@ -0,0 +1,93 @@ +// file : odb/transaction.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include +#include + +namespace odb +{ + // + // transaction + // + + static transaction* current_transaction = 0; + + transaction:: + transaction (transaction_impl* impl) + : finilized_ (false), impl_ (impl) + { + current_transaction = this; + } + + transaction:: + ~transaction () + { + if (!finilized_) + { + try + { + rollback (); + } + catch (const database_exception&) + { + // Ignore it. + } + } + + current_transaction = 0; + delete impl_; + } + + bool transaction:: + has_current () + { + return current_transaction != 0; + } + + transaction& transaction:: + current () + { + if (current_transaction == 0) + throw not_in_transaction (); + + return *current_transaction; + } + + void transaction:: + commit () + { + if (finilized_) + throw transaction_already_finilized (); + + // Flush the session if we are in the session-per-transaction mode. + // + if (impl_->own_session ()) + session ().flush (); + + impl_->commit (); + finilized_ = true; + } + + void transaction:: + rollback () + { + if (finilized_) + throw transaction_already_finilized (); + + finilized_ = true; + impl_->rollback (); + } + + // + // transaction_impl + // + + transaction_impl:: + ~transaction_impl () + { + if (own_session ()) + reinterpret_cast (&session_mem_)->~session (); + } +} diff --git a/odb/transaction.hxx b/odb/transaction.hxx new file mode 100644 index 0000000..01d4a38 --- /dev/null +++ b/odb/transaction.hxx @@ -0,0 +1,139 @@ +// file : odb/transaction.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_TRANSACTION_HXX +#define ODB_TRANSACTION_HXX + +#include // placement new + +#include + +namespace odb +{ + class transaction_impl; + + class transaction + { + public: + typedef odb::session session_type; + typedef odb::database database_type; + + explicit + transaction (transaction_impl*); + + // Unless the transaction has been already been finilized (explicitly + // committed or rolled back), the destructor will roll it back. + // + ~transaction (); + + void + commit (); + + void + rollback (); + + // Return the database this transaction is on. + // + database_type& + database (); + + // Return the session this transaction is part of. + // + session_type& + session (); + + // Return current transaction or throw if there is no transaction + // in effect. + // + static transaction& + current (); + + // Return true if there is a transaction in effect. + // + static bool + has_current (); + + public: + transaction_impl& + implementation (); + + private: + // Copying or assignment of transactions is not supported. + // + transaction (const transaction&); + transaction& operator= (const transaction&); + + protected: + bool finilized_; + transaction_impl* impl_; + }; +} + +#include + +namespace odb +{ + class transaction_impl + { + protected: + friend class transaction; + + typedef odb::session session_type; + typedef odb::database database_type; + + transaction_impl (database_type& db, session_type& s) + : database_ (db), session_ (s) + { + } + + transaction_impl (database_type& db) + : database_ (db), + session_ (*reinterpret_cast (&session_mem_)) + { + new (&session_mem_) session_type (); + } + + virtual + ~transaction_impl (); + + virtual void + commit () = 0; + + virtual void + rollback () = 0; + + session_type& + session () + { + return session_; + } + + database_type& + database () + { + return database_; + } + + bool + own_session () const + { + return &session_ == reinterpret_cast (&session_mem_); + } + + protected: + database_type& database_; + session_type& session_; + + union + { + void* align_; + char data_[sizeof (session_type)]; + } session_mem_; + }; +} + +#include + +#endif // ODB_TRANSACTION_HXX diff --git a/odb/transaction.ixx b/odb/transaction.ixx new file mode 100644 index 0000000..e6247e6 --- /dev/null +++ b/odb/transaction.ixx @@ -0,0 +1,25 @@ +// file : odb/transaction.ixx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + inline transaction::database_type& transaction:: + database () + { + return impl_->database (); + } + + inline transaction::session_type& transaction:: + session () + { + return impl_->session (); + } + + inline transaction_impl& transaction:: + implementation () + { + return *impl_; + } +} -- cgit v1.1