2012-05-02 15:21:36 -07:00
|
|
|
|
/* Copyright (c) 2009, 2010, 2011 Nicira, Inc.
|
2009-12-16 10:49:31 -08:00
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at:
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
|
|
#include "mutation.h"
|
|
|
|
|
|
|
|
|
|
#include <float.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
|
|
#include "column.h"
|
|
|
|
|
#include "ovsdb-error.h"
|
|
|
|
|
#include "json.h"
|
|
|
|
|
#include "row.h"
|
|
|
|
|
#include "table.h"
|
|
|
|
|
|
|
|
|
|
struct ovsdb_error *
|
|
|
|
|
ovsdb_mutator_from_string(const char *name, enum ovsdb_mutator *mutator)
|
|
|
|
|
{
|
|
|
|
|
#define OVSDB_MUTATOR(ENUM, NAME) \
|
|
|
|
|
if (!strcmp(name, NAME)) { \
|
|
|
|
|
*mutator = ENUM; \
|
|
|
|
|
return NULL; \
|
|
|
|
|
}
|
|
|
|
|
OVSDB_MUTATORS;
|
|
|
|
|
#undef OVSDB_MUTATOR
|
|
|
|
|
|
|
|
|
|
return ovsdb_syntax_error(NULL, "unknown mutator",
|
|
|
|
|
"No mutator named %s.", name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
ovsdb_mutator_to_string(enum ovsdb_mutator mutator)
|
|
|
|
|
{
|
|
|
|
|
switch (mutator) {
|
|
|
|
|
#define OVSDB_MUTATOR(ENUM, NAME) case ENUM: return NAME;
|
|
|
|
|
OVSDB_MUTATORS;
|
|
|
|
|
#undef OVSDB_MUTATOR
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static WARN_UNUSED_RESULT struct ovsdb_error *
|
|
|
|
|
type_mismatch(const struct ovsdb_mutation *m, const struct json *json)
|
|
|
|
|
{
|
|
|
|
|
struct ovsdb_error *error;
|
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
|
|
s = ovsdb_type_to_english(&m->column->type);
|
|
|
|
|
error = ovsdb_syntax_error(
|
|
|
|
|
json, NULL, "Type mismatch: \"%s\" operator may not be "
|
|
|
|
|
"applied to column %s of type %s.",
|
|
|
|
|
ovsdb_mutator_to_string(m->mutator), m->column->name, s);
|
|
|
|
|
free(s);
|
|
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static WARN_UNUSED_RESULT struct ovsdb_error *
|
|
|
|
|
ovsdb_mutation_from_json(const struct ovsdb_table_schema *ts,
|
|
|
|
|
const struct json *json,
|
2010-02-08 16:03:21 -08:00
|
|
|
|
struct ovsdb_symbol_table *symtab,
|
2009-12-16 10:49:31 -08:00
|
|
|
|
struct ovsdb_mutation *m)
|
|
|
|
|
{
|
|
|
|
|
const struct json_array *array;
|
|
|
|
|
struct ovsdb_error *error;
|
|
|
|
|
const char *mutator_name;
|
|
|
|
|
const char *column_name;
|
|
|
|
|
|
|
|
|
|
if (json->type != JSON_ARRAY
|
|
|
|
|
|| json->u.array.n != 3
|
|
|
|
|
|| json->u.array.elems[0]->type != JSON_STRING
|
|
|
|
|
|| json->u.array.elems[1]->type != JSON_STRING) {
|
|
|
|
|
return ovsdb_syntax_error(json, NULL, "Parse error in mutation.");
|
|
|
|
|
}
|
|
|
|
|
array = json_array(json);
|
|
|
|
|
|
|
|
|
|
column_name = json_string(array->elems[0]);
|
|
|
|
|
m->column = ovsdb_table_schema_get_column(ts, column_name);
|
|
|
|
|
if (!m->column) {
|
|
|
|
|
return ovsdb_syntax_error(json, "unknown column",
|
|
|
|
|
"No column %s in table %s.",
|
|
|
|
|
column_name, ts->name);
|
|
|
|
|
}
|
2010-02-08 14:09:36 -08:00
|
|
|
|
ovsdb_type_clone(&m->type, &m->column->type);
|
2009-12-16 10:49:31 -08:00
|
|
|
|
|
|
|
|
|
mutator_name = json_string(array->elems[1]);
|
|
|
|
|
error = ovsdb_mutator_from_string(mutator_name, &m->mutator);
|
|
|
|
|
if (error) {
|
2010-02-08 14:09:36 -08:00
|
|
|
|
goto exit;
|
2009-12-16 10:49:31 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type-check and relax restrictions on 'type' if appropriate. */
|
|
|
|
|
switch (m->mutator) {
|
|
|
|
|
case OVSDB_M_ADD:
|
|
|
|
|
case OVSDB_M_SUB:
|
|
|
|
|
case OVSDB_M_MUL:
|
|
|
|
|
case OVSDB_M_DIV:
|
|
|
|
|
case OVSDB_M_MOD:
|
|
|
|
|
if ((!ovsdb_type_is_scalar(&m->type) && !ovsdb_type_is_set(&m->type))
|
2010-02-08 14:09:36 -08:00
|
|
|
|
|| (m->type.key.type != OVSDB_TYPE_INTEGER
|
|
|
|
|
&& m->type.key.type != OVSDB_TYPE_REAL)
|
2009-12-16 10:49:31 -08:00
|
|
|
|
|| (m->mutator == OVSDB_M_MOD
|
2010-02-08 14:09:36 -08:00
|
|
|
|
&& m->type.key.type == OVSDB_TYPE_REAL)) {
|
2009-12-16 10:49:31 -08:00
|
|
|
|
return type_mismatch(m, json);
|
|
|
|
|
}
|
2010-02-08 14:09:36 -08:00
|
|
|
|
ovsdb_base_type_clear_constraints(&m->type.key);
|
2009-12-16 10:49:31 -08:00
|
|
|
|
m->type.n_min = m->type.n_max = 1;
|
2010-02-08 14:09:36 -08:00
|
|
|
|
error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2],
|
|
|
|
|
symtab);
|
|
|
|
|
break;
|
2009-12-16 10:49:31 -08:00
|
|
|
|
|
|
|
|
|
case OVSDB_M_INSERT:
|
|
|
|
|
case OVSDB_M_DELETE:
|
|
|
|
|
if (!ovsdb_type_is_set(&m->type) && !ovsdb_type_is_map(&m->type)) {
|
|
|
|
|
return type_mismatch(m, json);
|
|
|
|
|
}
|
|
|
|
|
m->type.n_min = 0;
|
|
|
|
|
if (m->mutator == OVSDB_M_DELETE) {
|
|
|
|
|
m->type.n_max = UINT_MAX;
|
|
|
|
|
}
|
|
|
|
|
error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2],
|
|
|
|
|
symtab);
|
|
|
|
|
if (error && ovsdb_type_is_map(&m->type)
|
|
|
|
|
&& m->mutator == OVSDB_M_DELETE) {
|
|
|
|
|
ovsdb_error_destroy(error);
|
2010-02-08 14:09:36 -08:00
|
|
|
|
m->type.value.type = OVSDB_TYPE_VOID;
|
2009-12-16 10:49:31 -08:00
|
|
|
|
error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2],
|
|
|
|
|
symtab);
|
|
|
|
|
}
|
2010-02-08 14:09:36 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
NOT_REACHED();
|
2009-12-16 10:49:31 -08:00
|
|
|
|
}
|
|
|
|
|
|
2010-02-08 14:09:36 -08:00
|
|
|
|
exit:
|
|
|
|
|
if (error) {
|
|
|
|
|
ovsdb_type_destroy(&m->type);
|
|
|
|
|
}
|
|
|
|
|
return error;
|
2009-12-16 10:49:31 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ovsdb_mutation_free(struct ovsdb_mutation *m)
|
|
|
|
|
{
|
|
|
|
|
ovsdb_datum_destroy(&m->arg, &m->type);
|
2010-02-08 14:09:36 -08:00
|
|
|
|
ovsdb_type_destroy(&m->type);
|
2009-12-16 10:49:31 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ovsdb_error *
|
|
|
|
|
ovsdb_mutation_set_from_json(const struct ovsdb_table_schema *ts,
|
|
|
|
|
const struct json *json,
|
2010-02-08 16:03:21 -08:00
|
|
|
|
struct ovsdb_symbol_table *symtab,
|
2009-12-16 10:49:31 -08:00
|
|
|
|
struct ovsdb_mutation_set *set)
|
|
|
|
|
{
|
|
|
|
|
const struct json_array *array = json_array(json);
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
set->mutations = xmalloc(array->n * sizeof *set->mutations);
|
|
|
|
|
set->n_mutations = 0;
|
|
|
|
|
for (i = 0; i < array->n; i++) {
|
|
|
|
|
struct ovsdb_error *error;
|
|
|
|
|
error = ovsdb_mutation_from_json(ts, array->elems[i], symtab,
|
|
|
|
|
&set->mutations[i]);
|
|
|
|
|
if (error) {
|
|
|
|
|
ovsdb_mutation_set_destroy(set);
|
|
|
|
|
set->mutations = NULL;
|
|
|
|
|
set->n_mutations = 0;
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
set->n_mutations++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct json *
|
|
|
|
|
ovsdb_mutation_to_json(const struct ovsdb_mutation *m)
|
|
|
|
|
{
|
|
|
|
|
return json_array_create_3(
|
|
|
|
|
json_string_create(m->column->name),
|
|
|
|
|
json_string_create(ovsdb_mutator_to_string(m->mutator)),
|
|
|
|
|
ovsdb_datum_to_json(&m->arg, &m->type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct json *
|
|
|
|
|
ovsdb_mutation_set_to_json(const struct ovsdb_mutation_set *set)
|
|
|
|
|
{
|
|
|
|
|
struct json **mutations;
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
mutations = xmalloc(set->n_mutations * sizeof *mutations);
|
|
|
|
|
for (i = 0; i < set->n_mutations; i++) {
|
|
|
|
|
mutations[i] = ovsdb_mutation_to_json(&set->mutations[i]);
|
|
|
|
|
}
|
|
|
|
|
return json_array_create(mutations, set->n_mutations);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ovsdb_mutation_set_destroy(struct ovsdb_mutation_set *set)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < set->n_mutations; i++) {
|
|
|
|
|
ovsdb_mutation_free(&set->mutations[i]);
|
|
|
|
|
}
|
|
|
|
|
free(set->mutations);
|
|
|
|
|
}
|
2010-02-08 14:09:36 -08:00
|
|
|
|
|
|
|
|
|
enum ovsdb_mutation_scalar_error {
|
|
|
|
|
ME_OK,
|
|
|
|
|
ME_DOM,
|
|
|
|
|
ME_RANGE
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ovsdb_scalar_mutation {
|
|
|
|
|
int (*mutate_integer)(int64_t *x, int64_t y);
|
|
|
|
|
int (*mutate_real)(double *x, double y);
|
|
|
|
|
enum ovsdb_mutator mutator;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct ovsdb_scalar_mutation add_mutation;
|
|
|
|
|
static const struct ovsdb_scalar_mutation sub_mutation;
|
|
|
|
|
static const struct ovsdb_scalar_mutation mul_mutation;
|
|
|
|
|
static const struct ovsdb_scalar_mutation div_mutation;
|
|
|
|
|
static const struct ovsdb_scalar_mutation mod_mutation;
|
|
|
|
|
|
|
|
|
|
static struct ovsdb_error *
|
|
|
|
|
ovsdb_mutation_scalar_error(enum ovsdb_mutation_scalar_error error,
|
|
|
|
|
enum ovsdb_mutator mutator)
|
|
|
|
|
{
|
|
|
|
|
switch (error) {
|
|
|
|
|
case ME_OK:
|
|
|
|
|
return OVSDB_BUG("unexpected success");
|
|
|
|
|
|
|
|
|
|
case ME_DOM:
|
|
|
|
|
return ovsdb_error("domain error", "Division by zero.");
|
|
|
|
|
|
|
|
|
|
case ME_RANGE:
|
|
|
|
|
return ovsdb_error("range error",
|
|
|
|
|
"Result of \"%s\" operation is out of range.",
|
|
|
|
|
ovsdb_mutator_to_string(mutator));
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return OVSDB_BUG("unexpected error");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
check_real_range(double x)
|
|
|
|
|
{
|
|
|
|
|
return x >= -DBL_MAX && x <= DBL_MAX ? 0 : ME_RANGE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct ovsdb_error *
|
|
|
|
|
mutate_scalar(const struct ovsdb_type *dst_type, struct ovsdb_datum *dst,
|
|
|
|
|
const union ovsdb_atom *arg,
|
|
|
|
|
const struct ovsdb_scalar_mutation *mutation)
|
|
|
|
|
{
|
|
|
|
|
const struct ovsdb_base_type *base = &dst_type->key;
|
|
|
|
|
struct ovsdb_error *error;
|
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
|
|
if (base->type == OVSDB_TYPE_INTEGER) {
|
|
|
|
|
int64_t y = arg->integer;
|
|
|
|
|
for (i = 0; i < dst->n; i++) {
|
|
|
|
|
enum ovsdb_mutation_scalar_error me;
|
|
|
|
|
|
|
|
|
|
me = (mutation->mutate_integer)(&dst->keys[i].integer, y);
|
|
|
|
|
if (me != ME_OK) {
|
|
|
|
|
return ovsdb_mutation_scalar_error(me, mutation->mutator);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (base->type == OVSDB_TYPE_REAL) {
|
|
|
|
|
double y = arg->real;
|
|
|
|
|
for (i = 0; i < dst->n; i++) {
|
|
|
|
|
double *x = &dst->keys[i].real;
|
|
|
|
|
enum ovsdb_mutation_scalar_error me;
|
|
|
|
|
|
|
|
|
|
me = (mutation->mutate_real)(x, y);
|
|
|
|
|
if (me == ME_OK) {
|
|
|
|
|
me = check_real_range(*x);
|
|
|
|
|
}
|
|
|
|
|
if (me != ME_OK) {
|
|
|
|
|
return ovsdb_mutation_scalar_error(me, mutation->mutator);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
NOT_REACHED();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < dst->n; i++) {
|
|
|
|
|
error = ovsdb_atom_check_constraints(&dst->keys[i], base);
|
|
|
|
|
if (error) {
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-25 14:59:33 -08:00
|
|
|
|
error = ovsdb_datum_sort(dst, dst_type->key.type);
|
2010-02-08 14:09:36 -08:00
|
|
|
|
if (error) {
|
|
|
|
|
ovsdb_error_destroy(error);
|
|
|
|
|
return ovsdb_error("constraint violation",
|
|
|
|
|
"Result of \"%s\" operation contains duplicates.",
|
|
|
|
|
ovsdb_mutator_to_string(mutation->mutator));
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct ovsdb_error *
|
|
|
|
|
ovsdb_mutation_check_count(struct ovsdb_datum *dst,
|
|
|
|
|
const struct ovsdb_type *dst_type)
|
|
|
|
|
{
|
|
|
|
|
if (!ovsdb_datum_conforms_to_type(dst, dst_type)) {
|
|
|
|
|
char *s = ovsdb_type_to_english(dst_type);
|
|
|
|
|
struct ovsdb_error *e = ovsdb_error(
|
2011-05-31 11:30:16 -07:00
|
|
|
|
"constraint violation",
|
2010-02-08 14:09:36 -08:00
|
|
|
|
"Attempted to store %u elements in %s.", dst->n, s);
|
|
|
|
|
free(s);
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ovsdb_error *
|
|
|
|
|
ovsdb_mutation_set_execute(struct ovsdb_row *row,
|
|
|
|
|
const struct ovsdb_mutation_set *set)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < set->n_mutations; i++) {
|
|
|
|
|
const struct ovsdb_mutation *m = &set->mutations[i];
|
|
|
|
|
struct ovsdb_datum *dst = &row->fields[m->column->index];
|
|
|
|
|
const struct ovsdb_type *dst_type = &m->column->type;
|
|
|
|
|
const struct ovsdb_datum *arg = &set->mutations[i].arg;
|
|
|
|
|
const struct ovsdb_type *arg_type = &m->type;
|
|
|
|
|
struct ovsdb_error *error;
|
|
|
|
|
|
|
|
|
|
switch (m->mutator) {
|
|
|
|
|
case OVSDB_M_ADD:
|
|
|
|
|
error = mutate_scalar(dst_type, dst, &arg->keys[0], &add_mutation);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OVSDB_M_SUB:
|
|
|
|
|
error = mutate_scalar(dst_type, dst, &arg->keys[0], &sub_mutation);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OVSDB_M_MUL:
|
|
|
|
|
error = mutate_scalar(dst_type, dst, &arg->keys[0], &mul_mutation);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OVSDB_M_DIV:
|
|
|
|
|
error = mutate_scalar(dst_type, dst, &arg->keys[0], &div_mutation);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OVSDB_M_MOD:
|
|
|
|
|
error = mutate_scalar(dst_type, dst, &arg->keys[0], &mod_mutation);
|
|
|
|
|
break;
|
2009-12-16 10:49:31 -08:00
|
|
|
|
|
2010-02-08 14:09:36 -08:00
|
|
|
|
case OVSDB_M_INSERT:
|
|
|
|
|
ovsdb_datum_union(dst, arg, dst_type, false);
|
|
|
|
|
error = ovsdb_mutation_check_count(dst, dst_type);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OVSDB_M_DELETE:
|
|
|
|
|
ovsdb_datum_subtract(dst, dst_type, arg, arg_type);
|
|
|
|
|
error = ovsdb_mutation_check_count(dst, dst_type);
|
|
|
|
|
break;
|
2010-02-10 10:51:11 -08:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
NOT_REACHED();
|
2010-02-08 14:09:36 -08:00
|
|
|
|
}
|
|
|
|
|
if (error) {
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-16 10:49:31 -08:00
|
|
|
|
static int
|
|
|
|
|
add_int(int64_t *x, int64_t y)
|
|
|
|
|
{
|
|
|
|
|
/* Check for overflow. See _Hacker's Delight_ pp. 27. */
|
|
|
|
|
int64_t z = ~(*x ^ y) & INT64_MIN;
|
|
|
|
|
if ((~(*x ^ y) & ~(((*x ^ z) + y) ^ y)) >> 63) {
|
|
|
|
|
return ME_RANGE;
|
|
|
|
|
} else {
|
|
|
|
|
*x += y;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
sub_int(int64_t *x, int64_t y)
|
|
|
|
|
{
|
|
|
|
|
/* Check for overflow. See _Hacker's Delight_ pp. 27. */
|
|
|
|
|
int64_t z = (*x ^ y) & INT64_MIN;
|
|
|
|
|
if (((*x ^ y) & (((*x ^ z) - y) ^ y)) >> 63) {
|
|
|
|
|
return ME_RANGE;
|
|
|
|
|
} else {
|
|
|
|
|
*x -= y;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
mul_int(int64_t *x, int64_t y)
|
|
|
|
|
{
|
|
|
|
|
/* Check for overflow. See _Hacker's Delight_ pp. 30. */
|
|
|
|
|
if (*x > 0
|
|
|
|
|
? (y > 0
|
|
|
|
|
? *x >= INT64_MAX / y
|
|
|
|
|
: y < INT64_MIN / *x)
|
|
|
|
|
: (y > 0
|
|
|
|
|
? *x < INT64_MIN / y
|
|
|
|
|
: *x != 0 && y < INT64_MAX / y)) {
|
|
|
|
|
return ME_RANGE;
|
|
|
|
|
} else {
|
|
|
|
|
*x *= y;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
check_int_div(int64_t x, int64_t y)
|
|
|
|
|
{
|
|
|
|
|
/* Check for overflow. See _Hacker's Delight_ pp. 32. */
|
|
|
|
|
if (!y) {
|
|
|
|
|
return ME_DOM;
|
|
|
|
|
} else if (x == INT64_MIN && y == -1) {
|
|
|
|
|
return ME_RANGE;
|
|
|
|
|
} else {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
div_int(int64_t *x, int64_t y)
|
|
|
|
|
{
|
|
|
|
|
int error = check_int_div(*x, y);
|
|
|
|
|
if (!error) {
|
|
|
|
|
*x /= y;
|
|
|
|
|
}
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
mod_int(int64_t *x, int64_t y)
|
|
|
|
|
{
|
|
|
|
|
int error = check_int_div(*x, y);
|
|
|
|
|
if (!error) {
|
|
|
|
|
*x %= y;
|
|
|
|
|
}
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
add_double(double *x, double y)
|
|
|
|
|
{
|
|
|
|
|
*x += y;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
sub_double(double *x, double y)
|
|
|
|
|
{
|
|
|
|
|
*x -= y;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
mul_double(double *x, double y)
|
|
|
|
|
{
|
|
|
|
|
*x *= y;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
div_double(double *x, double y)
|
|
|
|
|
{
|
|
|
|
|
if (y == 0) {
|
|
|
|
|
return ME_DOM;
|
|
|
|
|
} else {
|
|
|
|
|
*x /= y;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-08 14:09:36 -08:00
|
|
|
|
static const struct ovsdb_scalar_mutation add_mutation = {
|
|
|
|
|
add_int, add_double, OVSDB_M_ADD
|
|
|
|
|
};
|
2009-12-16 10:49:31 -08:00
|
|
|
|
|
2010-02-08 14:09:36 -08:00
|
|
|
|
static const struct ovsdb_scalar_mutation sub_mutation = {
|
|
|
|
|
sub_int, sub_double, OVSDB_M_SUB
|
|
|
|
|
};
|
2009-12-16 10:49:31 -08:00
|
|
|
|
|
2010-02-08 14:09:36 -08:00
|
|
|
|
static const struct ovsdb_scalar_mutation mul_mutation = {
|
|
|
|
|
mul_int, mul_double, OVSDB_M_MUL
|
|
|
|
|
};
|
2009-12-16 10:49:31 -08:00
|
|
|
|
|
2010-02-08 14:09:36 -08:00
|
|
|
|
static const struct ovsdb_scalar_mutation div_mutation = {
|
|
|
|
|
div_int, div_double, OVSDB_M_DIV
|
|
|
|
|
};
|
2009-12-16 10:49:31 -08:00
|
|
|
|
|
2010-02-08 14:09:36 -08:00
|
|
|
|
static const struct ovsdb_scalar_mutation mod_mutation = {
|
|
|
|
|
mod_int, NULL, OVSDB_M_MOD
|
|
|
|
|
};
|