LCOV - code coverage report
Current view: top level - libgnucash/engine - kvp-frame.cpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 90.7 % 205 186
Test Date: 2026-11-02 18:19:43 Functions: 100.0 % 21 21
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /********************************************************************
       2              :  * kvp_frame.cpp -- Implements a key-value frame system             *
       3              :  * Copyright (C) 2000 Bill Gribble                                  *
       4              :  * Copyright (C) 2001,2003 Linas Vepstas <linas@linas.org>          *
       5              :  *                                                                  *
       6              :  * This program is free software; you can redistribute it and/or    *
       7              :  * modify it under the terms of the GNU General Public License as   *
       8              :  * published by the Free Software Foundation; either version 2 of   *
       9              :  * the License, or (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, contact:                        *
      18              :  *                                                                  *
      19              :  * Free Software Foundation           Voice:  +1-617-542-5942       *
      20              :  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
      21              :  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
      22              :  *                                                                  *
      23              :  ********************************************************************/
      24              : #include <config.h>
      25              : #include "qof.h"
      26              : #include <glib.h>
      27              : #include <stdarg.h>
      28              : #include <stdio.h>
      29              : #include <string.h>
      30              : #include <cstdint>
      31              : 
      32              : #include "kvp-value.hpp"
      33              : #include "kvp-frame.hpp"
      34              : #include <typeinfo>
      35              : #include <sstream>
      36              : #include <algorithm>
      37              : #include <vector>
      38              : #include <numeric>
      39              : 
      40              : /* This static indicates the debugging module that this .o belongs to.  */
      41              : static QofLogModule log_module = "qof.kvp";
      42              : 
      43         9265 : KvpFrameImpl::KvpFrameImpl(const KvpFrameImpl & rhs) noexcept
      44              : {
      45         9265 :     std::for_each(rhs.m_valuemap.begin(), rhs.m_valuemap.end(),
      46        10751 :         [this](const map_type::value_type & a)
      47              :         {
      48        10751 :             auto key = qof_string_cache_insert(a.first);
      49        10751 :             auto val = new KvpValueImpl(*a.second);
      50        10751 :             this->m_valuemap.insert({key,val});
      51        10751 :         }
      52              :     );
      53         9265 : }
      54              : 
      55       127677 : KvpFrameImpl::~KvpFrameImpl() noexcept
      56              : {
      57       127677 :     std::for_each(m_valuemap.begin(), m_valuemap.end(),
      58        24955 :                  [](const map_type::value_type &a){
      59        24955 :                       qof_string_cache_remove(a.first);
      60        24955 :                       delete a.second;
      61        24955 :                   }
      62              :         );
      63       127677 :     m_valuemap.clear();
      64       127677 : }
      65              : 
      66              : KvpFrame *
      67       244271 : KvpFrame::get_child_frame_or_nullptr (Path const & path) noexcept
      68              : {
      69       244271 :     if (!path.size ())
      70       234057 :         return this;
      71        10214 :     auto key = path.front ();
      72        10214 :     auto map_iter = m_valuemap.find (key.c_str ());
      73        10214 :     if (map_iter == m_valuemap.end ())
      74         9061 :         return nullptr;
      75         1153 :     auto child = map_iter->second->get <KvpFrame *> ();
      76         1153 :     if (!child)
      77            6 :         return nullptr;
      78         1147 :     Path send;
      79         2294 :     std::copy (path.begin () + 1, path.end (), std::back_inserter (send));
      80         1147 :     return child->get_child_frame_or_nullptr (send);
      81        10214 : }
      82              : 
      83              : KvpFrame *
      84        20883 : KvpFrame::get_child_frame_or_create (Path const & path) noexcept
      85              : {
      86        20883 :     if (!path.size ())
      87        20152 :         return this;
      88          731 :     auto key = path.front ();
      89          731 :     auto spot = m_valuemap.find (key.c_str ());
      90          731 :     if (spot == m_valuemap.end () || spot->second->get_type () != KvpValue::Type::FRAME)
      91         1173 :         delete set_impl (key.c_str (), new KvpValue {new KvpFrame});
      92          731 :     Path send;
      93         1462 :     std::copy (path.begin () + 1, path.end (), std::back_inserter (send));
      94          731 :     auto child_val = m_valuemap.at (key.c_str ());
      95          731 :     auto child = child_val->get <KvpFrame *> ();
      96          731 :     return child->get_child_frame_or_create (send);
      97          731 : }
      98              : 
      99              : 
     100              : KvpValue *
     101        23840 : KvpFrame::set_impl (std::string const & key, KvpValue * value) noexcept
     102              : {
     103        23840 :     KvpValue * ret {};
     104        23840 :     auto spot = m_valuemap.find (key.c_str ());
     105        23840 :     if (spot != m_valuemap.end ())
     106              :     {
     107          274 :         qof_string_cache_remove (spot->first);
     108          274 :         ret = spot->second;
     109          274 :         m_valuemap.erase (spot);
     110              :     }
     111        23840 :     if (value)
     112              :     {
     113        20122 :         auto cachedkey = static_cast <char const *> (qof_string_cache_insert (key.c_str ()));
     114        20122 :         m_valuemap.emplace (cachedkey, value);
     115              :     }
     116        23840 :     return ret;
     117              : }
     118              : 
     119              : KvpValue *
     120         3304 : KvpFrameImpl::set (Path path, KvpValue* value) noexcept
     121              : {
     122         3304 :     if (path.empty())
     123            0 :         return nullptr;
     124         3304 :     auto key = path.back ();
     125         3304 :     path.pop_back ();
     126         3304 :     auto target = get_child_frame_or_nullptr (path);
     127         3304 :     if (!target)
     128            7 :         return nullptr;
     129         3297 :     return target->set_impl (key, value);
     130         3304 : }
     131              : 
     132              : KvpValue *
     133        20152 : KvpFrameImpl::set_path (Path path, KvpValue* value) noexcept
     134              : {
     135        20152 :     auto key = path.back();
     136        20152 :     path.pop_back();
     137        20152 :     auto target = get_child_frame_or_create (path);
     138        20152 :     if (!target)
     139            0 :         return nullptr;
     140        20152 :     return target->set_impl (key, value);
     141        20152 : }
     142              : 
     143              : KvpValue *
     144       239820 : KvpFrameImpl::get_slot (Path path) noexcept
     145              : {
     146       239820 :     auto key = path.back();
     147       239820 :     path.pop_back();
     148       239820 :     auto target = get_child_frame_or_nullptr (path);
     149       239820 :     if (!target)
     150         9060 :         return nullptr;
     151       230760 :     auto spot = target->m_valuemap.find (key.c_str ());
     152       230760 :     if (spot != target->m_valuemap.end ())
     153         2807 :         return spot->second;
     154       227953 :     return nullptr;
     155       239820 : }
     156              : 
     157              : std::string
     158           22 : KvpFrameImpl::to_string() const noexcept
     159              : {
     160           44 :     return to_string("");
     161              : }
     162              : 
     163              : std::string
     164           39 : KvpFrameImpl::to_string(std::string const & prefix) const noexcept
     165              : {
     166           39 :     if (!m_valuemap.size())
     167            0 :         return prefix;
     168           39 :     std::ostringstream ret;
     169           39 :     std::for_each(m_valuemap.begin(), m_valuemap.end(),
     170          141 :         [&ret,&prefix](const map_type::value_type &a)
     171              :         {
     172          141 :             std::string new_prefix {prefix};
     173          141 :             if (a.first)
     174              :             {
     175          141 :                 new_prefix += a.first;
     176          141 :                 new_prefix += "/";
     177              :             }
     178          141 :             if (a.second)
     179          141 :                 ret << a.second->to_string(new_prefix) << "\n";
     180              :             else
     181            0 :                 ret << new_prefix << "(null)\n";
     182          141 :         }
     183              :     );
     184           39 :     return ret.str();
     185           39 : }
     186              : 
     187              : std::vector<std::string>
     188           16 : KvpFrameImpl::get_keys() const noexcept
     189              : {
     190           16 :     std::vector<std::string> ret;
     191           16 :     ret.reserve (m_valuemap.size());
     192           16 :     std::for_each(m_valuemap.begin(), m_valuemap.end(),
     193           11 :         [&ret](const KvpFrameImpl::map_type::value_type &a)
     194              :         {
     195           22 :             ret.push_back(a.first);
     196           11 :         }
     197              :     );
     198           16 :     return ret;
     199              : }
     200              : 
     201         1117 : int compare(const KvpFrameImpl * one, const KvpFrameImpl * two) noexcept
     202              : {
     203         1117 :     if (one && !two) return 1;
     204         1117 :     if (!one && two) return -1;
     205         1117 :     if (!one && !two) return 0;
     206         1117 :     return compare(*one, *two);
     207              : }
     208              : 
     209              : /**
     210              :  * If the first KvpFrameImpl has an item that the second does not, 1 is returned.
     211              :  * The first item within the two KvpFrameImpl that is not similar, that comparison is returned.
     212              :  * If all the items within the first KvpFrameImpl match items within the second, but the
     213              :  *   second has more elements, -1 is returned.
     214              :  * Otherwise, 0 is returned.
     215              :  */
     216         1117 : int compare(const KvpFrameImpl & one, const KvpFrameImpl & two) noexcept
     217              : {
     218         5080 :     for (const auto & a : one.m_valuemap)
     219              :     {
     220         3966 :         auto otherspot = two.m_valuemap.find(a.first);
     221         3966 :         if (otherspot == two.m_valuemap.end())
     222              :         {
     223            0 :             return 1;
     224              :         }
     225         3966 :         auto comparison = compare(a.second,otherspot->second);
     226              : 
     227         3966 :         if (comparison != 0)
     228            3 :             return comparison;
     229              :     }
     230              : 
     231         1114 :     if (one.m_valuemap.size() < two.m_valuemap.size())
     232            0 :         return -1;
     233         1114 :     return 0;
     234              : }
     235              : 
     236              : void
     237        11517 : gvalue_from_kvp_value (const KvpValue *kval, GValue* val)
     238              : {
     239        11517 :     if (kval == NULL) return;
     240         1022 :     g_value_unset(val);
     241              : 
     242         1022 :     switch (kval->get_type())
     243              :     {
     244          454 :         case KvpValue::Type::INT64:
     245          454 :             g_value_init (val, G_TYPE_INT64);
     246          454 :             g_value_set_int64 (val, kval->get<int64_t>());
     247          454 :             break;
     248            3 :         case KvpValue::Type::DOUBLE:
     249            3 :             g_value_init (val, G_TYPE_DOUBLE);
     250            3 :             g_value_set_double (val, kval->get<double>());
     251            3 :             break;
     252           21 :         case KvpValue::Type::NUMERIC:
     253           21 :             g_value_init (val, GNC_TYPE_NUMERIC);
     254           21 :             g_value_set_static_boxed (val, kval->get_ptr<gnc_numeric>());
     255           21 :             break;
     256          125 :         case KvpValue::Type::STRING:
     257          125 :             g_value_init (val, G_TYPE_STRING);
     258          125 :             g_value_set_static_string (val, kval->get<const char*>());
     259          125 :             break;
     260          416 :         case KvpValue::Type::GUID:
     261          416 :             g_value_init (val, GNC_TYPE_GUID);
     262          416 :             g_value_set_static_boxed (val, kval->get<GncGUID*>());
     263          416 :             break;
     264            3 :         case KvpValue::Type::TIME64:
     265            3 :             g_value_init (val, GNC_TYPE_TIME64);
     266            3 :             g_value_set_boxed (val, kval->get_ptr<Time64>());
     267            3 :             break;
     268            0 :         case KvpValue::Type::GDATE:
     269            0 :             g_value_init (val, G_TYPE_DATE);
     270            0 :             g_value_set_static_boxed (val, kval->get_ptr<GDate>());
     271            0 :             break;
     272            0 :         default:
     273              : /* No transfer outside of QofInstance-derived classes! */
     274            0 :             PWARN ("Error! Invalid attempt to transfer Kvp type %d", kval->get_type());
     275            0 :             break;
     276              :     }
     277              : }
     278              : 
     279              : KvpValue*
     280         2327 : kvp_value_from_gvalue (const GValue *gval)
     281              : {
     282         2327 :     KvpValue *val = NULL;
     283              :     GType type;
     284         2327 :     if (gval == NULL)
     285         1825 :         return NULL;
     286          502 :     type = G_VALUE_TYPE (gval);
     287          502 :     g_return_val_if_fail (G_VALUE_TYPE (gval), NULL);
     288              : 
     289          502 :     if (type == G_TYPE_INT64)
     290          101 :         val = new KvpValue(g_value_get_int64 (gval));
     291          401 :     else if (type == G_TYPE_DOUBLE)
     292            3 :         val = new KvpValue(g_value_get_double (gval));
     293          398 :     else if (type == G_TYPE_BOOLEAN)
     294              :     {
     295            0 :         auto bval = g_value_get_boolean(gval);
     296            0 :         if (bval)
     297            0 :             val = new KvpValue(g_strdup("true"));
     298              :     }
     299          398 :     else if (type == GNC_TYPE_NUMERIC)
     300           23 :         val = new KvpValue(*(gnc_numeric*)g_value_get_boxed (gval));
     301          375 :     else if (type == G_TYPE_STRING)
     302              :     {
     303          143 :         auto string = g_value_get_string(gval);
     304          143 :         if (string != nullptr)
     305          242 :             val = new KvpValue(g_strdup(string));
     306              :     }
     307          232 :     else if (type == GNC_TYPE_GUID)
     308              :     {
     309          230 :         auto boxed = g_value_get_boxed(gval);
     310          230 :         if (boxed != nullptr)
     311          222 :             val = new KvpValue(guid_copy(static_cast<GncGUID*>(boxed)));
     312              :     }
     313            2 :     else if (type == GNC_TYPE_TIME64)
     314            2 :         val = new KvpValue(*(Time64*)g_value_get_boxed (gval));
     315            0 :     else if (type == G_TYPE_DATE)
     316            0 :         val = new KvpValue(*(GDate*)g_value_get_boxed (gval));
     317              :     else
     318            0 :         PWARN ("Error! Don't know how to make a KvpValue from a %s",
     319              :                G_VALUE_TYPE_NAME (gval));
     320              : 
     321          502 :     return val;
     322              : }
     323              : 
     324              : void
     325            8 : KvpFrame::flatten_kvp_impl(std::vector <std::string> path, std::vector <KvpEntry> & entries) const noexcept
     326              : {
     327           22 :     for (auto const & entry : m_valuemap)
     328              :     {
     329           14 :         std::vector<std::string> new_path {path};
     330           14 :         new_path.push_back("/");
     331           14 :         if (entry.second->get_type() == KvpValue::Type::FRAME)
     332              :         {
     333            7 :             new_path.push_back(entry.first);
     334            7 :             entry.second->get<KvpFrame*>()->flatten_kvp_impl(new_path, entries);
     335              :         }
     336              :         else
     337              :         {
     338            7 :             new_path.emplace_back (entry.first);
     339            7 :             entries.emplace_back (new_path, entry.second);
     340              :         }
     341           14 :     }
     342            8 : }
     343              : 
     344              : std::vector <KvpEntry>
     345            1 : KvpFrame::flatten_kvp(void) const noexcept
     346              : {
     347            1 :     std::vector <KvpEntry> ret;
     348            1 :     flatten_kvp_impl({}, ret);
     349            1 :     return ret;
     350              : }
        

Generated by: LCOV version 2.0-1