aboutsummaryrefslogtreecommitdiff
path: root/odb/object-result.hxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-09-05 10:20:47 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-09-05 10:20:47 +0200
commit9c275a93cec797a021571ba8545906e0b4ffbfbc (patch)
treed1a697417df10bd7b5fc35fa795d20855047c5e9 /odb/object-result.hxx
parent713b3a62d97c6bea7c23597094af6b2439314b8c (diff)
Support for views; native part
Diffstat (limited to 'odb/object-result.hxx')
-rw-r--r--odb/object-result.hxx336
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