LCOV - code coverage report
Current view: top level - versiontheca - decimal.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 33 33 100.0 %
Date: 2023-01-24 22:36:19 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2023  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/versiontheca
       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             : 
      19             : /** \file
      20             :  * \brief Parse and compare decimal based versions.
      21             :  *
      22             :  * A decimal based version is a version which is formed with two numbers
      23             :  * separated by a decimal period (.) character. It can then be retrieved
      24             :  * as a floating point number.
      25             :  *
      26             :  * \note
      27             :  * It is possible that the result will not be exactly correct when retrieved
      28             :  * as a floating point. Internally, though, the version is kept as two
      29             :  * separate integers which are always perfectly defined.
      30             :  */
      31             : 
      32             : // self
      33             : //
      34             : #include    <versiontheca/decimal.h>
      35             : 
      36             : 
      37             : 
      38             : // C++
      39             : //
      40             : #include    <cmath>
      41             : #include    <iomanip>
      42             : #include    <iostream>
      43             : #include    <sstream>
      44             : 
      45             : 
      46             : // last include
      47             : //
      48             : #include    <snapdev/poison.h>
      49             : 
      50             : 
      51             : 
      52             : namespace versiontheca
      53             : {
      54             : 
      55             : 
      56             : 
      57       10039 : bool decimal::parse(std::string const & v)
      58             : {
      59       10039 :     if(!trait::parse(v))
      60             :     {
      61          22 :         return false;
      62             :     }
      63             : 
      64             :     // decimal version must be:
      65             :     //
      66             :     // 1. one or two parts
      67             :     // 2. separated by a period
      68             :     // 3. integers
      69             :     //
      70             :     // note: since we limit characters to only digits, clearly the parts
      71             :     //       should already be integers or an error occurred earlier
      72             :     //
      73       15033 :     return (size() == 1 || size() == 2)
      74       10015 :         && at(0).is_integer()
      75       30047 :         && (size() == 1
      76       15031 :             || (at(1).get_separator() == '.' && at(1).is_integer()));
      77             : }
      78             : 
      79             : 
      80          21 : bool decimal::is_valid_character(char32_t c) const
      81             : {
      82          21 :     return c >= '0' && c <= '9';
      83             : }
      84             : 
      85             : 
      86       10030 : std::string decimal::to_string() const
      87             : {
      88             :     // ignore all .0 at the end except for the minor version
      89             :     // (i.e. "1.0" keep that zero)
      90             :     //
      91       10030 :     if(empty())
      92             :     {
      93           3 :         f_last_error = "no parts to output.";
      94           3 :         return std::string();
      95             :     }
      96             : 
      97             : 
      98       10027 :     part_integer_t fraction(0);
      99       10027 :     int width(1);
     100       10027 :     if(size() == 2)
     101             :     {
     102        5025 :         fraction = at(1).get_integer();
     103        5025 :         width = std::max(static_cast<std::uint8_t>(1), at(1).get_width());
     104             :     }
     105             : 
     106       20054 :     std::stringstream ss;
     107       10027 :     ss << at(0).get_integer()
     108             :        << '.'
     109             :        << std::setfill('0')
     110       10027 :        << std::setw(width)
     111       10027 :        << fraction;
     112             : 
     113       10027 :     return ss.str();
     114             : }
     115             : 
     116             : 
     117             : /** \brief Get the version as a floating point.
     118             :  *
     119             :  * This function converts the version of one or two parts in a floating
     120             :  * pointer number.
     121             :  *
     122             :  * If the version is considered invalid, this function returns a NaN.
     123             :  * You can verify such using the std::isnan() function.
     124             :  *
     125             :  * \note
     126             :  * Keep in mind that decimal numbers are not always properly represented
     127             :  * by floating point numbers. In most cases, for numbers with 2 or 3 digits
     128             :  * after the decimal point, it is likely to work as expected. Just don't
     129             :  * use the `==` to compare such numbers. Instead, look at our nearly_equal()
     130             :  * template function in snapcatch2/snapcatch2.hpp for an example of properly
     131             :  * comparing two floating point numbers of any precision.
     132             :  *
     133             :  * \return The version as a floating point double.
     134             :  */
     135       10017 : double decimal::get_decimal_version() const
     136             : {
     137       10017 :     if(size() > 0)
     138             :     {
     139       10015 :         double version(at(0).get_integer());
     140       10015 :         if(size() == 2)
     141             :         {
     142        5014 :             double const width(at(1).get_width());
     143        5014 :             double const fraction(at(1).get_integer());
     144             :             //double digits(1 + significant_zeroes);
     145             :             //if(fraction > 0)
     146             :             //{
     147             :             //    digits += static_cast<int>(log(fraction));
     148             :             //}
     149        5014 :             version += fraction * pow(10, -width);
     150             :         }
     151       10015 :         return version;
     152             :     }
     153             : 
     154           2 :     return std::numeric_limits<double>::quiet_NaN();
     155             : }
     156             : 
     157             : 
     158             : 
     159           6 : }
     160             : // namespace versiontheca
     161             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13