HP refactoring:
[libcds.git] / cds / algo / split_bitstring.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8     
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifndef CDSLIB_ALGO_SPLIT_BITSTRING_H
32 #define CDSLIB_ALGO_SPLIT_BITSTRING_H
33
34 #include <cds/algo/base.h>
35
36 namespace cds { namespace algo {
37
38     /// Cuts a bit sequence from fixed-size bit-string
39     /**
40         The splitter can be used as iterator over bit-string.
41         Each call of \p cut() or \p safe_cut() cuts the bit count specified
42         and keeps the position inside bit-string for the next call.
43
44         The splitter stores a const reference to bit-string, not a copy.
45         The maximum count of bits that can be cut in a single call is <tt> sizeof(UInt) * 8 </tt>
46     */
47     template <typename BitString, typename UInt = typename std::conditional< sizeof(BitString) % sizeof(size_t) == 0, size_t, unsigned >::type >
48     class split_bitstring
49     {
50     public:
51         typedef BitString bitstring;    ///< Bit-string type
52         typedef UInt      uint_type;    ///< Bit-string portion type
53
54         //@cond
55         static CDS_CONSTEXPR size_t const c_nHashSize   = (sizeof(bitstring) + sizeof(uint_type) - 1) / sizeof(uint_type);
56         static CDS_CONSTEXPR size_t const c_nBitPerByte = 8;
57         static CDS_CONSTEXPR size_t const c_nBitPerHash = sizeof(bitstring) * c_nBitPerByte;
58         static CDS_CONSTEXPR size_t const c_nBitPerInt  = sizeof(uint_type) * c_nBitPerByte;
59         //@endcond
60
61     public:
62         /// Initializises the splitter with reference to \p h and zero start bit offset
63         explicit split_bitstring( bitstring const& h )
64             : m_ptr(reinterpret_cast<uint_type const*>( &h ))
65             , m_offset(0)
66             , m_first( m_ptr )
67 #   ifdef _DEBUG
68             , m_last( m_ptr + c_nHashSize )
69 #   endif
70         {}
71
72         /// Initializises the splitter with reference to \p h and start bit offset \p nBitOffset
73         split_bitstring( bitstring const& h, size_t nBitOffset )
74             : m_ptr( reinterpret_cast<uint_type const*>( &h ) + nBitOffset / c_nBitPerInt )
75             , m_offset( nBitOffset )
76             , m_first( reinterpret_cast<uint_type const*>(&h))
77 #   ifdef _DEBUG
78             , m_last( m_first + c_nHashSize )
79 #   endif
80         {}
81
82
83         /// Returns \p true if end-of-string is not reached yet
84         explicit operator bool() const
85         {
86             return !eos();
87         }
88
89         /// Returns \p true if end-of-stream encountered
90         bool eos() const
91         {
92             return m_offset >= c_nBitPerHash;
93         }
94
95         /// Cuts next \p nBits from bit-string
96         /**
97             Precondition: <tt>nBits <= sizeof(uint_type) * 8</tt>
98
99             This function does not manage out-of-bound condition.
100             To control that use \p safe_cut().
101         */
102         uint_type cut( size_t nBits )
103         {
104             assert( !eos() );
105             assert( nBits <= c_nBitPerInt );
106             assert( m_offset + nBits <= c_nBitPerHash );
107 #   ifdef _DEBUG
108             assert( m_ptr < m_last );
109 #   endif
110             uint_type result;
111
112             uint_type const nRest = c_nBitPerInt - m_offset % c_nBitPerInt;
113             m_offset += nBits;
114             if ( nBits < nRest ) {
115                 result = *m_ptr << ( nRest - nBits );
116                 result = result >> ( c_nBitPerInt - nBits );
117             }
118             else if ( nBits == nRest ) {
119                 result = *m_ptr >> ( c_nBitPerInt - nRest );
120                 ++m_ptr;
121                 assert( m_offset % c_nBitPerInt == 0 );
122             }
123             else {
124                 uint_type const lsb = *m_ptr >> ( c_nBitPerInt - nRest );
125                 nBits -= nRest;
126                 ++m_ptr;
127
128                 result = *m_ptr << ( c_nBitPerInt - nBits );
129                 result = result >> ( c_nBitPerInt - nBits );
130                 result = (result << nRest) + lsb;
131             }
132
133             assert( m_offset <= c_nBitPerHash );
134 #   ifdef _DEBUG
135             assert( m_ptr <= m_last );
136 #   endif
137             return result;
138         }
139
140         /// Cuts up to \p nBits from the bit-string
141         /**
142             Analog of \p cut() but if \p nBits is more than the rest of bit-string,
143             only the rest is returned.
144             If \p eos() is \p true the function returns 0.
145         */
146         uint_type safe_cut( size_t nBits )
147         {
148             if ( eos() )
149                 return 0;
150
151             assert( nBits <= sizeof(uint_type) * c_nBitPerByte );
152
153             if ( m_offset + nBits > c_nBitPerHash )
154                 nBits = c_nBitPerHash - m_offset;
155             return nBits ? cut( nBits ) : 0;
156         }
157
158         /// Resets the splitter
159         void reset() CDS_NOEXCEPT
160         {
161             m_ptr = m_first;
162             m_offset = 0;
163         }
164
165         /// Returns pointer to source bitstring
166         bitstring const * source() const
167         {
168             return reinterpret_cast<bitstring const *>( m_first );
169         }
170
171         /// Returns current bit offset from beginning of bit-string
172         size_t bit_offset() const
173         {
174             return m_offset;
175         }
176
177     private:
178         //@cond
179         uint_type const* m_ptr;     ///< current position in the hash
180         size_t           m_offset;  ///< current bit offset in bit-string
181         uint_type const* m_first;   ///< first position
182 #   ifdef _DEBUG
183         uint_type const* m_last;    ///< last position
184 #   endif
185         //@endcond
186     };
187
188 }} // namespace cds::algo
189
190 #endif // #ifndef CDSLIB_ALGO_SPLIT_BITSTRING_H