blob: bdc8694ee7edfa4082de8f364eb0e5167dff2beb [file] [log] [blame]
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -05001
2#include <prdfBitString.H>
3
4#include <prdfAssert.h>
5
6#include <algorithm>
7
Zane Shelley871adec2019-07-30 11:01:39 -05008namespace libhei
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -05009{
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -050010
11//##############################################################################
12// BitString class
13//##############################################################################
14
15const uint32_t BitString::CPU_WORD_BIT_LEN = sizeof(CPU_WORD) * 8;
16
17const CPU_WORD BitString::CPU_WORD_MASK = static_cast<CPU_WORD>(-1);
18
19//------------------------------------------------------------------------------
20
21CPU_WORD BitString::getField( uint32_t i_pos, uint32_t i_len ) const
22{
23 PRDF_ASSERT( nullptr != getBufAddr() ); // must to have a valid address
24 PRDF_ASSERT( 0 < i_len ); // must have at least one bit
25 PRDF_ASSERT( i_len <= CPU_WORD_BIT_LEN ); // i_len length must be valid
26 PRDF_ASSERT( i_pos + i_len <= getBitLen() ); // field must be within range
27
28 // The returned value.
29 CPU_WORD o_val = 0;
30
31 // Get the relative address and position of the field.
32 uint32_t relPos = 0;
33 CPU_WORD * relAddr = getRelativePosition( relPos, i_pos );
34
35 // The return value may cross two CPU_WORD addresses. Get length of each
36 // chunk, mask to clear the right-handed bits, and the shift value to make
37 // each chunk left-justified.
38 uint32_t len0 = i_len, len1 = 0;
39 if ( CPU_WORD_BIT_LEN < relPos + i_len )
40 {
41 len0 = CPU_WORD_BIT_LEN - relPos;
42 len1 = i_len - len0;
43 }
44
45 CPU_WORD mask0 = CPU_WORD_MASK << (CPU_WORD_BIT_LEN - len0);
46 CPU_WORD mask1 = CPU_WORD_MASK << (CPU_WORD_BIT_LEN - len1);
47
48 uint32_t shift0 = relPos;
49 uint32_t shift1 = CPU_WORD_BIT_LEN - relPos;
50
51 // Get first half of the value.
52 o_val = (*relAddr << shift0) & mask0;
53
54 // Get the second half of the value, if needed
55 if ( CPU_WORD_BIT_LEN < relPos + i_len )
56 {
57 ++relAddr;
58 o_val |= (*relAddr & mask1) >> shift1;
59 }
60
61 return o_val;
62}
63
64//------------------------------------------------------------------------------
65
66void BitString::setField( uint32_t i_pos, uint32_t i_len, CPU_WORD i_val )
67{
68 PRDF_ASSERT( nullptr != getBufAddr() ); // must to have a valid address
69 PRDF_ASSERT( 0 < i_len ); // must have at least one bit
70 PRDF_ASSERT( i_len <= CPU_WORD_BIT_LEN ); // i_len length must be valid
71 PRDF_ASSERT( i_pos + i_len <= getBitLen() ); // field must be within range
72
73 // Get the relative address and position of the field.
74 uint32_t relPos = 0;
75 CPU_WORD * relAddr = getRelativePosition( relPos, i_pos );
76
77 // The value is left-justified. Ignore all other bits.
78 CPU_WORD mask = CPU_WORD_MASK << (CPU_WORD_BIT_LEN - i_len);
79 CPU_WORD val = i_val & mask;
80
81 // Set first half of the value.
82 *relAddr &= ~(mask >> relPos); // Clear field
83 *relAddr |= (val >> relPos); // Set field
84
85 // Get the second half of the value, if needed
86 if ( CPU_WORD_BIT_LEN < relPos + i_len )
87 {
88 relAddr++;
89 *relAddr &= ~(mask << (CPU_WORD_BIT_LEN - relPos)); // Clear field
90 *relAddr |= (val << (CPU_WORD_BIT_LEN - relPos)); // Set field
91 }
92}
93
94//------------------------------------------------------------------------------
95
96void BitString::setPattern( uint32_t i_sPos, uint32_t i_sLen,
97 CPU_WORD i_pattern, uint32_t i_pLen )
98{
99 PRDF_ASSERT(nullptr != getBufAddr()); // must to have a valid address
100 PRDF_ASSERT(0 < i_sLen); // must have at least one bit
101 PRDF_ASSERT(i_sPos + i_sLen <= getBitLen()); // field must be within range
102 PRDF_ASSERT(0 < i_pLen); // must have at least one bit
103 PRDF_ASSERT(i_pLen <= CPU_WORD_BIT_LEN); // i_pLen length must be valid
104
105 // Get a bit string for the pattern subset (right justified).
106 BitString bso ( i_pLen, &i_pattern, CPU_WORD_BIT_LEN - i_pLen );
107
108 // Iterate the range in chunks the size of i_pLen.
109 uint32_t endPos = i_sPos + i_sLen;
110 for ( uint32_t pos = i_sPos; pos < endPos; pos += i_pLen )
111 {
112 // The true chunk size is either i_pLen or the leftovers at the end.
113 uint32_t len = std::min( i_pLen, endPos - pos );
114
115 // Get this chunk's pattern value, truncate (left justified) if needed.
116 CPU_WORD pattern = bso.getField( 0, len );
117
118 // Set the pattern in this string.
119 setField( pos, len, pattern );
120 }
121}
122
123//------------------------------------------------------------------------------
124
125void BitString::setString( const BitString & i_sStr, uint32_t i_sPos,
126 uint32_t i_sLen, uint32_t i_dPos )
127{
128 // Ensure the source parameters are valid.
129 PRDF_ASSERT( nullptr != i_sStr.getBufAddr() );
130 PRDF_ASSERT( 0 < i_sLen ); // at least one bit to copy
131 PRDF_ASSERT( i_sPos + i_sLen <= i_sStr.getBitLen() );
132
133 // Ensure the destination has at least one bit available to copy.
134 PRDF_ASSERT( nullptr != getBufAddr() );
135 PRDF_ASSERT( i_dPos < getBitLen() );
136
137 // If the source length is greater than the destination length than the
138 // extra source bits are ignored.
139 uint32_t actLen = std::min( i_sLen, getBitLen() - i_dPos );
140
141 // The bit strings may be in overlapping memory spaces. So we need to copy
142 // the data in the correct direction to prevent overlapping.
143 uint32_t sRelOffset = 0, dRelOffset = 0;
144 CPU_WORD * sRelAddr = i_sStr.getRelativePosition( sRelOffset, i_sPos );
145 CPU_WORD * dRelAddr = getRelativePosition( dRelOffset, i_dPos );
146
147 // Copy the data.
148 if ( (dRelAddr == sRelAddr) && (dRelOffset == sRelOffset) )
149 {
150 // Do nothing. The source and destination are the same.
151 }
152 else if ( (dRelAddr < sRelAddr) ||
153 ((dRelAddr == sRelAddr) && (dRelOffset < sRelOffset)) )
154 {
155 // Copy the data forward.
156 for ( uint32_t pos = 0; pos < actLen; pos += CPU_WORD_BIT_LEN )
157 {
158 uint32_t len = std::min( actLen - pos, CPU_WORD_BIT_LEN );
159
160 CPU_WORD value = i_sStr.getField( i_sPos + pos, len );
161 setField( i_dPos + pos, len, value );
162 }
163 }
164 else // Copy the data backwards.
165 {
166 // Get the first position of the last chunk (CPU_WORD aligned).
167 uint32_t lastPos = ((actLen-1) / CPU_WORD_BIT_LEN) * CPU_WORD_BIT_LEN;
168
169 // Start with the last chunk and work backwards.
170 for ( int32_t pos = lastPos; 0 <= pos; pos -= CPU_WORD_BIT_LEN )
171 {
172 uint32_t len = std::min( actLen - pos, CPU_WORD_BIT_LEN );
173
174 CPU_WORD value = i_sStr.getField( i_sPos + pos, len );
175 setField( i_dPos + pos, len, value );
176 }
177 }
178}
179
180//------------------------------------------------------------------------------
181
182void BitString::maskString( const BitString & i_mask )
183{
184 // Get the length of the smallest string.
185 uint32_t actLen = std::min( getBitLen(), i_mask.getBitLen() );
186
187 for ( uint32_t pos = 0; pos < actLen; pos += CPU_WORD_BIT_LEN )
188 {
189 uint32_t len = std::min( actLen - pos, CPU_WORD_BIT_LEN );
190
191 CPU_WORD dVal = getField( pos, len );
192 CPU_WORD sVal = i_mask.getField( pos, len );
193
194 setField( pos, len, dVal & ~sVal );
195 }
196}
197
198//------------------------------------------------------------------------------
199
200bool BitString::isEqual( const BitString & i_str ) const
201{
202 if ( getBitLen() != i_str.getBitLen() )
203 return false; // size not equal
204
205 for ( uint32_t pos = 0; pos < getBitLen(); pos += CPU_WORD_BIT_LEN )
206 {
207 uint32_t len = std::min( getBitLen() - pos, CPU_WORD_BIT_LEN );
208
209 if ( getField(pos, len) != i_str.getField(pos, len) )
210 return false; // bit strings do not match
211 }
212
213 return true; // bit strings match
214}
215
216//------------------------------------------------------------------------------
217
218bool BitString::isZero() const
219{
220 for ( uint32_t pos = 0; pos < getBitLen(); pos += CPU_WORD_BIT_LEN )
221 {
222 uint32_t len = std::min( getBitLen() - pos, CPU_WORD_BIT_LEN );
223
224 if ( 0 != getField(pos, len) )
225 return false; // something is non-zero
226 }
227
228 return true; // everything was zero
229}
230
231//------------------------------------------------------------------------------
232
233uint32_t BitString::getSetCount( uint32_t i_pos, uint32_t i_len ) const
234{
235 uint32_t endPos = i_pos + i_len;
236
237 PRDF_ASSERT( endPos <= getBitLen() );
238
239 uint32_t count = 0;
240
241 for ( uint32_t i = i_pos; i < endPos; i++ )
242 {
243 if ( isBitSet(i) ) count++;
244 }
245
246 return count;
247}
248
249//------------------------------------------------------------------------------
250
251BitStringBuffer BitString::operator~() const
252{
253 BitStringBuffer bsb( getBitLen() );
254
255 for ( uint32_t pos = 0; pos < getBitLen(); pos += CPU_WORD_BIT_LEN )
256 {
257 uint32_t len = std::min( getBitLen() - pos, CPU_WORD_BIT_LEN );
258
259 CPU_WORD dVal = getField( pos, len );
260
261 bsb.setField( pos, len, ~dVal );
262 }
263
264 return bsb;
265}
266
267//------------------------------------------------------------------------------
268
269BitStringBuffer BitString::operator&( const BitString & i_bs ) const
270{
271 // Get the length of the smallest string.
272 uint32_t actLen = std::min( getBitLen(), i_bs.getBitLen() );
273
274 BitStringBuffer bsb( actLen );
275
276 for ( uint32_t pos = 0; pos < actLen; pos += CPU_WORD_BIT_LEN )
277 {
278 uint32_t len = std::min( actLen - pos, CPU_WORD_BIT_LEN );
279
280 CPU_WORD dVal = getField( pos, len );
281 CPU_WORD sVal = i_bs.getField( pos, len );
282
283 bsb.setField( pos, len, dVal & sVal );
284 }
285
286 return bsb;
287}
288
289//------------------------------------------------------------------------------
290
291BitStringBuffer BitString::operator|( const BitString & i_bs ) const
292{
293 // Get the length of the smallest string.
294 uint32_t actLen = std::min( getBitLen(), i_bs.getBitLen() );
295
296 BitStringBuffer bsb( actLen );
297
298 for ( uint32_t pos = 0; pos < actLen; pos += CPU_WORD_BIT_LEN )
299 {
300 uint32_t len = std::min( actLen - pos, CPU_WORD_BIT_LEN );
301
302 CPU_WORD dVal = getField( pos, len );
303 CPU_WORD sVal = i_bs.getField( pos, len );
304
305 bsb.setField( pos, len, dVal | sVal );
306 }
307
308 return bsb;
309}
310
311//------------------------------------------------------------------------------
312
313BitStringBuffer BitString::operator>>( uint32_t i_shift ) const
314{
315 BitStringBuffer bsb( getBitLen() ); // default all zeros
316
317 if ( i_shift < getBitLen() )
318 {
319 // bso overlays bsb, containing the shifted offset.
320 BitString bso ( bsb.getBitLen() - i_shift, bsb.getBufAddr(), i_shift );
321
322 // Copy this into bso.
323 bso.setString( *this );
324 }
325
326 return bsb;
327}
328
329//------------------------------------------------------------------------------
330
331BitStringBuffer BitString::operator<<( uint32_t i_shift ) const
332{
333 BitStringBuffer bsb( getBitLen() ); // default all zeros
334
335 if ( i_shift < getBitLen() )
336 {
337 // bso overlays *this, containing the shifted offset.
338 BitString bso ( this->getBitLen() - i_shift, this->getBufAddr(),
339 i_shift );
340
341 // Copy bso into bsb.
342 bsb.setString( bso );
343 }
344
345 return bsb;
346}
347
348//------------------------------------------------------------------------------
349
350CPU_WORD * BitString::getRelativePosition( uint32_t & o_relPos,
351 uint32_t i_absPos ) const
352{
353 PRDF_ASSERT( nullptr != getBufAddr() ); // must to have a valid address
354 PRDF_ASSERT( i_absPos < getBitLen() ); // must be a valid position
355
356 o_relPos = (i_absPos + iv_offset) % CPU_WORD_BIT_LEN;
357
358 return iv_bufAddr + ((i_absPos + iv_offset) / CPU_WORD_BIT_LEN);
359}
360
361//##############################################################################
362// BitStringBuffer class
363//##############################################################################
364
365BitStringBuffer::BitStringBuffer( uint32_t i_bitLen ) :
366 BitString( i_bitLen, nullptr )
367{
368 initBuffer();
369}
370
371//------------------------------------------------------------------------------
372
373BitStringBuffer::~BitStringBuffer()
374{
375 delete [] getBufAddr();
376}
377
378//------------------------------------------------------------------------------
379
380BitStringBuffer::BitStringBuffer( const BitString & i_bs ) :
381 BitString( i_bs.getBitLen(), nullptr )
382{
383 initBuffer();
384 if ( !i_bs.isZero() ) setString( i_bs );
385}
386
387//------------------------------------------------------------------------------
388
389BitStringBuffer::BitStringBuffer( const BitStringBuffer & i_bsb ) :
390 BitString( i_bsb.getBitLen(), nullptr )
391{
392 initBuffer();
393 if ( !i_bsb.isZero() ) setString( i_bsb );
394}
395
396//------------------------------------------------------------------------------
397
398BitStringBuffer & BitStringBuffer::operator=( const BitString & i_bs )
399{
400 // The initBuffer() function will deallocate the buffer as well, however we
401 // also need to deallocate the buffer here before we set the length.
402 delete [] getBufAddr();
403 setBufAddr( nullptr );
404
405 setBitLen( i_bs.getBitLen() );
406 initBuffer();
407 if ( !i_bs.isZero() ) setString( i_bs );
408
409 return *this;
410}
411
412//------------------------------------------------------------------------------
413
414BitStringBuffer & BitStringBuffer::operator=( const BitStringBuffer & i_bsb )
415{
416 if ( this != &i_bsb ) // Check for assignment to self
417 {
418 // The initBuffer() function will deallocate the buffer as well, however
419 // we also need to deallocate the buffer here before we set the length.
420 delete [] getBufAddr();
421 setBufAddr( nullptr );
422
423 setBitLen( i_bsb.getBitLen() );
424 initBuffer();
425 if ( !i_bsb.isZero() ) setString( i_bsb );
426 }
427
428 return *this;
429}
430
431//------------------------------------------------------------------------------
432
433void BitStringBuffer::initBuffer()
434{
435 // Deallocate the current buffer.
436 delete [] getBufAddr();
437
438 // Allocate the new buffer.
439 setBufAddr( new CPU_WORD[ getNumCpuWords(getBitLen()) ] );
440
441 // Clear the new buffer.
442 if ( !isZero() ) clearAll();
443}
444
Zane Shelley871adec2019-07-30 11:01:39 -0500445} // end namespace libhei
Zane Shelleyfd3f9cc2019-07-29 15:02:24 -0500446