struct ovsdb_datum_sort_cbdata {
enum ovsdb_atomic_type key_type;
+ enum ovsdb_atomic_type value_type;
struct ovsdb_datum *datum;
};
ovsdb_datum_sort_compare_cb(size_t a, size_t b, void *cbdata_)
{
struct ovsdb_datum_sort_cbdata *cbdata = cbdata_;
+ int retval;
- return ovsdb_atom_compare_3way(&cbdata->datum->keys[a],
- &cbdata->datum->keys[b],
- cbdata->key_type);
+ retval = ovsdb_atom_compare_3way(&cbdata->datum->keys[a],
+ &cbdata->datum->keys[b],
+ cbdata->key_type);
+ if (retval || cbdata->value_type == OVSDB_TYPE_VOID) {
+ return retval;
+ }
+
+ return ovsdb_atom_compare_3way(&cbdata->datum->values[a],
+ &cbdata->datum->values[b],
+ cbdata->value_type);
}
static void
}
}
+static void
+ovsdb_datum_sort__(struct ovsdb_datum *datum, enum ovsdb_atomic_type key_type,
+ enum ovsdb_atomic_type value_type)
+{
+ struct ovsdb_datum_sort_cbdata cbdata;
+
+ cbdata.key_type = key_type;
+ cbdata.value_type = value_type;
+ cbdata.datum = datum;
+ sort(datum->n, ovsdb_datum_sort_compare_cb, ovsdb_datum_sort_swap_cb,
+ &cbdata);
+}
+
/* The keys in an ovsdb_datum must be unique and in sorted order. Most
* functions that modify an ovsdb_datum maintain these invariants. For those
* that don't, this function checks and restores these invariants for 'datum',
struct ovsdb_error *
ovsdb_datum_sort(struct ovsdb_datum *datum, enum ovsdb_atomic_type key_type)
{
+ size_t i;
+
if (datum->n < 2) {
return NULL;
- } else {
- struct ovsdb_datum_sort_cbdata cbdata;
- size_t i;
+ }
- cbdata.key_type = key_type;
- cbdata.datum = datum;
- sort(datum->n, ovsdb_datum_sort_compare_cb, ovsdb_datum_sort_swap_cb,
- &cbdata);
-
- for (i = 0; i < datum->n - 1; i++) {
- if (ovsdb_atom_equals(&datum->keys[i], &datum->keys[i + 1],
- key_type)) {
- if (datum->values) {
- return ovsdb_error(NULL, "map contains duplicate key");
- } else {
- return ovsdb_error(NULL, "set contains duplicate");
- }
+ ovsdb_datum_sort__(datum, key_type, OVSDB_TYPE_VOID);
+
+ for (i = 0; i < datum->n - 1; i++) {
+ if (ovsdb_atom_equals(&datum->keys[i], &datum->keys[i + 1],
+ key_type)) {
+ if (datum->values) {
+ return ovsdb_error(NULL, "map contains duplicate key");
+ } else {
+ return ovsdb_error(NULL, "set contains duplicate");
}
}
-
- return NULL;
}
+ return NULL;
}
/* This function is the same as ovsdb_datum_sort(), except that the caller
}
}
+/* This is similar to ovsdb_datum_sort(), except that it drops duplicate keys
+ * instead of reporting an error. In a map type, the smallest value among a
+ * group of duplicate pairs is retained and the others are dropped.
+ *
+ * Returns the number of keys (or pairs) that were dropped. */
+size_t
+ovsdb_datum_sort_unique(struct ovsdb_datum *datum,
+ enum ovsdb_atomic_type key_type,
+ enum ovsdb_atomic_type value_type)
+{
+ size_t src, dst;
+
+ if (datum->n < 2) {
+ return 0;
+ }
+
+ ovsdb_datum_sort__(datum, key_type, value_type);
+
+ dst = 1;
+ for (src = 1; src < datum->n; src++) {
+ if (ovsdb_atom_equals(&datum->keys[src], &datum->keys[dst - 1],
+ key_type)) {
+ ovsdb_atom_destroy(&datum->keys[src], key_type);
+ if (value_type != OVSDB_TYPE_VOID) {
+ ovsdb_atom_destroy(&datum->values[src], value_type);
+ }
+ } else {
+ if (src != dst) {
+ datum->keys[dst] = datum->keys[src];
+ if (value_type != OVSDB_TYPE_VOID) {
+ datum->values[dst] = datum->values[src];
+ }
+ }
+ dst++;
+ }
+ }
+ datum->n = dst;
+ return datum->n - src;
+}
+
/* Checks that each of the atoms in 'datum' conforms to the constraints
* specified by its 'type'. Returns an error if a constraint is violated,
* otherwise a null pointer.
return NULL;
}
-/* Parses 'json' as a datum of the type described by 'type'. If successful,
- * returns NULL and initializes 'datum' with the parsed datum. On failure,
- * returns an error and the contents of 'datum' are indeterminate. The caller
- * is responsible for freeing the error or the datum that is returned.
- *
- * Violations of constraints expressed by 'type' are treated as errors.
- *
- * If 'symtab' is nonnull, then named UUIDs in 'symtab' are accepted. Refer to
- * ovsdb/SPECS for information about this, and for the syntax that this
- * function accepts. */
-struct ovsdb_error *
-ovsdb_datum_from_json(struct ovsdb_datum *datum,
- const struct ovsdb_type *type,
- const struct json *json,
- struct ovsdb_symbol_table *symtab)
+static struct ovsdb_error *
+ovsdb_datum_from_json__(struct ovsdb_datum *datum,
+ const struct ovsdb_type *type,
+ const struct json *json,
+ struct ovsdb_symbol_table *symtab)
{
struct ovsdb_error *error;
datum->n++;
}
-
- error = ovsdb_datum_sort(datum, type->key.type);
- if (error) {
- goto error;
- }
-
return NULL;
error:
}
}
+/* Parses 'json' as a datum of the type described by 'type'. If successful,
+ * returns NULL and initializes 'datum' with the parsed datum. On failure,
+ * returns an error and the contents of 'datum' are indeterminate. The caller
+ * is responsible for freeing the error or the datum that is returned.
+ *
+ * Violations of constraints expressed by 'type' are treated as errors.
+ *
+ * If 'symtab' is nonnull, then named UUIDs in 'symtab' are accepted. Refer to
+ * ovsdb/SPECS for information about this, and for the syntax that this
+ * function accepts. */
+struct ovsdb_error *
+ovsdb_datum_from_json(struct ovsdb_datum *datum,
+ const struct ovsdb_type *type,
+ const struct json *json,
+ struct ovsdb_symbol_table *symtab)
+{
+ struct ovsdb_error *error;
+
+ error = ovsdb_datum_from_json__(datum, type, json, symtab);
+ if (error) {
+ return error;
+ }
+
+ error = ovsdb_datum_sort(datum, type->key.type);
+ if (error) {
+ ovsdb_datum_destroy(datum, type);
+ }
+ return error;
+}
+
+/* This is the same as ovsdb_datum_from_json(), except that duplicate values
+ * in a set or map are dropped instead of being treated as an error. */
+struct ovsdb_error *
+ovsdb_datum_from_json_unique(struct ovsdb_datum *datum,
+ const struct ovsdb_type *type,
+ const struct json *json,
+ struct ovsdb_symbol_table *symtab)
+{
+ struct ovsdb_error *error;
+
+ error = ovsdb_datum_from_json__(datum, type, json, symtab);
+ if (!error) {
+ ovsdb_datum_sort_unique(datum, type->key.type, type->value.type);
+ }
+ return error;
+}
/* Converts 'datum', of the specified 'type', to JSON format, and returns the
* JSON. The caller is responsible for freeing the returned JSON.
" print JSON ATOMs in sorted order\n"
" parse-data TYPE DATUM...\n"
" parse JSON DATUMs as data of given TYPE, and re-serialize\n"
+ " parse-data-unique TYPE DATUM...\n"
+ " parse JSON DATUMs as data of given TYPE, eliminating\n"
+ " duplicate keys, and re-serialize\n"
" parse-data-strings TYPE DATUM...\n"
" parse string DATUMs as data of given TYPE, and re-serialize\n"
" parse-column NAME OBJECT\n"
}
static void
-do_parse_data(int argc, char *argv[])
+do_parse_data__(int argc, char *argv[],
+ struct ovsdb_error *
+ (*parse)(struct ovsdb_datum *datum,
+ const struct ovsdb_type *type,
+ const struct json *json,
+ struct ovsdb_symbol_table *symtab))
{
struct ovsdb_type type;
struct json *json;
struct ovsdb_datum datum;
json = unbox_json(parse_json(argv[i]));
- check_ovsdb_error(ovsdb_datum_from_json(&datum, &type, json, NULL));
+ check_ovsdb_error(parse(&datum, &type, json, NULL));
json_destroy(json);
print_and_free_json(ovsdb_datum_to_json(&datum, &type));
ovsdb_type_destroy(&type);
}
+static void
+do_parse_data(int argc, char *argv[])
+{
+ do_parse_data__(argc, argv, ovsdb_datum_from_json);
+}
+
+static void
+do_parse_data_unique(int argc, char *argv[])
+{
+ do_parse_data__(argc, argv, ovsdb_datum_from_json_unique);
+}
+
static void
do_parse_data_strings(int argc, char *argv[])
{
{ "parse-atoms", 2, INT_MAX, do_parse_atoms },
{ "parse-atom-strings", 2, INT_MAX, do_parse_atom_strings },
{ "parse-data", 2, INT_MAX, do_parse_data },
+ { "parse-data-unique", 2, INT_MAX, do_parse_data_unique },
{ "parse-data-strings", 2, INT_MAX, do_parse_data_strings },
{ "sort-atoms", 2, 2, do_sort_atoms },
{ "parse-column", 2, 2, do_parse_column },