bdb_map.hpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:18k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: bdb_map.hpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/04/29 15:32:57  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [CATCHUP_003] Dev-tree R1.11
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. #ifndef BDB_MAP__HPP
  10. #define BDB_MAP__HPP
  11. /* $Id: bdb_map.hpp,v 1000.2 2004/04/29 15:32:57 gouriano Exp $
  12.  * ===========================================================================
  13.  *
  14.  *                            PUBLIC DOMAIN NOTICE
  15.  *               National Center for Biotechnology Information
  16.  *
  17.  *  This software/database is a "United States Government Work" under the
  18.  *  terms of the United States Copyright Act.  It was written as part of
  19.  *  the author's official duties as a United States Government employee and
  20.  *  thus cannot be copyrighted.  This software/database is freely available
  21.  *  to the public for use. The National Library of Medicine and the U.S.
  22.  *  Government have not placed any restriction on its use or reproduction.
  23.  *
  24.  *  Although all reasonable efforts have been taken to ensure the accuracy
  25.  *  and reliability of the software and data, the NLM and the U.S.
  26.  *  Government do not and cannot warrant the performance or results that
  27.  *  may be obtained by using this software or data. The NLM and the U.S.
  28.  *  Government disclaim all warranties, express or implied, including
  29.  *  warranties of performance, merchantability or fitness for any particular
  30.  *  purpose.
  31.  *
  32.  *  Please cite the author in any work or product based on this material.
  33.  *
  34.  * ===========================================================================
  35.  *
  36.  * Author:  Anatoliy Kuznetsov
  37.  *   
  38.  * File Description: Templates implementing Berkeley DB based maps with syntax
  39.  *                   close to standard associative containers
  40.  */
  41. #include <bdb/bdb_cursor.hpp>
  42. BEGIN_NCBI_SCOPE
  43. /** @addtogroup BDB_Map
  44.  *
  45.  * @{
  46.  */
  47. /// Internal template used for compiler based type mapping  
  48. /// (C++ templates specialization emplyed here)
  49. ///
  50. template<class T> struct CBDB_TypeMapper
  51. {
  52.     typedef T  TFieldType;
  53. };
  54. template<> struct CBDB_TypeMapper<int>
  55. {
  56.     typedef CBDB_FieldInt4 TFieldType;
  57. };
  58. template<> struct CBDB_TypeMapper<string>
  59. {
  60.     typedef CBDB_FieldLString TFieldType;
  61. };
  62. /// db_map_base 
  63. /// 
  64. template<class K, class T> class db_map_base
  65. {
  66. public:
  67.     typedef typename CBDB_TypeMapper<K>::TFieldType  db_first_type;
  68.     typedef typename CBDB_TypeMapper<T>::TFieldType  db_second_type;
  69.     typedef std::pair<K, T>   value_type;
  70.     struct File : public CBDB_File
  71.     {
  72.         db_first_type  key;
  73.         db_second_type value;
  74.         File(CBDB_File::EDuplicateKeys dup_keys)
  75.         : CBDB_File(dup_keys)
  76.         {
  77.             BindKey("Key", &key);
  78.             BindData("Value", &value, 1024);
  79.         }
  80.     };
  81.     typedef typename db_map_base<K, T>::File  map_file_type;
  82. protected:
  83.     // Base class for all db_map iterators
  84.     // Class opens its own copy of BerkeleyDB file and cursor on it.
  85.     class iterator_base
  86.     {        
  87.     protected:
  88.         enum EIteratorStatus {
  89.             eUnknown,
  90.             eEnd,
  91.             eBeforeBegin,
  92.             eInFile
  93.         };
  94.         iterator_base(map_file_type* db_file)
  95.         : m_ParentFile(db_file),
  96.           m_CursorFile(0),
  97.           m_Cur(0),
  98.           m_OpenMode(CBDB_RawFile::eReadOnly),
  99.           m_IStatus(eUnknown)
  100.         {
  101.         }
  102.         ~iterator_base()
  103.         {
  104.             delete m_Cur;
  105.             delete m_CursorFile;
  106.         }
  107.         iterator_base(const iterator_base& it)
  108.         {
  109.             init_from(it);
  110.         }
  111.         iterator_base& operator=(const iterator_base& it)
  112.         {
  113.             return init_from(it);
  114.         }
  115.         iterator_base& init_from(const iterator_base& it)
  116.         {
  117.             m_ParentFile = it.m_ParentFile;
  118.             m_CursorFile = 0;
  119.             m_Cur = 0;
  120.             m_OpenMode = it.m_OpenMode;
  121.             m_SearchFlag = it.m_SearchFlag;
  122.             m_pair.first = it.m_pair.first;
  123.             m_pair.second = it.m_pair.second;
  124.             m_IStatus = it.m_IStatus;
  125.             return *this;
  126.         }
  127.         void open_cursor(CBDB_RawFile::EOpenMode open_mode, 
  128.                          CBDB_FileCursor::ECondition cursor_condition) const
  129.         {
  130.             delete m_Cur; m_Cur = 0;
  131.             bool attached = m_CursorFile->IsAttached();
  132.             if (!attached) {
  133.                 m_CursorFile->Attach(*m_ParentFile);
  134.             }
  135.             m_Cur = new CBDB_FileCursor(*m_CursorFile);
  136.             m_Cur->SetCondition(cursor_condition);
  137.         }
  138.         void open_cursor(CBDB_RawFile::EOpenMode open_mode, 
  139.                          CBDB_FileCursor::ECondition cursor_condition,
  140.                          const K& key) const
  141.         {
  142.             open_cursor(open_mode, cursor_condition);
  143.             m_Cur->From << key;
  144.         }
  145.         // db_map iterators are quite heavy (opens BDB cursors and stuff) and
  146.         // to simplify the iteratros coping and assignments we use lazy initilization
  147.         // It means actual db operation is postponed until the first iterator access.
  148.         void check_open_cursor() const
  149.         {
  150.             if (m_CursorFile == 0) {
  151.                 _ASSERT(m_ParentFile);
  152.                 m_CursorFile = new map_file_type(m_ParentFile->GetDupKeysMode());
  153.                 _ASSERT(m_Cur == 0);
  154.                 if (m_SearchFlag) {
  155.                     open_cursor(m_OpenMode, CBDB_FileCursor::eGE, m_pair.first);
  156.                 } else {
  157.                     if (m_IStatus == eEnd) {
  158.                         open_cursor(m_OpenMode, CBDB_FileCursor::eLast);
  159.                         m_Cur->ReverseFetchDirection();
  160.                     } else {
  161.                         open_cursor(m_OpenMode, CBDB_FileCursor::eFirst);
  162.                     }
  163.                 }
  164.                 if (m_Cur->Fetch() ==  eBDB_Ok) {
  165.                     m_SearchFlag = true;
  166.                     m_pair.first = m_CursorFile->key;
  167.                     m_pair.second= m_CursorFile->value;
  168.                     if (m_IStatus == eEnd) {
  169.                     } else {
  170.                         m_IStatus = eInFile;
  171.                     }
  172.                 } else { // No data...
  173.                     // go to the end
  174.                     open_cursor(m_OpenMode, CBDB_FileCursor::eLast);
  175.                     m_IStatus = eEnd;
  176.                 }
  177.             }
  178.         }
  179.         void go_end()
  180.         {
  181.             if (m_IStatus == eEnd) return;
  182.             // if it's "end()" iterartor, no need to open any files here
  183.             if (m_CursorFile == 0) {
  184.                 m_IStatus = eEnd;
  185.                 return;
  186.             }
  187.             open_cursor(m_OpenMode, CBDB_FileCursor::eLast);
  188.             m_Cur->ReverseFetchDirection();
  189.             if (m_Cur->Fetch() == eBDB_Ok) {
  190.                 m_pair.first = (K)m_CursorFile->key;
  191.                 m_pair.second= (T)m_CursorFile->value;
  192.             }
  193.             m_IStatus = eEnd;
  194.         }
  195.         void fetch_next()
  196.         {
  197.             _ASSERT(m_IStatus != eEnd);
  198.             check_open_cursor();
  199.             if (m_Cur->Fetch() == eBDB_Ok) {
  200.                 m_pair.first = m_CursorFile->key;
  201.                 m_pair.second= m_CursorFile->value;
  202.                 m_IStatus = eInFile;
  203.             } else {
  204.                 m_IStatus = eEnd;
  205.             }
  206.         }
  207.         void fetch_prev()
  208.         {
  209.             _ASSERT(m_IStatus != eBeforeBegin);
  210.             check_open_cursor();
  211.             if (m_Cur->Fetch(CBDB_FileCursor::eBackward) == eBDB_Ok) {
  212.                 m_pair.first = m_CursorFile->key;
  213.                 m_pair.second= m_CursorFile->value;
  214.                 m_IStatus = eInFile;
  215.             } else {
  216.                 m_IStatus = eBeforeBegin;
  217.             }
  218.         }
  219.         bool is_equal(const iterator_base& it) const
  220.         {
  221.             if (m_ParentFile != it.m_ParentFile) 
  222.                 return false;
  223.             if (m_IStatus == eUnknown) {
  224.                 check_open_cursor();
  225.             }
  226.             if (m_IStatus == it.m_IStatus) {
  227.                 if (m_IStatus == eEnd && it.m_IStatus == eEnd) 
  228.                     return true;
  229.                 if (m_IStatus == eBeforeBegin && it.m_IStatus == eBeforeBegin)
  230.                     return true;
  231.                 return (m_pair.first == it.m_pair.first);
  232.             }
  233.             return false;
  234.         }
  235.     public: 
  236.         // Return TRUE while iterator is in the correct range
  237.         bool valid() const
  238.         {
  239.             check_open_cursor();
  240.             if (m_IStatus == eEnd) return false;
  241.             if (m_IStatus == eBeforeBegin) return false;
  242.             return true;
  243.         }
  244.     protected:
  245.         mutable map_file_type*             m_ParentFile;
  246.         mutable map_file_type*             m_CursorFile;
  247.         mutable CBDB_FileCursor*           m_Cur;
  248.         // Cursor open mode
  249.         CBDB_RawFile::EOpenMode m_OpenMode;
  250.         // TRUE if iterator searches for the specific key
  251.         mutable bool                    m_SearchFlag;
  252.          // Current key-value pair
  253.         mutable value_type              m_pair;
  254.         // Iterator "navigation" status
  255.         mutable EIteratorStatus         m_IStatus;
  256.     };
  257. public:
  258.     class const_iterator : public iterator_base
  259.     {
  260.     public:
  261.         const_iterator(map_file_type* db_file)
  262.         : iterator_base(db_file)
  263.         {
  264.             this->m_SearchFlag = false;
  265.         }
  266.         const_iterator(map_file_type* db_file, const K& key)
  267.         : iterator_base(db_file)
  268.         {
  269.             this->m_SearchFlag = true;
  270.             this->m_pair.first = key;
  271.         }
  272.         const_iterator& go_end()
  273.         {
  274.             iterator_base::go_end();
  275.             return *this;
  276.         }
  277.         const_iterator() : iterator_base(0) 
  278.         {}
  279.         const_iterator(const const_iterator& it) : iterator_base(it)
  280.         {}
  281.         
  282.         const_iterator& operator=(const const_iterator& it) 
  283.         { 
  284.             init_from(it);return *this;
  285.         }
  286.         const value_type& operator*() const
  287.         {
  288.             this->check_open_cursor();
  289.             return this->m_pair;
  290.         }
  291.         const value_type* operator->() const
  292.         {
  293.             this->check_open_cursor();
  294.             return &this->m_pair;
  295.         }
  296.         
  297.         const_iterator& operator++() 
  298.         { 
  299.             this->fetch_next();
  300.             return *this; 
  301.         }
  302.         const_iterator operator++(int) 
  303.         {
  304.             const_iterator tmp(*this);
  305.             this->fetch_next();
  306.             return tmp; 
  307.         }
  308.         const_iterator& operator--() 
  309.         { 
  310.             this->fetch_prev();
  311.             return *this;
  312.         }
  313.         const_iterator operator--(int) 
  314.         {
  315.             const_iterator tmp(*this);    
  316.             this->fetch_prev(); 
  317.             return tmp;
  318.         }
  319.         bool operator==(const const_iterator& it) 
  320.         { 
  321.             return is_equal(it); 
  322.         }
  323.         bool operator!=(const const_iterator& it) 
  324.         { 
  325.             return !is_equal(it);
  326.         }
  327.     };
  328. public:
  329.     db_map_base(CBDB_File::EDuplicateKeys dup_keys) : m_Dbf(dup_keys) {}
  330.     void open(const char* fname, 
  331.               ios_base::openmode mode=ios_base::in|ios_base::out,
  332.               unsigned int cache_size=0);
  333.     void open(const char* fname, 
  334.               CBDB_RawFile::EOpenMode db_mode,
  335.               unsigned int cache_size=0);
  336.     const_iterator begin() const;
  337.     const_iterator end() const;
  338.     const_iterator find(const K& key) const;
  339.     size_t  size() const;
  340.     void clear();
  341.     void erase(const K& key);
  342. protected:
  343.     mutable File       m_Dbf;
  344. };
  345. /// db_map template, mimics std::map<> using BerkeleyDB as the underlying
  346. /// Btree mechanism.
  347. ///
  348. /// NOTE: const methods of this template are conditionally thread safe due 
  349. /// to the use of mutable variables.
  350. /// If you access to access one instance of db_map from more than one thread,
  351. /// external syncronization is required.
  352. template<class K, class T> class db_map : public db_map_base<K, T>
  353. {
  354. public:
  355.     typedef typename CBDB_TypeMapper<K>::TFieldType  db_first_type;
  356.     typedef typename CBDB_TypeMapper<T>::TFieldType  db_second_type;
  357.     typedef K                                        key_type;
  358.     typedef T                                        referent_type;
  359.     typedef std::pair<const K, T>                          value_type;
  360.     typedef db_map<K, T>                             self_type;
  361.     typedef typename self_type::iterator_base        iterator_base_type;
  362. public:
  363.     db_map() : db_map_base<K, T>(CBDB_File::eDuplicatesDisable) {}
  364.     //
  365.     // Determines whether an element y exists in the map whose key matches that of x.
  366.     // If not creates such an element and returns TRUE. Otherwise returns FALSE.
  367.     bool insert(const value_type& x);
  368.     referent_type operator[](const K& key);
  369. };
  370. /// db_multimap template, mimics std::multimap<> using BerkeleyDB as 
  371. /// the underlying Btree mechanism.
  372. ///
  373. /// NOTE: const methods of this template are conditionally thread safe due 
  374. /// to the use of mutable variables.
  375. /// If you access to access one instance of db_map from more than one thread,
  376. /// external syncronization is required.
  377. ///
  378. template<class K, class T> class db_multimap : public db_map_base<K, T>
  379. {
  380. public:
  381.     typedef typename CBDB_TypeMapper<K>::TFieldType  db_first_type;
  382.     typedef typename CBDB_TypeMapper<T>::TFieldType  db_second_type;
  383.     typedef K                       key_type;
  384.     typedef T                       referent_type;
  385.     typedef std::pair<const K, T>   value_type;
  386.     typedef db_multimap<K, T>       self_type;
  387.     typedef typename self_type::iterator_base iterator_base_type;
  388. public:
  389.     db_multimap() : db_map_base<K, T>(CBDB_File::eDuplicatesEnable) {}
  390.     void insert(const value_type& x);
  391. };
  392. /* @} */
  393. /////////////////////////////////////////////////////////////////////////////
  394. //  IMPLEMENTATION of INLINE functions
  395. /////////////////////////////////////////////////////////////////////////////
  396. inline 
  397. CBDB_RawFile::EOpenMode iosbase2BDB(ios_base::openmode mode)
  398. {
  399.     CBDB_RawFile::EOpenMode db_mode = CBDB_RawFile::eReadWriteCreate;
  400.     // Mapping iostream based open mode into BDB open mode
  401.     //
  402.     if (mode & ios_base::in) {
  403.         db_mode = 
  404.           (mode & ios_base::out) 
  405.             ? CBDB_RawFile::eReadWriteCreate : CBDB_RawFile::eReadOnly;
  406.     } else {
  407.         if (mode & ios_base::out) {
  408.             db_mode = CBDB_RawFile::eReadWriteCreate;
  409.             if (mode & ios_base::trunc) {
  410.                 db_mode = CBDB_RawFile::eCreate;
  411.             }
  412.         }
  413.     }
  414.     return db_mode;
  415. }
  416. /////////////////////////////////////////////////////////////////////////////
  417. //
  418. //  db_map_base
  419. //
  420. template<class K, class T>
  421. void db_map_base<K, T>::open(const char* fname,
  422.                              ios_base::openmode mode,
  423.                              unsigned int cache_size)
  424. {
  425.     CBDB_RawFile::EOpenMode db_mode = iosbase2BDB(mode);
  426.     open(fname, db_mode, cache_size);
  427. }
  428. template<class K, class T>
  429. void db_map_base<K, T>::open(const char* fname, 
  430.                              CBDB_RawFile::EOpenMode db_mode,
  431.                              unsigned int cache_size)
  432. {
  433.     if (cache_size)
  434.         m_Dbf.SetCacheSize(cache_size);
  435.     m_Dbf.Open(fname, db_mode);
  436.     m_Dbf.SetLegacyStringsCheck(true);
  437. }
  438. template<class K, class T>
  439. typename db_map_base<K, T>::const_iterator  db_map_base<K, T>::begin() const
  440. {
  441.     return const_iterator(&m_Dbf);
  442. }
  443. template<class K, class T>
  444. typename db_map_base<K, T>::const_iterator  db_map_base<K, T>::end() const
  445. {
  446.     const_iterator it(&m_Dbf);
  447.     return it.go_end();
  448. }
  449. template<class K, class T>
  450. typename db_map_base<K, T>::const_iterator db_map_base<K, T>::find(const K& key) const
  451. {
  452.     return const_iterator(&m_Dbf, key);
  453. }
  454. template<class K, class T>
  455. size_t db_map_base<K, T>::size() const
  456. {
  457.     return m_Dbf.CountRecs();
  458. }
  459. template<class K, class T>
  460. void db_map_base<K, T>::clear()
  461. {
  462.     m_Dbf.Truncate();
  463. }
  464. template<class K, class T>
  465. void db_map_base<K, T>::erase(const K& key)
  466. {
  467.     m_Dbf.key = key;
  468.     m_Dbf.Delete();
  469. }
  470. /////////////////////////////////////////////////////////////////////////////
  471. //
  472. //  db_map
  473. //
  474. template<class K, class T>
  475. bool db_map<K, T>::insert(const value_type& x)
  476. {
  477.     this->m_Dbf.key = x.first;
  478.     this->m_Dbf.value = x.second;
  479.     EBDB_ErrCode ret = this->m_Dbf.Insert();
  480.     return (ret == eBDB_Ok);
  481. }
  482. template<class K, class T>
  483. typename db_map<K, T>::referent_type  db_map<K, T>::operator[](const K& key)
  484. {
  485.     this->m_Dbf.key = key;
  486.     EBDB_ErrCode ret = this->m_Dbf.Fetch();
  487.     if (ret == eBDB_Ok) {
  488.         return (T) this->m_Dbf.value;
  489.     }
  490.     return (T) this->m_Dbf.value;
  491. }
  492. /////////////////////////////////////////////////////////////////////////////
  493. //
  494. //  db_multimap
  495. //
  496. template<class K, class T>
  497. void db_multimap<K, T>::insert(const value_type& x)
  498. {
  499.     this->m_Dbf.key = x.first;
  500.     this->m_Dbf.value = x.second;
  501.     EBDB_ErrCode ret = this->m_Dbf.Insert();
  502.     BDB_CHECK(ret, this->m_Dbf.GetFileName().c_str());
  503. }
  504. END_NCBI_SCOPE
  505. /*
  506.  * ===========================================================================
  507.  * $Log: bdb_map.hpp,v $
  508.  * Revision 1000.2  2004/04/29 15:32:57  gouriano
  509.  * PRODUCTION: UPGRADED [CATCHUP_003] Dev-tree R1.11
  510.  *
  511.  * Revision 1.11  2004/04/26 16:43:59  ucko
  512.  * Qualify inherited dependent names with this-> where needed by GCC 3.4.
  513.  *
  514.  * Revision 1.10  2004/02/11 17:59:05  kuznets
  515.  * Set legacy strings checking by default
  516.  *
  517.  * Revision 1.9  2004/02/04 17:04:58  kuznets
  518.  * Make use of LString type in map objects to handle non-ASCIIZ strings
  519.  *
  520.  * Revision 1.8  2003/12/16 17:47:09  kuznets
  521.  * minor code cleanup
  522.  *
  523.  * Revision 1.7  2003/09/29 14:30:22  kuznets
  524.  * Comments doxygenification
  525.  *
  526.  * Revision 1.6  2003/07/24 15:43:25  kuznets
  527.  * Fixed SUN compilation problems
  528.  *
  529.  * Revision 1.5  2003/07/23 20:22:50  kuznets
  530.  * Implemened:  clean(), erase()
  531.  *
  532.  * Revision 1.4  2003/07/23 18:09:51  kuznets
  533.  * + "cache size" parameter for bdb_map bdb_multimap
  534.  *
  535.  * Revision 1.3  2003/07/22 16:38:00  kuznets
  536.  * Fixing compilation problems
  537.  *
  538.  * Revision 1.2  2003/07/22 15:15:46  kuznets
  539.  * Work in progress, multiple changes, added db_multimap template.
  540.  *
  541.  * Revision 1.1  2003/07/18 20:48:29  kuznets
  542.  * Initial revision
  543.  *
  544.  *
  545.  * ===========================================================================
  546.  */
  547. #endif