Skip to content
Snippets Groups Projects
Select Git revision
  • master
  • L2SS-1914-fix_job_dispatch
  • TMSS-3170
  • TMSS-3167
  • TMSS-3161
  • TMSS-3158-Front-End-Only-Allow-Changing-Again
  • TMSS-3133
  • TMSS-3319-Fix-Templates
  • test-fix-deploy
  • TMSS-3134
  • TMSS-2872
  • defer-state
  • add-custom-monitoring-points
  • TMSS-3101-Front-End-Only
  • TMSS-984-choices
  • SDC-1400-Front-End-Only
  • TMSS-3079-PII
  • TMSS-2936
  • check-for-max-244-subbands
  • TMSS-2927---Front-End-Only-PXII
  • Before-Remove-TMSS
  • LOFAR-Release-4_4_318 protected
  • LOFAR-Release-4_4_317 protected
  • LOFAR-Release-4_4_316 protected
  • LOFAR-Release-4_4_315 protected
  • LOFAR-Release-4_4_314 protected
  • LOFAR-Release-4_4_313 protected
  • LOFAR-Release-4_4_312 protected
  • LOFAR-Release-4_4_311 protected
  • LOFAR-Release-4_4_310 protected
  • LOFAR-Release-4_4_309 protected
  • LOFAR-Release-4_4_308 protected
  • LOFAR-Release-4_4_307 protected
  • LOFAR-Release-4_4_306 protected
  • LOFAR-Release-4_4_304 protected
  • LOFAR-Release-4_4_303 protected
  • LOFAR-Release-4_4_302 protected
  • LOFAR-Release-4_4_301 protected
  • LOFAR-Release-4_4_300 protected
  • LOFAR-Release-4_4_299 protected
40 results

LofarGeneral.cmake

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    compressed_mask_data.h 8.56 KiB
    // SPDX-License-Identifier: LGPL-3.0-only
    
    #ifndef RADLER_UTILS_COMPRESSED_MASK_DATA_H_
    #define RADLER_UTILS_COMPRESSED_MASK_DATA_H_
    
    #include <algorithm>
    #include <cassert>
    #include <cstdint>
    #include <string>
    #include <vector>
    
    namespace radler::utils::implementation {
    
    /**
     * Helper class for @ref CompressedData. This class holds the compressed
     * data counts, and provides low-level operations on this count. This class
     * makes it possible to test these low-level operations while the interface
     * CompressedData can remain simple.
     */
    class CompressedMaskData {
     public:
      using iterator = std::vector<unsigned char>::iterator;
      using const_iterator = std::vector<unsigned char>::const_iterator;
    
      CompressedMaskData() noexcept = default;
      CompressedMaskData(CompressedMaskData&&) noexcept = default;
      CompressedMaskData(std::vector<unsigned char>&& data)
          : data_(std::move(data)) {}
      CompressedMaskData& operator=(CompressedMaskData&&) noexcept = default;
    
      const std::vector<unsigned char>& Data() const { return data_; }
      const_iterator begin() const { return data_.begin(); }
      iterator begin() { return data_.begin(); }
      const_iterator end() const { return data_.end(); }
      iterator end() { return data_.end(); }
    
      void Clear() { data_.clear(); }
    
      /** Sum of all compressed values, i.e., size of the uncompressed data. */
      size_t SumCount() const {
        size_t sum = 0;
        const_iterator iterator = data_.begin();
        while (iterator != data_.end()) {
          sum += GetCount(iterator);
        }
        return sum;
      }
    
      /**
       * Add a given number of samples with constant value add the end of the
       * compressed data. Values smaller than 255 take up 1 byte, whereas values >=
       * 256 take up 9 bytes (1 byte of value zero to indicate this is a long value,
       * then 8 bytes of data).
       * @param count should be larger than zero.
       */
      void PushBackCount(uint64_t count) {
        assert(count != 0);
        if (count < 255)
          data_.emplace_back(count);
        else if (count < 65536) {
          data_.emplace_back(255);
          data_.emplace_back(count % 256u);
          data_.emplace_back(count / 256u);
        } else {
          data_.emplace_back(0);
          const char* count_data = reinterpret_cast<char*>(&count);
          for (size_t i = 0; i != 8; ++i) data_.emplace_back(count_data[i]);
        }
      }
    
      /**
       * Compress a sequence of values and push them to the back of the data array.
       * @param [in] size Number of samples to compress in sequence
       * @param [in,out] sequence The data to compress of the specified size. The
       * pointer is moved to the end of the sequence.
       * @param [in,out] residual_count The number of samples with value
       * 'current_value' that needs to be added to the next pushed value.
       * @param [in,out] current_value The value associated to the next pushed count
       * (so the negation of the value associated to the previous pushed count).
       */
      void PushBackSequence(size_t size, const bool*& sequence,
                            size_t& residual_count, bool& current_value) {
        for (size_t i = 0; i != size; ++i) {
          if (*sequence != current_value) {
            PushBackCount(residual_count);
            residual_count = 0;
          }
          current_value = *sequence;
          ++residual_count;
          ++sequence;
        }
      }
    
      /**
       * Add a sequence from one compressed mask to this compressed mask.
       * @param [in,out] residual_count number of samples still available from
       * the source mask until the next read is required.
       * @return The number of samples with value 'current_value' that needs
       * to be added to the next pushed value.
       */
      size_t PushBackCompressedSequence(
          size_t size, const CompressedMaskData& source,
          std::vector<unsigned char>::const_iterator& source_iterator,
          size_t& residual_count, bool& current_value) {
        while (residual_count < size) {
          size -= residual_count;
          PushBackCount(residual_count);
          current_value = !current_value;
          // because we are inside while(residual_count < size), the iterator can
          // never be at the end, because then we would be asked more values than
          // available (which is considered undefined behaviour).
          residual_count = source.GetCount(source_iterator);
        }
        residual_count -= size;
        return size;
      }
    
      /**
       * Move the iterator one count value forward.
       */
      void SkipCount(std::vector<unsigned char>::const_iterator& iter) const {
        assert(iter != data_.end());
        const unsigned char value = *iter;
        ++iter;
        if (value == 255) {
          iter += 2;
        } else if (value == 0) {
          iter += 8;
        }
      }
    
      /**
       * Decode the count value of the iterator and move the iterator forward.
       * Behaviour is undefined when iter is at end.
       * @returns the decoded value (> 0).
       */
      uint64_t GetCount(std::vector<unsigned char>::const_iterator& iter) const {
        assert(iter != data_.end());
        const unsigned char value = *iter;
        ++iter;
        if (value == 0) {
          uint64_t u64_value;
          // The uint64_t is not stored aligned inside the vector, so it can not be
          // directly copied. Instead, copy it byte by byte.
          char* value_ptr = reinterpret_cast<char*>(&u64_value);
          std::copy_n(iter, 8, value_ptr);
          iter += 8;
          return u64_value;
        } else if (value == 255) {
          uint16_t u16_value = *iter;
          ++iter;
          u16_value += *iter << 8;
          ++iter;
          return u16_value;
        } else {
          return value;
        }
      }
    
      /**
       * Move iterator and update counters to skip a given number of uncompressed
       * samples.
       * @param [in] offset amount of uncompressed samples to skip
       * @param [in,out] iterator iterator into data pointing to the next compressed
       * count that needs to be read, or end when all values have been read.
       * @param [in,out] residual_count number of samples of the current count
       * available from the last read count, until the next change of value.
       * @param [in,out] value the value of the current serie of values. The next
       * uncompressed value has this value. Everytime a new count is read and the
       * iterator is increased, the value is negated.
       */
      void MoveIterator(size_t offset,
                        std::vector<unsigned char>::const_iterator& iterator,
                        size_t& residual_count, bool& value) const {
        while (offset >= residual_count) {
          offset -= residual_count;
          value = !value;
          if (iterator == data_.end()) {
            assert(offset == 0);
            residual_count = 0;
            break;
          } else {
            residual_count = GetCount(iterator);
          }
        }
        residual_count -= offset;
      }
    
      /**
       * Similar as @ref MoveIterator(), but will leave the iterator before the last
       * compressed value. On input, iterator should also point before the count
       * that is already in residual_count, i.e. it should lag one value behind
       * compared to @ref MoveIterator. Also, unlike MoveIterator, it will return
       * residual_count = 0 (and not read the next value already) in case offset
       * falls exactly after a compressed count value.
       */
      void MoveIteratorBefore(size_t offset,
                              std::vector<unsigned char>::const_iterator& iterator,
                              size_t& residual_count, bool& value) const {
        std::vector<unsigned char>::const_iterator next_iterator = iterator;
        SkipCount(next_iterator);
    
        while (offset > residual_count) {
          offset -= residual_count;
          value = !value;
          iterator = next_iterator;
          residual_count = GetCount(next_iterator);
        }
        residual_count -= offset;
      }
    
      /**
       * Decode a consecutive sequence of values and stop after a given number of
       * samples was decoded.
       * @param [in] size The number of uncompressed values to extract.
       * @param [in,out] destination Place for storing @c size values. The pointer
       * is moved to point the end of the sequence.
       * @param [in,out] iterator Position for the next read.
       * @param [in,out] residual_count How many values are still to be read with
       * the given value.
       * @param [in,out] value Value of the current read sequence.
       */
      void ExtractSequence(size_t size, bool*& destination,
                           std::vector<unsigned char>::const_iterator& iterator,
                           size_t& residual_count, bool& value) const {
        while (residual_count < size) {
          destination = std::fill_n(destination, residual_count, value);
          value = !value;
          size -= residual_count;
          residual_count = GetCount(iterator);
        }
        destination = std::fill_n(destination, size, value);
        residual_count -= size;
      }
    
      std::string ToString(bool first_value, size_t width) const;
    
     private:
      std::vector<unsigned char> data_;
    };
    
    }  // namespace radler::utils::implementation
    
    #endif