"Fossies" - the Fresh Open Source Software Archive

Member "darktable-2.6.3/src/external/rawspeed/src/librawspeed/io/BitStream.h" (19 Oct 2019, 7374 Bytes) of package /linux/misc/darktable-2.6.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "BitStream.h" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.6.2_vs_2.6.3.

    1 /*
    2     RawSpeed - RAW file decoder.
    3 
    4     Copyright (C) 2009-2014 Klaus Post
    5     Copyright (C) 2017 Axel Waggershauser
    6     Copyright (C) 2017-2019 Roman Lebedev
    7 
    8     This library is free software; you can redistribute it and/or
    9     modify it under the terms of the GNU Lesser General Public
   10     License as published by the Free Software Foundation; either
   11     version 2 of the License, or (at your option) any later version.
   12 
   13     This library is distributed in the hope that it will be useful,
   14     but WITHOUT ANY WARRANTY; without even the implied warranty of
   15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   16     Lesser General Public License for more details.
   17 
   18     You should have received a copy of the GNU Lesser General Public
   19     License along with this library; if not, write to the Free Software
   20     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   21 */
   22 
   23 #pragma once
   24 
   25 #include "common/Common.h" // for uint32_t, uint8_t, uint64_t
   26 #include "io/Buffer.h"     // for Buffer::size_type, BUFFER_PADDING
   27 #include "io/ByteStream.h"  // for ByteStream
   28 #include "io/IOException.h" // for IOException (ptr only), ThrowIOE
   29 #include <cassert>          // for assert
   30 #include <cstring>          // for memcpy
   31 
   32 namespace rawspeed {
   33 
   34 // simple 64-bit wide cache implementation that acts like a FiFo.
   35 // There are two variants:
   36 //  * L->R: new bits are pushed in on the left and pulled out on the right
   37 //  * L<-R: new bits are pushed in on the right and pulled out on the left
   38 // Each BitStream specialization uses one of the two.
   39 
   40 struct BitStreamCacheBase
   41 {
   42   uint64_t cache = 0;         // the actual bits stored in the cache
   43   unsigned int fillLevel = 0; // bits left in cache
   44   static constexpr unsigned Size = sizeof(cache)*8;
   45 
   46   // how many bits could be requested to be filled
   47   static constexpr unsigned MaxGetBits = Size/2;
   48 
   49   // maximal number of bytes the implementation may read.
   50   // NOTE: this is not the same as MaxGetBits/8 !!!
   51   static constexpr unsigned MaxProcessBytes = 8;
   52 };
   53 
   54 struct BitStreamCacheLeftInRightOut : BitStreamCacheBase
   55 {
   56   inline void push(uint64_t bits, uint32_t count) noexcept {
   57     assert(count + fillLevel <= Size);
   58     cache |= bits << fillLevel;
   59     fillLevel += count;
   60   }
   61 
   62   inline uint32_t peek(uint32_t count) const noexcept {
   63     return cache & ((1U << count) - 1U);
   64   }
   65 
   66   inline void skip(uint32_t count) noexcept {
   67     cache >>= count;
   68     fillLevel -= count;
   69   }
   70 };
   71 
   72 struct BitStreamCacheRightInLeftOut : BitStreamCacheBase
   73 {
   74   inline void push(uint64_t bits, uint32_t count) noexcept {
   75     assert(count + fillLevel <= Size);
   76     assert(count < BitStreamCacheBase::Size);
   77     cache = cache << count | bits;
   78     fillLevel += count;
   79   }
   80 
   81   inline uint32_t peek(uint32_t count) const noexcept {
   82     return (cache >> (fillLevel - count)) & ((1U << count) - 1U);
   83   }
   84 
   85   inline void skip(uint32_t count) noexcept { fillLevel -= count; }
   86 };
   87 
   88 template <typename BIT_STREAM> struct BitStreamTraits final {
   89   static constexpr bool canUseWithHuffmanTable = false;
   90 };
   91 
   92 template <typename Tag, typename Cache>
   93 class BitStream final : public ByteStream {
   94   Cache cache;
   95 
   96   // this method hase to be implemented in the concrete BitStream template
   97   // specializations. It will return the number of bytes processed. It needs
   98   // to process up to BitStreamCacheBase::MaxProcessBytes bytes of input.
   99   size_type fillCache(const uint8_t* input, size_type bufferSize,
  100                       size_type* bufPos);
  101 
  102 public:
  103   BitStream() = default;
  104 
  105   explicit BitStream(const ByteStream& s)
  106       : ByteStream(s.getSubStream(s.getPosition(), s.getRemainSize())) {
  107     setByteOrder(Endianness::unknown);
  108   }
  109 
  110 private:
  111   inline void fillSafe() {
  112     assert(data);
  113     if (pos + BitStreamCacheBase::MaxProcessBytes <= size) {
  114       std::array<uint8_t, BitStreamCacheBase::MaxProcessBytes> tmp;
  115       tmp.fill(0);
  116       assert(!(size - pos < BitStreamCacheBase::MaxProcessBytes));
  117       memcpy(tmp.data(), data + pos, BitStreamCacheBase::MaxProcessBytes);
  118       pos += fillCache(tmp.data(), size, &pos);
  119     } else if (pos < size) {
  120       std::array<uint8_t, BitStreamCacheBase::MaxProcessBytes> tmp;
  121       tmp.fill(0);
  122       assert(size - pos < BitStreamCacheBase::MaxProcessBytes);
  123       memcpy(tmp.data(), data + pos, size - pos);
  124       pos += fillCache(tmp.data(), size, &pos);
  125     } else if (pos <= size + BitStreamCacheBase::MaxProcessBytes) {
  126       std::array<uint8_t, BitStreamCacheBase::MaxProcessBytes> tmp;
  127       tmp.fill(0);
  128       pos += fillCache(tmp.data(), size, &pos);
  129     } else {
  130       // assert(size < pos);
  131       ThrowIOE("Buffer overflow read in BitStream");
  132     }
  133   }
  134 
  135   // In non-DEBUG builds, fillSafe() will be called at most once
  136   // per the life-time of the BitStream  therefore it should *NOT* be inlined
  137   // into the normal codepath.
  138   inline void __attribute__((noinline, cold)) fillSafeNoinline() { fillSafe(); }
  139 
  140 public:
  141   inline void fill(uint32_t nbits = Cache::MaxGetBits) {
  142     assert(data);
  143     assert(nbits <= Cache::MaxGetBits);
  144     if (cache.fillLevel < nbits) {
  145 #if defined(DEBUG)
  146       // really slow, but best way to check all the assumptions.
  147       fillSafe();
  148 #elif BUFFER_PADDING >= 8
  149       static_assert(BitStreamCacheBase::MaxProcessBytes == 8,
  150                     "update these too");
  151       // FIXME: this looks very wrong. We don't check pos at all here.
  152       // I suspect this should be:  if (pos <= size)
  153       pos += fillCache(data + pos, size, &pos);
  154 #else
  155       // disabling this run-time bounds check saves about 1% on intel x86-64
  156       if (pos + BitStreamCacheBase::MaxProcessBytes <= size)
  157         pos += fillCache(data + pos, size, &pos);
  158       else
  159         fillSafeNoinline();
  160 #endif
  161     }
  162   }
  163 
  164   // these methods might be specialized by implementations that support it
  165   inline size_type getBufferPosition() const {
  166     return pos - (cache.fillLevel >> 3);
  167   }
  168 
  169   inline size_type getFillLevel() const { return cache.fillLevel; }
  170 
  171   // rewinds to the beginning of the buffer.
  172   void resetBufferPosition() {
  173     pos = 0;
  174     cache.fillLevel = 0;
  175     cache.cache = 0;
  176   }
  177 
  178   void setBufferPosition(size_type newPos);
  179 
  180   inline uint32_t __attribute__((pure)) peekBitsNoFill(uint32_t nbits) {
  181     assert(nbits != 0);
  182     assert(nbits < Cache::MaxGetBits);
  183     assert(nbits <= cache.fillLevel);
  184     return cache.peek(nbits);
  185   }
  186 
  187   inline void skipBitsNoFill(uint32_t nbits) {
  188     assert(nbits <= Cache::MaxGetBits);
  189     assert(nbits <= cache.fillLevel);
  190     cache.skip(nbits);
  191   }
  192 
  193   inline uint32_t getBitsNoFill(uint32_t nbits) {
  194     uint32_t ret = peekBitsNoFill(nbits);
  195     skipBitsNoFill(nbits);
  196     return ret;
  197   }
  198 
  199   inline uint32_t peekBits(uint32_t nbits) {
  200     fill(nbits);
  201     return peekBitsNoFill(nbits);
  202   }
  203 
  204   inline uint32_t getBits(uint32_t nbits) {
  205     fill(nbits);
  206     return getBitsNoFill(nbits);
  207   }
  208 
  209   // This may be used to skip arbitrarily large number of *bytes*,
  210   // not limited by the fill level.
  211   inline void skipBytes(uint32_t nbytes) {
  212     uint32_t remainingBitsToSkip = 8 * nbytes;
  213     for (; remainingBitsToSkip >= Cache::MaxGetBits;
  214          remainingBitsToSkip -= Cache::MaxGetBits) {
  215       fill(Cache::MaxGetBits);
  216       skipBitsNoFill(Cache::MaxGetBits);
  217     }
  218     if (remainingBitsToSkip > 0) {
  219       fill(remainingBitsToSkip);
  220       skipBitsNoFill(remainingBitsToSkip);
  221     }
  222   }
  223 };
  224 
  225 } // namespace rawspeed