// file : odb/result.hxx // author : Boris Kolpackov // copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_RESULT_HXX #define ODB_RESULT_HXX #include #include // std::ptrdiff_t, std::size_t #include // iterator categories #include #include #include namespace odb { template class result; template class result_iterator; template class result_impl: public details::shared_base { public: virtual ~result_impl (); result_impl () : end_ (false), current_ () {} protected: friend class result; friend class result_iterator; typedef object_traits traits; typedef typename traits::pointer_type pointer_type; typedef typename traits::pointer_traits pointer_traits; pointer_type current (bool release) { if (pointer_traits::null_ptr (current_) && !end_) current (); pointer_type r (current_); if (release) { current_ = pointer_type (); guard_.release (); } return r; } bool end () const { return end_; } protected: virtual void current () = 0; virtual void current (T&) = 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 end_; private: 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; public: explicit result_iterator (result_impl* res = 0) : res_ (res) { } // Input iterator requirements. // public: reference operator* () const { return pointer_traits::get_ref (res_->current (false)); } // 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 (false)); } 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 () { return res_->current (true); } void load (T& x) { res_->current (x); } public: bool equal (result_iterator j) const { return (res_ ? res_->end () : true) == (j.res_ ? j.res_->end () : true); } private: typedef typename object_traits::pointer_traits 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 () { 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 { return impl_ == 0 || 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_RESULT_HXX