make versioned lists more flexible by using an external comparator
authorFelix Fietkau <nbd@openwrt.org>
Sun, 2 Oct 2011 17:22:08 +0000 (19:22 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 2 Oct 2011 17:22:08 +0000 (19:22 +0200)
interface-ip.c
interface-ip.h
utils.c
utils.h

index 2e2e9d8c5316111b85d54040e61e8cb268072219..084516994ec46547eb55237d52cec9d31fac89b7 100644 (file)
 #include "ubus.h"
 #include "system.h"
 
+static int
+addr_cmp(const void *k1, const void *k2, void *ptr)
+{
+       const struct device_addr *a1 = k1, *a2 = k2;
+
+       return memcmp(&a1->mask, &a2->mask,
+               sizeof(*a1) - offsetof(struct device_addr, mask));
+}
+
+static int
+route_cmp(const void *k1, const void *k2, void *ptr)
+{
+       const struct device_route *r1 = k1, *r2 = k2;
+
+       return memcmp(&r1->mask, &r2->mask,
+               sizeof(*r1) - offsetof(struct device_route, mask));
+}
+
 static void
 interface_update_proto_addr(struct vlist_tree *tree,
                            struct vlist_node *node_new,
@@ -65,9 +83,8 @@ interface_update_proto_route(struct vlist_tree *tree,
 void
 interface_ip_init(struct interface *iface)
 {
-       vlist_init(&iface->proto_route, interface_update_proto_route,
-                  struct device_route, node, mask, addr);
-       vlist_init(&iface->proto_addr, interface_update_proto_addr,
-                  struct device_addr, node, mask, addr);
+       vlist_init(&iface->proto_route, route_cmp, interface_update_proto_route,
+                  struct device_route, node);
+       vlist_init(&iface->proto_addr, addr_cmp, interface_update_proto_addr,
+                  struct device_addr, node);
 }
-
index ba7b6c826575cafe73e3cdda3c3108d38e33e7ef..057f0d05526b66dfce511010ccd9c23ce28e9db2 100644 (file)
@@ -24,6 +24,7 @@ struct device_addr {
 
        enum device_addr_flags flags;
 
+       /* must be last */
        unsigned int mask;
        union if_addr addr;
 };
@@ -34,10 +35,12 @@ struct device_route {
        enum device_addr_flags flags;
        bool keep;
 
-       unsigned int mask;
-       union if_addr addr;
        union if_addr nexthop;
        struct device *device;
+
+       /* must be last */
+       unsigned int mask;
+       union if_addr addr;
 };
 
 void interface_ip_init(struct interface *iface);
diff --git a/utils.c b/utils.c
index 15f0525941b9b31792dc3a467f720cea7e1f9df2..42d3176c4e9371b4f59bd07dc98ce3a15300fdef 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -7,22 +7,15 @@ avl_strcmp(const void *k1, const void *k2, void *ptr)
        return strcmp(k1, k2);
 }
 
-static int
-vlist_cmp(const void *k1, const void *k2, void *ptr)
-{
-       struct vlist_tree *vl = ptr;
-       return memcmp(k1, k2, vl->data_len);
-}
-
 void
-__vlist_init(struct vlist_tree *tree, vlist_update_cb update, int offset, int len)
+__vlist_init(struct vlist_tree *tree, avl_tree_comp cmp,
+            vlist_update_cb update, int offset)
 {
-       tree->data_offset = offset;
-       tree->data_len = len;
+       tree->node_offset = offset;
        tree->update = update;
        tree->version = 1;
 
-       avl_init(&tree->avl, vlist_cmp, 0, tree);
+       avl_init(&tree->avl, cmp, 0, tree);
 }
 
 void
@@ -37,11 +30,12 @@ vlist_add(struct vlist_tree *tree, struct vlist_node *node)
 {
        struct vlist_node *old_node = NULL;
        struct avl_node *anode;
+       void *key = (char *) node - tree->node_offset;
 
-       node->avl.key = (char *) node + tree->data_offset;
+       node->avl.key = key;
        node->version = tree->version;
 
-       anode = avl_find(&tree->avl, (char *) node + tree->data_offset);
+       anode = avl_find(&tree->avl, key);
        if (anode) {
                old_node = container_of(anode, struct vlist_node, avl);
                avl_delete(&tree->avl, anode);
diff --git a/utils.h b/utils.h
index e872dc55fff872080035fe550c798f280ca9ac78..c8101e7323a88bc790f806a2f058d414ed1886f2 100644 (file)
--- a/utils.h
+++ b/utils.h
@@ -27,9 +27,7 @@ struct vlist_tree {
        struct avl_tree avl;
 
        vlist_update_cb update;
-
-       int data_offset;
-       int data_len;
+       int node_offset;
 
        int version;
 };
@@ -39,11 +37,10 @@ struct vlist_node {
        int version;
 };
 
-void __vlist_init(struct vlist_tree *tree, vlist_update_cb update, int offset, int len);
+void __vlist_init(struct vlist_tree *tree, avl_tree_comp cmp, vlist_update_cb update, int offset);
 
-#define vlist_init(tree, update, type, vlist, first, last) \
-       __vlist_init(tree, update, offsetof(type, first) - offsetof(type, vlist), \
-                    offsetof(type, last) - offsetof(type, first) + sizeof(((type *) 0)->last))
+#define vlist_init(tree, cmp, update, type, node) \
+       __vlist_init(tree, cmp, update, offsetof(type, node))
 
 void vlist_add(struct vlist_tree *tree, struct vlist_node *node);
 void vlist_delete(struct vlist_tree *tree, struct vlist_node *node);