// file : odb/result.hxx // author : Boris Kolpackov // copyright : Copyright (c) 2009-2011 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 (); 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_; }; namespace core { using odb::result; } } #include #include #endif // ODB_RESULT_HXX