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 /odb/object-result.hxx | |
parent | 713b3a62d97c6bea7c23597094af6b2439314b8c (diff) |
Support for views; native part
Diffstat (limited to 'odb/object-result.hxx')
-rw-r--r-- | odb/object-result.hxx | 336 |
1 files changed, 336 insertions, 0 deletions
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 |