diff options
Diffstat (limited to 'gnu/lib/libg++/include/bitdo2.h')
-rw-r--r-- | gnu/lib/libg++/include/bitdo2.h | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/gnu/lib/libg++/include/bitdo2.h b/gnu/lib/libg++/include/bitdo2.h new file mode 100644 index 0000000..6e99523 --- /dev/null +++ b/gnu/lib/libg++/include/bitdo2.h @@ -0,0 +1,184 @@ +#ifndef ONES +#define ONES ((_BS_word)(~0L)) +#endif + +#ifndef DOIT_SOLID +#ifdef DOIT +#define DOIT_SOLID(dst, src) DOIT(dst, src, (_BS_word)(~0)) +#else +#define DOIT_SOLID(dst, src) (dst) = (COMBINE(dst, src)) +#endif +#endif + +#ifndef DOIT +#define DOIT(dst, src, mask) \ + (dst) = ((COMBINE(dst, src)) & (mask)) | ((dst) & ~(mask)) +#endif + + _BS_word word0, mask; + int shift0, shift1; + + if (length == 0) + goto done; + + shift0 = srcbit - dstbit; + + /* First handle the case that only one destination word is touched. */ + if (length + dstbit <= _BS_BITS_PER_WORD) + { + _BS_word mask + = (ONES _BS_LEFT (_BS_BITS_PER_WORD - length)) _BS_RIGHT dstbit; + _BS_word word0 = *psrc++; + if (shift0 <= 0) /* dstbit >= srcbit */ + { + word0 = word0 _BS_RIGHT (-shift0); + } + else + { + word0 = word0 _BS_LEFT shift0; + if (length + srcbit > _BS_BITS_PER_WORD) + word0 = word0 | (*psrc _BS_RIGHT (_BS_BITS_PER_WORD - shift0)); + } + DOIT(*pdst, word0, mask); + goto done; + } + + /* Next optimize the case that the source and destination are aligned. */ + if (shift0 == 0) + { + _BS_word mask; + if (psrc > pdst) + { + if (srcbit) + { + mask = ONES _BS_RIGHT srcbit; + DOIT(*pdst, *psrc, mask); + pdst++; psrc++; + length -= _BS_BITS_PER_WORD - srcbit; + } + for (; length >= _BS_BITS_PER_WORD; length -= _BS_BITS_PER_WORD) + { + DOIT_SOLID(*pdst, *psrc); + pdst++; psrc++; + } + if (length) + { + mask = ONES _BS_LEFT (_BS_BITS_PER_WORD - length); + DOIT(*pdst, *psrc, mask); + } + } + else if (psrc < pdst) + { + _BS_size_t span = srcbit + length; + pdst += span / (_BS_size_t)_BS_BITS_PER_WORD; + psrc += span / (_BS_size_t)_BS_BITS_PER_WORD; + span %= (_BS_size_t)_BS_BITS_PER_WORD; + if (span) + { + mask = ONES _BS_LEFT (_BS_BITS_PER_WORD - span); + DOIT(*pdst, *psrc, mask); + length -= span; + } + pdst--; psrc--; + for (; length >= _BS_BITS_PER_WORD; length -= _BS_BITS_PER_WORD) + { + DOIT_SOLID(*pdst, *psrc); + pdst--; psrc--; + } + if (srcbit) + { + mask = ONES _BS_RIGHT srcbit; + DOIT(*pdst, *psrc, mask); + } + } + /* else if (psrc == pdst) --nothing to do--; */ + goto done; + } + + /* Now we assume shift!=0, and more than on destination word is changed. */ + if (psrc >= pdst) /* Do the updates in forward direction. */ + { + _BS_word word0 = *psrc++; + _BS_word mask = ONES _BS_RIGHT dstbit; + if (shift0 > 0) + { + _BS_word word1 = *psrc++; + shift1 = _BS_BITS_PER_WORD - shift0; + DOIT(*pdst, (word0 _BS_LEFT shift0) | (word1 _BS_RIGHT shift1), mask); + word0 = word1; + } + else /* dstbit > srcbit */ + { + shift1 = -shift0; + shift0 += _BS_BITS_PER_WORD; + DOIT(*pdst, word0 _BS_RIGHT shift1, mask); + } + pdst++; + length -= _BS_BITS_PER_WORD - dstbit; + + for ( ; length >= _BS_BITS_PER_WORD; length -= _BS_BITS_PER_WORD) + { + register _BS_word word1 = *psrc++; + DOIT_SOLID(*pdst, + (word0 _BS_LEFT shift0) | (word1 _BS_RIGHT shift1)); + pdst++; + word0 = word1; + } + if (length > 0) + { + _BS_size_t mask = ONES _BS_LEFT (_BS_BITS_PER_WORD - length); + word0 = word0 _BS_LEFT shift0; + if (length > shift1) + word0 = word0 | (*psrc _BS_RIGHT shift1) ; + DOIT (*pdst, word0, mask); + } + } + else /* Do the updates in backward direction. */ + { + _BS_word word0; + + /* Make (psrc, srcbit) and (pdst, dstbit) point to *last* bit. */ + psrc += (srcbit + length - 1) / _BS_BITS_PER_WORD; + srcbit = (srcbit + length - 1) % _BS_BITS_PER_WORD; + pdst += (dstbit + length - 1) / _BS_BITS_PER_WORD; + dstbit = (dstbit + length - 1) % _BS_BITS_PER_WORD; + + shift0 = srcbit - dstbit; + + word0 = *psrc--; + mask = ONES _BS_LEFT (_BS_BITS_PER_WORD - 1 - dstbit); + if (shift0 < 0) + { + _BS_word word1 = *psrc--; + shift1 = -shift0; + shift0 += _BS_BITS_PER_WORD; + DOIT (*pdst, (word0 _BS_RIGHT shift1) | (word1 _BS_LEFT shift0), + mask); + word0 = word1; + } + else + { + shift1 = _BS_BITS_PER_WORD - shift0; + DOIT(*pdst, word0 _BS_LEFT shift0, mask); + } + pdst--; + length -= dstbit + 1; + + for ( ; length >= _BS_BITS_PER_WORD; length -= _BS_BITS_PER_WORD) + { + register _BS_word word1 = *psrc--; + DOIT_SOLID(*pdst, + (word0 _BS_RIGHT shift1) | (word1 _BS_LEFT shift0)); + pdst--; + word0 = word1; + } + if (length > 0) + { + _BS_size_t mask = ONES _BS_RIGHT (_BS_BITS_PER_WORD - length); + word0 = word0 _BS_RIGHT shift1; + if (length > shift0) + word0 = word0 | (*psrc _BS_LEFT shift0) ; + DOIT (*pdst, word0, mask); + } + } + done: ; |