GnuCash c935c2f+
Loading...
Searching...
No Matches
kvp-frame.cpp
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. */
41static QofLogModule log_module = "qof.kvp";
42
43KvpFrameImpl::KvpFrameImpl(const KvpFrameImpl & rhs) noexcept
44{
45 std::for_each(rhs.m_valuemap.begin(), rhs.m_valuemap.end(),
46 [this](const map_type::value_type & a)
47 {
48 auto key = qof_string_cache_insert(a.first);
49 auto val = new KvpValueImpl(*a.second);
50 this->m_valuemap.insert({key,val});
51 }
52 );
53}
54
56{
57 std::for_each(m_valuemap.begin(), m_valuemap.end(),
58 [](const map_type::value_type &a){
59 qof_string_cache_remove(a.first);
60 delete a.second;
61 }
62 );
63 m_valuemap.clear();
64}
65
66KvpFrame *
67KvpFrame::get_child_frame_or_nullptr (Path const & path) noexcept
68{
69 if (!path.size ())
70 return this;
71 auto key = path.front ();
72 auto map_iter = m_valuemap.find (key.c_str ());
73 if (map_iter == m_valuemap.end ())
74 return nullptr;
75 auto child = map_iter->second->get <KvpFrame *> ();
76 if (!child)
77 return nullptr;
78 Path send;
79 std::copy (path.begin () + 1, path.end (), std::back_inserter (send));
80 return child->get_child_frame_or_nullptr (send);
81}
82
83KvpFrame *
84KvpFrame::get_child_frame_or_create (Path const & path) noexcept
85{
86 if (!path.size ())
87 return this;
88 auto key = path.front ();
89 auto spot = m_valuemap.find (key.c_str ());
90 if (spot == m_valuemap.end () || spot->second->get_type () != KvpValue::Type::FRAME)
91 delete set_impl (key.c_str (), new KvpValue {new KvpFrame});
92 Path send;
93 std::copy (path.begin () + 1, path.end (), std::back_inserter (send));
94 auto child_val = m_valuemap.at (key.c_str ());
95 auto child = child_val->get <KvpFrame *> ();
96 return child->get_child_frame_or_create (send);
97}
98
99
100KvpValue *
101KvpFrame::set_impl (std::string const & key, KvpValue * value) noexcept
102{
103 KvpValue * ret {};
104 auto spot = m_valuemap.find (key.c_str ());
105 if (spot != m_valuemap.end ())
106 {
107 qof_string_cache_remove (spot->first);
108 ret = spot->second;
109 m_valuemap.erase (spot);
110 }
111 if (value)
112 {
113 auto cachedkey = static_cast <char const *> (qof_string_cache_insert (key.c_str ()));
114 m_valuemap.emplace (cachedkey, value);
115 }
116 return ret;
117}
118
119KvpValue *
120KvpFrameImpl::set (Path path, KvpValue* value) noexcept
121{
122 if (path.empty())
123 return nullptr;
124 auto key = path.back ();
125 path.pop_back ();
126 auto target = get_child_frame_or_nullptr (path);
127 if (!target)
128 return nullptr;
129 return target->set_impl (key, value);
130}
131
132KvpValue *
133KvpFrameImpl::set_path (Path path, KvpValue* value) noexcept
134{
135 auto key = path.back();
136 path.pop_back();
137 auto target = get_child_frame_or_create (path);
138 if (!target)
139 return nullptr;
140 return target->set_impl (key, value);
141}
142
143KvpValue *
144KvpFrameImpl::get_slot (Path path) noexcept
145{
146 auto key = path.back();
147 path.pop_back();
148 auto target = get_child_frame_or_nullptr (path);
149 if (!target)
150 return nullptr;
151 auto spot = target->m_valuemap.find (key.c_str ());
152 if (spot != target->m_valuemap.end ())
153 return spot->second;
154 return nullptr;
155}
156
157std::string
159{
160 return to_string("");
161}
162
163std::string
164KvpFrameImpl::to_string(std::string const & prefix) const noexcept
165{
166 if (!m_valuemap.size())
167 return prefix;
168 std::ostringstream ret;
169 std::for_each(m_valuemap.begin(), m_valuemap.end(),
170 [&ret,&prefix](const map_type::value_type &a)
171 {
172 std::string new_prefix {prefix};
173 if (a.first)
174 {
175 new_prefix += a.first;
176 new_prefix += "/";
177 }
178 if (a.second)
179 ret << a.second->to_string(new_prefix) << "\n";
180 else
181 ret << new_prefix << "(null)\n";
182 }
183 );
184 return ret.str();
185}
186
187std::vector<std::string>
189{
190 std::vector<std::string> ret;
191 ret.reserve (m_valuemap.size());
192 std::for_each(m_valuemap.begin(), m_valuemap.end(),
193 [&ret](const KvpFrameImpl::map_type::value_type &a)
194 {
195 ret.push_back(a.first);
196 }
197 );
198 return ret;
199}
200
201int compare(const KvpFrameImpl * one, const KvpFrameImpl * two) noexcept
202{
203 if (one && !two) return 1;
204 if (!one && two) return -1;
205 if (!one && !two) return 0;
206 return compare(*one, *two);
207}
208
216int compare(const KvpFrameImpl & one, const KvpFrameImpl & two) noexcept
217{
218 for (const auto & a : one.m_valuemap)
219 {
220 auto otherspot = two.m_valuemap.find(a.first);
221 if (otherspot == two.m_valuemap.end())
222 {
223 return 1;
224 }
225 auto comparison = compare(a.second,otherspot->second);
226
227 if (comparison != 0)
228 return comparison;
229 }
230
231 if (one.m_valuemap.size() < two.m_valuemap.size())
232 return -1;
233 return 0;
234}
235
236void
237gvalue_from_kvp_value (const KvpValue *kval, GValue* val)
238{
239 if (kval == NULL) return;
240 g_value_unset(val);
241
242 switch (kval->get_type())
243 {
244 case KvpValue::Type::INT64:
245 g_value_init (val, G_TYPE_INT64);
246 g_value_set_int64 (val, kval->get<int64_t>());
247 break;
248 case KvpValue::Type::DOUBLE:
249 g_value_init (val, G_TYPE_DOUBLE);
250 g_value_set_double (val, kval->get<double>());
251 break;
252 case KvpValue::Type::NUMERIC:
253 g_value_init (val, GNC_TYPE_NUMERIC);
254 g_value_set_static_boxed (val, kval->get_ptr<gnc_numeric>());
255 break;
256 case KvpValue::Type::STRING:
257 g_value_init (val, G_TYPE_STRING);
258 g_value_set_static_string (val, kval->get<const char*>());
259 break;
260 case KvpValue::Type::GUID:
261 g_value_init (val, GNC_TYPE_GUID);
262 g_value_set_static_boxed (val, kval->get<GncGUID*>());
263 break;
264 case KvpValue::Type::TIME64:
265 g_value_init (val, GNC_TYPE_TIME64);
266 g_value_set_boxed (val, kval->get_ptr<Time64>());
267 break;
268 case KvpValue::Type::GDATE:
269 g_value_init (val, G_TYPE_DATE);
270 g_value_set_static_boxed (val, kval->get_ptr<GDate>());
271 break;
272 default:
273/* No transfer outside of QofInstance-derived classes! */
274 PWARN ("Error! Invalid attempt to transfer Kvp type %d", kval->get_type());
275 break;
276 }
277}
278
279KvpValue*
280kvp_value_from_gvalue (const GValue *gval)
281{
282 KvpValue *val = NULL;
283 GType type;
284 if (gval == NULL)
285 return NULL;
286 type = G_VALUE_TYPE (gval);
287 g_return_val_if_fail (G_VALUE_TYPE (gval), NULL);
288
289 if (type == G_TYPE_INT64)
290 val = new KvpValue(g_value_get_int64 (gval));
291 else if (type == G_TYPE_DOUBLE)
292 val = new KvpValue(g_value_get_double (gval));
293 else if (type == G_TYPE_BOOLEAN)
294 {
295 auto bval = g_value_get_boolean(gval);
296 if (bval)
297 val = new KvpValue(g_strdup("true"));
298 }
299 else if (type == GNC_TYPE_NUMERIC)
300 val = new KvpValue(*(gnc_numeric*)g_value_get_boxed (gval));
301 else if (type == G_TYPE_STRING)
302 {
303 auto string = g_value_get_string(gval);
304 if (string != nullptr)
305 val = new KvpValue(g_strdup(string));
306 }
307 else if (type == GNC_TYPE_GUID)
308 {
309 auto boxed = g_value_get_boxed(gval);
310 if (boxed != nullptr)
311 val = new KvpValue(guid_copy(static_cast<GncGUID*>(boxed)));
312 }
313 else if (type == GNC_TYPE_TIME64)
314 val = new KvpValue(*(Time64*)g_value_get_boxed (gval));
315 else if (type == G_TYPE_DATE)
316 val = new KvpValue(*(GDate*)g_value_get_boxed (gval));
317 else
318 PWARN ("Error! Don't know how to make a KvpValue from a %s",
319 G_VALUE_TYPE_NAME (gval));
320
321 return val;
322}
323
324void
325KvpFrame::flatten_kvp_impl(std::vector <std::string> path, std::vector <KvpEntry> & entries) const noexcept
326{
327 for (auto const & entry : m_valuemap)
328 {
329 std::vector<std::string> new_path {path};
330 new_path.push_back("/");
331 if (entry.second->get_type() == KvpValue::Type::FRAME)
332 {
333 new_path.push_back(entry.first);
334 entry.second->get<KvpFrame*>()->flatten_kvp_impl(new_path, entries);
335 }
336 else
337 {
338 new_path.emplace_back (entry.first);
339 entries.emplace_back (new_path, entry.second);
340 }
341 }
342}
343
344std::vector <KvpEntry>
345KvpFrame::flatten_kvp(void) const noexcept
346{
347 std::vector <KvpEntry> ret;
348 flatten_kvp_impl({}, ret);
349 return ret;
350}
GncGUID * guid_copy(const GncGUID *guid)
Returns a newly allocated GncGUID that matches the passed-in GUID.
Definition guid.cpp:155
std::vector< std::string > get_keys() const noexcept
Report the keys in the immediate frame.
~KvpFrameImpl() noexcept
Perform a deep delete.
Definition kvp-frame.cpp:55
std::string to_string() const noexcept
Make a string representation of the frame.
KvpValue * set(Path path, KvpValue *newvalue) noexcept
Set the value with the key in the immediate frame, replacing and returning the old value if it exists...
void gvalue_from_kvp_value(const KvpValue *kval, GValue *val)
Convert a kvp_value into a GValue.
KvpValue * get_slot(Path keys) noexcept
Get the value for the tail of the path or nullptr if it doesn't exist.
KvpValue * set_path(Path path, KvpValue *newvalue) noexcept
Set the value with the key in a subframe following the keys in path, replacing and returning the old ...
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
const char * qof_string_cache_insert(const char *key)
You can use this function with g_hash_table_insert(), for the key (or value), as long as you use the ...
void qof_string_cache_remove(const char *key)
You can use this function as a destroy notifier for a GHashTable that uses common strings as keys (or...
The type used to store guids in C.
Definition guid.h:75
Implements KvpFrame.