aboutsummaryrefslogtreecommitdiff
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
parent713b3a62d97c6bea7c23597094af6b2439314b8c (diff)
Support for views; native part
-rw-r--r--odb/database.hxx6
-rw-r--r--odb/database.ixx18
-rw-r--r--odb/database.txx32
-rw-r--r--odb/forward.hxx13
-rw-r--r--odb/object-result.hxx336
-rw-r--r--odb/object-result.txx (renamed from odb/result.txx)13
-rw-r--r--odb/query.hxx32
-rw-r--r--odb/result.hxx327
-rw-r--r--odb/traits.hxx90
-rw-r--r--odb/view-result.hxx331
-rw-r--r--odb/view-result.txx49
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);
+ }
+}