Fairport  v1.0.38
fairport/util/btree.h
Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00015 
00016 #ifndef FAIRPORT_UTIL_BTREE_H
00017 #define FAIRPORT_UTIL_BTREE_H
00018 
00019 #include <iterator>
00020 #include <vector>
00021 #include <boost/iterator/iterator_facade.hpp>
00022 
00023 #include "fairport/util/primitives.h"
00024 #include "fairport/util/errors.h"
00025 
00026 #ifdef _MSC_VER
00027 #pragma warning(push)
00028 #pragma warning(disable:4250)
00029 #endif
00030 
00031 namespace fairport
00032 {
00033 
00034 template<typename K, typename V>
00035 struct btree_iter_impl;
00036 
00037 template<typename K, typename V>
00038 class const_btree_node_iter;
00039 
00040 template<typename K, typename V>
00041 class btree_node_nonleaf;
00042 
00050 template<typename K, typename V>
00051 class btree_node
00052 {
00053 public:
00054     typedef const_btree_node_iter<K,V> const_iterator;
00055 
00056     virtual ~btree_node() { }
00057 
00064     virtual const V& lookup(const K& key) const = 0;
00065     
00071     virtual const K& get_key(uint pos) const = 0;
00072 
00077     virtual uint num_values() const = 0;
00078 
00085     const_iterator begin() const
00086         { return const_iterator(this, false); }
00087 
00093     const_iterator end() const
00094         { return const_iterator(this, true); }
00095 
00099     int binary_search(const K& key) const;
00100 
00101 protected:
00102 
00103     // iter support
00104     friend class const_btree_node_iter<K,V>;
00105     friend class btree_node_nonleaf<K,V>;
00108     virtual void first(btree_iter_impl<K,V>& iter) const = 0;
00111     virtual void last(btree_iter_impl<K,V>& iter) const = 0;
00114     virtual void next(btree_iter_impl<K,V>& iter) const = 0;
00117     virtual void prev(btree_iter_impl<K,V>& iter) const = 0;
00118 };
00119 
00130 template<typename K, typename V>
00131 class btree_node_leaf : public virtual btree_node<K,V>
00132 {
00133 public:
00134     virtual ~btree_node_leaf() { }
00135 
00140     const V& lookup(const K& key) const;
00141 
00145     virtual const V& get_value(uint pos) const = 0;
00146 
00147 protected:
00148 
00149     // iter support
00150     friend class const_btree_node_iter<K,V>;
00151     void first(btree_iter_impl<K,V>& iter) const
00152         { iter.m_leaf = const_cast<btree_node_leaf<K,V>* >(this); iter.m_leaf_pos = 0; }
00153     void last(btree_iter_impl<K,V>& iter) const
00154         { iter.m_leaf = const_cast<btree_node_leaf<K,V>* >(this); iter.m_leaf_pos = this->num_values()-1; }
00155     void next(btree_iter_impl<K,V>& iter) const;
00156     void prev(btree_iter_impl<K,V>& iter) const;
00157 };
00158 
00170 template<typename K, typename V>
00171 class btree_node_nonleaf : public virtual btree_node<K,V>
00172 {
00173 public:
00174     virtual ~btree_node_nonleaf() { }
00175 
00177     const V& lookup(const K& key) const;
00178 
00179 protected:
00183     virtual btree_node<K,V>* get_child(uint i) = 0;
00187     virtual const btree_node<K,V>* get_child(uint i) const = 0;
00188 
00189     // iter support
00190     friend class const_btree_node_iter<K,V>;
00191     friend class btree_node_leaf<K,V>;
00192     void first(btree_iter_impl<K,V>& iter) const;
00193     void last(btree_iter_impl<K,V>& iter) const;
00194     void next(btree_iter_impl<K,V>& iter) const;
00195     void prev(btree_iter_impl<K,V>& iter) const;
00196 };
00197 
00207 template<typename K, typename V>
00208 struct btree_iter_impl
00209 {
00210     btree_node_leaf<K,V>* m_leaf;   
00211     uint m_leaf_pos;                
00212 
00213     std::vector<std::pair<btree_node_nonleaf<K,V>*, uint> > m_path; 
00214     typedef typename std::vector<std::pair<btree_node_nonleaf<K,V>*, uint> >::iterator path_iter;
00215 };
00216 
00227 template<typename K, typename V>
00228 class const_btree_node_iter : public boost::iterator_facade<const_btree_node_iter<K,V>, const V, boost::bidirectional_traversal_tag>
00229 {
00230 public:
00232     const_btree_node_iter();
00233 
00237     const_btree_node_iter(const btree_node<K,V>* root, bool last);
00238 
00239 private:
00240     friend class boost::iterator_core_access;
00241 
00243     void increment() { m_impl.m_leaf->next(m_impl); }
00244 
00247     bool equal(const const_btree_node_iter& other) const 
00248         { return ((m_impl.m_leaf == other.m_impl.m_leaf) && (m_impl.m_leaf_pos == other.m_impl.m_leaf_pos)); }
00249 
00252     const V& dereference() const
00253         { return m_impl.m_leaf->get_value(m_impl.m_leaf_pos); }
00254 
00256     void decrement() { m_impl.m_leaf->prev(m_impl); }
00257 
00258     mutable btree_iter_impl<K,V> m_impl;    
00259 };
00260 
00261 } // end namespace
00262 
00263 template<typename K, typename V>
00264 int fairport::btree_node<K,V>::binary_search(const K& k) const
00265 {
00266     uint end = num_values();
00267     uint start = 0;
00268     uint mid = (start + end) / 2;
00269 
00270     while(mid < end)
00271     {
00272         if(get_key(mid) < k)
00273         {
00274             start = mid + 1;
00275         }
00276         else if(get_key(mid) == k)
00277         {
00278             return mid; 
00279         }
00280         else
00281         {
00282             end = mid;
00283         }
00284 
00285         mid = (start + end) / 2;
00286     }
00287 
00288     return mid - 1;
00289 }
00290 
00291 template<typename K, typename V>
00292 const V& fairport::btree_node_leaf<K,V>::lookup(const K& k) const
00293 {
00294     int location = this->binary_search(k);
00295 
00296     if(location == -1)
00297         throw key_not_found<K>(k);
00298     
00299     if(this->get_key(location) != k)
00300         throw key_not_found<K>(k);
00301 
00302     return get_value(location);
00303 }
00304     
00305 template<typename K, typename V>
00306 void fairport::btree_node_leaf<K,V>::next(btree_iter_impl<K,V>& iter) const
00307 {
00308     if(++iter.m_leaf_pos == this->num_values())
00309     {
00310         if(!iter.m_path.empty())
00311         {
00312             for(typename btree_iter_impl<K,V>::path_iter piter = iter.m_path.begin();
00313                 piter != iter.m_path.end(); 
00314                 ++piter)
00315             {
00316                 if((*piter).second + 1 < (*piter).first->num_values())
00317                 {
00318                     // we're done with this leaf
00319                     iter.m_leaf = NULL;
00320                     
00321                     iter.m_path.back().first->next(iter);
00322                     break;
00323                 }
00324             }
00325         }
00326     }
00327 }
00328 
00329 template<typename K, typename V>
00330 void fairport::btree_node_leaf<K,V>::prev(btree_iter_impl<K,V>& iter) const
00331 {
00332     if(iter.m_leaf_pos == 0)
00333     {
00334         if(!iter.m_path.empty())
00335         {
00336             for(typename btree_iter_impl<K,V>::path_iter piter = iter.m_path.begin();
00337                 piter != iter.m_path.end();
00338                 ++piter)
00339             {
00340                 // we're done with this leaf
00341                 iter.m_leaf = NULL;
00342                 
00343                 if((*piter).second != 0 && (*piter).first->num_values() > 1)
00344                 {
00345                     iter.m_path.back().first->prev(iter);
00346                     break;
00347                 }
00348             }
00349         }
00350     }
00351     else
00352     {
00353         --iter.m_leaf_pos;
00354     }
00355 }
00356 
00357 template<typename K, typename V>
00358 const V& fairport::btree_node_nonleaf<K,V>::lookup(const K& k) const
00359 {
00360     int location = this->binary_search(k);
00361 
00362     if(location == -1)
00363         throw key_not_found<K>(k);
00364 
00365     return get_child(location)->lookup(k);
00366 }
00367 
00368 template<typename K, typename V>
00369 void fairport::btree_node_nonleaf<K,V>::first(btree_iter_impl<K,V>& iter) const
00370 {
00371     iter.m_path.push_back(std::make_pair(const_cast<btree_node_nonleaf<K,V>*>(this), 0));
00372     get_child(0)->first(iter);
00373 }
00374 
00375 template<typename K, typename V>
00376 void fairport::btree_node_nonleaf<K,V>::last(btree_iter_impl<K,V>& iter) const
00377 {
00378     iter.m_path.push_back(std::make_pair(const_cast<btree_node_nonleaf<K,V>*>(this), this->num_values()-1));
00379     get_child(this->num_values()-1)->last(iter);
00380 }
00381 
00382 template<typename K, typename V>
00383 void fairport::btree_node_nonleaf<K,V>::next(btree_iter_impl<K,V>& iter) const
00384 {
00385     std::pair<btree_node_nonleaf<K,V>*, uint>& me = iter.m_path.back();
00386 
00387     if(++me.second == this->num_values())
00388     {
00389         // we're done, pop us off the path and call up
00390         if(iter.m_path.size() > 1)
00391         {
00392             iter.m_path.pop_back();
00393             iter.m_path.back().first->next(iter);
00394         }
00395     }
00396     else
00397     {
00398         // call into the next leaf
00399         get_child(me.second)->first(iter);
00400     }
00401 }
00402 
00403 template<typename K, typename V>
00404 void fairport::btree_node_nonleaf<K,V>::prev(btree_iter_impl<K,V>& iter) const
00405 {
00406     std::pair<btree_node_nonleaf<K,V>*, uint>& me = iter.m_path.back();
00407 
00408     if(me.second == 0)
00409     {
00410         // we're done, pop us off the path and call up
00411         if(iter.m_path.size() > 1)
00412         {
00413             iter.m_path.pop_back();
00414             iter.m_path.back().first->prev(iter);
00415         }
00416     }
00417     else
00418     {
00419         // call into the next child
00420         get_child(--me.second)->last(iter);
00421     }
00422 }
00423 
00424 template<typename K, typename V>
00425 fairport::const_btree_node_iter<K,V>::const_btree_node_iter()
00426 {
00427     m_impl.m_leaf_pos = 0;
00428     m_impl.m_leaf = NULL;
00429 }
00430 
00431 template<typename K, typename V>
00432 fairport::const_btree_node_iter<K,V>::const_btree_node_iter(const btree_node<K,V>* root, bool last)
00433 {
00434     if(last)
00435     {
00436         root->last(m_impl);
00437         ++m_impl.m_leaf_pos;
00438     }
00439     else
00440     {
00441         root->first(m_impl);
00442     }
00443 }
00444 
00445 #ifdef _MSC_VER
00446 #pragma warning(pop)
00447 #endif
00448 
00449 #endif