LCOV - code coverage report
Current view: top level - src/MIDI_Parsers - HexPuller.hpp (source / functions) Hit Total Coverage
Test: b8a30b4b7040ae1abf162fd0a258beaa2de43626 Lines: 17 18 94.4 %
Date: 2024-12-21 21:28:55 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <AH/STL/utility> // std::forward
       4             : #include <AH/STL/vector>  // std::vector
       5             : #include <Settings/NamespaceSettings.hpp>
       6             : #include <ctype.h> // isxdigit, tolower
       7             : 
       8             : BEGIN_CS_NAMESPACE
       9             : 
      10             : /**
      11             :  * @brief   Class that parses hexadecimal ASCII text to bytes.
      12             :  *
      13             :  * For example, parses the string `"7f A 123456"` to the bytes 
      14             :  * `{0x7F, 0x0A, 0x12, 0x34, 0x56}`.
      15             :  *
      16             :  * @tparam  CharPuller
      17             :  *          Class that supplies the ASCII characters to parse.
      18             :  *
      19             :  * @see     @ref BufferPuller
      20             :  * @see     @ref StreamPuller
      21             :  * 
      22             :  * @ingroup MIDIParsers
      23             :  */
      24             : template <class CharPuller>
      25             : class HexPuller {
      26             :   public:
      27          16 :     HexPuller(CharPuller &&puller) : puller(std::forward<CharPuller>(puller)) {}
      28             : 
      29             :     /// Pull out a new byte. Pulls characters from the `CharPuller` until a
      30             :     /// hexadecimal number was found, decodes it, and returns it.
      31             :     ///
      32             :     /// @param[out] output
      33             :     ///             A new byte (if available).
      34             :     /// @return True if a byte was available, false otherwise.
      35          21 :     bool pull(uint8_t &output) {
      36          21 :         uint8_t input;
      37          53 :         while (puller.pull(input)) {
      38             :             // If we receive a hexadecimal digit
      39          53 :             if (isxdigit(input)) {
      40          40 :                 (char1 ? char2 : char1) = tolower(input);
      41             :             }
      42             :             // If we received two hex characters
      43          53 :             if (char1 && char2) {
      44          19 :                 output = hex2int(char1) << 4 | hex2int(char2);
      45          19 :                 char1 = '\0';
      46          19 :                 char2 = '\0';
      47          19 :                 return true;
      48             :             }
      49             :             // If we received one hex character followed by whitespace/other
      50          34 :             else if (!isxdigit(input) && char1) {
      51           2 :                 output = hex2int(char1);
      52           2 :                 char1 = '\0';
      53           2 :                 return true;
      54             :             }
      55             :         }
      56           0 :         return false;
      57             :     }
      58             : 
      59             :   private:
      60             :     /// Convert a hexadecimal character to a 4-bit nibble.
      61          40 :     static uint8_t hex2int(char hex) {
      62          40 :         return hex < 'a' ? hex - '0' : hex - 'a' + 10;
      63             :     }
      64             : 
      65             :   public:
      66             :     CharPuller puller;
      67             : 
      68             :   private:
      69             :     char char1 = '\0';
      70             :     char char2 = '\0';
      71             : };
      72             : 
      73             : END_CS_NAMESPACE

Generated by: LCOV version 1.15