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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: resize_iter.hpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 19:38:43  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.9
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. #ifndef RESIZE_ITER__HPP
  10. #define RESIZE_ITER__HPP
  11. /*  $Id: resize_iter.hpp,v 1000.3 2004/06/01 19:38:43 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:  Aaron Ucko
  37. *
  38. * File Description:
  39. *   CConstResizingIterator: handles sequences represented as packed
  40. *   sequences of elements of a different size; for instance, a
  41. *   "vector<char>" might actually hold 2-bit nucleotides or 32-bit integers.
  42. *   Assumes a big-endian representation: the MSBs of the first elements of
  43. *   the input and output sequences line up.
  44. */
  45. #include <corelib/ncbistd.hpp>
  46. #include <iterator>
  47. #include <limits.h>
  48. /** @addtogroup ResizingIterator
  49.  *
  50.  * @{
  51.  */
  52. BEGIN_NCBI_SCOPE
  53. template <class TSeq, class TOut = int>
  54. class CConstResizingIterator
  55. {
  56.     // Acts like an STL input iterator, with two exceptions:
  57.     //  1. It does not support ->, but TOut should be scalar anyway.
  58.     //  2. It caches the last value read, so might not adequately
  59.     //     reflect changes to the underlying sequence.
  60.     // Also has forward-iterator semantics iff TSeq::const_iterator does.
  61.     typedef typename TSeq::const_iterator TRawIterator;
  62.     typedef typename TSeq::value_type     TRawValue;
  63. public:
  64.     typedef input_iterator_tag iterator_category;
  65.     typedef TOut               value_type;
  66.     typedef size_t             difference_type;
  67.     // no pointer or reference.
  68.     CConstResizingIterator(const TSeq& s, size_t new_size /* in bits */)
  69.         : m_RawIterator(s.begin()), m_End(s.end()), m_NewSize(new_size),
  70.           m_BitOffset(0), m_ValueKnown(false) {}
  71.     CConstResizingIterator(const TRawIterator& it, const TRawIterator& end,
  72.                            size_t new_size)
  73.         : m_RawIterator(it), m_End(end), m_NewSize(new_size), m_BitOffset(0),
  74.           m_ValueKnown(false) {}
  75.     CConstResizingIterator<TSeq, TOut> & operator++(); // prefix
  76.     CConstResizingIterator<TSeq, TOut> operator++(int); // postfix
  77.     TOut operator*();
  78.     // No operator->; see above.
  79.     bool AtEnd() const;
  80. private:
  81.     TRawIterator m_RawIterator;
  82.     TRawIterator m_End;
  83.     size_t       m_NewSize;
  84.     size_t       m_BitOffset;
  85.     TOut         m_Value;
  86.     bool         m_ValueKnown;
  87.     // If m_ValueKnown is true, we have already determined the value at
  88.     // the current position and stored it in m_Value, advancing 
  89.     // m_RawIterator + m_BitOffset along the way.  Otherwise, m_Value still
  90.     // holds the previously accessed value, and m_RawIterator + m_BitOffset
  91.     // points at the beginning of the current value.  This system is
  92.     // necessary to handle multiple dereferences to a value spanning
  93.     // multiple elements of the original sequence.
  94. };
  95. template <class TSeq, class TVal = int>
  96. class CResizingIterator
  97. {
  98.     typedef typename TSeq::iterator   TRawIterator;
  99.     // must be a mutable forward iterator.
  100.     typedef typename TSeq::value_type TRawValue;
  101. public:
  102.     typedef forward_iterator_tag iterator_category;
  103.     typedef TVal                 value_type;
  104.     typedef size_t               difference_type;
  105.     // no pointer or reference.
  106.     CResizingIterator(TSeq& s, size_t new_size)
  107.         : m_RawIterator(s.begin()), m_End(s.end()), m_NewSize(new_size),
  108.           m_BitOffset(0) {}
  109.     CResizingIterator(const TRawIterator& start, const TRawIterator& end,
  110.                       size_t new_size)
  111.         : m_RawIterator(start), m_End(end), m_NewSize(new_size), m_BitOffset(0)
  112.         {}
  113.     CResizingIterator<TSeq, TVal> & operator++(); // prefix
  114.     CResizingIterator<TSeq, TVal> operator++(int); // postfix
  115.     CResizingIterator<TSeq, TVal> operator*()
  116.         { return *this; } // acts as its own proxy type
  117.     // Again, no operator->.
  118.     void operator=(TVal value);
  119.     operator TVal();
  120.     bool AtEnd() const;
  121. private:
  122.     TRawIterator m_RawIterator;
  123.     TRawIterator m_End;
  124.     size_t       m_NewSize;
  125.     size_t       m_BitOffset;    
  126. };
  127. /* @} */
  128. ///////////////////////////////////////////////////////////////////////////
  129. //
  130. // INLINE FUNCTIONS
  131. //
  132. // This code contains some heavy bit-fiddling; take care when modifying it.
  133. #ifndef CHAR_BIT
  134. #define CHAR_BIT 8
  135. #endif
  136. template <class T>
  137. size_t xx_BitsPerElement(const T*)
  138. {
  139.     return CHAR_BIT * sizeof(T);
  140. }
  141. template <class TIterator>
  142. size_t x_BitsPerElement(const TIterator&)
  143. {
  144. #ifdef _RWSTD_NO_CLASS_PARTIAL_SPEC
  145.     // Sun cares way too much about backward bug-for-bug compatibility...
  146.     return xx_BitsPerElement(__value_type(TIterator()));
  147. #elif defined(NCBI_COMPILER_MSVC)
  148.     // iterator_traits seems to be broken under MSVC. :-/
  149.     return xx_BitsPerElement(_Val_type(TIterator()));    
  150. #else
  151.     return CHAR_BIT * sizeof(typename iterator_traits<TIterator>::value_type);
  152. #endif    
  153. }
  154. template <class TIterator, class TOut>
  155. TOut ExtractBits(TIterator& start, const TIterator& end,
  156.                  size_t& bit_offset, size_t bit_count)
  157. {
  158. #if 1
  159.     static const size_t kBitsPerElement = x_BitsPerElement(start);
  160. #elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC)
  161.     static const size_t kBitsPerElement
  162.         = xx_BitsPerElement(__value_type(TIterator()));
  163. #elif defined(NCBI_COMPILER_MSVC)
  164.     static const size_t kBitsPerElement
  165.         = xx_BitsPerElement(_Val_type(TIterator()));    
  166. #else
  167.     static const size_t kBitsPerElement
  168.         = CHAR_BIT * sizeof(typename iterator_traits<TIterator>::value_type);
  169. #endif
  170.     const TOut kMask = (1 << bit_count) - 1;
  171.     static const TOut kMask2 = (1 << kBitsPerElement) - 1;
  172.     TOut value;
  173.     if (start == end) {
  174.         return 0;
  175.     } else if (bit_offset + bit_count <= kBitsPerElement) {
  176.         // the current element contains it all
  177.         bit_offset += bit_count;
  178.         value = (*start >> (kBitsPerElement - bit_offset)) & kMask;
  179.         if (bit_offset == kBitsPerElement) {
  180.             bit_offset = 0;
  181.             ++start;
  182.         }
  183.     } else {
  184.         // We have to deal with multiple elements.
  185.         value = *start & ((1 << (kBitsPerElement - bit_offset)) - 1);
  186.         ++start;
  187.         for (bit_offset += bit_count - kBitsPerElement;
  188.              bit_offset >= kBitsPerElement;
  189.              bit_offset -= kBitsPerElement) {
  190.             value <<= kBitsPerElement;
  191.             if (start != end) {
  192.                 value |= *start & kMask2;
  193.                 ++start;
  194.             }
  195.         }        
  196.         if (bit_offset) {
  197.             value <<= bit_offset;
  198.             if (start != end) {
  199.                 value |= ((*start >> (kBitsPerElement - bit_offset))
  200.                           & ((1 << bit_offset) - 1));
  201.             }
  202.         }
  203.     }
  204.     return value;
  205. }
  206. template <class TIterator, class TVal, class TElement>
  207. TElement StoreBits(TIterator& start, const TIterator& end,
  208.                    size_t& bit_offset, size_t bit_count,
  209.                    TElement partial, TVal data) // returns new partial
  210. {
  211.     static const size_t kBitsPerElement = CHAR_BIT * sizeof(TElement);
  212.     if (bit_offset) {
  213.         partial &= (~(TElement)0) << (kBitsPerElement - bit_offset);
  214.     } else {
  215.         partial = 0;
  216.     }
  217.     if (bit_offset + bit_count <= kBitsPerElement) {
  218.         // Everything fits in one element.
  219.         bit_offset += bit_count;
  220.         partial |= data << (kBitsPerElement - bit_offset);
  221.         if (bit_count == kBitsPerElement) {
  222.             *(start++) = partial;
  223.             bit_count = 0;
  224.             partial = 0;
  225.         }
  226.     } else {
  227.         // We need to split it up.
  228.         *(start++) = partial | ((data >> (bit_count + bit_offset
  229.                                           - kBitsPerElement))
  230.                                 & ((1 << (kBitsPerElement - bit_offset)) - 1));
  231.         for (bit_offset += bit_count - kBitsPerElement;
  232.              bit_offset >= kBitsPerElement;
  233.              bit_offset -= kBitsPerElement) {
  234.             if (start != end) {
  235.                 *(start++) = data >> (bit_offset - kBitsPerElement);
  236.             }
  237.         }
  238.         if (bit_offset) {
  239.             partial = data << (kBitsPerElement - bit_offset);
  240.         } else {
  241.             partial = 0;
  242.         }
  243.     }
  244.     return partial;
  245. }
  246. // CConstResizingIterator members.
  247. template <class TSeq, class TOut>
  248. CConstResizingIterator<TSeq, TOut> &
  249. CConstResizingIterator<TSeq, TOut>::operator++() // prefix
  250. {
  251.     static const size_t kBitsPerElement = CHAR_BIT * sizeof(TRawValue);
  252.     // We advance the raw iterator past things we read, so only advance
  253.     // it now if we haven't read the current value.
  254.     if (!m_ValueKnown) {
  255.         for (m_BitOffset += m_NewSize;  m_BitOffset >= kBitsPerElement;
  256.              m_BitOffset -= kBitsPerElement) {
  257.             ++m_RawIterator;
  258.         }
  259.     }
  260.     m_ValueKnown = false;
  261.     return *this;
  262. }
  263. template <class TSeq, class TOut>
  264. CConstResizingIterator<TSeq, TOut>
  265. CConstResizingIterator<TSeq, TOut>::operator++(int) // postfix
  266. {
  267.     CConstResizingIterator<TSeq, TOut> copy(*this);
  268.     ++(*this);
  269.     return copy;
  270. }
  271. template <class TSeq, class TOut>
  272. TOut CConstResizingIterator<TSeq, TOut>::operator*()
  273. {
  274.     if (m_ValueKnown)
  275.         return m_Value;
  276.     m_ValueKnown = true;
  277.     return m_Value = ExtractBits<TRawIterator, TOut>
  278.         (m_RawIterator, m_End, m_BitOffset, m_NewSize);
  279. }
  280. template <class TSeq, class TOut>
  281. bool CConstResizingIterator<TSeq, TOut>::AtEnd() const
  282. {
  283.     size_t avail = 0, goal = m_BitOffset + m_NewSize;
  284.     for (TRawIterator it2 = m_RawIterator;  it2 != m_End  &&  avail < goal;
  285.          ++it2) {
  286.         avail += x_BitsPerElement(m_RawIterator);
  287.     }
  288.     return avail < goal;
  289. }
  290. // CResizingIterator members.
  291. template <class TSeq, class TVal>
  292. CResizingIterator<TSeq, TVal>& CResizingIterator<TSeq, TVal>::operator++()
  293.     // prefix
  294. {
  295.     static const size_t kBitsPerElement = CHAR_BIT * sizeof(TRawValue);
  296.     for (m_BitOffset += m_NewSize;  m_BitOffset >= kBitsPerElement;
  297.          m_BitOffset -= kBitsPerElement) {
  298.         ++m_RawIterator;
  299.     }
  300.     return *this;
  301. }
  302. template <class TSeq, class TVal>
  303. CResizingIterator<TSeq, TVal> CResizingIterator<TSeq, TVal>::operator++(int)
  304.     // postfix
  305. {
  306.     CResizingIterator<TSeq, TVal> copy(*this);
  307.     ++(*this);
  308.     return copy;
  309. }
  310. template <class TSeq, class TVal>
  311. void CResizingIterator<TSeq, TVal>::operator=(TVal value)
  312. {
  313.     // don't advance iterator in object.
  314.     TRawIterator it = m_RawIterator;
  315.     size_t offset = m_BitOffset;
  316.     TRawValue tmp;
  317.     tmp = StoreBits<TRawIterator, TVal, TRawValue>
  318.         (it, m_End, offset, m_NewSize, *it, value);
  319.     if (offset > 0) {
  320.         *it = tmp;
  321.     }
  322. }
  323. template <class TSeq, class TVal>
  324. CResizingIterator<TSeq, TVal>::operator TVal()
  325. {
  326.     // don't advance iterator in object.
  327.     TRawIterator it = m_RawIterator;
  328.     size_t offset = m_BitOffset;
  329.     return ExtractBits<TRawIterator, TVal>(it, m_End, offset, m_NewSize);
  330. }
  331. template <class TSeq, class TVal>
  332. bool CResizingIterator<TSeq, TVal>::AtEnd() const
  333. {
  334.     size_t avail = 0, goal = m_BitOffset + m_NewSize;
  335.     for (TRawIterator it2 = m_RawIterator;  it2 != m_End  &&  avail < goal;
  336.          ++it2) {
  337.         avail += x_BitsPerElement(m_RawIterator);
  338.     }
  339.     return avail < goal;
  340. }
  341. END_NCBI_SCOPE
  342. /*
  343. * ===========================================================================
  344. *
  345. * $Log: resize_iter.hpp,v $
  346. * Revision 1000.3  2004/06/01 19:38:43  gouriano
  347. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.9
  348. *
  349. * Revision 1.9  2004/04/26 14:50:59  ucko
  350. * Fix a typo caught by GCC 3.4.
  351. *
  352. * Revision 1.8  2004/03/05 18:25:26  dicuccio
  353. * Fixed logic in AtEnd(): return avail < goal
  354. *
  355. * Revision 1.7  2004/02/12 21:42:45  ucko
  356. * Rework AtEnd() to avoid distance(), which has no portable form.
  357. *
  358. * Revision 1.6  2004/02/12 20:09:46  ucko
  359. * Add safeguards to avoid overshooting when misaligned.
  360. *
  361. * Revision 1.5  2004/02/06 18:32:35  vasilche
  362. * Added missing typename keyword.
  363. *
  364. * Revision 1.4  2003/10/14 19:00:18  ucko
  365. * CResizingIterator::operator =: don't store empty partial elements (led
  366. * to off-by-one errors in some cases)
  367. *
  368. * Revision 1.3  2003/04/17 17:50:28  siyan
  369. * Added doxygen support
  370. *
  371. * Revision 1.2  2002/12/30 20:38:14  ucko
  372. * Miscellaneous cleanups: CVS log moved to end, .inl folded in,
  373. * test for MSVC fixed, AtEnd made const, useless comments dropped,
  374. * kBitsPerByte changed to CHAR_BIT (using 8 as a fallback).
  375. *
  376. * Revision 1.1  2001/09/04 14:06:30  ucko
  377. * Add resizing iterators for sequences whose representation uses an
  378. * unnatural unit size -- for instance, ASN.1 octet strings corresponding
  379. * to sequences of 32-bit integers or of packed nucleotides.
  380. *
  381. * ===========================================================================
  382. */
  383. #endif  /* RESIZE_ITER__HPP */