Added new option hash_size for FeldmanHashSet
[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 parameters:
48         - \p BitString - a fixed-sized type that interprets as bit string
49         - \p BitStringSize - the siZe of \p BitString in bytes, default is <tt>sizeof( BitString )</tt>
50         - \p UInt - an unsigned integer, return type of \p cut()
51     */
52     template <typename BitString, size_t BitStringSize = sizeof( BitString ), typename UInt = typename std::conditional< BitStringSize % sizeof(size_t) == 0, size_t, unsigned >::type >
53     class split_bitstring
54     {
55     public:
56         typedef BitString bitstring;    ///< Bit-string type
57         typedef UInt      uint_type;    ///< Bit-string portion type
58         static CDS_CONSTEXPR size_t const c_bitstring_size = BitStringSize; ///< size of \p BitString in bytes
59
60         //@cond
61         static CDS_CONSTEXPR size_t const c_nHashSize   = (c_bitstring_size + sizeof(uint_type) - 1) / sizeof(uint_type);
62         static CDS_CONSTEXPR size_t const c_nBitPerByte = 8;
63         static CDS_CONSTEXPR size_t const c_nBitPerHash = c_bitstring_size * c_nBitPerByte;
64         static CDS_CONSTEXPR size_t const c_nBitPerInt  = sizeof( uint_type ) * c_nBitPerByte;
65         //@endcond
66
67     public:
68         /// Initializises the splitter with reference to \p h and zero start bit offset
69         explicit split_bitstring( bitstring const& h )
70             : m_ptr(reinterpret_cast<uint_type const*>( &h ))
71             , m_offset(0)
72             , m_first( m_ptr )
73 #   ifdef _DEBUG
74             , m_last( m_ptr + c_nHashSize )
75 #   endif
76         {}
77
78         /// Initializises the splitter with reference to \p h and start bit offset \p nBitOffset
79         split_bitstring( bitstring const& h, size_t nBitOffset )
80             : m_ptr( reinterpret_cast<uint_type const*>( &h ) + nBitOffset / c_nBitPerInt )
81             , m_offset( nBitOffset )
82             , m_first( reinterpret_cast<uint_type const*>(&h))
83 #   ifdef _DEBUG
84             , m_last( m_first + c_nHashSize )
85 #   endif
86         {}
87
88
89         /// Returns \p true if end-of-string is not reached yet
90         explicit operator bool() const
91         {
92             return !eos();
93         }
94
95         /// Returns \p true if end-of-stream encountered
96         bool eos() const
97         {
98             return m_offset >= c_nBitPerHash;
99         }
100
101         /// Cuts next \p nBits from bit-string
102         /**
103             Precondition: <tt>nBits <= sizeof(uint_type) * 8</tt>
104
105             This function does not manage out-of-bound condition.
106             To control that use \p safe_cut().
107         */
108         uint_type cut( size_t nBits )
109         {
110             assert( !eos());
111             assert( nBits <= c_nBitPerInt );
112             assert( m_offset + nBits <= c_nBitPerHash );
113 #   ifdef _DEBUG
114             assert( m_ptr < m_last );
115 #   endif
116             uint_type result;
117
118             uint_type const nRest = c_nBitPerInt - m_offset % c_nBitPerInt;
119             m_offset += nBits;
120             if ( nBits < nRest ) {
121                 result = *m_ptr << ( nRest - nBits );
122                 result = result >> ( c_nBitPerInt - nBits );
123             }
124             else if ( nBits == nRest ) {
125                 result = *m_ptr >> ( c_nBitPerInt - nRest );
126                 ++m_ptr;
127                 assert( m_offset % c_nBitPerInt == 0 );
128             }
129             else {
130                 uint_type const lsb = *m_ptr >> ( c_nBitPerInt - nRest );
131                 nBits -= nRest;
132                 ++m_ptr;
133
134                 result = *m_ptr << ( c_nBitPerInt - nBits );
135                 result = result >> ( c_nBitPerInt - nBits );
136                 result = (result << nRest) + lsb;
137             }
138
139             assert( m_offset <= c_nBitPerHash );
140 #   ifdef _DEBUG
141             assert( m_ptr <= m_last );
142 #   endif
143             return result;
144         }
145
146         /// Cuts up to \p nBits from the bit-string
147         /**
148             Analog of \p cut() but if \p nBits is more than the rest of bit-string,
149             only the rest is returned.
150             If \p eos() is \p true the function returns 0.
151         */
152         uint_type safe_cut( size_t nBits )
153         {
154             if ( eos())
155                 return 0;
156
157             assert( nBits <= sizeof(uint_type) * c_nBitPerByte );
158
159             if ( m_offset + nBits > c_nBitPerHash )
160                 nBits = c_nBitPerHash - m_offset;
161             return nBits ? cut( nBits ) : 0;
162         }
163
164         /// Resets the splitter
165         void reset() CDS_NOEXCEPT
166         {
167             m_ptr = m_first;
168             m_offset = 0;
169         }
170
171         /// Returns pointer to source bitstring
172         bitstring const * source() const
173         {
174             return reinterpret_cast<bitstring const *>( m_first );
175         }
176
177         /// Returns current bit offset from beginning of bit-string
178         size_t bit_offset() const
179         {
180             return m_offset;
181         }
182
183     private:
184         //@cond
185         uint_type const* m_ptr;     ///< current position in the hash
186         size_t           m_offset;  ///< current bit offset in bit-string
187         uint_type const* m_first;   ///< first position
188 #   ifdef _DEBUG
189         uint_type const* m_last;    ///< last position
190 #   endif
191         //@endcond
192     };
193
194 }} // namespace cds::algo
195
196 #endif // #ifndef CDSLIB_ALGO_SPLIT_BITSTRING_H