GnuCash c935c2f+
Loading...
Searching...
No Matches
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.
 
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.
 
std::string KvpFrameImpl::to_string () const noexcept
 Make a string representation of the frame.
 
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.
 
std::vector< std::string > KvpFrameImpl::get_keys () const noexcept
 Report the keys in the immediate frame.
 
KvpValue * KvpFrameImpl::get_slot (Path keys) noexcept
 Get the value for the tail of the path or nullptr if it doesn't exist.
 
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.
 
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.
 
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.
 
int compare (const KvpFrameImpl &, const KvpFrameImpl &) noexcept
 If the first KvpFrameImpl has an item that the second does not, 1 is returned.
 
int compare (const KvpFrameImpl *, const KvpFrameImpl *) noexcept
 
void gvalue_from_kvp_value (const KvpValue *kval, GValue *val)
 Convert a kvp_value into a GValue.
 
KvpValue * kvp_value_from_gvalue (const GValue *gval)
 Convert a gvalue into a kvpvalue.
 
void qof_book_load_options (QofBook *book, GncOptionLoad load_cb, GncOptionDB *odb)
 Load a GncOptionsDB from KVP data.
 
void qof_book_save_options (QofBook *book, GncOptionSave save_cb, GncOptionDB *odb, gboolean clear)
 Save a GncOptionsDB back to the book's KVP.
 
void qof_book_set_option (QofBook *book, KvpValue *value, GSList *path)
 Save a single option value.
 
KvpValue * qof_book_get_option (QofBook *book, GSList *path)
 Read a single option value.
 
void qof_book_options_delete (QofBook *book, GSList *path)
 Delete the options.
 
gboolean qof_instance_has_kvp (QofInstance *inst)
 Report whether a QofInstance has anything stored in KVP.
 
void qof_instance_set_kvp (QofInstance *, GValue const *value, unsigned count,...)
 Sets a KVP slot to a value from a GValue.
 
void qof_instance_get_kvp (QofInstance *, GValue *value, unsigned count,...)
 Retrieves the contents of a KVP slot into a provided GValue.
 

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

Typedef Documentation

◆ KvpEntry

using KvpEntry = std::pair <std::vector <std::string>, KvpValue*>

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

◆ map_type

using KvpFrameImpl::map_type = std::map<const char *, KvpValue*, cstring_comparer>

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

◆ Path

using Path = std::vector<std::string>

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

Function Documentation

◆ begin()

map_type::iterator KvpFrameImpl::begin ( )
inline

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

229{ return m_valuemap.begin(); }

◆ compare() [1/2]

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

◆ compare() [2/2]

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

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

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}

◆ 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(); }

◆ end()

map_type::iterator KvpFrameImpl::end ( )
inline

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

230{ return m_valuemap.end(); }

◆ 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:155

◆ KvpFrameImpl() [1/2]

KvpFrameImpl::KvpFrameImpl ( )
inlinenoexcept

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

124{};

◆ KvpFrameImpl() [2/2]

KvpFrameImpl::KvpFrameImpl ( const KvpFrameImpl rhs)
noexcept

Performs a deep copy.

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

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}

◆ operator()()

bool KvpFrameImpl::cstring_comparer::operator() ( const char *  one,
const char *  two 
) const
inline

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

116 {
117 auto ret = std::strcmp(one, two) < 0;
118 return ret;
119 }

◆ 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 1392 of file qofbook.cpp.

1393{
1394 KvpFrame *root = qof_instance_get_slots(QOF_INSTANCE (book));
1395 return root->get_slot(gslist_to_option_path(path));
1396}

◆ 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 1334 of file qofbook.cpp.

1335{
1336 load_cb (odb, book);
1337}

◆ 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 1399 of file qofbook.cpp.

1400{
1401 KvpFrame *root = qof_instance_get_slots(QOF_INSTANCE (book));
1402 if (path != nullptr)
1403 {
1404 Path path_v {str_KVP_OPTION_PATH};
1405 Path tmp_path;
1406 for (auto item = path; item != nullptr; item = g_slist_next(item))
1407 tmp_path.push_back(static_cast<const char*>(item->data));
1408 delete root->set_path(gslist_to_option_path(path), nullptr);
1409 }
1410 else
1411 delete root->set_path({str_KVP_OPTION_PATH}, nullptr);
1412}

◆ 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 1340 of file qofbook.cpp.

1342{
1343 /* Wrap this in begin/commit so that it commits only once instead of doing
1344 * so for every option. Qof_book_set_option will take care of dirtying the
1345 * book.
1346 */
1347 qof_book_begin_edit (book);
1348 save_cb (odb, book, clear);
1349 qof_book_commit_edit (book);
1350}

◆ 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 1379 of file qofbook.cpp.

1380{
1381 KvpFrame *root = qof_instance_get_slots (QOF_INSTANCE (book));
1382 qof_book_begin_edit (book);
1383 delete root->set_path(gslist_to_option_path(path), value);
1384 qof_instance_set_dirty (QOF_INSTANCE (book));
1385 qof_book_commit_edit (book);
1386
1387 // Also, mark any cached value as invalid
1388 book->cached_num_field_source_isvalid = FALSE;
1389}

◆ qof_instance_get_kvp()

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

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

Parameters
instThe QofInstance
valueA GValue into which to store the value of the slot. It will be set to the correct type.
countThe number of path elements passed in the varargs
...The path elements as const char*

Definition at line 1092 of file qofinstance.cpp.

1093{
1094 std::vector<std::string> path;
1095 va_list args;
1096 va_start (args, count);
1097 for (unsigned i{0}; i < count; ++i)
1098 path.push_back (va_arg (args, char const *));
1099 va_end (args);
1100 gvalue_from_kvp_value (inst->kvp_data->get_slot (path), value);
1101}
void gvalue_from_kvp_value(const KvpValue *kval, GValue *val)
Convert a kvp_value into a GValue.

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

1035{
1036 return (inst->kvp_data != nullptr && !inst->kvp_data->empty());
1037}

◆ qof_instance_set_kvp()

void qof_instance_set_kvp ( QofInstance inst,
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.
valueA GValue containing an item of a type which KvpValue knows how to store.
countThe number of path elements passed in the varargs
...The path elements as const char*

Definition at line 1045 of file qofinstance.cpp.

1046{
1047 std::vector<std::string> path;
1048 va_list args;
1049 va_start (args, count);
1050 for (unsigned i{0}; i < count; ++i)
1051 path.push_back (va_arg (args, char const *));
1052 va_end (args);
1053 delete inst->kvp_data->set_path (path, kvp_value_from_gvalue (value));
1054}

◆ 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.

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

◆ ~KvpFrameImpl()

KvpFrameImpl::~KvpFrameImpl ( )
noexcept

Perform a deep delete.

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

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}

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.