Filter: Add operators to find minimum and maximum element of sets
Add operators .min and .max to find minumum or maximum element in sets of types: clist, eclist, lclist. Example usage: bgp_community.min bgp_ext_community.max filter(bgp_large_community, [(as1, as2, *)]).min Signed-off-by: Alexander Zubkov <green@qrator.net>
This commit is contained in:
parent
e15e465720
commit
0e1fd7ea6a
7 changed files with 238 additions and 0 deletions
|
@ -287,6 +287,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
||||||
DEFINED,
|
DEFINED,
|
||||||
ADD, DELETE, CONTAINS, RESET,
|
ADD, DELETE, CONTAINS, RESET,
|
||||||
PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
|
PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
|
||||||
|
MIN, MAX,
|
||||||
EMPTY,
|
EMPTY,
|
||||||
FILTER, WHERE, EVAL, ATTRIBUTE,
|
FILTER, WHERE, EVAL, ATTRIBUTE,
|
||||||
BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
|
BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
|
||||||
|
@ -800,6 +801,8 @@ term:
|
||||||
| term '.' DATA { $$ = f_new_inst(FI_PAIR_DATA, $1); }
|
| term '.' DATA { $$ = f_new_inst(FI_PAIR_DATA, $1); }
|
||||||
| term '.' DATA1 { $$ = f_new_inst(FI_LC_DATA1, $1); }
|
| term '.' DATA1 { $$ = f_new_inst(FI_LC_DATA1, $1); }
|
||||||
| term '.' DATA2 { $$ = f_new_inst(FI_LC_DATA2, $1); }
|
| term '.' DATA2 { $$ = f_new_inst(FI_LC_DATA2, $1); }
|
||||||
|
| term '.' MIN { $$ = f_new_inst(FI_MIN, $1); }
|
||||||
|
| term '.' MAX { $$ = f_new_inst(FI_MAX, $1); }
|
||||||
|
|
||||||
/* Communities */
|
/* Communities */
|
||||||
/* This causes one shift/reduce conflict
|
/* This causes one shift/reduce conflict
|
||||||
|
|
|
@ -68,6 +68,17 @@ f_type_name(enum f_type t)
|
||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum f_type
|
||||||
|
f_type_element_type(enum f_type t)
|
||||||
|
{
|
||||||
|
switch(t) {
|
||||||
|
case T_CLIST: return T_PAIR;
|
||||||
|
case T_ECLIST: return T_EC;
|
||||||
|
case T_LCLIST: return T_LC;
|
||||||
|
default: return T_VOID;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const struct f_val f_const_empty_path = {
|
const struct f_val f_const_empty_path = {
|
||||||
.type = T_PATH,
|
.type = T_PATH,
|
||||||
.val.ad = &null_adata,
|
.val.ad = &null_adata,
|
||||||
|
|
|
@ -188,6 +188,8 @@ void trie_format(const struct f_trie *t, buffer *buf);
|
||||||
|
|
||||||
const char *f_type_name(enum f_type t);
|
const char *f_type_name(enum f_type t);
|
||||||
|
|
||||||
|
enum f_type f_type_element_type(enum f_type t);
|
||||||
|
|
||||||
int val_same(const struct f_val *v1, const struct f_val *v2);
|
int val_same(const struct f_val *v1, const struct f_val *v2);
|
||||||
int val_compare(const struct f_val *v1, const struct f_val *v2);
|
int val_compare(const struct f_val *v1, const struct f_val *v2);
|
||||||
void val_format(const struct f_val *v, buffer *buf);
|
void val_format(const struct f_val *v, buffer *buf);
|
||||||
|
|
|
@ -983,6 +983,74 @@
|
||||||
RESULT(T_INT, i, v1.val.lc.ldp2);
|
RESULT(T_INT, i, v1.val.lc.ldp2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INST(FI_MIN, 1, 1) { /* Get minimum element from set */
|
||||||
|
ARG_ANY(1);
|
||||||
|
RESULT_TYPE(f_type_element_type(v1.type));
|
||||||
|
switch(v1.type)
|
||||||
|
{
|
||||||
|
case T_CLIST:
|
||||||
|
{
|
||||||
|
u32 val = 0;
|
||||||
|
int_set_min(v1.val.ad, &val);
|
||||||
|
RESULT_(T_PAIR, i, val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_ECLIST:
|
||||||
|
{
|
||||||
|
u64 val = 0;
|
||||||
|
ec_set_min(v1.val.ad, &val);
|
||||||
|
RESULT_(T_EC, ec, val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_LCLIST:
|
||||||
|
{
|
||||||
|
lcomm val = { 0, 0, 0 };
|
||||||
|
lc_set_min(v1.val.ad, &val);
|
||||||
|
RESULT_(T_LC, lc, val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
runtime( "Clist or lclist expected" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INST(FI_MAX, 1, 1) { /* Get maximum element from set */
|
||||||
|
ARG_ANY(1);
|
||||||
|
RESULT_TYPE(f_type_element_type(v1.type));
|
||||||
|
switch(v1.type)
|
||||||
|
{
|
||||||
|
case T_CLIST:
|
||||||
|
{
|
||||||
|
u32 val = 0;
|
||||||
|
int_set_max(v1.val.ad, &val);
|
||||||
|
RESULT_(T_PAIR, i, val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_ECLIST:
|
||||||
|
{
|
||||||
|
u64 val = 0;
|
||||||
|
ec_set_max(v1.val.ad, &val);
|
||||||
|
RESULT_(T_EC, ec, val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_LCLIST:
|
||||||
|
{
|
||||||
|
lcomm val = { 0, 0, 0 };
|
||||||
|
lc_set_max(v1.val.ad, &val);
|
||||||
|
RESULT_(T_LC, lc, val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
runtime( "Clist or lclist expected" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
INST(FI_RETURN, 1, 1) {
|
INST(FI_RETURN, 1, 1) {
|
||||||
NEVER_CONSTANT;
|
NEVER_CONSTANT;
|
||||||
/* Acquire the return value */
|
/* Acquire the return value */
|
||||||
|
|
|
@ -781,6 +781,12 @@ clist r;
|
||||||
r = filter(l, [(3,1), (*,2)]);
|
r = filter(l, [(3,1), (*,2)]);
|
||||||
bt_assert(r = add(add(-empty-, (3,1)), (3,2)));
|
bt_assert(r = add(add(-empty-, (3,1)), (3,2)));
|
||||||
bt_assert(format(r) = "(clist (3,1) (3,2))");
|
bt_assert(format(r) = "(clist (3,1) (3,2))");
|
||||||
|
|
||||||
|
# minimim & maximum element
|
||||||
|
r = add(add(add(add(add(-empty-, (2,1)), (1,3)), (2,2)), (3,1)), (2,3));
|
||||||
|
bt_assert(format(r) = "(clist (2,1) (1,3) (2,2) (3,1) (2,3))");
|
||||||
|
bt_assert(r.min = (1,3));
|
||||||
|
bt_assert(r.max = (3,1));
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_test_suite(t_clist, "Testing lists of communities");
|
bt_test_suite(t_clist, "Testing lists of communities");
|
||||||
|
@ -886,6 +892,12 @@ eclist r;
|
||||||
r = filter(el, [(rt, 10, 1), (rt, 10, 25..30), (ro, 10, 40)]);
|
r = filter(el, [(rt, 10, 1), (rt, 10, 25..30), (ro, 10, 40)]);
|
||||||
bt_assert(r = add(add(--empty--, (rt, 10, 1)), (rt, 10, 30)));
|
bt_assert(r = add(add(--empty--, (rt, 10, 1)), (rt, 10, 30)));
|
||||||
bt_assert(format(r) = "(eclist (rt, 10, 1) (rt, 10, 30))");
|
bt_assert(format(r) = "(eclist (rt, 10, 1) (rt, 10, 30))");
|
||||||
|
|
||||||
|
# minimim & maximum element
|
||||||
|
r = add(add(add(add(add(--empty--, (rt, 2, 1)), (rt, 1, 3)), (rt, 2, 2)), (rt, 3, 1)), (rt, 2, 3));
|
||||||
|
bt_assert(format(r) = "(eclist (rt, 2, 1) (rt, 1, 3) (rt, 2, 2) (rt, 3, 1) (rt, 2, 3))");
|
||||||
|
bt_assert(r.min = (rt, 1, 3));
|
||||||
|
bt_assert(r.max = (rt, 3, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_test_suite(t_eclist, "Testing lists of extended communities");
|
bt_test_suite(t_eclist, "Testing lists of extended communities");
|
||||||
|
@ -995,6 +1007,12 @@ lclist r;
|
||||||
r = filter(ll, [(5..15, *, *), (20, 15..25, *)]);
|
r = filter(ll, [(5..15, *, *), (20, 15..25, *)]);
|
||||||
bt_assert(r = add(add(---empty---, (10, 10, 10)), (20, 20, 20)));
|
bt_assert(r = add(add(---empty---, (10, 10, 10)), (20, 20, 20)));
|
||||||
bt_assert(format(r) = "(lclist (10, 10, 10) (20, 20, 20))");
|
bt_assert(format(r) = "(lclist (10, 10, 10) (20, 20, 20))");
|
||||||
|
|
||||||
|
# minimim & maximum element
|
||||||
|
r = add(add(add(add(add(---empty---, (2, 3, 3)), (1, 2, 3)), (2, 3, 1)), (3, 1, 2)), (2, 1, 3));
|
||||||
|
bt_assert(format(r) = "(lclist (2, 3, 3) (1, 2, 3) (2, 3, 1) (3, 1, 2) (2, 1, 3))");
|
||||||
|
bt_assert(r.min = (1, 2, 3));
|
||||||
|
bt_assert(r.max = (3, 1, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_test_suite(t_lclist, "Testing lists of large communities");
|
bt_test_suite(t_lclist, "Testing lists of large communities");
|
||||||
|
|
130
nest/a-set.c
130
nest/a-set.c
|
@ -516,6 +516,48 @@ int_set_sort(struct linpool *pool, const struct adata *src)
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
int_set_min(const struct adata *list, u32 *val)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u32 *l = (u32 *) list->data;
|
||||||
|
int len = int_set_get_size(list);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (len < 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*val = *l++;
|
||||||
|
for (i = 1; i < len; i++, l++)
|
||||||
|
if (int_set_cmp(val, l) > 0)
|
||||||
|
*val = *l;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
int_set_max(const struct adata *list, u32 *val)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u32 *l = (u32 *) list->data;
|
||||||
|
int len = int_set_get_size(list);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (len < 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*val = *l++;
|
||||||
|
for (i = 1; i < len; i++, l++)
|
||||||
|
if (int_set_cmp(val, l) < 0)
|
||||||
|
*val = *l;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ec_set_cmp(const void *X, const void *Y)
|
ec_set_cmp(const void *X, const void *Y)
|
||||||
|
@ -541,6 +583,50 @@ ec_set_sort_x(struct adata *set)
|
||||||
qsort(set->data, set->length / 8, 8, ec_set_cmp);
|
qsort(set->data, set->length / 8, 8, ec_set_cmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ec_set_min(const struct adata *list, u64 *val)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u32 *l = int_set_get_data(list);
|
||||||
|
int len = int_set_get_size(list);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (len < 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u32 *res = l; l += 2;
|
||||||
|
for (i = 2; i < len; i += 2, l += 2)
|
||||||
|
if (ec_set_cmp(res, l) > 0)
|
||||||
|
res = l;
|
||||||
|
|
||||||
|
*val = ec_generic(res[0], res[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ec_set_max(const struct adata *list, u64 *val)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u32 *l = int_set_get_data(list);
|
||||||
|
int len = int_set_get_size(list);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (len < 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u32 *res = l; l += 2;
|
||||||
|
for (i = 2; i < len; i += 2, l += 2)
|
||||||
|
if (ec_set_cmp(res, l) < 0)
|
||||||
|
res = l;
|
||||||
|
|
||||||
|
*val = ec_generic(res[0], res[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lc_set_cmp(const void *X, const void *Y)
|
lc_set_cmp(const void *X, const void *Y)
|
||||||
|
@ -563,3 +649,47 @@ lc_set_sort(struct linpool *pool, const struct adata *src)
|
||||||
qsort(dst->data, dst->length / LCOMM_LENGTH, LCOMM_LENGTH, lc_set_cmp);
|
qsort(dst->data, dst->length / LCOMM_LENGTH, LCOMM_LENGTH, lc_set_cmp);
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lc_set_min(const struct adata *list, lcomm *val)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u32 *l = int_set_get_data(list);
|
||||||
|
int len = int_set_get_size(list);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (len < 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u32 *res = l; l += 3;
|
||||||
|
for (i = 3; i < len; i += 3, l += 3)
|
||||||
|
if (lc_set_cmp(res, l) > 0)
|
||||||
|
res = l;
|
||||||
|
|
||||||
|
*val = (lcomm) { res[0], res[1], res[2] };
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lc_set_max(const struct adata *list, lcomm *val)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u32 *l = int_set_get_data(list);
|
||||||
|
int len = int_set_get_size(list);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (len < 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u32 *res = l; l += 3;
|
||||||
|
for (i = 3; i < len; i += 3, l += 3)
|
||||||
|
if (lc_set_cmp(res, l) < 0)
|
||||||
|
res = l;
|
||||||
|
|
||||||
|
*val = (lcomm) { res[0], res[1], res[2] };
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
|
@ -218,6 +218,12 @@ struct adata *ec_set_del_nontrans(struct linpool *pool, const struct adata *set)
|
||||||
struct adata *int_set_sort(struct linpool *pool, const struct adata *src);
|
struct adata *int_set_sort(struct linpool *pool, const struct adata *src);
|
||||||
struct adata *ec_set_sort(struct linpool *pool, const struct adata *src);
|
struct adata *ec_set_sort(struct linpool *pool, const struct adata *src);
|
||||||
struct adata *lc_set_sort(struct linpool *pool, const struct adata *src);
|
struct adata *lc_set_sort(struct linpool *pool, const struct adata *src);
|
||||||
|
int int_set_min(const struct adata *list, u32 *val);
|
||||||
|
int ec_set_min(const struct adata *list, u64 *val);
|
||||||
|
int lc_set_min(const struct adata *list, lcomm *val);
|
||||||
|
int int_set_max(const struct adata *list, u32 *val);
|
||||||
|
int ec_set_max(const struct adata *list, u64 *val);
|
||||||
|
int lc_set_max(const struct adata *list, lcomm *val);
|
||||||
|
|
||||||
void ec_set_sort_x(struct adata *set); /* Sort in place */
|
void ec_set_sort_x(struct adata *set); /* Sort in place */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue