LCOV - code coverage report
Current view: top level - include/Tools/Algo/Bit_packer - Bit_packer.hxx (source / functions) Hit Total Coverage
Test: streampu_clean.info Lines: 34 64 53.1 %
Date: 2024-07-31 15:48:41 Functions: 4 40 10.0 %

          Line data    Source code
       1             : #ifndef _USE_MATH_DEFINES
       2             : #define _USE_MATH_DEFINES
       3             : #endif
       4             : #include <algorithm>
       5             : #include <cmath>
       6             : #include <sstream>
       7             : 
       8             : #include "Tools/Algo/Bit_packer/Bit_packer.hpp"
       9             : #include "Tools/Exception/exception.hpp"
      10             : 
      11             : namespace spu
      12             : {
      13             : namespace tools
      14             : {
      15             : template<typename B, class AB, typename S, class AS>
      16             : void
      17             : Bit_packer::pack(const std::vector<B, AB>& vec_in,
      18             :                  std::vector<S, AS>& vec_out,
      19             :                  const int n_frames,
      20             :                  const bool msb_to_lsb,
      21             :                  const bool pack_per_byte,
      22             :                  const int Nbps)
      23             : {
      24             :     if (n_frames <= 0)
      25             :     {
      26             :         std::stringstream message;
      27             :         message << "'n_frames' has to be greater than 0 ('n_frames' = " << n_frames << ").";
      28             :         throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
      29             :     }
      30             : 
      31             :     if (vec_in.size() % n_frames)
      32             :     {
      33             :         std::stringstream message;
      34             :         message << "'vec_in.size()' has to be divisible by 'n_frames' ('vec_in.size()' = " << vec_in.size()
      35             :                 << ", 'n_frames' = " << n_frames << ").";
      36             :         throw length_error(__FILE__, __LINE__, __func__, message.str());
      37             :     }
      38             : 
      39             :     if (pack_per_byte)
      40             :     {
      41             : 
      42             :         if ((vec_out.size() * sizeof(S) * Nbps) < vec_in.size())
      43             :         {
      44             :             std::stringstream message;
      45             :             message << "'vec_out.size()' has to be equal or greater than ('vec_in.size()' / 'sizeof(S)' / 'Nbps') "
      46             :                     << "('vec_out.size()' = " << vec_out.size() << ", 'vec_in.size()' = " << vec_in.size()
      47             :                     << ", 'sizeof(S)' = " << sizeof(S) << ", 'Nbps' = " << Nbps << ").";
      48             :             throw length_error(__FILE__, __LINE__, __func__, message.str());
      49             :         }
      50             : 
      51             :         Bit_packer::pack(
      52             :           vec_in.data(), (unsigned char*)vec_out.data(), (int)(vec_in.size() / n_frames), n_frames, msb_to_lsb, Nbps);
      53             :     }
      54             :     else
      55             :     {
      56             :         if ((vec_out.size() * Nbps) < vec_in.size())
      57             :         {
      58             :             std::stringstream message;
      59             :             message << "'vec_out.size()' has to be equal or greater than ('vec_in.size()' / 'Nbps') "
      60             :                     << "('vec_out.size()' = " << vec_out.size() << ", 'vec_in.size()' = " << vec_in.size()
      61             :                     << ", 'Nbps' = " << Nbps << ").";
      62             :             throw length_error(__FILE__, __LINE__, __func__, message.str());
      63             :         }
      64             : 
      65             :         Bit_packer::pack(vec_in.data(), vec_out.data(), (int)(vec_in.size() / n_frames), n_frames, msb_to_lsb, Nbps);
      66             :     }
      67             : }
      68             : 
      69             : template<typename B, typename S>
      70             : void
      71       11763 : Bit_packer::pack(const B* vec_in,
      72             :                  S* vec_out,
      73             :                  const int n_bits_per_frame,
      74             :                  const int n_frames,
      75             :                  const bool msb_to_lsb,
      76             :                  const int Nbps)
      77             : {
      78       11763 :     if (Nbps > (int)(sizeof(S) * CHAR_BIT) || Nbps <= 0)
      79             :     {
      80           0 :         std::stringstream message;
      81           0 :         message << "'Nbps' must be between 1 and (sizeof(S) * CHAR_BIT). ('Nbps' = " << Nbps
      82           0 :                 << ", 'sizeof(S)' = " << sizeof(S) << ", 'CHAR_BIT' = " << CHAR_BIT << ").";
      83           0 :         throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
      84           0 :     }
      85             : 
      86       11763 :     const auto n_symbols_per_frame = static_cast<int>(std::ceil((float)n_bits_per_frame / Nbps));
      87             : 
      88       23526 :     for (auto f = 0; f < n_frames; f++)
      89       11763 :         Bit_packer::_pack(
      90       11763 :           vec_in + f * n_bits_per_frame, vec_out + f * n_symbols_per_frame, n_bits_per_frame, msb_to_lsb, Nbps);
      91       11763 : }
      92             : 
      93             : template<typename B, class AB>
      94             : void
      95             : Bit_packer::pack(std::vector<B, AB>& vec, const int n_frames, const bool msb_to_lsb, const int Nbps)
      96             : {
      97             :     if (n_frames <= 0)
      98             :     {
      99             :         std::stringstream message;
     100             :         message << "'n_frames' has to be greater than 0 ('n_frames' = " << n_frames << ").";
     101             :         throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
     102             :     }
     103             : 
     104             :     if (vec.size() % n_frames)
     105             :     {
     106             :         std::stringstream message;
     107             :         message << "'vec.size()' has to be divisible by 'n_frames' ('vec.size()' = " << vec.size()
     108             :                 << ", 'n_frames' = " << n_frames << ").";
     109             :         throw length_error(__FILE__, __LINE__, __func__, message.str());
     110             :     }
     111             : 
     112             :     Bit_packer::pack(vec.data(), (int)(vec.size() / n_frames), n_frames, msb_to_lsb, Nbps);
     113             : }
     114             : 
     115             : template<typename B>
     116             : void
     117             : Bit_packer::pack(B* vec, const int n_bits_per_frame, const int n_frames, const bool msb_to_lsb, const int Nbps)
     118             : {
     119             :     if (Nbps > (int)CHAR_BIT || Nbps <= 0)
     120             :     {
     121             :         std::stringstream message;
     122             :         message << "'Nbps' must be between 1 and CHAR_BIT. ('Nbps' = " << Nbps << ").";
     123             :         throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
     124             :     }
     125             : 
     126             :     const auto n_symbs_per_frame = static_cast<int>(std::ceil((float)n_bits_per_frame / Nbps));
     127             : 
     128             :     unsigned char* symbs_out = (unsigned char*)vec;
     129             : 
     130             :     for (auto f = 0; f < n_frames; f++)
     131             :         Bit_packer::_pack(
     132             :           vec + f * n_bits_per_frame, symbs_out + f * n_symbs_per_frame, n_bits_per_frame, msb_to_lsb, Nbps);
     133             : }
     134             : 
     135             : template<typename B, class AB, typename S, class AS>
     136             : void
     137             : Bit_packer::unpack(const std::vector<S, AS>& vec_in,
     138             :                    std::vector<B, AB>& vec_out,
     139             :                    const int n_frames,
     140             :                    const bool msb_to_lsb,
     141             :                    const bool unpack_per_byte,
     142             :                    const int Nbps)
     143             : {
     144             :     if (n_frames <= 0)
     145             :     {
     146             :         std::stringstream message;
     147             :         message << "'n_frames' has to be greater than 0 ('n_frames' = " << n_frames << ").";
     148             :         throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
     149             :     }
     150             : 
     151             :     if (vec_out.size() % n_frames)
     152             :     {
     153             :         std::stringstream message;
     154             :         message << "'vec_out.size()' has to be divisible by 'n_frames' ('vec_out.size()' = " << vec_out.size()
     155             :                 << ", 'n_frames' = " << n_frames << ").";
     156             :         throw length_error(__FILE__, __LINE__, __func__, message.str());
     157             :     }
     158             : 
     159             :     if (unpack_per_byte)
     160             :     {
     161             :         if ((vec_in.size() * sizeof(B) * Nbps) < vec_out.size())
     162             :         {
     163             :             std::stringstream message;
     164             :             message << "('vec_in.size()' * 'sizeof(B)' * 'Nbps') has to be equal or greater than 'vec_out.size()' "
     165             :                     << "('vec_in.size()' = " << vec_in.size() << ", 'vec_out.size()' = " << vec_out.size()
     166             :                     << ", 'sizeof(B)' = " << sizeof(B) << ", 'Nbps' = " << Nbps << ").";
     167             :             throw length_error(__FILE__, __LINE__, __func__, message.str());
     168             :         }
     169             : 
     170             :         Bit_packer::unpack(
     171             :           (unsigned char*)vec_in.data(), vec_out.data(), (int)(vec_out.size() / n_frames), n_frames, msb_to_lsb, Nbps);
     172             :     }
     173             :     else
     174             :     {
     175             :         if ((vec_in.size() * Nbps) < vec_out.size())
     176             :         {
     177             :             std::stringstream message;
     178             :             message << "('vec_in.size()' * 'Nbps') has to be equal or greater than 'vec_out.size()' "
     179             :                     << "('vec_in.size()' = " << vec_in.size() << ", 'vec_out.size()' = " << vec_out.size()
     180             :                     << ", 'Nbps' = " << Nbps << ").";
     181             :             throw length_error(__FILE__, __LINE__, __func__, message.str());
     182             :         }
     183             : 
     184             :         Bit_packer::unpack(vec_in.data(), vec_out.data(), (int)(vec_out.size() / n_frames), n_frames, msb_to_lsb, Nbps);
     185             :     }
     186             : }
     187             : 
     188             : template<typename B, typename S>
     189             : void
     190       11749 : Bit_packer::unpack(const S* vec_in,
     191             :                    B* vec_out,
     192             :                    const int n_bits_per_frame,
     193             :                    const int n_frames,
     194             :                    const bool msb_to_lsb,
     195             :                    const int Nbps)
     196             : {
     197       11749 :     if (Nbps > (int)(sizeof(S) * CHAR_BIT) || Nbps <= 0)
     198             :     {
     199           0 :         std::stringstream message;
     200           0 :         message << "'Nbps' must be between 1 and (sizeof(S) * CHAR_BIT). ('Nbps' = " << Nbps
     201           0 :                 << ", 'sizeof(S)' = " << sizeof(S) << ", 'CHAR_BIT' = " << CHAR_BIT << ").";
     202           0 :         throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
     203           0 :     }
     204             : 
     205       11749 :     const auto n_symbs_per_frame = static_cast<int>(std::ceil((float)n_bits_per_frame / Nbps));
     206             : 
     207       23498 :     for (auto f = 0; f < n_frames; f++)
     208       11749 :         Bit_packer::_unpack(
     209       11749 :           vec_in + f * n_symbs_per_frame, vec_out + f * n_bits_per_frame, n_bits_per_frame, msb_to_lsb, Nbps);
     210       11749 : }
     211             : 
     212             : template<typename B, class AB>
     213             : void
     214             : Bit_packer::unpack(std::vector<B, AB>& vec, const int n_frames, const bool msb_to_lsb, const int Nbps)
     215             : {
     216             :     if (n_frames <= 0)
     217             :     {
     218             :         std::stringstream message;
     219             :         message << "'n_frames' has to be greater than 0 ('n_frames' = " << n_frames << ").";
     220             :         throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
     221             :     }
     222             : 
     223             :     if (vec.size() % n_frames)
     224             :     {
     225             :         std::stringstream message;
     226             :         message << "'vec.size()' has to be divisible by 'n_frames' ('vec.size()' = " << vec.size()
     227             :                 << ", 'n_frames' = " << n_frames << ").";
     228             :         throw length_error(__FILE__, __LINE__, __func__, message.str());
     229             :     }
     230             : 
     231             :     Bit_packer::unpack(vec.data(), (int)(vec.size() / n_frames), n_frames, msb_to_lsb, Nbps);
     232             : }
     233             : 
     234             : template<typename B>
     235             : void
     236             : Bit_packer::unpack(B* vec, const int n_bits_per_frame, const int n_frames, const bool msb_to_lsb, const int Nbps)
     237             : {
     238             :     if (Nbps > (int)CHAR_BIT || Nbps <= 0)
     239             :     {
     240             :         std::stringstream message;
     241             :         message << "'Nbps' must be between 1 and CHAR_BIT. ('Nbps' = " << Nbps << ").";
     242             :         throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
     243             :     }
     244             : 
     245             :     const auto n_symbs_per_frame = static_cast<int>(std::ceil((float)n_bits_per_frame / Nbps));
     246             : 
     247             :     unsigned char* bytes = (unsigned char*)vec;
     248             :     std::vector<unsigned char> bytes_cpy(n_symbs_per_frame); // TODO: find a way to avoid this allocation
     249             : 
     250             :     for (auto f = 0; f < n_frames; f++)
     251             :     {
     252             :         // TODO: find a way to avoid this copy
     253             :         std::copy(&bytes[f * n_symbs_per_frame], &bytes[(f + 1) * n_symbs_per_frame], bytes_cpy.begin());
     254             : 
     255             :         Bit_packer::_unpack(
     256             :           bytes_cpy.data() + f * n_symbs_per_frame, vec + f * n_bits_per_frame, n_bits_per_frame, msb_to_lsb, Nbps);
     257             :     }
     258             : }
     259             : 
     260             : template<typename B, typename S>
     261             : void
     262       11763 : Bit_packer::_pack(const B* vec_in, S* symbs_out, const int n_bits, const bool msb_to_lsb, const int Nbps)
     263             : {
     264       11763 :     const auto n_symbs = n_bits / Nbps;
     265       11763 :     const auto rest = n_bits - n_symbs * Nbps;
     266             : 
     267       11763 :     if (!msb_to_lsb) // lsb_to_msb
     268             :     {
     269      127380 :         for (auto i = 0; i < n_symbs; i++, symbs_out++)
     270             :         {
     271      115617 :             S symb = 0;
     272     1040553 :             for (auto j = 0; j < Nbps; j++, vec_in++)
     273      924936 :                 symb |= ((S)(*vec_in != 0)) << j;
     274      115617 :             *symbs_out = symb;
     275             :         }
     276             : 
     277       11763 :         if (rest != 0)
     278             :         {
     279           0 :             S symb = 0;
     280           0 :             for (auto j = 0; j < rest; j++, vec_in++)
     281           0 :                 symb |= ((S)(*vec_in != 0)) << j;
     282           0 :             *symbs_out = symb;
     283             :         }
     284             :     }
     285             :     else // msb_to_lsb
     286             :     {
     287           0 :         for (auto i = 0; i < n_symbs; i++, symbs_out++)
     288             :         {
     289           0 :             S symb = 0;
     290           0 :             for (auto j = 0; j < Nbps; j++, vec_in++)
     291           0 :                 symb = (symb << 1) | (*vec_in != 0);
     292           0 :             *symbs_out = symb << (sizeof(S) * CHAR_BIT - Nbps);
     293             :         }
     294             : 
     295           0 :         if (rest != 0)
     296             :         {
     297           0 :             S symb = 0;
     298           0 :             for (auto j = 0; j < rest; j++, vec_in++)
     299           0 :                 symb = (symb << 1) | (*vec_in != 0);
     300           0 :             *symbs_out = symb << (sizeof(S) * CHAR_BIT - rest);
     301             :         }
     302             :     }
     303       11763 : }
     304             : 
     305             : template<typename B, typename S>
     306             : void
     307       11749 : Bit_packer::_unpack(const S* symbs_in, B* vec_out, const int n_bits, const bool msb_to_lsb, const int Nbps)
     308             : {
     309       11749 :     const auto n_symbs = n_bits / Nbps;
     310       11749 :     const auto rest = n_bits - n_symbs * Nbps;
     311             : 
     312       11749 :     if (!msb_to_lsb) // lsb_to_msb
     313             :     {
     314      127366 :         for (auto i = 0; i < n_symbs; i++, symbs_in++)
     315     1040553 :             for (auto j = 0; j < Nbps; j++, vec_out++)
     316      924936 :                 *vec_out = (*symbs_in >> j) & (S)1;
     317             : 
     318       11749 :         for (auto j = 0; j < rest; j++, vec_out++)
     319           0 :             *vec_out = (*symbs_in >> j) & (S)1;
     320             :     }
     321             :     else // msb_to_lsb
     322             :     {
     323           0 :         for (auto i = 0; i < n_symbs; i++, symbs_in++)
     324           0 :             for (auto j = 0; j < Nbps; j++, vec_out++)
     325           0 :                 *vec_out = (*symbs_in >> (sizeof(S) * CHAR_BIT - 1 - j)) & (S)1;
     326             : 
     327           0 :         for (auto j = 0; j < rest; j++, vec_out++)
     328           0 :             *vec_out = (*symbs_in >> (sizeof(S) * CHAR_BIT - 1 - j)) & (S)1;
     329             :     }
     330       11749 : }
     331             : }
     332             : }
     333             : 
     334             : /* Test code :
     335             : #include "Tools/Algo/Bit_packer.hpp"
     336             : #include "Tools/Display/Frame_trace/Frame_trace.hpp"
     337             : #include <random>
     338             : #include <string>
     339             : #include <vector>
     340             : 
     341             : int main(int argc, char** argv)
     342             : {
     343             :         using namespace spu;
     344             :         using B = int;
     345             :         using S = short;
     346             : 
     347             :         std::random_device rd;
     348             : 
     349             :         size_t size_in    = (argc >= 2) ? std::stoi(argv[1]) : 16;
     350             :         int    Nbps       = (argc >= 3) ? std::stoi(argv[2]) : CHAR_BIT;
     351             :         int    n_frames   = (argc >= 4) ? std::stoi(argv[3]) : 1;
     352             :         int    msb_to_lsb = (argc >= 5) ? std::stoi(argv[4]) : 0;
     353             :         int pack_per_byte = (argc >= 6) ? std::stoi(argv[5]) : 1;
     354             :         int    seed       = (argc >= 7) ? std::stoi(argv[6]) : rd();
     355             : 
     356             :         size_t size_out   = std::ceil(1.f * size_in / Nbps);
     357             : 
     358             :         std::vector<B> vec_in      (size_in  * n_frames);
     359             :         std::vector<S> vec_packed  (size_out * n_frames);
     360             :         std::vector<B> vec_unpacked(size_in  * n_frames);
     361             : 
     362             :         std::mt19937 gen(seed);
     363             :         std::bernoulli_distribution d(0.5);
     364             : 
     365             :         for (auto& v : vec_in)
     366             :                 v = d(gen);
     367             : 
     368             :         tools::Frame_trace<> ft;
     369             : 
     370             :         std::cout << "Vec in" << std::endl;
     371             :         ft.display_bit_vector(vec_in, Nbps);
     372             : 
     373             :         tools::Bit_packer::pack(vec_in, vec_packed, n_frames, msb_to_lsb, pack_per_byte, Nbps);
     374             : 
     375             :         std::cout << "Vec packed" << std::endl;
     376             : 
     377             :         if (pack_per_byte)
     378             :         {
     379             :                 std::vector<char> vec_char(vec_packed.size() * sizeof(S));
     380             :                 std::copy_n((char*)vec_packed.data(), vec_char.size(), vec_char.data());
     381             :                 ft.display_hex_vector(vec_char, size_out * sizeof(S));
     382             :         }
     383             :         else
     384             :                 ft.display_hex_vector(vec_packed, size_out);
     385             : 
     386             :         tools::Bit_packer::unpack(vec_packed, vec_unpacked, n_frames, msb_to_lsb, pack_per_byte, Nbps);
     387             : 
     388             :         std::cout << "Vec unpacked" << std::endl;
     389             :         ft.display_bit_vector(vec_unpacked, Nbps);
     390             : 
     391             :         bool same = true;
     392             :         for (unsigned i = 0; i < vec_unpacked.size(); i++)
     393             :                 same &= vec_unpacked[i] == vec_in[i];
     394             : 
     395             :         std::cout << "Same in and unpacked = " << same << std::endl;
     396             : }
     397             : */

Generated by: LCOV version 1.14