LCOV - code coverage report
Current view: top level - snapdev - int128_literal.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 41.9 % 86 36
Test Date: 2026-02-16 17:48:13 Functions: 100.0 % 4 4
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2022-2026  Made to Order Software Corp.  All Rights Reserved
       2              : //
       3              : // https://snapwebsites.org/project/snapdev
       4              : // contact@m2osw.com
       5              : //
       6              : // This program is free software: you can redistribute it and/or modify
       7              : // it under the terms of the GNU General Public License as published by
       8              : // the Free Software Foundation, either version 3 of the License, or
       9              : // (at your option) any later version.
      10              : //
      11              : // This program is distributed in the hope that it will be useful,
      12              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              : // GNU General Public License for more details.
      15              : //
      16              : // You should have received a copy of the GNU General Public License
      17              : // along with this program.  If not, see <https://www.gnu.org/licenses/>.
      18              : #pragma once
      19              : 
      20              : /** \file
      21              :  * \brief Convert a numeric or string literal to a 128 bit value.
      22              :  *
      23              :  * These functions transform string literals or numeric literals to 128 bit
      24              :  * values as supported by g++. We support signed and unsigned in decimal,
      25              :  * hexadecimal, octal, and binary.
      26              :  */
      27              : 
      28              : // C++
      29              : //
      30              : #include    <cstring>
      31              : #include    <limits>
      32              : #include    <stdexcept>
      33              : 
      34              : 
      35              : namespace snapdev
      36              : {
      37              : namespace literals
      38              : {
      39              : 
      40              : /** \brief Convert a literal to a signed __int128.
      41              :  *
      42              :  * This function converts a literal string to a signed __int128 integer
      43              :  * number.
      44              :  *
      45              :  * \code
      46              :  * using namespace snapdev::literals;
      47              :  *
      48              :  * __int128 value = "0xabcd000000000000"_int128;
      49              :  * \endcode
      50              :  *
      51              :  * \todo
      52              :  * Make sure that the first '\0' represents the end of the string.
      53              :  *
      54              :  * \todo
      55              :  * Support the negative (and positive) sign at the start of the string
      56              :  * (with number literal, it is viewed as an operator so it works as is,
      57              :  * with with string literals, we have to handle those ourselves).
      58              :  *
      59              :  * \param[in] literal  A 128 bit literal number.
      60              :  *
      61              :  * \return The __int128 number.
      62              :  *
      63              :  * \sa operator ""_uint128()
      64              :  */
      65              : #pragma GCC diagnostic push
      66              : #pragma GCC diagnostic ignored "-Wpedantic"
      67         1408 : constexpr __int128 operator ""_int128(char const * literal, std::size_t len)
      68              : {
      69         1408 :     __int128 result(0);
      70         1408 :     __int128 base(10);
      71              : 
      72         1408 :     if(len == 0)
      73              :     {
      74            0 :         throw std::invalid_argument("A string literal of a int128 must be at least one cahracter.");
      75              :     }
      76              : 
      77         1408 :     if(*literal == '0')
      78              :     {
      79            0 :         ++literal;
      80            0 :         if(*literal == '\0')
      81              :         {
      82            0 :             return result;
      83              :         }
      84            0 :         if(*literal == 'x'
      85            0 :         || *literal == 'X')
      86              :         {
      87              :             // parse a hexadecimal number
      88              :             //
      89            0 :             base = 16;
      90            0 :             ++literal;
      91            0 :             if(*literal == '\0')
      92              :             {
      93            0 :                 throw std::invalid_argument("0x must be followed by at least one hexadecimal digit.");
      94              :             }
      95              :         }
      96            0 :         else if(*literal == 'b'
      97            0 :              || *literal == 'B')
      98              :         {
      99              :             // parse a binary number
     100              :             //
     101            0 :             base = 2;
     102            0 :             ++literal;
     103            0 :             if(*literal == '\0')
     104              :             {
     105            0 :                 throw std::invalid_argument("0b must be followed by at least one binary digit.");
     106              :             }
     107              :         }
     108              :         else
     109              :         {
     110              :             // parse an octal number
     111              :             //
     112            0 :             base = 8;
     113              :         }
     114              :     }
     115              :     // else -- parse a decimal number
     116              : 
     117              :     for(;;)
     118              :     {
     119         2816 :         char const c(*literal++);
     120         2816 :         if(c == '\0')
     121              :         {
     122              :             // valid
     123              :             //
     124         1408 :             return result;
     125              :         }
     126         1408 :         int digit(std::numeric_limits<int>::max());
     127         1408 :         if(c >= '0' && c <= '9')
     128              :         {
     129         1408 :             digit = c - '0';
     130              :         }
     131            0 :         else if(c >= 'a' && c <= 'f')
     132              :         {
     133            0 :             digit = c - ('a' - 10);
     134              :         }
     135            0 :         else if(c >= 'A' && c <= 'F')
     136              :         {
     137            0 :             digit = c - ('A' - 10);
     138              :         }
     139         1408 :         if(digit >= base)
     140              :         {
     141              :             throw std::domain_error(
     142            0 :                   std::string("digit '")
     143            0 :                 + c
     144            0 :                 + "' too large for the selected base");
     145              :         }
     146              : 
     147         1408 :         __int128 const old(result);
     148         1408 :         result = result * base + digit;
     149         1408 :         if(result < old)
     150              :         {
     151              :             // overflow
     152              :             //
     153              :             // IMPORTANT NOTE: This test works because we do not deal with
     154              :             // the '-' sign which the C++ compiler handles for us
     155              :             //
     156            0 :             throw std::domain_error("signed __int128 literal too large.");
     157              :         }
     158         1408 :     }
     159              : 
     160              :     return result;
     161              : }
     162              : #pragma GCC diagnostic pop
     163              : 
     164              : 
     165              : /** \brief Convert a literal number to an __int128.
     166              :  *
     167              :  * This function converts a literal number to an __int128. For example:
     168              :  *
     169              :  * \code
     170              :  * using namespace snapdev::literals;
     171              :  *
     172              :  * __int128 value = 123_int128;
     173              :  * \endcode
     174              :  *
     175              :  * \param[in] literal  A literal number.
     176              :  *
     177              :  * \return The literal number converted to an __int128 value.
     178              :  */
     179              : #pragma GCC diagnostic push
     180              : #pragma GCC diagnostic ignored "-Wpedantic"
     181         1408 : constexpr __int128 operator ""_int128(char const * literal)
     182              : {
     183         1408 :     return operator ""_int128(literal, strlen(literal));
     184              : }
     185              : #pragma GCC diagnostic pop
     186              : 
     187              : 
     188              : /** \brief Convert a literal to an unsigned __int128.
     189              :  *
     190              :  * This function converts a literal string to an unsigned __int128 integer
     191              :  * number.
     192              :  *
     193              :  * \todo
     194              :  * Make sure that the first '\0' represents the end of the string.
     195              :  *
     196              :  * \param[in] literal  A 128 bit literal number.
     197              :  *
     198              :  * \return The unsigned __int128 number.
     199              :  *
     200              :  * \sa operator ""_int128()
     201              :  */
     202              : #pragma GCC diagnostic push
     203              : #pragma GCC diagnostic ignored "-Wpedantic"
     204          768 : constexpr unsigned __int128 operator ""_uint128(char const * literal, std::size_t len)
     205              : {
     206          768 :     unsigned __int128 result(0);
     207          768 :     unsigned __int128 base(10);
     208              : 
     209          768 :     if(len == 0)
     210              :     {
     211            0 :         throw std::invalid_argument("A string literal of a uint128 must be at least one cahracter.");
     212              :     }
     213              : 
     214          768 :     if(*literal == '0')
     215              :     {
     216            0 :         ++literal;
     217            0 :         if(*literal == '\0')
     218              :         {
     219            0 :             return result;
     220              :         }
     221            0 :         if(*literal == 'x'
     222            0 :         || *literal == 'X')
     223              :         {
     224              :             // parse a hexadecimal number
     225              :             //
     226            0 :             base = 16;
     227            0 :             ++literal;
     228            0 :             if(*literal == '\0')
     229              :             {
     230            0 :                 throw std::invalid_argument("0x must be followed by at least one hexadecimal digit.");
     231              :             }
     232              :         }
     233            0 :         else if(*literal == 'b'
     234            0 :              || *literal == 'B')
     235              :         {
     236              :             // parse a binary number
     237              :             //
     238            0 :             base = 2;
     239            0 :             ++literal;
     240            0 :             if(*literal == '\0')
     241              :             {
     242            0 :                 throw std::invalid_argument("0b must be followed by at least one binary digit.");
     243              :             }
     244              :         }
     245              :         else
     246              :         {
     247              :             // parse an octal number
     248              :             //
     249            0 :             base = 8;
     250              :         }
     251              :     }
     252              :     // else -- parse a decimal number
     253              : 
     254              :     for(;;)
     255              :     {
     256         1536 :         char const c(*literal++);
     257         1536 :         if(c == '\0')
     258              :         {
     259              :             // valid
     260              :             //
     261          768 :             return result;
     262              :         }
     263          768 :         unsigned int digit(std::numeric_limits<unsigned int>::max());
     264          768 :         if(c >= '0' && c <= '9')
     265              :         {
     266          768 :             digit = c - '0';
     267              :         }
     268            0 :         else if(c >= 'a' && c <= 'f')
     269              :         {
     270            0 :             digit = c - ('a' - 10);
     271              :         }
     272            0 :         else if(c >= 'A' && c <= 'F')
     273              :         {
     274            0 :             digit = c - ('A' - 10);
     275              :         }
     276          768 :         if(digit >= base)
     277              :         {
     278              :             throw std::domain_error(
     279            0 :                   std::string("digit '")
     280            0 :                 + c
     281            0 :                 + "' too large for the selected base");
     282              :         }
     283              : 
     284          768 :         unsigned __int128 const old(result);
     285          768 :         result = result * base + digit;
     286          768 :         if(result < old)
     287              :         {
     288              :             // overflow
     289              :             //
     290            0 :             throw std::domain_error("unsigned __int128 literal too large.");
     291              :         }
     292          768 :     }
     293              : 
     294              :     return result;
     295              : }
     296              : #pragma GCC diagnostic pop
     297              : 
     298              : 
     299              : /** \brief Convert a literal number to an unsigned __int128 value.
     300              :  *
     301              :  * This function converts a literal number to an unsigned __int128.
     302              :  * For example:
     303              :  *
     304              :  * \code
     305              :  * using namespace snapdev::literals;
     306              :  *
     307              :  * unsigned __int128 value = 123_uint128;
     308              :  * \endcode
     309              :  *
     310              :  * \param[in] literal  A literal number.
     311              :  *
     312              :  * \return The literal number converted to an unsigned __int128 value.
     313              :  */
     314              : #pragma GCC diagnostic push
     315              : #pragma GCC diagnostic ignored "-Wpedantic"
     316          768 : constexpr unsigned __int128 operator ""_uint128(char const * literal)
     317              : {
     318          768 :     return operator ""_uint128(literal, strlen(literal));
     319              : }
     320              : #pragma GCC diagnostic pop
     321              : 
     322              : 
     323              : 
     324              : } // namespace literals
     325              : } // namespace snapdev
     326              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions