Branch data 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 : 9025 : KvpFrameImpl::KvpFrameImpl(const KvpFrameImpl & rhs) noexcept
44 : : {
45 : 9025 : std::for_each(rhs.m_valuemap.begin(), rhs.m_valuemap.end(),
46 : 10645 : [this](const map_type::value_type & a)
47 : : {
48 : 10645 : auto key = qof_string_cache_insert(a.first);
49 : 10645 : auto val = new KvpValueImpl(*a.second);
50 : 10645 : this->m_valuemap.insert({key,val});
51 : 10645 : }
52 : : );
53 : 9025 : }
54 : :
55 : 124037 : KvpFrameImpl::~KvpFrameImpl() noexcept
56 : : {
57 : 124037 : std::for_each(m_valuemap.begin(), m_valuemap.end(),
58 : 24696 : [](const map_type::value_type &a){
59 : 24696 : qof_string_cache_remove(a.first);
60 : 24696 : delete a.second;
61 : 24696 : }
62 : : );
63 : 124037 : m_valuemap.clear();
64 : 124037 : }
65 : :
66 : : KvpFrame *
67 : 304124 : KvpFrame::get_child_frame_or_nullptr (Path const & path) noexcept
68 : : {
69 : 304124 : if (!path.size ())
70 : 291988 : return this;
71 : 12136 : auto key = path.front ();
72 : 12136 : auto map_iter = m_valuemap.find (key.c_str ());
73 : 12136 : if (map_iter == m_valuemap.end ())
74 : 10804 : return nullptr;
75 : 1332 : auto child = map_iter->second->get <KvpFrame *> ();
76 : 1332 : if (!child)
77 : 6 : return nullptr;
78 : 1326 : Path send;
79 : 1326 : std::copy (path.begin () + 1, path.end (), std::back_inserter (send));
80 : 1326 : return child->get_child_frame_or_nullptr (send);
81 : 12136 : }
82 : :
83 : : KvpFrame *
84 : 20522 : KvpFrame::get_child_frame_or_create (Path const & path) noexcept
85 : : {
86 : 20522 : if (!path.size ())
87 : 19880 : return this;
88 : 642 : auto key = path.front ();
89 : 642 : auto spot = m_valuemap.find (key.c_str ());
90 : 642 : if (spot == m_valuemap.end () || spot->second->get_type () != KvpValue::Type::FRAME)
91 : 1053 : delete set_impl (key.c_str (), new KvpValue {new KvpFrame});
92 : 642 : Path send;
93 : 642 : std::copy (path.begin () + 1, path.end (), std::back_inserter (send));
94 : 642 : auto child_val = m_valuemap.at (key.c_str ());
95 : 642 : auto child = child_val->get <KvpFrame *> ();
96 : 642 : return child->get_child_frame_or_create (send);
97 : 642 : }
98 : :
99 : :
100 : : KvpValue *
101 : 23454 : KvpFrame::set_impl (std::string const & key, KvpValue * value) noexcept
102 : : {
103 : 23454 : KvpValue * ret {};
104 : 23454 : auto spot = m_valuemap.find (key.c_str ());
105 : 23454 : if (spot != m_valuemap.end ())
106 : : {
107 : 263 : qof_string_cache_remove (spot->first);
108 : 263 : ret = spot->second;
109 : 263 : m_valuemap.erase (spot);
110 : : }
111 : 23454 : if (value)
112 : : {
113 : 19790 : auto cachedkey = static_cast <char const *> (qof_string_cache_insert (key.c_str ()));
114 : 19790 : m_valuemap.emplace (cachedkey, value);
115 : : }
116 : 23454 : return ret;
117 : : }
118 : :
119 : : KvpValue *
120 : 3230 : KvpFrameImpl::set (Path path, KvpValue* value) noexcept
121 : : {
122 : 3230 : if (path.empty())
123 : 0 : return nullptr;
124 : 3230 : auto key = path.back ();
125 : 3230 : path.pop_back ();
126 : 3230 : auto target = get_child_frame_or_nullptr (path);
127 : 3230 : if (!target)
128 : 7 : return nullptr;
129 : 3223 : return target->set_impl (key, value);
130 : 3230 : }
131 : :
132 : : KvpValue *
133 : 19880 : KvpFrameImpl::set_path (Path path, KvpValue* value) noexcept
134 : : {
135 : 19880 : auto key = path.back();
136 : 19880 : path.pop_back();
137 : 19880 : auto target = get_child_frame_or_create (path);
138 : 19880 : if (!target)
139 : 0 : return nullptr;
140 : 19880 : return target->set_impl (key, value);
141 : 19880 : }
142 : :
143 : : KvpValue *
144 : 299568 : KvpFrameImpl::get_slot (Path path) noexcept
145 : : {
146 : 299568 : auto key = path.back();
147 : 299568 : path.pop_back();
148 : 299568 : auto target = get_child_frame_or_nullptr (path);
149 : 299568 : if (!target)
150 : 10803 : return nullptr;
151 : 288765 : auto spot = target->m_valuemap.find (key.c_str ());
152 : 288765 : if (spot != target->m_valuemap.end ())
153 : 2897 : return spot->second;
154 : 285868 : return nullptr;
155 : 299568 : }
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 : 290180 : gvalue_from_kvp_value (const KvpValue *kval, GValue* val)
238 : : {
239 : 290180 : if (kval == NULL) return;
240 : 2642 : g_value_unset(val);
241 : :
242 : 2642 : switch (kval->get_type())
243 : : {
244 : 868 : case KvpValue::Type::INT64:
245 : 868 : g_value_init (val, G_TYPE_INT64);
246 : 868 : g_value_set_int64 (val, kval->get<int64_t>());
247 : 868 : 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 : 75 : case KvpValue::Type::NUMERIC:
253 : 75 : g_value_init (val, GNC_TYPE_NUMERIC);
254 : 75 : g_value_set_static_boxed (val, kval->get_ptr<gnc_numeric>());
255 : 75 : break;
256 : 1045 : case KvpValue::Type::STRING:
257 : 1045 : g_value_init (val, G_TYPE_STRING);
258 : 1045 : g_value_set_static_string (val, kval->get<const char*>());
259 : 1045 : break;
260 : 568 : case KvpValue::Type::GUID:
261 : 568 : g_value_init (val, GNC_TYPE_GUID);
262 : 568 : g_value_set_static_boxed (val, kval->get<GncGUID*>());
263 : 568 : break;
264 : 83 : case KvpValue::Type::TIME64:
265 : 83 : g_value_init (val, GNC_TYPE_TIME64);
266 : 83 : g_value_set_boxed (val, kval->get_ptr<Time64>());
267 : 83 : 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 : 5723 : kvp_value_from_gvalue (const GValue *gval)
281 : : {
282 : 5723 : KvpValue *val = NULL;
283 : : GType type;
284 : 5723 : if (gval == NULL)
285 : 1846 : return NULL;
286 : 3877 : type = G_VALUE_TYPE (gval);
287 : 3877 : g_return_val_if_fail (G_VALUE_TYPE (gval), NULL);
288 : :
289 : 3877 : if (type == G_TYPE_INT64)
290 : 121 : val = new KvpValue(g_value_get_int64 (gval));
291 : 3756 : else if (type == G_TYPE_DOUBLE)
292 : 3 : val = new KvpValue(g_value_get_double (gval));
293 : 3753 : 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 : 3753 : else if (type == GNC_TYPE_NUMERIC)
300 : 413 : val = new KvpValue(*(gnc_numeric*)g_value_get_boxed (gval));
301 : 3340 : else if (type == G_TYPE_STRING)
302 : : {
303 : 931 : auto string = g_value_get_string(gval);
304 : 931 : if (string != nullptr)
305 : 1800 : val = new KvpValue(g_strdup(string));
306 : : }
307 : 2409 : else if (type == GNC_TYPE_GUID)
308 : : {
309 : 197 : auto boxed = g_value_get_boxed(gval);
310 : 197 : if (boxed != nullptr)
311 : 189 : val = new KvpValue(guid_copy(static_cast<GncGUID*>(boxed)));
312 : : }
313 : 2212 : else if (type == GNC_TYPE_TIME64)
314 : 66 : val = new KvpValue(*(Time64*)g_value_get_boxed (gval));
315 : 2146 : else if (type == G_TYPE_DATE)
316 : 2146 : 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 : 3877 : 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 : : }
|