GnuCash  5.6-38-g01bffa485a+
Data Structures | Typedefs | Functions | Friends
KVP: Key-Value Pairs

A KvpFrame is a set of associations between character strings (keys) and KvpValues. More...

Data Structures

struct  KvpFrameImpl
 Implements KvpFrame. More...
 
class  KvpFrameImpl::cstring_comparer
 
struct  KvpValue
 Implements KvpValue using boost::variant. More...
 

Typedefs

using Path = std::vector< std::string >
 
using KvpEntry = std::pair< std::vector< std::string >, KvpValue * >
 
using KvpFrameImpl::map_type = std::map< const char *, KvpValue *, cstring_comparer >
 

Functions

bool KvpFrameImpl::cstring_comparer::operator() (const char *one, const char *two) const
 
 KvpFrameImpl::KvpFrameImpl (const KvpFrameImpl &) noexcept
 Performs a deep copy.
 
 KvpFrameImpl::~KvpFrameImpl () noexcept
 Perform a deep delete.
 
KvpValue * KvpFrameImpl::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 or nullptr if it doesn't. More...
 
KvpValue * KvpFrameImpl::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 value if it exists or nullptr if it doesn't. More...
 
std::string KvpFrameImpl::to_string () const noexcept
 Make a string representation of the frame. More...
 
std::string KvpFrameImpl::to_string (std::string const &) const noexcept
 Make a string representation of the frame with the specified string prefixed to every item in the frame. More...
 
std::vector< std::string > KvpFrameImpl::get_keys () const noexcept
 Report the keys in the immediate frame. More...
 
KvpValue * KvpFrameImpl::get_slot (Path keys) noexcept
 Get the value for the tail of the path or nullptr if it doesn't exist. More...
 
template<typename func_type , typename data_type >
void KvpFrameImpl::for_each_slot_temp (func_type const &, data_type &) const noexcept
 The function should be of the form: <anything> func (char const *, KvpValue *, data_type &); Do not pass nullptr as the function.
 
template<typename func_type >
void KvpFrameImpl::for_each_slot_temp (func_type const &) const noexcept
 
template<typename func_type , typename data_type >
void KvpFrameImpl::for_each_slot_prefix (std::string const &prefix, func_type const &, data_type &) const noexcept
 Like for_each_slot, but doesn't traverse nested values. More...
 
template<typename func_type >
void KvpFrameImpl::for_each_slot_prefix (std::string const &prefix, func_type const &) const noexcept
 
std::vector< KvpEntry > KvpFrameImpl::flatten_kvp (void) const noexcept
 Returns all keys and values of this frame recursively, flattening the frame-containing values.
 
bool KvpFrameImpl::empty () const noexcept
 Test for emptiness. More...
 
map_type::iterator KvpFrameImpl::begin ()
 
map_type::iterator KvpFrameImpl::end ()
 
int compare (const KvpValueImpl *, const KvpValue *) noexcept
 

Friends

int KvpFrameImpl::compare (const KvpFrameImpl &, const KvpFrameImpl &) noexcept
 If the first KvpFrameImpl has an item that the second does not, 1 is returned. More...
 
int compare (const KvpFrameImpl &, const KvpFrameImpl &) noexcept
 If the first KvpFrameImpl has an item that the second does not, 1 is returned. More...
 
int compare (const KvpFrameImpl *, const KvpFrameImpl *) noexcept
 
GValue * gvalue_from_kvp_value (const KvpValue *kval, GValue *val=nullptr)
 Convert a kvp_value into a GValue. More...
 
KvpValue * kvp_value_from_gvalue (const GValue *gval)
 Convert a gvalue into a kvpvalue. More...
 
void qof_book_load_options (QofBook *book, GncOptionLoad load_cb, GncOptionDB *odb)
 Load a GncOptionsDB from KVP data. More...
 
void qof_book_save_options (QofBook *book, GncOptionSave save_cb, GncOptionDB *odb, gboolean clear)
 Save a GncOptionsDB back to the book's KVP. More...
 
void qof_book_set_option (QofBook *book, KvpValue *value, GSList *path)
 Save a single option value. More...
 
KvpValue * qof_book_get_option (QofBook *book, GSList *path)
 Read a single option value. More...
 
void qof_book_options_delete (QofBook *book, GSList *path)
 Delete the options. More...
 
gboolean qof_instance_has_kvp (QofInstance *inst)
 Report whether a QofInstance has anything stored in KVP. More...
 
void qof_instance_set_kvp (QofInstance *, GValue const *value, unsigned count,...)
 Sets a KVP slot to a value from a GValue. More...
 
void qof_instance_get_kvp (QofInstance *, GValue *value, unsigned count,...)
 Retrieves the contents of a KVP slot into a provided GValue. More...
 

Detailed Description

A KvpFrame is a set of associations between character strings (keys) and KvpValues.

A KvpValue is notionally a union with possible types enumerated in the KvpValue::Type enum, and includes, among other things, ints, doubles, strings, guids, lists, time and numeric values. KvpValues may also be other frames, so KVP is inherently hierarchical.

Values are stored in a 'slot' associated with a key. Pointers passed as arguments into set_slot and get_slot are the responsibility of the caller. Pointers returned by get_slot are owned by the kvp_frame. Make copies as needed.

A 'path' is a sequence of keys that can be followed to a value. Paths are passed as either '/'-delimited strings or as std::vectors of keys. Unlike file system paths, the tokens '.' and '..' have no special meaning.

KVP is an implementation detail whose direct use should be avoided; create an abstraction object in libqof to keep KVP encapsulated here and ensure that KVP modifications are written to the database. Two generic abstractions are provided:

KVP Values used By GnuCash provides a catolog of KVP entries including what objects they're part of and how they're used.

Purpose

KVP is used to extend the class structure without directly reflecting the extension in the database or xML schema. The backend will directly load and store KVP slots without any checking, which allows older versions of GnuCash to load the database without complaint and without damaging the KVP data that they don't understand.

When a feature is entirely implemented in KVP and doesn't affect the meaning of the books or other features, this isn't a problem, but when it's not true then it should be registered in Features so that older versions of GnuCash will refuse to load the database.

Policy

Function Documentation

◆ compare()

int compare ( const KvpFrameImpl one,
const KvpFrameImpl two 
)
noexcept

If the first KvpFrameImpl has an item that the second does not, 1 is returned.

The first item within the two KvpFrameImpl that is not similar, that comparison is returned. If all the items within the first KvpFrameImpl match items within the second, but the second has more elements, -1 is returned. Otherwise, 0 is returned.

Definition at line 215 of file kvp-frame.cpp.

216 {
217  for (const auto & a : one.m_valuemap)
218  {
219  auto otherspot = two.m_valuemap.find(a.first);
220  if (otherspot == two.m_valuemap.end())
221  {
222  return 1;
223  }
224  auto comparison = compare(a.second,otherspot->second);
225 
226  if (comparison != 0)
227  return comparison;
228  }
229 
230  if (one.m_valuemap.size() < two.m_valuemap.size())
231  return -1;
232  return 0;
233 }
int compare(const KvpFrameImpl &one, const KvpFrameImpl &two) noexcept
If the first KvpFrameImpl has an item that the second does not, 1 is returned.
Definition: kvp-frame.cpp:215

◆ empty()

bool KvpFrameImpl::empty ( ) const
inlinenoexcept

Test for emptiness.

Returns
true if the frame contains nothing.

Definition at line 226 of file kvp-frame.hpp.

226 { return m_valuemap.empty(); }

◆ for_each_slot_prefix()

template<typename func_type , typename data_type >
void KvpFrameImpl::for_each_slot_prefix ( std::string const &  prefix,
func_type const &  ,
data_type &   
) const
noexcept

Like for_each_slot, but doesn't traverse nested values.

This will only loop over root-level values whose keys match the specified prefix.

◆ get_keys()

std::vector< std::string > KvpFrameImpl::get_keys ( ) const
noexcept

Report the keys in the immediate frame.

Be sensible about using this, it isn't a very efficient way to iterate.

Returns
std::vector of keys as std::strings.

Definition at line 187 of file kvp-frame.cpp.

188 {
189  std::vector<std::string> ret;
190  ret.reserve (m_valuemap.size());
191  std::for_each(m_valuemap.begin(), m_valuemap.end(),
192  [&ret](const KvpFrameImpl::map_type::value_type &a)
193  {
194  ret.push_back(a.first);
195  }
196  );
197  return ret;
198 }

◆ get_slot()

KvpValue * KvpFrameImpl::get_slot ( Path  keys)
noexcept

Get the value for the tail of the path or nullptr if it doesn't exist.

Parameters
pathPath of keys leading to the desired value.
Returns
The value at the key or nullptr.

Definition at line 143 of file kvp-frame.cpp.

144 {
145  auto key = path.back();
146  path.pop_back();
147  auto target = get_child_frame_or_nullptr (path);
148  if (!target)
149  return nullptr;
150  auto spot = target->m_valuemap.find (key.c_str ());
151  if (spot != target->m_valuemap.end ())
152  return spot->second;
153  return nullptr;
154 }

◆ gvalue_from_kvp_value()

GValue* gvalue_from_kvp_value ( const KvpValue *  kval,
GValue *  val = nullptr 
)

Convert a kvp_value into a GValue.

Frames aren't converted.

Parameters
kvalA KvpValue.
Returns
GValue*. Must be freed with g_free().

Definition at line 236 of file kvp-frame.cpp.

237 {
238  if (kval == NULL) return NULL;
239  if (!val)
240  val = g_slice_new0 (GValue);
241  else
242  g_value_unset(val);
243 
244  switch (kval->get_type())
245  {
246  case KvpValue::Type::INT64:
247  g_value_init (val, G_TYPE_INT64);
248  g_value_set_int64 (val, kval->get<int64_t>());
249  break;
250  case KvpValue::Type::DOUBLE:
251  g_value_init (val, G_TYPE_DOUBLE);
252  g_value_set_double (val, kval->get<double>());
253  break;
254  case KvpValue::Type::NUMERIC:
255  g_value_init (val, GNC_TYPE_NUMERIC);
256  g_value_set_static_boxed (val, kval->get_ptr<gnc_numeric>());
257  break;
258  case KvpValue::Type::STRING:
259  g_value_init (val, G_TYPE_STRING);
260  g_value_set_static_string (val, kval->get<const char*>());
261  break;
262  case KvpValue::Type::GUID:
263  g_value_init (val, GNC_TYPE_GUID);
264  g_value_set_static_boxed (val, kval->get<GncGUID*>());
265  break;
266  case KvpValue::Type::TIME64:
267  g_value_init (val, GNC_TYPE_TIME64);
268  g_value_set_boxed (val, kval->get_ptr<Time64>());
269  break;
270  case KvpValue::Type::GDATE:
271  g_value_init (val, G_TYPE_DATE);
272  g_value_set_static_boxed (val, kval->get_ptr<GDate>());
273  break;
274  default:
275 /* No transfer outside of QofInstance-derived classes! */
276  PWARN ("Error! Invalid attempt to transfer Kvp type %d", kval->get_type());
277  g_slice_free (GValue, val);
278  val = NULL;
279  break;
280  }
281  return val;
282 }
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
The type used to store guids in C.
Definition: guid.h:75

◆ kvp_value_from_gvalue()

KvpValue* kvp_value_from_gvalue ( const GValue *  gval)

Convert a gvalue into a kvpvalue.

Parameters
gvalA GValue of a type KvpValue can digest.
Returns
KvpValue created from the GValue's contents.

Definition at line 285 of file kvp-frame.cpp.

286 {
287  KvpValue *val = NULL;
288  GType type;
289  if (gval == NULL)
290  return NULL;
291  type = G_VALUE_TYPE (gval);
292  g_return_val_if_fail (G_VALUE_TYPE (gval), NULL);
293 
294  if (type == G_TYPE_INT64)
295  val = new KvpValue(g_value_get_int64 (gval));
296  else if (type == G_TYPE_DOUBLE)
297  val = new KvpValue(g_value_get_double (gval));
298  else if (type == G_TYPE_BOOLEAN)
299  {
300  auto bval = g_value_get_boolean(gval);
301  if (bval)
302  val = new KvpValue(g_strdup("true"));
303  }
304  else if (type == GNC_TYPE_NUMERIC)
305  val = new KvpValue(*(gnc_numeric*)g_value_get_boxed (gval));
306  else if (type == G_TYPE_STRING)
307  {
308  auto string = g_value_get_string(gval);
309  if (string != nullptr)
310  val = new KvpValue(g_strdup(string));
311  }
312  else if (type == GNC_TYPE_GUID)
313  {
314  auto boxed = g_value_get_boxed(gval);
315  if (boxed != nullptr)
316  val = new KvpValue(guid_copy(static_cast<GncGUID*>(boxed)));
317  }
318  else if (type == GNC_TYPE_TIME64)
319  val = new KvpValue(*(Time64*)g_value_get_boxed (gval));
320  else if (type == G_TYPE_DATE)
321  val = new KvpValue(*(GDate*)g_value_get_boxed (gval));
322  else
323  PWARN ("Error! Don't know how to make a KvpValue from a %s",
324  G_VALUE_TYPE_NAME (gval));
325 
326  return val;
327 }
GncGUID * guid_copy(const GncGUID *guid)
Returns a newly allocated GncGUID that matches the passed-in GUID.
Definition: guid.cpp:120
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250

◆ qof_book_get_option()

KvpValue* qof_book_get_option ( QofBook *  book,
GSList *  path 
)

Read a single option value.

Used from Scheme, the KvpValue<–>SCM translation is handled by the functions in kvp-scm.c and automated by SWIG. The starting element is set as KVP_OPTION_PATH in qofbookslots.h.

Parameters
bookThe book.
pathA GSList of keys which form a path under KVP_OPTION_PATH.

Definition at line 1374 of file qofbook.cpp.

1375 {
1376  KvpFrame *root = qof_instance_get_slots(QOF_INSTANCE (book));
1377  return root->get_slot(gslist_to_option_path(path));
1378 }

◆ qof_book_load_options()

void qof_book_load_options ( QofBook *  book,
GncOptionLoad  load_cb,
GncOptionDB odb 
)

Load a GncOptionsDB from KVP data.

Parameters
bookThe book.
load_cbA callback function that does the loading.
odbThe GncOptionDB to load.

Definition at line 1316 of file qofbook.cpp.

1317 {
1318  load_cb (odb, book);
1319 }

◆ qof_book_options_delete()

void qof_book_options_delete ( QofBook *  book,
GSList *  path 
)

Delete the options.

Primarily used from Scheme to clear out the options before saving a new set.

Parameters
bookThe book.
listA GList of keys which from a path under KVP_OPTION_PATH. If GList is Null, the whole option is deleted.

Definition at line 1381 of file qofbook.cpp.

1382 {
1383  KvpFrame *root = qof_instance_get_slots(QOF_INSTANCE (book));
1384  if (path != nullptr)
1385  {
1386  Path path_v {str_KVP_OPTION_PATH};
1387  Path tmp_path;
1388  for (auto item = path; item != nullptr; item = g_slist_next(item))
1389  tmp_path.push_back(static_cast<const char*>(item->data));
1390  delete root->set_path(gslist_to_option_path(path), nullptr);
1391  }
1392  else
1393  delete root->set_path({str_KVP_OPTION_PATH}, nullptr);
1394 }

◆ qof_book_save_options()

void qof_book_save_options ( QofBook *  book,
GncOptionSave  save_cb,
GncOptionDB odb,
gboolean  clear 
)

Save a GncOptionsDB back to the book's KVP.

Parameters
bookThe book.
save_cbA callback function that does the saving.
odbThe GncOptionsDB to save from.
clearShould the GncOptionsDB be emptied after the save?

Definition at line 1322 of file qofbook.cpp.

1324 {
1325  /* Wrap this in begin/commit so that it commits only once instead of doing
1326  * so for every option. Qof_book_set_option will take care of dirtying the
1327  * book.
1328  */
1329  qof_book_begin_edit (book);
1330  save_cb (odb, book, clear);
1331  qof_book_commit_edit (book);
1332 }

◆ qof_book_set_option()

void qof_book_set_option ( QofBook *  book,
KvpValue *  value,
GSList *  path 
)

Save a single option value.

Used from Scheme, the KvpValue<–>SCM translation is handled by the functions in kvp-scm.c and automated by SWIG. The starting element is set as KVP_OPTION_PATH in qofbookslots.h.

Parameters
bookThe book.
valueThe KvpValue to store.
pathA GSList of keys which form a path under KVP_OPTION_PATH.

Definition at line 1361 of file qofbook.cpp.

1362 {
1363  KvpFrame *root = qof_instance_get_slots (QOF_INSTANCE (book));
1364  qof_book_begin_edit (book);
1365  delete root->set_path(gslist_to_option_path(path), value);
1366  qof_instance_set_dirty (QOF_INSTANCE (book));
1367  qof_book_commit_edit (book);
1368 
1369  // Also, mark any cached value as invalid
1370  book->cached_num_field_source_isvalid = FALSE;
1371 }

◆ qof_instance_get_kvp()

void qof_instance_get_kvp ( QofInstance ,
GValue *  value,
unsigned  count,
  ... 
)

Retrieves the contents of a KVP slot into a provided GValue.

Parameters
instThe QofInstance
keyThe path to the slot.
valueA GValue into which to store the value of the slot. It will be set to the correct type.

Definition at line 1072 of file qofinstance.cpp.

1073 {
1074  std::vector<std::string> path;
1075  va_list args;
1076  va_start (args, count);
1077  for (unsigned i{0}; i < count; ++i)
1078  path.push_back (va_arg (args, char const *));
1079  va_end (args);
1080  gvalue_from_kvp_value (inst->kvp_data->get_slot (path), value);
1081 }
GValue * gvalue_from_kvp_value(const KvpValue *kval, GValue *val)
Convert a kvp_value into a GValue.
Definition: kvp-frame.cpp:236

◆ qof_instance_has_kvp()

gboolean qof_instance_has_kvp ( QofInstance inst)

Report whether a QofInstance has anything stored in KVP.

Parameters
instThe QofInstance
Returns
TRUE if Kvp isn't empty.

Definition at line 1044 of file qofinstance.cpp.

1045 {
1046  return (inst->kvp_data != nullptr && !inst->kvp_data->empty());
1047 }

◆ qof_instance_set_kvp()

void qof_instance_set_kvp ( QofInstance ,
GValue const *  value,
unsigned  count,
  ... 
)

Sets a KVP slot to a value from a GValue.

Intermediate container frames will be created if necessary. Commits the change to the QofInstance.

Parameters
instThe QofInstance on which to set the value.
keyThe path to the slot.
valueA GValue containing an item of a type which KvpValue knows how to store.

Definition at line 1055 of file qofinstance.cpp.

1056 {
1057  std::vector<std::string> path;
1058  va_list args;
1059  va_start (args, count);
1060  for (unsigned i{0}; i < count; ++i)
1061  path.push_back (va_arg (args, char const *));
1062  va_end (args);
1063  delete inst->kvp_data->set_path (path, kvp_value_from_gvalue (value));
1064 }
KvpValue * kvp_value_from_gvalue(const GValue *gval)
Convert a gvalue into a kvpvalue.
Definition: kvp-frame.cpp:285

◆ set()

KvpValue * KvpFrameImpl::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 or nullptr if it doesn't.

Takes ownership of new value and releases ownership of the returned old value. Values must be allocated on the free store with operator new.

Parameters
keyThe key to insert/replace.
newvalueThe value to set at key.
Returns
The old value if there was one or nullptr. Set the value with the key in a subframe following the keys in path, replacing and returning the old value if it exists or nullptr if it doesn't. Takes ownership of new value and releases ownership of the returned old value. Values must be allocated on the free store with operator new.
Parameters
keyThe key to insert/replace.
Exceptions
invalid_argumentif the path doesn't exist.
Parameters
pathThe path of subframes leading to the frame in which to insert/replace.
newvalueThe value to set at key.
Returns
The old value if there was one or nullptr.

Definition at line 119 of file kvp-frame.cpp.

120 {
121  if (path.empty())
122  return nullptr;
123  auto key = path.back ();
124  path.pop_back ();
125  auto target = get_child_frame_or_nullptr (path);
126  if (!target)
127  return nullptr;
128  return target->set_impl (key, value);
129 }

◆ set_path()

KvpValue * KvpFrameImpl::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 value if it exists or nullptr if it doesn't.

Creates any missing intermediate frames.Takes ownership of new value and releases ownership of the returned old value. Values must be allocated on the free store with operator new.

Parameters
pathThe path of subframes as a std::vector leading to the frame in which to insert/replace.
newvalueThe value to set at key.
Returns
The old value if there was one or nullptr.

Definition at line 132 of file kvp-frame.cpp.

133 {
134  auto key = path.back();
135  path.pop_back();
136  auto target = get_child_frame_or_create (path);
137  if (!target)
138  return nullptr;
139  return target->set_impl (key, value);
140 }

◆ to_string() [1/2]

std::string KvpFrameImpl::to_string ( ) const
noexcept

Make a string representation of the frame.

Mostly useful for debugging.

Returns
A std::string representing the frame and all its children.

Definition at line 157 of file kvp-frame.cpp.

158 {
159  return to_string("");
160 }
std::string to_string() const noexcept
Make a string representation of the frame.
Definition: kvp-frame.cpp:157

◆ to_string() [2/2]

std::string KvpFrameImpl::to_string ( std::string const &  prefix) const
noexcept

Make a string representation of the frame with the specified string prefixed to every item in the frame.

Returns
A std::string representing all the children of the frame.

Definition at line 163 of file kvp-frame.cpp.

164 {
165  if (!m_valuemap.size())
166  return prefix;
167  std::ostringstream ret;
168  std::for_each(m_valuemap.begin(), m_valuemap.end(),
169  [&ret,&prefix](const map_type::value_type &a)
170  {
171  std::string new_prefix {prefix};
172  if (a.first)
173  {
174  new_prefix += a.first;
175  new_prefix += "/";
176  }
177  if (a.second)
178  ret << a.second->to_string(new_prefix) << "\n";
179  else
180  ret << new_prefix << "(null)\n";
181  }
182  );
183  return ret.str();
184 }

Friends

◆ compare

int compare ( const KvpFrameImpl ,
const KvpFrameImpl  
)
friend

If the first KvpFrameImpl has an item that the second does not, 1 is returned.

The first item within the two KvpFrameImpl that is not similar, that comparison is returned. If all the items within the first KvpFrameImpl match items within the second, but the second has more elements, -1 is returned. Otherwise, 0 is returned.

Definition at line 215 of file kvp-frame.cpp.

216 {
217  for (const auto & a : one.m_valuemap)
218  {
219  auto otherspot = two.m_valuemap.find(a.first);
220  if (otherspot == two.m_valuemap.end())
221  {
222  return 1;
223  }
224  auto comparison = compare(a.second,otherspot->second);
225 
226  if (comparison != 0)
227  return comparison;
228  }
229 
230  if (one.m_valuemap.size() < two.m_valuemap.size())
231  return -1;
232  return 0;
233 }
friend int compare(const KvpFrameImpl &, const KvpFrameImpl &) noexcept
If the first KvpFrameImpl has an item that the second does not, 1 is returned.
Definition: kvp-frame.cpp:215