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 : }
|