diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2011-09-05 10:20:47 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2011-09-05 10:20:47 +0200 |
commit | 9c275a93cec797a021571ba8545906e0b4ffbfbc (patch) | |
tree | d1a697417df10bd7b5fc35fa795d20855047c5e9 | |
parent | 713b3a62d97c6bea7c23597094af6b2439314b8c (diff) |
Support for views; native part
-rw-r--r-- | odb/database.hxx | 6 | ||||
-rw-r--r-- | odb/database.ixx | 18 | ||||
-rw-r--r-- | odb/database.txx | 32 | ||||
-rw-r--r-- | odb/forward.hxx | 13 | ||||
-rw-r--r-- | odb/object-result.hxx | 336 | ||||
-rw-r--r-- | odb/object-result.txx (renamed from odb/result.txx) | 13 | ||||
-rw-r--r-- | odb/query.hxx | 32 | ||||
-rw-r--r-- | odb/result.hxx | 327 | ||||
-rw-r--r-- | odb/traits.hxx | 90 | ||||
-rw-r--r-- | odb/view-result.hxx | 331 | ||||
-rw-r--r-- | odb/view-result.txx | 49 |
11 files changed, 893 insertions, 354 deletions
diff --git a/odb/database.hxx b/odb/database.hxx index 5ec98a7..f24e0fa 100644 --- a/odb/database.hxx +++ b/odb/database.hxx @@ -19,6 +19,7 @@ #include <odb/exceptions.hxx> #include <odb/details/export.hxx> +#include <odb/details/meta/remove-const.hxx> namespace odb { @@ -159,7 +160,7 @@ namespace odb template <typename T> result<T> - query (const odb::query<typename object_traits<T>::object_type>&, + query (const odb::query<typename details::meta::remove_const<T>::result>&, bool cache = true); // Native database statement execution. @@ -208,6 +209,9 @@ namespace odb void erase_ (const typename object_traits<T>::pointer_type&); + template <typename T, class_kind kind> + struct query_; + private: database (const database&); database& operator= (const database&); diff --git a/odb/database.ixx b/odb/database.ixx index dbdcaec..c4b3c77 100644 --- a/odb/database.ixx +++ b/odb/database.ixx @@ -200,33 +200,33 @@ namespace odb inline result<T> database:: query (bool cache) { - // T can be const T while object_type will always be T. + // T can be const T. // - typedef typename odb::object_traits<T>::object_type object_type; + typedef typename details::meta::remove_const<T>::result type; - return query<T> (odb::query<object_type> (), cache); + return query<T> (odb::query<type> (), cache); } template <typename T> inline result<T> database:: query (const char* q, bool cache) { - // T can be const T while object_type will always be T. + // T can be const T. // - typedef typename odb::object_traits<T>::object_type object_type; + typedef typename details::meta::remove_const<T>::result type; - return query<T> (odb::query<object_type> (q), cache); + return query<T> (odb::query<type> (q), cache); } template <typename T> inline result<T> database:: query (const std::string& q, bool cache) { - // T can be const T while object_type will always be T. + // T can be const T. // - typedef typename odb::object_traits<T>::object_type object_type; + typedef typename details::meta::remove_const<T>::result type; - return query<T> (odb::query<object_type> (q), cache); + return query<T> (odb::query<type> (q), cache); } inline unsigned long long database:: diff --git a/odb/database.txx b/odb/database.txx index e60d7a8..8117997 100644 --- a/odb/database.txx +++ b/odb/database.txx @@ -223,19 +223,43 @@ namespace odb } template <typename T> - result<T> database:: - query (const odb::query<typename object_traits<T>::object_type>& q, - bool cache) + struct database::query_<T, class_object> { // 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; + static result<T> + call (database& db, const odb::query<object_type>& q) + { + return object_traits::template query<T> (db, q); + } + }; + + template <typename T> + struct database::query_<T, class_view> + { + // Const views are not supported. + // + typedef odb::view_traits<T> view_traits; + + static result<T> + call (database& db, const odb::query<T>& q) + { + return view_traits::query (db, q); + } + }; + + template <typename T> + result<T> database:: + query (const odb::query<typename details::meta::remove_const<T>::result>& q, + bool cache) + { if (!transaction::has_current ()) throw not_in_transaction (); - result<T> r (object_traits::template query<T> (*this, q)); + result<T> r (query_<T, class_traits<T>::kind>::call (*this, q)); if (cache) r.cache (); diff --git a/odb/forward.hxx b/odb/forward.hxx index 830193c..b253118 100644 --- a/odb/forward.hxx +++ b/odb/forward.hxx @@ -18,9 +18,6 @@ namespace odb class transaction; class session; - template <typename T> - class result; - namespace core { using odb::database; @@ -28,7 +25,6 @@ namespace odb using odb::connection_ptr; using odb::transaction; using odb::session; - using odb::result; } // Implementation details. @@ -43,6 +39,12 @@ namespace odb template <typename T, typename P> class object_factory; + template <typename T> + class view_traits; + + template <typename T, typename P> + class view_factory; + template <typename T, typename P> class pointer_factory; @@ -56,6 +58,9 @@ namespace odb template <typename T> struct object_traits; + template <typename T> + struct view_traits; + namespace details { template <> diff --git a/odb/object-result.hxx b/odb/object-result.hxx new file mode 100644 index 0000000..fcee125 --- /dev/null +++ b/odb/object-result.hxx @@ -0,0 +1,336 @@ +// file : odb/object-result.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_OBJECT_RESULT_HXX +#define ODB_OBJECT_RESULT_HXX + +#include <odb/pre.hxx> + +#include <cstddef> // std::ptrdiff_t, std::size_t +#include <iterator> // iterator categories + +#include <odb/forward.hxx> +#include <odb/result.hxx> +#include <odb/pointer-traits.hxx> + +#include <odb/details/shared-ptr.hxx> + +namespace odb +{ + template <typename T> + class result_impl<T, class_object>: public details::shared_base + { + public: + virtual + ~result_impl (); + + protected: + friend class result<T, class_object>; + friend class result_iterator<T, class_object>; + + typedef odb::database database_type; + + typedef typename odb::object_traits<T>::pointer_type pointer_type; + typedef odb::pointer_traits<pointer_type> pointer_traits; + + typedef typename odb::object_traits<T>::object_type object_type; + typedef typename odb::object_traits<T>::id_type id_type; + typedef odb::object_traits<object_type> object_traits; + + 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: + virtual void + load (object_type&) = 0; + + virtual id_type + load_id () = 0; + + virtual void + next () = 0; + + virtual void + cache () = 0; + + virtual std::size_t + size () = 0; + + protected: + void + current (pointer_type p) + { + current_ = p; + guard_.reset (current_); + } + + bool begin_; + bool end_; + + private: + database_type& db_; + pointer_type current_; + typename pointer_traits::guard guard_; + }; + + template <typename T> + class result_iterator<T, class_object> + { + public: + typedef T value_type; + typedef value_type& reference; + typedef value_type* pointer; + 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<T>::object_type object_type; + typedef typename object_traits<T>::id_type id_type; + + typedef result_impl<T, class_object> result_impl_type; + + public: + explicit + result_iterator (result_impl_type* res = 0) + : res_ (res) + { + } + + // Input iterator requirements. + // + public: + reference + operator* () const + { + return pointer_traits::get_ref (res_->current ()); + } + + // Our value_type is already a pointer so return it instead of + // a pointer to it (operator-> will just have to go one deeper + // in the latter case). + // + pointer + operator-> () const + { + return pointer_traits::get_ptr (res_->current ()); + } + + result_iterator& + operator++ () + { + res_->next (); + return *this; + } + + result_iterator + operator++ (int) + { + // All non-end iterators for a result object move together. + // + res_->next (); + return *this; + } + + 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&); + + public: + bool + equal (result_iterator j) const + { + return (res_ ? res_->end () : true) == (j.res_ ? j.res_->end () : true); + } + + private: + typedef + odb::pointer_traits<typename object_traits<T>::pointer_type> + pointer_traits; + + result_impl_type* res_; + }; + + // Input iterator requirements. + // + template <typename T> + inline bool + operator== (result_iterator<T, class_object> i, + result_iterator<T, class_object> j) + { + return i.equal (j); + } + + template <typename T> + inline bool + operator!= (result_iterator<T, class_object> i, + result_iterator<T, class_object> j) + { + return !i.equal (j); + } + + // + // + template <typename T> + class result<T, class_object> + { + public: + typedef typename object_traits<T>::pointer_type value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + + typedef result_iterator<T, class_object> iterator; + + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef result_impl<T, class_object> result_impl_type; + + public: + result () + { + } + + explicit + result (details::shared_ptr<result_impl_type> impl) + : impl_ (impl) + { + } + + // Copying or assignment of a result object leads to one instance + // being an alias for another. Think of copying a result as copying + // a file handle -- the file you access through either of them is + // still the same. + // + public: + result (const result& r) + : impl_ (r.impl_) + { + } + + result& + operator= (const result& r) + { + if (impl_ != r.impl_) + impl_ = r.impl_; + + return *this; + } + + void + swap (result& r) + { + // @@ add swap() to shared_ptr. + // + details::shared_ptr<result_impl_type> p (impl_); + impl_ = r.impl_; + r.impl_ = p; + } + + public: + iterator + begin () + { + if (impl_) + impl_->begin (); + + return iterator (impl_.get ()); + } + + iterator + end () + { + return iterator (); + } + + // Cache the result instead of fetching the data from the database + // one object at a time. This is necessary if you plan on performing + // database operations while iterating over the result. + // + public: + void + cache () + { + if (impl_) + impl_->cache (); + } + + public: + bool + empty () const + { + if (impl_ == 0) + return true; + + impl_->begin (); + return impl_->end (); + } + + // Size is only known in cached results. + // + size_type + size () const + { + return impl_ ? impl_->size () : 0; + } + + private: + details::shared_ptr<result_impl_type> impl_; + }; +} + +#include <odb/object-result.txx> + +#include <odb/post.hxx> + +#endif // ODB_OBJECT_RESULT_HXX diff --git a/odb/result.txx b/odb/object-result.txx index b0c4d61..bd4e95e 100644 --- a/odb/result.txx +++ b/odb/object-result.txx @@ -1,4 +1,4 @@ -// file : odb/result.txx +// file : odb/object-result.txx // author : Boris Kolpackov <boris@codesynthesis.com> // copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file @@ -8,14 +8,19 @@ namespace odb { + // + // result_impl + // + template <typename T> - result_impl<T>:: + result_impl<T, class_object>:: ~result_impl () { } template <typename T> - typename result_impl<T>::pointer_type& result_impl<T>:: + typename result_impl<T, class_object>::pointer_type& + result_impl<T, class_object>:: current () { typedef typename object_traits::pointer_type unrestricted_pointer_type; @@ -66,7 +71,7 @@ namespace odb // template <typename T> - void result_iterator<T>:: + void result_iterator<T, class_object>:: load (object_type& obj) { if (res_->end ()) diff --git a/odb/query.hxx b/odb/query.hxx index 5cdeb6f..780ae39 100644 --- a/odb/query.hxx +++ b/odb/query.hxx @@ -12,8 +12,36 @@ namespace odb { - template <typename T, - typename Q = typename object_traits<T>::query_base_type> + template <typename T, class_kind kind = class_traits<T>::kind> + struct query_selector; + + template <typename T> + struct query_selector<T, class_object> + { + typedef typename object_traits<T>::query_base_type base_type; + typedef typename object_traits<T>::query_type type; + + static const char* + table_name () + { + return object_traits<T>::table_name; + } + }; + + template <typename T> + struct query_selector<T, class_view> + { + typedef typename view_traits<T>::query_base_type base_type; + typedef typename view_traits<T>::query_type type; + + static const char* + table_name () + { + return ""; + } + }; + + template <typename T, typename Q = typename query_selector<T>::base_type> class query; namespace core diff --git a/odb/result.hxx b/odb/result.hxx index 17406e7..a997615 100644 --- a/odb/result.hxx +++ b/odb/result.hxx @@ -8,333 +8,34 @@ #include <odb/pre.hxx> -#include <cstddef> // std::ptrdiff_t, std::size_t -#include <iterator> // iterator categories - -#include <odb/forward.hxx> -#include <odb/pointer-traits.hxx> - -#include <odb/details/shared-ptr.hxx> +#include <odb/forward.hxx> // result +#include <odb/traits.hxx> namespace odb { - template <typename T> + template <typename T, class_kind kind = class_traits<T>::kind> class result; - template <typename T> + template <typename T, class_kind kind = class_traits<T>::kind> class result_iterator; - template <typename T> - class result_impl: public details::shared_base - { - public: - virtual - ~result_impl (); - - protected: - friend class result<T>; - friend class result_iterator<T>; - - typedef odb::database database_type; - - typedef typename odb::object_traits<T>::pointer_type pointer_type; - typedef odb::pointer_traits<pointer_type> pointer_traits; - - typedef typename odb::object_traits<T>::object_type object_type; - typedef typename odb::object_traits<T>::id_type id_type; - typedef odb::object_traits<object_type> object_traits; - - 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: - virtual void - load (object_type&) = 0; - - virtual id_type - load_id () = 0; - - virtual void - next () = 0; - - virtual void - cache () = 0; - - virtual std::size_t - size () = 0; - - protected: - void - current (pointer_type p) - { - current_ = p; - guard_.reset (current_); - } - - bool begin_; - bool end_; - - private: - database_type& db_; - pointer_type current_; - typename pointer_traits::guard guard_; - }; - - template <typename T> - class result_iterator - { - public: - typedef T value_type; - typedef value_type& reference; - typedef value_type* pointer; - 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<T>::object_type object_type; - typedef typename object_traits<T>::id_type id_type; - - public: - explicit - result_iterator (result_impl<T>* res = 0) - : res_ (res) - { - } - - // Input iterator requirements. - // - public: - reference - operator* () const - { - return pointer_traits::get_ref (res_->current ()); - } - - // Our value_type is already a pointer so return it instead of - // a pointer to it (operator-> will just have to go one deeper - // in the latter case). - // - pointer - operator-> () const - { - return pointer_traits::get_ptr (res_->current ()); - } - - result_iterator& - operator++ () - { - res_->next (); - return *this; - } - - result_iterator - operator++ (int) - { - // All non-end iterators for a result object move together. - // - res_->next (); - return *this; - } - - 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&); - - public: - bool - equal (result_iterator j) const - { - return (res_ ? res_->end () : true) == (j.res_ ? j.res_->end () : true); - } - - private: - typedef - odb::pointer_traits<typename object_traits<T>::pointer_type> - pointer_traits; - - result_impl<T>* res_; - }; - - // Input iterator requirements. - // - template <typename T> - inline bool - operator== (result_iterator<T> i, result_iterator<T> j) - { - return i.equal (j); - } - - template <typename T> - inline bool - operator!= (result_iterator<T> i, result_iterator<T> j) - { - return !i.equal (j); - } - - // - // - template <typename T> - class result - { - public: - typedef typename object_traits<T>::pointer_type value_type; - typedef value_type* pointer; - typedef const value_type* const_pointer; - typedef value_type& reference; - typedef const value_type& const_reference; - - typedef result_iterator<T> iterator; - - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - public: - result () - { - } - - explicit - result (details::shared_ptr<result_impl<T> > impl) - : impl_ (impl) - { - } - - // Copying or assignment of a result object leads to one instance - // being an alias for another. Think of copying a result as copying - // a file handle -- the file you access through either of them is - // still the same. - // - public: - result (const result& r) - : impl_ (r.impl_) - { - } - - result& - operator= (const result& r) - { - if (impl_ != r.impl_) - impl_ = r.impl_; - - return *this; - } - - void - swap (result& r) - { - // @@ add swap() to shared_ptr. - // - details::shared_ptr<result_impl<T> > p (impl_); - impl_ = r.impl_; - r.impl_ = p; - } - - public: - iterator - begin () - { - if (impl_) - impl_->begin (); - - return iterator (impl_.get ()); - } - - iterator - end () - { - return iterator (); - } - - // Cache the result instead of fetching the data from the database - // one object at a time. This is necessary if you plan on performing - // database operations while iterating over the result. - // - public: - void - cache () - { - if (impl_) - impl_->cache (); - } - - public: - bool - empty () const - { - if (impl_ == 0) - return true; - - impl_->begin (); - return impl_->end (); - } - - // Size is only known in cached results. - // - size_type - size () const - { - return impl_ ? impl_->size () : 0; - } - - private: - details::shared_ptr<result_impl<T> > impl_; - }; + template <typename T, class_kind kind> + class result_impl; namespace core { using odb::result; + using odb::result_iterator; } } -#include <odb/result.txx> - #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/traits.hxx b/odb/traits.hxx index 838373d..3f400cb 100644 --- a/odb/traits.hxx +++ b/odb/traits.hxx @@ -13,22 +13,6 @@ namespace odb { - // template <typename T> - // class access::object_traits; - // - // Specializations should define the following members: - // - // id_type - object id (primary key) type - // id_type id (const T&) - get object id - // - // void persist (database&, T&) - // void update (database&, T&) - // void erase (database&, const id_type&) - // pointer_type find (database&, const id_type&) - // bool find (database&, const id_type&, T&) - // - // - template <typename T, typename P> class access::object_factory { @@ -46,10 +30,26 @@ namespace odb }; template <typename T, typename P> + class access::view_factory + { + public: + typedef T view_type; + typedef P pointer_type; + + static P + create () + { + // By default use pointer-specific construction. + // + return pointer_factory<T, P>::create (); + } + }; + + template <typename T, typename P> class access::pointer_factory { public: - typedef T object_type; + typedef T value_type; typedef P pointer_type; static P @@ -61,6 +61,7 @@ namespace odb g.release (); return p; } + private: struct mem_guard { @@ -71,6 +72,33 @@ namespace odb }; }; + // + // class_traits + // + enum class_kind + { + class_object, + class_view, + class_composite, + class_other + }; + + template <typename T> + struct class_traits + { + static const class_kind kind = class_other; + }; + + template <typename T> + struct class_traits<const T> + { + static const class_kind kind = class_traits<T>::kind; + }; + + // + // object_traits + // + template <typename T> struct object_traits: access::object_traits<T>, @@ -142,6 +170,34 @@ namespace odb struct id_type {}; }; + // + // view_traits + // + + template <typename T> + struct view_traits: + access::view_traits<T>, + access::view_factory<T, typename access::view_traits<T>::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 view + // Or you forgot to include the corresponding -odb.hxx file. + // + + typedef + odb::pointer_traits<typename access::view_traits<T>::pointer_type> + pointer_traits; + + typedef typename access::view_traits<T>::view_type view_type; + typedef typename access::view_traits<T>::pointer_type pointer_type; + }; + + // + // composite_value_traits + // + template <typename T> struct composite_value_traits: access::composite_value_traits<T> { diff --git a/odb/view-result.hxx b/odb/view-result.hxx new file mode 100644 index 0000000..088969a --- /dev/null +++ b/odb/view-result.hxx @@ -0,0 +1,331 @@ +// file : odb/view-result.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_VIEW_RESULT_HXX +#define ODB_VIEW_RESULT_HXX + +#include <odb/pre.hxx> + +#include <cstddef> // std::ptrdiff_t, std::size_t +#include <iterator> // iterator categories + +#include <odb/forward.hxx> +#include <odb/result.hxx> +#include <odb/pointer-traits.hxx> + +#include <odb/details/shared-ptr.hxx> + +namespace odb +{ + template <typename T> + class result_impl<T, class_view>: public details::shared_base + { + public: + virtual + ~result_impl (); + + protected: + friend class result<T, class_view>; + friend class result_iterator<T, class_view>; + + typedef odb::database database_type; + + typedef typename odb::view_traits<T>::pointer_type pointer_type; + typedef odb::pointer_traits<pointer_type> pointer_traits; + + typedef typename odb::view_traits<T>::view_type view_type; + typedef odb::view_traits<view_type> view_traits; + + 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: + virtual void + load (view_type&) = 0; + + virtual void + next () = 0; + + virtual void + cache () = 0; + + virtual std::size_t + size () = 0; + + protected: + void + current (pointer_type p) + { + current_ = p; + guard_.reset (current_); + } + + bool begin_; + bool end_; + + private: + database_type& db_; + pointer_type current_; + typename pointer_traits::guard guard_; + }; + + template <typename T> + class result_iterator<T, class_view> + { + public: + typedef T value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef std::ptrdiff_t difference_type; + typedef std::input_iterator_tag iterator_category; + + // Const views are not supported, so this should be the same as T. + // + typedef typename view_traits<T>::view_type view_type; + + typedef result_impl<T, class_view> result_impl_type; + + public: + explicit + result_iterator (result_impl_type* res = 0) + : res_ (res) + { + } + + // Input iterator requirements. + // + public: + reference + operator* () const + { + return pointer_traits::get_ref (res_->current ()); + } + + // Our value_type is already a pointer so return it instead of + // a pointer to it (operator-> will just have to go one deeper + // in the latter case). + // + pointer + operator-> () const + { + return pointer_traits::get_ptr (res_->current ()); + } + + result_iterator& + operator++ () + { + res_->next (); + return *this; + } + + result_iterator + operator++ (int) + { + // All non-end iterators for a result object move together. + // + res_->next (); + return *this; + } + + public: + typename view_traits<T>::pointer_type + load () + { + typename view_traits<T>::pointer_type r (res_->current ()); + res_->release (); + return r; + } + + void + load (view_type&); + + public: + bool + equal (result_iterator j) const + { + return (res_ ? res_->end () : true) == (j.res_ ? j.res_->end () : true); + } + + private: + typedef + odb::pointer_traits<typename view_traits<T>::pointer_type> + pointer_traits; + + result_impl_type* res_; + }; + + // Input iterator requirements. + // + template <typename T> + inline bool + operator== (result_iterator<T, class_view> i, + result_iterator<T, class_view> j) + { + return i.equal (j); + } + + template <typename T> + inline bool + operator!= (result_iterator<T, class_view> i, + result_iterator<T, class_view> j) + { + return !i.equal (j); + } + + // + // + template <typename T> + class result<T, class_view> + { + public: + typedef typename view_traits<T>::pointer_type value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + + typedef result_iterator<T, class_view> iterator; + + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef result_impl<T, class_view> result_impl_type; + + public: + result () + { + } + + explicit + result (details::shared_ptr<result_impl_type> impl) + : impl_ (impl) + { + } + + // Copying or assignment of a result object leads to one instance + // being an alias for another. Think of copying a result as copying + // a file handle -- the file you access through either of them is + // still the same. + // + public: + result (const result& r) + : impl_ (r.impl_) + { + } + + result& + operator= (const result& r) + { + if (impl_ != r.impl_) + impl_ = r.impl_; + + return *this; + } + + void + swap (result& r) + { + // @@ add swap() to shared_ptr. + // + details::shared_ptr<result_impl_type> p (impl_); + impl_ = r.impl_; + r.impl_ = p; + } + + public: + iterator + begin () + { + if (impl_) + impl_->begin (); + + return iterator (impl_.get ()); + } + + iterator + end () + { + return iterator (); + } + + // Cache the result instead of fetching the data from the database + // one view at a time. This is necessary if you plan on performing + // database operations while iterating over the result. + // + public: + void + cache () + { + if (impl_) + impl_->cache (); + } + + public: + bool + empty () const + { + if (impl_ == 0) + return true; + + impl_->begin (); + return impl_->end (); + } + + // Size is only known in cached results. + // + size_type + size () const + { + return impl_ ? impl_->size () : 0; + } + + private: + details::shared_ptr<result_impl_type> impl_; + }; +} + +#include <odb/view-result.txx> + +#include <odb/post.hxx> + +#endif // ODB_VIEW_RESULT_HXX diff --git a/odb/view-result.txx b/odb/view-result.txx new file mode 100644 index 0000000..52d478e --- /dev/null +++ b/odb/view-result.txx @@ -0,0 +1,49 @@ +// file : odb/view-result.txx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + // + // result_impl + // + + template <typename T> + result_impl<T, class_view>:: + ~result_impl () + { + } + + template <typename T> + typename result_impl<T, class_view>::pointer_type& + result_impl<T, class_view>:: + current () + { + if (pointer_traits::null_ptr (current_) && !end_) + { + // For views, pointer_type is unrestricted_pointer_type. + // + pointer_type p (view_traits::create ()); + view_type& view (pointer_traits::get_ref (p)); + current (p); + load (view); + } + + return current_; + } + + // + // result_iterator + // + + template <typename T> + void result_iterator<T, class_view>:: + load (view_type& view) + { + if (res_->end ()) + return; + + res_->load (view); + } +} |