GnuCash  5.6-150-g038405b370+
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
 
void gvalue_from_kvp_value (const KvpValue *kval, GValue *val)
 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 216 of file kvp-frame.cpp.

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

◆ 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 188 of file kvp-frame.cpp.

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 }

◆ 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 144 of file kvp-frame.cpp.

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 }

◆ gvalue_from_kvp_value()

void gvalue_from_kvp_value ( const KvpValue *  kval,
GValue *  val 
)

Convert a kvp_value into a GValue.

Frames aren't converted.

Parameters
kvalA KvpValue.
valThe GValue in which to store the converted value.

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

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 }
#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 280 of file kvp-frame.cpp.

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 }
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 1099 of file qofinstance.cpp.

1100 {
1101  std::vector<std::string> path;
1102  va_list args;
1103  va_start (args, count);
1104  for (unsigned i{0}; i < count; ++i)
1105  path.push_back (va_arg (args, char const *));
1106  va_end (args);
1107  gvalue_from_kvp_value (inst->kvp_data->get_slot (path), value);
1108 }
void gvalue_from_kvp_value(const KvpValue *kval, GValue *val)
Convert a kvp_value into a GValue.
Definition: kvp-frame.cpp:237

◆ 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 1045 of file qofinstance.cpp.

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

◆ 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 1056 of file qofinstance.cpp.

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

◆ 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 120 of file kvp-frame.cpp.

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 }

◆ 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 133 of file kvp-frame.cpp.

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 }

◆ 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 158 of file kvp-frame.cpp.

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

◆ 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 164 of file kvp-frame.cpp.

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 }

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 216 of file kvp-frame.cpp.

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