LCOV - code coverage report
Current view: top level - snapdev - ostream_int128.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 64 70 91.4 %
Date: 2023-05-29 16:11:08 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2021-2023  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 Print large integers to any iostream.
      22             :  *
      23             :  * This function prints large integers (128 bits) to the specified iostream.
      24             :  */
      25             : 
      26             : // C++
      27             : //
      28             : #include    <ostream>
      29             : #include    <sstream>
      30             : 
      31             : 
      32             : namespace snapdev
      33             : {
      34             : 
      35             : /** \brief Convert an __int128 to a string.
      36             :  *
      37             :  * This function converts an __int128 to a string.
      38             :  *
      39             :  * \param[in] x  An __int128 number.
      40             :  *
      41             :  * \return A string representing that __int128 number.
      42             :  */
      43             : #pragma GCC diagnostic push
      44             : #pragma GCC diagnostic ignored "-Wpedantic"
      45        2043 : inline std::string to_string(__int128 x, __int128 base = 10, bool uppercase = false)
      46             : {
      47        2043 :     char buf[129];  // binary requires 128 + '-' = 129 chars
      48             : 
      49        2043 :     char const adjust((uppercase ? 'A' : 'a') - ('9' + 1));
      50             : 
      51        2043 :     int idx(sizeof(buf));
      52        2043 :     unsigned __int128 y(x < 0
      53        2043 :         ? -static_cast<unsigned __int128>(x)
      54             :         : static_cast<unsigned __int128>(x));
      55       19066 :     while(y >= static_cast<unsigned __int128>(base))
      56             :     {
      57       17023 :         --idx;
      58       17023 :         buf[idx] = y % base + '0';
      59       17023 :         if(buf[idx] > '9')
      60             :         {
      61           0 :             buf[idx] += adjust;
      62             :         }
      63       17023 :         y /= base;
      64             :     }
      65        2043 :     --idx;
      66        2043 :     buf[idx] = y + '0';
      67        2043 :     if(buf[idx] > '9')
      68             :     {
      69           0 :         buf[idx] += adjust;
      70             :     }
      71        2043 :     if(x < 0)
      72             :     {
      73        1021 :         --idx;
      74        1021 :         buf[idx] = '-';
      75             :     }
      76             : 
      77        4086 :     return std::string(buf + idx, sizeof(buf) - idx);
      78             : }
      79             : #pragma GCC diagnostic pop
      80             : 
      81             : 
      82             : /** \brief Convert an unsigned __int128 to a string.
      83             :  *
      84             :  * This function converts an unsigned __int128 to a string.
      85             :  *
      86             :  * \param[in] x  An unsigned __int128 number.
      87             :  *
      88             :  * \return A string representing that unsigned __int128 number.
      89             :  */
      90             : #pragma GCC diagnostic push
      91             : #pragma GCC diagnostic ignored "-Wpedantic"
      92         174 : inline std::string to_string(unsigned __int128 x, unsigned __int128 base = 10, bool uppercase = false)
      93             : {
      94         174 :     char buf[128];  // binary requires 128 chars
      95             : 
      96         174 :     char const adjust((uppercase ? 'A' : 'a') - ('9' + 1));
      97             : 
      98         174 :     int idx(sizeof(buf));
      99        3186 :     while(x >= base)
     100             :     {
     101        3012 :         --idx;
     102        3012 :         buf[idx] = x % base + '0';
     103        3012 :         if(buf[idx] > '9')
     104             :         {
     105        1654 :             buf[idx] += adjust;
     106             :         }
     107        3012 :         x /= base;
     108             :     }
     109         174 :     --idx;
     110         174 :     buf[idx] = x + '0';
     111         174 :     if(buf[idx] > '9')
     112             :     {
     113          59 :         buf[idx] += adjust;
     114             :     }
     115             : 
     116         348 :     return std::string(buf + idx, sizeof(buf) - idx);
     117             : }
     118             : #pragma GCC diagnostic pop
     119             : 
     120             : } //namespace snap
     121             : 
     122             : 
     123             : // no namespace for operators, it's easier that way
     124             : 
     125             : 
     126             : /** \brief Output an __int128 number.
     127             :  *
     128             :  * This function outputs the specified __int128 number to this output
     129             :  * stream. It respects the base and for hexadecimal, it also respects
     130             :  * the uppercase format.
     131             :  *
     132             :  * \note
     133             :  * The hexadecimal and octal formats do not understand negative numbers.
     134             :  * This function respects the C++ definition and prints out unsigned
     135             :  * numbers when one of the std::hex or std::oct format are set. If you
     136             :  * would prefer a negative number (i.e. -0x1 instead of 0xfff...fff)
     137             :  * then make sure to directly call the snapdev::to_string() function
     138             :  * instead.
     139             :  *
     140             :  * \warning
     141             :  * This implementation does not offer proper formatting.
     142             :  * It will first generate a string then output that string
     143             :  * which means the result is not what you'd expect if you
     144             :  * used formatting such as std::setfill() and std::setw().
     145             :  *
     146             :  * \param[in] os  The output stream.
     147             :  * \param[in] x  The value to be output in \p os.
     148             :  *
     149             :  * \return A reference to \p os.
     150             :  */
     151             : #pragma GCC diagnostic push
     152             : #pragma GCC diagnostic ignored "-Wpedantic"
     153        2212 : inline std::ostream & operator << (std::ostream & os, __int128 x)
     154             : {
     155        2212 :     std::ios_base::fmtflags const fmt(os.flags() & std::ios_base::basefield);
     156             : 
     157        2212 :     if(fmt == std::ios_base::oct)
     158             :     {
     159          63 :         if(x != 0
     160          63 :         && (os.flags() & std::ios_base::showbase) != 0)
     161             :         {
     162          40 :             os << '0';
     163             :         }
     164          63 :         return os << snapdev::to_string(static_cast<unsigned __int128>(x), 8);
     165             :     }
     166             : 
     167        2149 :     if(fmt == std::ios_base::hex)
     168             :     {
     169         106 :         bool const uppercase(os.flags() & std::ios_base::uppercase);
     170         106 :         if(x != 0
     171         106 :         && (os.flags() & std::ios_base::showbase) != 0)
     172             :         {
     173          40 :             if(uppercase)
     174             :             {
     175          20 :                 os << "0X";
     176             :             }
     177             :             else
     178             :             {
     179          20 :                 os << "0x";
     180             :             }
     181             :         }
     182         106 :         return os << snapdev::to_string(static_cast<unsigned __int128>(x), 16, uppercase);
     183             :     }
     184             : 
     185             :     // the '-' is added by the to_string(), but not the '+'
     186             :     //
     187        2043 :     if(x >= 0
     188        2043 :     && (os.flags() & std::ios_base::showpos) != 0)
     189             :     {
     190          11 :         os << '+';
     191             :     }
     192             : 
     193        2043 :     return os << snapdev::to_string(x);
     194             : }
     195             : #pragma GCC diagnostic pop
     196             : 
     197             : 
     198             : /** \brief Output an unsigned __int128 number.
     199             :  *
     200             :  * This function outputs the specified __int128 number to this output
     201             :  * stream. It respects the base and for hexadecimal, it also respects
     202             :  * the uppercase format.
     203             :  *
     204             :  * \warning
     205             :  * This implementation does not offer proper formatting.
     206             :  * It will first generate a string then output that string
     207             :  * which means the result is not what you'd expect if you
     208             :  * used formatting such as std::setfill() and std::setw().
     209             :  *
     210             :  * \param[in] os  The output stream.
     211             :  * \param[in] x  The value to be output in \p os.
     212             :  *
     213             :  * \return A reference to \p os.
     214             :  */
     215             : #pragma GCC diagnostic push
     216             : #pragma GCC diagnostic ignored "-Wpedantic"
     217           5 : inline std::ostream & operator << (std::ostream & os, unsigned __int128 x)
     218             : {
     219           5 :     std::ios_base::fmtflags const fmt(os.flags() & std::ios_base::basefield);
     220             : 
     221           5 :     if(fmt == std::ios_base::oct)
     222             :     {
     223           0 :         if(x != 0
     224           0 :         && (os.flags() & std::ios_base::showbase) != 0)
     225             :         {
     226           0 :             os << '0';
     227             :         }
     228           0 :         return os << snapdev::to_string(x, 8);
     229             :     }
     230             : 
     231           5 :     if(fmt == std::ios_base::hex)
     232             :     {
     233           4 :         bool const uppercase((os.flags() & std::ios_base::uppercase) != 0);
     234           4 :         if(x != 0
     235           4 :         && (os.flags() & std::ios_base::showbase) != 0)
     236             :         {
     237           2 :             if(uppercase)
     238             :             {
     239           1 :                 os << "0X";
     240             :             }
     241             :             else
     242             :             {
     243           1 :                 os << "0x";
     244             :             }
     245             :         }
     246           4 :         return os << snapdev::to_string(x, 16, uppercase);
     247             :     }
     248             : 
     249             :     // unsigned do not show the '+' sign at all
     250             :     //
     251           1 :     return os << snapdev::to_string(x, 10);
     252             : }
     253             : #pragma GCC diagnostic pop
     254             : 
     255             : 
     256             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.14