From 9c275a93cec797a021571ba8545906e0b4ffbfbc Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 5 Sep 2011 10:20:47 +0200 Subject: Support for views; native part --- odb/database.hxx | 6 +- odb/database.ixx | 18 +-- odb/database.txx | 32 ++++- odb/forward.hxx | 13 +- odb/object-result.hxx | 336 ++++++++++++++++++++++++++++++++++++++++++++++++++ odb/object-result.txx | 91 ++++++++++++++ odb/query.hxx | 32 ++++- odb/result.hxx | 327 +++--------------------------------------------- odb/result.txx | 86 ------------- odb/traits.hxx | 90 +++++++++++--- odb/view-result.hxx | 331 +++++++++++++++++++++++++++++++++++++++++++++++++ odb/view-result.txx | 49 ++++++++ 12 files changed, 975 insertions(+), 436 deletions(-) create mode 100644 odb/object-result.hxx create mode 100644 odb/object-result.txx delete mode 100644 odb/result.txx create mode 100644 odb/view-result.hxx create mode 100644 odb/view-result.txx (limited to 'odb') 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 #include +#include namespace odb { @@ -159,7 +160,7 @@ namespace odb template result - query (const odb::query::object_type>&, + query (const odb::query::result>&, bool cache = true); // Native database statement execution. @@ -208,6 +209,9 @@ namespace odb void erase_ (const typename object_traits::pointer_type&); + template + 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 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::object_type object_type; + typedef typename details::meta::remove_const::result type; - return query (odb::query (), cache); + return query (odb::query (), cache); } template inline result 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::object_type object_type; + typedef typename details::meta::remove_const::result type; - return query (odb::query (q), cache); + return query (odb::query (q), cache); } template inline result 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::object_type object_type; + typedef typename details::meta::remove_const::result type; - return query (odb::query (q), cache); + return query (odb::query (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 - result database:: - query (const odb::query::object_type>& q, - bool cache) + struct database::query_ { // 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; + static result + call (database& db, const odb::query& q) + { + return object_traits::template query (db, q); + } + }; + + template + struct database::query_ + { + // Const views are not supported. + // + typedef odb::view_traits view_traits; + + static result + call (database& db, const odb::query& q) + { + return view_traits::query (db, q); + } + }; + + template + result database:: + query (const odb::query::result>& q, + bool cache) + { if (!transaction::has_current ()) throw not_in_transaction (); - result r (object_traits::template query (*this, q)); + result r (query_::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 - 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 class object_factory; + template + class view_traits; + + template + class view_factory; + template class pointer_factory; @@ -56,6 +58,9 @@ namespace odb template struct object_traits; + template + 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 +// 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 + +#include // std::ptrdiff_t, std::size_t +#include // iterator categories + +#include +#include +#include + +#include + +namespace odb +{ + template + class result_impl: public details::shared_base + { + public: + virtual + ~result_impl (); + + protected: + friend class result; + friend class result_iterator; + + 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) + : 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 + 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::object_type object_type; + typedef typename object_traits::id_type id_type; + + typedef result_impl 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::pointer_type + load () + { + typename object_traits::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::pointer_type> + pointer_traits; + + result_impl_type* res_; + }; + + // Input iterator requirements. + // + template + inline bool + operator== (result_iterator i, + result_iterator j) + { + return i.equal (j); + } + + template + inline bool + operator!= (result_iterator i, + result_iterator j) + { + return !i.equal (j); + } + + // + // + template + class result + { + public: + typedef typename object_traits::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 iterator; + + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef result_impl result_impl_type; + + public: + result () + { + } + + explicit + result (details::shared_ptr 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 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 impl_; + }; +} + +#include + +#include + +#endif // ODB_OBJECT_RESULT_HXX diff --git a/odb/object-result.txx b/odb/object-result.txx new file mode 100644 index 0000000..bd4e95e --- /dev/null +++ b/odb/object-result.txx @@ -0,0 +1,91 @@ +// file : odb/object-result.txx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include +#include + +namespace odb +{ + // + // result_impl + // + + template + result_impl:: + ~result_impl () + { + } + + template + 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_) + { + if (!session::has_current ()) + { + unrestricted_pointer_type up (object_traits::create ()); + object_type& obj (unrestricted_pointer_traits::get_ref (up)); + current (pointer_type (up)); + load (obj); + } + else + { + // First check the session. + // + const id_type& id (load_id ()); + + pointer_type p ( + pointer_cache_traits::find (database (), id)); + + if (!pointer_traits::null_ptr (p)) + current (p); + else + { + unrestricted_pointer_type up (object_traits::create ()); + + typename + pointer_cache_traits::insert_guard ig ( + pointer_cache_traits::insert ( + database (), id, up)); + + object_type& obj (unrestricted_pointer_traits::get_ref (up)); + current (pointer_type (up)); + load (obj); + ig.release (); + } + } + } + + return current_; + } + + // + // result_iterator + // + + template + void result_iterator:: + load (object_type& obj) + { + if (res_->end ()) + return; + + if (!session::has_current ()) + res_->load (obj); + else + { + typename reference_cache_traits::insert_guard ig ( + reference_cache_traits::insert ( + res_->database (), res_->load_id (), obj)); + res_->load (obj); + ig.release (); + } + } +} 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 ::query_base_type> + template ::kind> + struct query_selector; + + template + struct query_selector + { + typedef typename object_traits::query_base_type base_type; + typedef typename object_traits::query_type type; + + static const char* + table_name () + { + return object_traits::table_name; + } + }; + + template + struct query_selector + { + typedef typename view_traits::query_base_type base_type; + typedef typename view_traits::query_type type; + + static const char* + table_name () + { + return ""; + } + }; + + template ::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 -#include // std::ptrdiff_t, std::size_t -#include // iterator categories - -#include -#include - -#include +#include // result +#include namespace odb { - template + template ::kind> class result; - template + template ::kind> class result_iterator; - template - class result_impl: public details::shared_base - { - public: - virtual - ~result_impl (); - - protected: - friend class result; - friend class result_iterator; - - 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) - : 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 - 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::object_type object_type; - typedef typename object_traits::id_type id_type; - - public: - explicit - result_iterator (result_impl* 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::pointer_type - load () - { - typename object_traits::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::pointer_type> - pointer_traits; - - result_impl* res_; - }; - - // Input iterator requirements. - // - template - inline bool - operator== (result_iterator i, result_iterator j) - { - return i.equal (j); - } - - template - inline bool - operator!= (result_iterator i, result_iterator j) - { - return !i.equal (j); - } - - // - // - template - class result - { - public: - typedef typename object_traits::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 iterator; - - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - public: - result () - { - } - - explicit - result (details::shared_ptr > 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 > 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 > impl_; - }; + template + class result_impl; namespace core { using odb::result; + using odb::result_iterator; } } -#include - #include #endif // ODB_RESULT_HXX + +// Include result specializations so that the user code only needs +// to include this header. +// + +#include +#include diff --git a/odb/result.txx b/odb/result.txx deleted file mode 100644 index b0c4d61..0000000 --- a/odb/result.txx +++ /dev/null @@ -1,86 +0,0 @@ -// file : odb/result.txx -// author : Boris Kolpackov -// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -#include -#include - -namespace odb -{ - template - result_impl:: - ~result_impl () - { - } - - template - 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_) - { - if (!session::has_current ()) - { - unrestricted_pointer_type up (object_traits::create ()); - object_type& obj (unrestricted_pointer_traits::get_ref (up)); - current (pointer_type (up)); - load (obj); - } - else - { - // First check the session. - // - const id_type& id (load_id ()); - - pointer_type p ( - pointer_cache_traits::find (database (), id)); - - if (!pointer_traits::null_ptr (p)) - current (p); - else - { - unrestricted_pointer_type up (object_traits::create ()); - - typename - pointer_cache_traits::insert_guard ig ( - pointer_cache_traits::insert ( - database (), id, up)); - - object_type& obj (unrestricted_pointer_traits::get_ref (up)); - current (pointer_type (up)); - load (obj); - ig.release (); - } - } - } - - return current_; - } - - // - // result_iterator - // - - template - void result_iterator:: - load (object_type& obj) - { - if (res_->end ()) - return; - - if (!session::has_current ()) - res_->load (obj); - else - { - typename reference_cache_traits::insert_guard ig ( - reference_cache_traits::insert ( - res_->database (), res_->load_id (), obj)); - res_->load (obj); - ig.release (); - } - } -} 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 - // 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 class access::object_factory { @@ -46,10 +30,26 @@ namespace odb }; template + 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::create (); + } + }; + + template 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 + struct class_traits + { + static const class_kind kind = class_other; + }; + + template + struct class_traits + { + static const class_kind kind = class_traits::kind; + }; + + // + // object_traits + // + template struct object_traits: access::object_traits, @@ -142,6 +170,34 @@ namespace odb struct id_type {}; }; + // + // view_traits + // + + template + struct view_traits: + access::view_traits, + access::view_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 view + // Or you forgot to include the corresponding -odb.hxx file. + // + + typedef + odb::pointer_traits::pointer_type> + pointer_traits; + + typedef typename access::view_traits::view_type view_type; + typedef typename access::view_traits::pointer_type pointer_type; + }; + + // + // composite_value_traits + // + template struct composite_value_traits: access::composite_value_traits { 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 +// 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 + +#include // std::ptrdiff_t, std::size_t +#include // iterator categories + +#include +#include +#include + +#include + +namespace odb +{ + template + class result_impl: public details::shared_base + { + public: + virtual + ~result_impl (); + + protected: + friend class result; + friend class result_iterator; + + typedef odb::database database_type; + + typedef typename odb::view_traits::pointer_type pointer_type; + typedef odb::pointer_traits pointer_traits; + + typedef typename odb::view_traits::view_type view_type; + typedef odb::view_traits 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 + 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; + + // Const views are not supported, so this should be the same as T. + // + typedef typename view_traits::view_type view_type; + + typedef result_impl 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::pointer_type + load () + { + typename view_traits::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::pointer_type> + pointer_traits; + + result_impl_type* res_; + }; + + // Input iterator requirements. + // + template + inline bool + operator== (result_iterator i, + result_iterator j) + { + return i.equal (j); + } + + template + inline bool + operator!= (result_iterator i, + result_iterator j) + { + return !i.equal (j); + } + + // + // + template + class result + { + public: + typedef typename view_traits::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 iterator; + + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef result_impl result_impl_type; + + public: + result () + { + } + + explicit + result (details::shared_ptr 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 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 impl_; + }; +} + +#include + +#include + +#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 +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + // + // result_impl + // + + template + result_impl:: + ~result_impl () + { + } + + template + typename result_impl::pointer_type& + result_impl:: + 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 + void result_iterator:: + load (view_type& view) + { + if (res_->end ()) + return; + + res_->load (view); + } +} -- cgit v1.1