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