LCOV - code coverage report
Current view: top level - libgnucash/engine - kvp-value.cpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 77.2 % 193 149
Test Date: 2025-02-07 16:25:45 Functions: 30.4 % 115 35
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /********************************************************************\
       2                 :             :  * kvp-value.cpp -- Implements a key-value frame system             *
       3                 :             :  * Copyright (C) 2014 Aaron Laws                                    *
       4                 :             :  *                                                                  *
       5                 :             :  * This program is free software; you can redistribute it and/or    *
       6                 :             :  * modify it under the terms of the GNU General Public License as   *
       7                 :             :  * published by the Free Software Foundation; either version 2 of   *
       8                 :             :  * the License, or (at your option) any later version.              *
       9                 :             :  *                                                                  *
      10                 :             :  * This program is distributed in the hope that it will be useful,  *
      11                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
      12                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
      13                 :             :  * GNU General Public License for more details.                     *
      14                 :             :  *                                                                  *
      15                 :             :  * You should have received a copy of the GNU General Public License*
      16                 :             :  * along with this program; if not, contact:                        *
      17                 :             :  *                                                                  *
      18                 :             :  * Free Software Foundation           Voice:  +1-617-542-5942       *
      19                 :             :  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
      20                 :             :  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
      21                 :             :  *                                                                  *
      22                 :             : \********************************************************************/
      23                 :             : 
      24                 :             : #include "kvp-value.hpp"
      25                 :             : #include "kvp-frame.hpp"
      26                 :             : #include <cmath>
      27                 :             : 
      28                 :             : #include <sstream>
      29                 :             : #include <iomanip>
      30                 :             : #include <stdexcept>
      31                 :             : 
      32                 :             : using boost::typeindex::type_id;
      33                 :             : 
      34                 :       14760 : KvpValueImpl::KvpValueImpl(KvpValueImpl const & other) noexcept
      35                 :             : {
      36                 :       14760 :     duplicate(other);
      37                 :       14760 : }
      38                 :             : 
      39                 :             : KvpValueImpl&
      40                 :           0 : KvpValueImpl::operator=(KvpValueImpl const & other) noexcept
      41                 :             : {
      42                 :           0 :     duplicate(other);
      43                 :           0 :     return *this;
      44                 :             : }
      45                 :             : 
      46                 :           0 : KvpValueImpl::KvpValueImpl(KvpValueImpl && b) noexcept
      47                 :             : {
      48                 :           0 :     datastore = b.datastore;
      49                 :           0 :     b.datastore = INT64_C(0);
      50                 :           0 : }
      51                 :             : 
      52                 :             : KvpValueImpl&
      53                 :           0 : KvpValueImpl::operator=(KvpValueImpl && b) noexcept
      54                 :             : {
      55                 :           0 :     std::swap (datastore, b.datastore);
      56                 :           0 :     return *this;
      57                 :             : }
      58                 :             : 
      59                 :             : KvpValueImpl *
      60                 :           0 : KvpValueImpl::add(KvpValueImpl * val) noexcept
      61                 :             : {
      62                 :             :     /* If already a glist here, just append */
      63                 :           0 :     if (this->datastore.type() == type_id<GList*>())
      64                 :             :     {
      65                 :           0 :         GList * list = boost::get<GList*>(datastore);
      66                 :           0 :         datastore = g_list_append (list, val);
      67                 :           0 :         return this;
      68                 :             :     }
      69                 :             :     /* If some other value, convert it to a glist */
      70                 :           0 :     GList *list = nullptr;
      71                 :             : 
      72                 :           0 :     list = g_list_append (list, this);
      73                 :           0 :     list = g_list_append (list, val);
      74                 :           0 :     return new KvpValueImpl(list);
      75                 :             : }
      76                 :             : 
      77                 :             : KvpValue::Type
      78                 :       19988 : KvpValueImpl::get_type() const noexcept
      79                 :             : {
      80                 :       19988 :     if (datastore.type() == type_id<int64_t>())
      81                 :        6230 :         return KvpValue::Type::INT64;
      82                 :       13758 :     else if (datastore.type() == type_id<double>())
      83                 :          82 :         return KvpValue::Type::DOUBLE;
      84                 :       13676 :     else if (datastore.type() == type_id<gnc_numeric>())
      85                 :        2594 :         return KvpValue::Type::NUMERIC;
      86                 :       11082 :     else if (datastore.type() == type_id<const gchar *>())
      87                 :        4172 :         return KvpValue::Type::STRING;
      88                 :        6910 :     else if (datastore.type() == type_id<GncGUID *>())
      89                 :        3387 :         return KvpValue::Type::GUID;
      90                 :        3523 :     else if (datastore.type() == type_id<Time64>())
      91                 :          96 :         return KvpValue::Type::TIME64;
      92                 :        3427 :     else if (datastore.type() == type_id<GList *>())
      93                 :        1526 :         return KvpValue::Type::GLIST;
      94                 :        1901 :     else if (datastore.type() == type_id<KvpFrameImpl *>())
      95                 :        1897 :         return KvpValue::Type::FRAME;
      96                 :           4 :     else if (datastore.type() == type_id<GDate>())
      97                 :           4 :         return KvpValue::Type::GDATE;
      98                 :             : 
      99                 :           0 :     return KvpValue::Type::INVALID;
     100                 :             : }
     101                 :             : 
     102                 :             : struct to_string_visitor : boost::static_visitor<void>
     103                 :             : {
     104                 :             :     std::ostringstream & output;
     105                 :             : 
     106                 :         207 :     to_string_visitor(std::ostringstream & val) : output(val){}
     107                 :             : 
     108                 :          69 :     void operator()(int64_t val)
     109                 :             :     {
     110                 :          69 :         output << val << " (64-bit int)";
     111                 :          69 :     }
     112                 :             : 
     113                 :           0 :     void operator()(KvpFrame* val)
     114                 :             :     {
     115                 :           0 :         output << val->to_string();
     116                 :           0 :     }
     117                 :             : 
     118                 :           0 :     void operator()(GDate val)
     119                 :             :     {
     120                 :           0 :         output << std::setw(4) << g_date_get_year(&val) << '-';
     121                 :           0 :         output << std::setw(2) << g_date_get_month(&val) << '-';
     122                 :           0 :         output << std::setw(2) << g_date_get_day(&val);
     123                 :           0 :         output << " (gdate)";
     124                 :           0 :     }
     125                 :             : 
     126                 :          26 :     void operator()(GList * val)
     127                 :             :     {
     128                 :          26 :         output << "KVP_VALUE_GLIST(";
     129                 :          26 :         output << "[ ";
     130                 :             :         /*Since val is passed by value, we can modify it*/
     131                 :         109 :         for (;val; val = val->next)
     132                 :             :         {
     133                 :          83 :             auto realvalue = static_cast<const KvpValue *>(val->data);
     134                 :          83 :             output << ' ' << realvalue->to_string() << ',';
     135                 :             :         }
     136                 :          26 :         output << " ]";
     137                 :          26 :         output << ")";
     138                 :          26 :     }
     139                 :             : 
     140                 :           0 :     void operator()(Time64 val)
     141                 :             :     {
     142                 :           0 :         char tmp1[MAX_DATE_LENGTH + 1] {};
     143                 :           0 :         gnc_time64_to_iso8601_buff (val.t, tmp1);
     144                 :           0 :         output << tmp1 << " (time64)";
     145                 :           0 :     }
     146                 :             : 
     147                 :          35 :     void operator()(gnc_numeric val)
     148                 :             :     {
     149                 :          35 :         auto tmp1 = gnc_numeric_to_string(val);
     150                 :          35 :         if (tmp1)
     151                 :             :         {
     152                 :          35 :             output << tmp1;
     153                 :          35 :             g_free(tmp1);
     154                 :             :         }
     155                 :             :         else
     156                 :             :         {
     157                 :           0 :             output << "(null)";
     158                 :             :         }
     159                 :          35 :         output << " (gnc_numeric)";
     160                 :          35 :     }
     161                 :             : 
     162                 :          31 :     void operator()(GncGUID * val)
     163                 :             :     {
     164                 :             :         char guidstr[GUID_ENCODING_LENGTH+1];
     165                 :          31 :         if (val)
     166                 :             :         {
     167                 :          31 :             guid_to_string_buff(val,guidstr);
     168                 :          31 :             output << guidstr;
     169                 :             :         }
     170                 :             :         else
     171                 :             :         {
     172                 :           0 :             output << "(null)";
     173                 :             :         }
     174                 :          31 :         output << " (guid)";
     175                 :          31 :     }
     176                 :             : 
     177                 :          44 :     void operator()(const char * val)
     178                 :             :     {
     179                 :          44 :         output << val << " (char *)";
     180                 :          44 :     }
     181                 :             : 
     182                 :           2 :     void operator()(double val)
     183                 :             :     {
     184                 :           2 :         output << val << " (double)";
     185                 :           2 :     }
     186                 :             : };
     187                 :             : 
     188                 :             : std::string
     189                 :         224 : KvpValueImpl::to_string(std::string const & prefix) const noexcept
     190                 :             : {
     191                 :         224 :     if (this->datastore.type() == type_id<KvpFrame*>())
     192                 :          17 :         return this->get<KvpFrame*>()->to_string(prefix);
     193                 :         207 :     std::ostringstream ret;
     194                 :         207 :     to_string_visitor visitor {ret};
     195                 :         207 :     boost::apply_visitor(visitor, datastore);
     196                 :             :     /*We still use g_strdup since the return value will be freed by g_free*/
     197                 :         207 :     return prefix + ret.str();
     198                 :         207 : }
     199                 :             : 
     200                 :             : std::string
     201                 :          83 : KvpValueImpl::to_string() const noexcept
     202                 :             : {
     203                 :         166 :     return to_string("");
     204                 :             : }
     205                 :             : 
     206                 :             : static int
     207                 :         509 : kvp_glist_compare(const GList * list1, const GList * list2)
     208                 :             : {
     209                 :             :     const GList *lp1;
     210                 :             :     const GList *lp2;
     211                 :             : 
     212                 :         509 :     if (list1 == list2) return 0;
     213                 :             : 
     214                 :             :     /* Nothing is always less than something */
     215                 :         509 :     if (!list1 && list2) return -1;
     216                 :         509 :     if (list1 && !list2) return 1;
     217                 :             : 
     218                 :         509 :     lp1 = list1;
     219                 :         509 :     lp2 = list2;
     220                 :        2068 :     while (lp1 && lp2)
     221                 :             :     {
     222                 :        1559 :         KvpValue *v1 = (KvpValue *) lp1->data;
     223                 :        1559 :         KvpValue *v2 = (KvpValue *) lp2->data;
     224                 :        1559 :         gint vcmp = compare(v1, v2);
     225                 :        1559 :         if (vcmp != 0) return vcmp;
     226                 :        1559 :         lp1 = lp1->next;
     227                 :        1559 :         lp2 = lp2->next;
     228                 :             :     }
     229                 :         509 :     if (!lp1 && lp2) return -1;
     230                 :         509 :     if (!lp2 && lp1) return 1;
     231                 :         509 :     return 0;
     232                 :             : }
     233                 :             : 
     234                 :             : static GList *
     235                 :        1362 : kvp_glist_copy(const GList * list)
     236                 :             : {
     237                 :        1362 :     GList * retval = NULL;
     238                 :             :     GList * lptr;
     239                 :             : 
     240                 :        1362 :     if (!list) return retval;
     241                 :             : 
     242                 :             :     /* Duplicate the backbone of the list (this duplicates the POINTERS
     243                 :             :      * to the values; we need to deep-copy the values separately) */
     244                 :        1362 :     retval = g_list_copy((GList *) list);
     245                 :             : 
     246                 :             :     /* This step deep-copies the values */
     247                 :        5463 :     for (lptr = retval; lptr; lptr = lptr->next)
     248                 :             :     {
     249                 :        4101 :         lptr->data = new KvpValue(*static_cast<KvpValue *>(lptr->data));
     250                 :             :     }
     251                 :             : 
     252                 :        1362 :     return retval;
     253                 :             : }
     254                 :             : 
     255                 :             : struct compare_visitor : boost::static_visitor<int>
     256                 :             : {
     257                 :             :     template <typename T, typename U>
     258                 :           0 :     int operator()( T& one, U& two) const
     259                 :             :     {
     260                 :           0 :         throw std::invalid_argument{"You may not compare objects of different type."};
     261                 :             :     }
     262                 :             : 
     263                 :             :     template <typename T>
     264                 :        1766 :     int operator()( T & one, T & two) const
     265                 :             :     {
     266                 :             :         /*This will work for any type that implements < and ==.*/
     267                 :        1766 :         if (one < two)
     268                 :           0 :             return -1;
     269                 :        1766 :         if (two < one)
     270                 :           0 :             return 1;
     271                 :        1766 :         return 0;
     272                 :             :     }
     273                 :             : };
     274                 :         987 : template <> int compare_visitor::operator()(const char * const & one, const char * const & two) const
     275                 :             : {
     276                 :         987 :     return strcmp(one, two);
     277                 :             : }
     278                 :         803 : template <> int compare_visitor::operator()(gnc_numeric const & one, gnc_numeric const & two) const
     279                 :             : {
     280                 :         803 :     return gnc_numeric_compare(one, two);
     281                 :             : }
     282                 :         904 : template <> int compare_visitor::operator()(GncGUID * const & one, GncGUID * const & two) const
     283                 :             : {
     284                 :         904 :     return guid_compare(one, two);
     285                 :             : }
     286                 :           1 : template <> int compare_visitor::operator()(Time64 const & one, Time64 const & two) const
     287                 :             : {
     288                 :           1 :     return one.t < two.t ? -1 : one.t > two.t ? 1 : 0;
     289                 :             : }
     290                 :           0 : template <> int compare_visitor::operator()(GDate const & one, GDate const & two) const
     291                 :             : {
     292                 :           0 :     return g_date_compare(&one,&two);
     293                 :             : }
     294                 :         509 : template <> int compare_visitor::operator()(GList * const & one, GList * const & two) const
     295                 :             : {
     296                 :         509 :     return kvp_glist_compare(one, two);
     297                 :             : }
     298                 :         539 : template <> int compare_visitor::operator()(KvpFrame * const & one, KvpFrame * const & two) const
     299                 :             : {
     300                 :         539 :     return compare(one, two);
     301                 :             : }
     302                 :          29 : template <> int compare_visitor::operator()(double const & one, double const & two) const
     303                 :             : {
     304                 :          29 :     if (std::isnan(one) && std::isnan(two))
     305                 :           0 :         return 0;
     306                 :          29 :     if (one < two) return -1;
     307                 :          29 :     if (two < one) return 1;
     308                 :          28 :     return 0;
     309                 :             : }
     310                 :             : 
     311                 :        5538 : int compare(const KvpValueImpl & one, const KvpValueImpl & two) noexcept
     312                 :             : {
     313                 :        5538 :     auto type1 = one.get_type();
     314                 :        5538 :     auto type2 = two.get_type();
     315                 :             : 
     316                 :        5538 :     if (type1 != type2)
     317                 :           0 :         return type1 < type2 ? -1 : 1;
     318                 :             : 
     319                 :             :     compare_visitor comparer;
     320                 :        5538 :     return boost::apply_visitor(comparer, one.datastore, two.datastore);
     321                 :             : }
     322                 :             : 
     323                 :             : int
     324                 :        5565 : compare(const KvpValueImpl * one, const KvpValueImpl * two) noexcept
     325                 :             : {
     326                 :        5565 :     if (one == two) return 0;
     327                 :        5538 :     if (one && !two) return 1;
     328                 :        5538 :     if (!one && two) return -1;
     329                 :        5538 :     assert (one && two);  /* Silence a static analysis warning. */
     330                 :        5538 :     return compare(*one, *two);
     331                 :             : }
     332                 :             : 
     333                 :             : struct delete_visitor : boost::static_visitor<void>
     334                 :             : {
     335                 :             :     template <typename T> void 
     336                 :       16796 :     operator()(T &) { /*do nothing*/ }
     337                 :             : };
     338                 :             : 
     339                 :             : static void
     340                 :        9162 : destroy_value(void* item)
     341                 :             : {
     342                 :        9162 :     delete static_cast<KvpValue*>(item);
     343                 :        9162 : }
     344                 :             : 
     345                 :             : template <> void
     346                 :        3046 : delete_visitor::operator()(GList * & value)
     347                 :             : {
     348                 :        3046 :     g_list_free_full(value, destroy_value);
     349                 :        3046 : }
     350                 :             : template <> void
     351                 :        5921 : delete_visitor::operator()(const gchar * & value)
     352                 :             : {
     353                 :        5921 :     g_free(const_cast<gchar *> (value));
     354                 :        5921 : }
     355                 :             : template <> void
     356                 :        5267 : delete_visitor::operator()(GncGUID * & value)
     357                 :             : {
     358                 :        5267 :     guid_free(value);
     359                 :        5267 : }
     360                 :             : template <> void
     361                 :        3028 : delete_visitor::operator()(KvpFrame * & value)
     362                 :             : {
     363                 :        3028 :     delete value;
     364                 :        3028 : }
     365                 :             : 
     366                 :       34058 : KvpValueImpl::~KvpValueImpl() noexcept
     367                 :             : {
     368                 :             :     delete_visitor d;
     369                 :       34058 :     boost::apply_visitor(d, datastore);
     370                 :       34058 : }
     371                 :             : 
     372                 :             : void
     373                 :       14760 : KvpValueImpl::duplicate(const KvpValueImpl& other) noexcept
     374                 :             : {
     375                 :       14760 :     if (other.datastore.type() == type_id<const gchar *>())
     376                 :        4970 :         this->datastore = const_cast<const gchar *>(g_strdup(other.get<const gchar *>()));
     377                 :       12275 :     else if (other.datastore.type() == type_id<GncGUID*>())
     378                 :        2401 :         this->datastore = guid_copy(other.get<GncGUID *>());
     379                 :        9874 :     else if (other.datastore.type() == type_id<GList*>())
     380                 :        1362 :         this->datastore = kvp_glist_copy(other.get<GList *>());
     381                 :        8512 :     else if (other.datastore.type() == type_id<KvpFrame*>())
     382                 :        1432 :         this->datastore = new KvpFrame(*other.get<KvpFrame *>());
     383                 :             :     else
     384                 :        7080 :         this->datastore = other.datastore;
     385                 :       14760 : }
     386                 :             : 
        

Generated by: LCOV version 2.0-1