Add interval tree

This commit is contained in:
luwenpeng
2024-03-21 10:06:11 +08:00
parent 1cdbb7c2a4
commit 36b9a8282a
12 changed files with 1528 additions and 14 deletions

1
deps/CMakeLists.txt vendored
View File

@@ -1,3 +1,4 @@
add_subdirectory(timeout) add_subdirectory(timeout)
add_subdirectory(dablooms) add_subdirectory(dablooms)
add_subdirectory(toml) add_subdirectory(toml)
add_subdirectory(interval_tree)

View File

@@ -1,7 +1,3 @@
###############################################################################
# gtest
###############################################################################
add_executable(gtest_dablooms gtest_dablooms.cpp) add_executable(gtest_dablooms gtest_dablooms.cpp)
target_link_libraries(gtest_dablooms dablooms gtest) target_link_libraries(gtest_dablooms dablooms gtest)

4
deps/interval_tree/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,4 @@
add_library(interval_tree STATIC interval.cpp interval_list.cpp itree.cpp)
target_include_directories(interval_tree PUBLIC ${CMAKE_CURRENT_LIST_DIR})
add_subdirectory(test)

71
deps/interval_tree/interval.cpp vendored Normal file
View File

@@ -0,0 +1,71 @@
/*
* Libitree: an interval tree library in C
*
* Copyright (C) 2018 Alessandro Vullo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "interval.h"
#include <stdlib.h>
interval_t *interval_new(uint64_t low, uint64_t high, void *data, dup_f dup, rel_f rel)
{
interval_t *ri = (interval_t *)malloc(sizeof *ri);
if (ri == NULL)
{
return NULL;
}
ri->low = low;
ri->high = high;
ri->dup = dup;
ri->rel = rel;
ri->data = ri->dup(data);
return ri;
}
interval_t *interval_copy(const interval_t *i)
{
return interval_new(i->low, i->high, i->data, i->dup, i->rel);
}
void interval_delete(interval_t *i)
{
if (i != NULL)
{
if (i->data)
{
i->rel(i->data);
}
free(i);
}
}
int interval_overlap(const interval_t *i1, const interval_t *i2)
{
return i1->low <= i2->high && i2->low <= i1->high;
}
int interval_equal(const interval_t *i1, const interval_t *i2)
{
return i1->low == i2->low && i1->high == i2->high;
}

59
deps/interval_tree/interval.h vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* Libitree: an interval tree library in C
*
* Copyright (C) 2018 Alessandro Vullo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _INTERVAL_H_
#define _INTERVAL_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include <stddef.h>
#include <stdint.h>
/* User-defined item handling */
typedef void *(*dup_f)(void *p);
typedef void (*rel_f)(void *p);
typedef struct interval
{
uint64_t low, high; /* Interval boundaries, inclusive */
void *data; /* User-defined content */
dup_f dup; /* Clone an interval data item */
rel_f rel; /* Destroy an interval data item */
} interval_t;
/* Interval functions */
interval_t *interval_new(uint64_t low, uint64_t high, void *data, dup_f dup, rel_f rel);
interval_t *interval_copy(const interval_t *i);
void interval_delete(interval_t *i);
int interval_overlap(const interval_t *i1, const interval_t *i2);
int interval_equal(const interval_t *i1, const interval_t *i2);
#ifdef __cplusplus
}
#endif
#endif /* _INTERVAL_H_ */

277
deps/interval_tree/interval_list.cpp vendored Normal file
View File

@@ -0,0 +1,277 @@
/*
* Libitree: an interval tree library in C
*
* Copyright (C) 2018 Alessandro Vullo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "interval_list.h"
#include <stdlib.h>
#include <stdio.h>
#ifndef HEIGHT_LIMIT
#define HEIGHT_LIMIT 64
#endif
/* Note: doesn't own the interval, comes from the tree
which is responsible for deallocating the interval. */
typedef struct ilistnode
{
const interval_t *interval;
struct ilistnode *next;
} ilistnode_t;
struct ilist
{
ilistnode_t *head, *tail; /* Dummy nodes */
size_t size;
};
struct ilisttrav
{
ilist_t *list; /* Paired list */
ilistnode_t *it; /* Current node */
};
static ilistnode_t *ilistnode_new(const interval_t *i, ilistnode_t *next)
{
ilistnode_t *node = (ilistnode_t *)malloc(sizeof *node);
if (node != NULL)
{
node->interval = i; /* NOTE: doesn't own the interval, pointer aliasing */
node->next = next;
}
return node;
}
/*
Destroy a single node, assuming it's been unlinked.
Returns the next node specified by the link.
*/
ilistnode_t *ilistnode_delete(ilistnode_t *node)
{
ilistnode_t *next = NULL;
if (node != NULL)
{
/* Save a reference to the next node
since we're about to destroy this one */
next = node->next;
free(node);
}
return next;
}
ilist_t *ilist_new()
{
ilist_t *list = (ilist_t *)malloc(sizeof *list);
if (list != NULL)
{
ilistnode_t *tail = ilistnode_new(NULL, NULL);
if (tail == NULL)
{
free(list);
list = NULL;
}
else
{
list->tail = tail;
list->head = ilistnode_new(NULL, list->tail);
if (list->head == NULL)
{
free(list);
list = NULL;
}
list->size = 0;
}
}
return list;
}
void ilist_delete(ilist_t *list)
{
if (list == NULL)
{
return;
}
ilistnode_t *it = list->head;
while (it != list->tail)
{
it = ilistnode_delete(it);
}
ilistnode_delete(it); /* Delete tail */
free(list);
}
size_t ilist_size(ilist_t *list)
{
return list->size;
}
static ilistnode_t *insert_before(ilist_t *, ilistnode_t *, interval_t *);
static ilistnode_t *insert_after(ilist_t *list, ilistnode_t *pos, interval_t *i)
{
ilistnode_t *node = NULL;
if (list != NULL && pos != NULL)
{
if (pos != list->tail)
{
node = ilistnode_new(i, pos->next);
if (node != NULL)
{
pos->next = node;
++list->size;
}
}
else
{
node = insert_before(list, pos, i);
}
}
return node;
}
static ilistnode_t *insert_before(ilist_t *list, ilistnode_t *pos, interval_t *i)
{
ilistnode_t *node = NULL;
if (list != NULL && pos != NULL)
{
if (pos != list->head)
{
/* Find the previous node */
ilistnode_t *it = list->head;
while (it->next != pos)
{
it = it->next;
}
/* Create a new node and set the new link */
node = ilistnode_new(i, it->next);
if (node != NULL)
{
it->next = node;
++list->size;
}
}
else
{
node = insert_after(list, pos, i);
}
}
return node;
}
int ilist_append(ilist_t *list, interval_t *i)
{
ilistnode_t *node = insert_before(list, list->tail, i);
if (node != NULL)
{
return 1;
}
return 0;
}
ilisttrav_t *ilisttrav_new(ilist_t *list)
{
if (list == NULL)
{
return NULL;
}
ilisttrav_t *trav = (ilisttrav_t *)malloc(sizeof(ilisttrav_t));
if (trav != NULL)
{
trav->list = list;
}
return trav;
}
void ilisttrav_delete(ilisttrav_t *trav)
{
free(trav);
}
const interval_t *ilisttrav_first(ilisttrav_t *trav)
{
if (trav->list == NULL)
{
return NULL;
}
trav->it = trav->list->head->next;
return trav->it == NULL || trav->it == trav->list->tail ? NULL : trav->it->interval;
}
const interval_t *ilisttrav_last(ilisttrav_t *trav)
{
if (trav->list == NULL)
{
return NULL;
}
trav->it = trav->list->head;
while (trav->it->next != trav->list->tail)
{
trav->it = trav->it->next;
}
return trav->it == trav->list->head || trav->it == NULL ? NULL : trav->it->interval;
}
const interval_t *ilisttrav_next(ilisttrav_t *trav)
{
if (trav == NULL)
{
return NULL;
}
trav->it = trav->it->next;
return trav->it == NULL || trav->it == trav->list->tail ? NULL : trav->it->interval;
}
/* Very inefficient, need a doubly linked list to properly support this */
const interval_t *ilisttrav_prev(ilisttrav_t *trav)
{
if (trav == NULL)
{
return NULL;
}
ilistnode_t *it = trav->list->head;
while (it->next != trav->it)
{
it = it->next;
}
trav->it = it;
return trav->it == trav->list->head || trav->it == NULL ? NULL : trav->it->interval;
}

57
deps/interval_tree/interval_list.h vendored Normal file
View File

@@ -0,0 +1,57 @@
/*
* Libitree: an interval tree library in C
*
* Copyright (C) 2018 Alessandro Vullo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _INTERVAL_LIST_H_
#define _INTERVAL_LIST_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include "interval.h"
/* Declarations for an interval list, opaque types */
typedef struct ilist ilist_t;
typedef struct ilisttrav ilisttrav_t;
/* Interval list functions */
ilist_t *ilist_new();
void ilist_delete(ilist_t *list);
size_t ilist_size(ilist_t *list);
int ilist_append(ilist_t *list, interval_t *i);
/* Interval list traversal functions */
ilisttrav_t *ilisttrav_new(ilist_t *list);
void ilisttrav_delete(ilisttrav_t *trav);
const interval_t *ilisttrav_first(ilisttrav_t *trav);
const interval_t *ilisttrav_last(ilisttrav_t *trav);
const interval_t *ilisttrav_next(ilisttrav_t *trav);
const interval_t *ilisttrav_prev(ilisttrav_t *trav);
#ifdef __cplusplus
}
#endif
#endif /* _INTERVAL_LIST_H_ */

629
deps/interval_tree/itree.cpp vendored Normal file
View File

@@ -0,0 +1,629 @@
/*
* Libitree: an interval tree library in C
*
* Copyright (C) 2018 Alessandro Vullo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
Interval Tree library
This is an adaptation of the AVL balanced tree C library
created by Julienne Walker which can be found here:
http://www.eternallyconfuzzled.com/Libraries.aspx
*/
#include "itree.h"
#include <stdlib.h>
#ifndef HEIGHT_LIMIT
#define HEIGHT_LIMIT 64 /* Tallest allowable tree */
#endif
typedef struct itreenode
{
int balance; /* Balance factor */
uint64_t max; /* Maximum high value in the subtree rooted at this node */
interval_t *interval; /* The interval the node represents */
struct itreenode *link[2]; /* Left (0) and right (1) links */
} itreenode_t;
struct itree
{
itreenode_t *root; /* Top of the tree */
dup_f dup; /* Clone an interval data item (user-defined) */
rel_f rel; /* Destroy an interval data item (user-defined) */
size_t size; /* Number of items (user-defined) */
};
struct itreetrav
{
itree_t *tree; /* Paired tree */
itreenode_t *it; /* Current node */
itreenode_t *path[HEIGHT_LIMIT]; /* Traversal path */
size_t top; /* Top of stack */
};
/* Two way single rotation */
#define single(root, dir) \
do \
{ \
itreenode_t *save = root->link[!dir]; \
root->link[!dir] = save->link[dir]; \
save->link[dir] = root; \
root = save; \
} while (0)
/* Two way double rotation */
#define double(root, dir) \
do \
{ \
itreenode_t *save = root->link[!dir]->link[dir]; \
root->link[!dir]->link[dir] = save->link[!dir]; \
save->link[!dir] = root->link[!dir]; \
root->link[!dir] = save; \
save = root->link[!dir]; \
root->link[!dir] = save->link[dir]; \
save->link[dir] = root; \
root = save; \
} while (0)
/* Adjust balance before double rotation */
#define adjust_balance(root, dir, bal) \
do \
{ \
itreenode_t *n = root->link[dir]; \
itreenode_t *nn = n->link[!dir]; \
if (nn->balance == 0) \
{ \
root->balance = n->balance = 0; \
} \
else if (nn->balance == bal) \
{ \
root->balance = -bal; \
n->balance = 0; \
} \
else \
{ /* nn->balance == -bal */ \
root->balance = 0; \
n->balance = bal; \
} \
nn->balance = 0; \
} while (0)
/* Rebalance after insertion */
#define insert_balance(root, dir) \
do \
{ \
itreenode_t *n = root->link[dir]; \
int bal = dir == 0 ? -1 : +1; \
if (n->balance == bal) \
{ \
root->balance = n->balance = 0; \
single(root, !dir); \
} \
else \
{ /* n->balance == -bal */ \
adjust_balance(root, dir, bal); \
double(root, !dir); \
} \
} while (0)
/* Rebalance after deletion */
#define remove_balance(root, dir, done) \
do \
{ \
itreenode_t *n = root->link[!dir]; \
int bal = dir == 0 ? -1 : +1; \
if (n->balance == -bal) \
{ \
root->balance = n->balance = 0; \
single(root, dir); \
} \
else if (n->balance == bal) \
{ \
adjust_balance(root, !dir, -bal); \
double(root, dir); \
} \
else \
{ /* n->balance == 0 */ \
root->balance = -bal; \
n->balance = bal; \
single(root, dir); \
done = 1; \
} \
} while (0)
static itreenode_t *new_node(itree_t *tree, interval_t *i)
{
itreenode_t *rn = (itreenode_t *)malloc(sizeof *rn);
if (rn == NULL)
{
return NULL;
}
rn->interval = (interval_t *)malloc(sizeof(interval_t));
if (rn->interval == NULL)
{
return NULL;
}
rn->interval->low = i->low;
rn->interval->high = i->high;
rn->interval->data = tree->dup(i->data);
rn->balance = 0;
rn->max = i->high;
rn->link[0] = rn->link[1] = NULL;
return rn;
}
itree_t *itree_new(dup_f dup, rel_f rel)
{
itree_t *rt = (itree_t *)malloc(sizeof *rt);
if (rt == NULL)
{
return NULL;
}
rt->root = NULL;
rt->dup = dup;
rt->rel = rel;
rt->size = 0;
return rt;
}
void itree_delete(itree_t *tree)
{
itreenode_t *it = tree->root;
itreenode_t *save;
/* Destruction by rotation */
while (it != NULL)
{
if (it->link[0] == NULL)
{
/* Remove node */
save = it->link[1];
tree->rel(it->interval->data);
free(it->interval);
free(it);
}
else
{
/* Rotate right */
save = it->link[0];
it->link[0] = save->link[1];
save->link[1] = it;
}
it = save;
}
free(tree);
}
interval_t *itree_find(itree_t *tree, interval_t *interval)
{
itreenode_t *it = tree->root;
while (it != NULL)
{
/* int cmp = tree->cmp ( it->data, data ); */
/* if ( cmp == 0 ) */
/* break; */
/* it = it->link[cmp < 0]; */
if (interval_overlap(it->interval, interval))
{
break;
}
it = it->link[it->link[0] == NULL || it->link[0]->max < interval->low];
}
return it == NULL ? NULL : it->interval;
}
void search(itreenode_t *node, interval_t *interval, ilist_t *results)
{
/*
* If interval is to the right of the rightmost point of any interval
* in this node and all its children, there won't be any matches
*/
if (node == NULL || interval->low > node->max)
{
return;
}
/* search the left subtree */
if (node->link[0] != NULL && node->link[0]->max >= interval->low)
{
search(node->link[0], interval, results);
}
/* search this node */
if (interval_overlap(node->interval, interval))
{
ilist_append(results, node->interval);
}
/*
* if interval is to the left of the start of this interval
* it can't be in any child to the right
*/
if (interval->high < node->interval->low)
{
return;
}
/* search the right subtree */
search(node->link[1], interval, results);
}
ilist_t *itree_findall(itree_t *tree, interval_t *interval)
{
ilist_t *results = ilist_new();
if (results != NULL)
{
/* empty tree case */
if (tree->root == NULL)
{
return results;
}
search(tree->root, interval, results);
}
return results;
}
int itree_insert(itree_t *tree, interval_t *interval)
{
/* Empty tree case */
if (tree->root == NULL)
{
tree->root = new_node(tree, interval);
if (tree->root == NULL)
{
return 0;
}
}
else
{
itreenode_t head = {0}; /* Temporary tree root */
itreenode_t *s, *t; /* Place to rebalance and parent */
itreenode_t *p, *q; /* Iterator and save pointer to the newly inserted node */
int dir;
/* Set up false root to ease maintenance */
t = &head;
t->link[1] = tree->root;
/* Search down the tree, saving rebalance points */
for (s = p = t->link[1];; p = q)
{
/* Duplicates admitted, placed in the right subtree */
dir = p->interval->low <= interval->low; /* tree->cmp ( p->data, data ) < 0; */
q = p->link[dir];
p->max = p->max < interval->high ? interval->high : p->max; /* Update ancestor's max if needed */
if (q == NULL)
{
break;
}
if (q->balance != 0)
{
t = p;
s = q;
}
}
p->link[dir] = q = new_node(tree, interval);
if (q == NULL)
{
return 0; /* TODO: should rollback to previous ancestors' max values */
}
/* Update balance factors */
for (p = s; p != q; p = p->link[dir])
{
dir = p->interval->low <= interval->low; /* tree->cmp ( p->data, data ) < 0; */
p->balance += dir == 0 ? -1 : +1;
}
q = s; /* Save rebalance point for parent fix */
/* Rebalance if necessary */
if (abs(s->balance) > 1)
{
dir = s->interval->low <= interval->low; /* tree->cmp ( s->data, data ) < 0; */
insert_balance(s, dir);
}
/* Fix parent */
if (q == head.link[1])
{
tree->root = s;
}
else
{
t->link[q == t->link[1]] = s;
}
}
++tree->size;
return 1;
}
int itree_remove(itree_t *tree, interval_t *interval)
{
if (tree->root != NULL)
{
itreenode_t *it, *up[HEIGHT_LIMIT];
int upd[HEIGHT_LIMIT], top = 0, top_max;
int done = 0;
it = tree->root;
/* Search down tree and save path */
for (;;)
{
if (it == NULL)
{
return 0;
}
// else if (interval_equal(it->interval, interval))
else if (it->interval->low >= interval->low && it->interval->high <= interval->high)
{
break;
}
/* Push direction and node onto stack */
upd[top] = it->interval->low <= interval->low; /* tree->cmp ( it->data, data ) < 0; */
up[top++] = it;
it = it->link[upd[top - 1]];
}
/* Remove the node */
if (it->link[0] == NULL || it->link[1] == NULL)
{
/* Which child is not null? */
int dir = it->link[0] == NULL;
/* Fix parent */
if (top != 0)
{
up[top - 1]->link[upd[top - 1]] = it->link[dir];
}
else
{
tree->root = it->link[dir];
}
tree->rel(it->interval->data);
free(it->interval);
free(it);
}
else
{
/* Find the inorder successor */
itreenode_t *heir = it->link[1];
void *save;
/* Save this path too */
upd[top] = 1;
up[top++] = it;
while (heir->link[0] != NULL)
{
upd[top] = 0;
up[top++] = heir;
heir = heir->link[0];
}
/* Swap data */
save = it->interval;
it->interval = heir->interval;
heir->interval = (interval_t *)save;
/* Unlink successor and fix parent */
up[top - 1]->link[up[top - 1] == it] = heir->link[1];
tree->rel(heir->interval->data);
free(heir->interval);
free(heir);
}
/* Update max: walk back up the search path and bubbles up to root */
top_max = top;
while (--top_max >= 0)
{
itreenode_t *left = up[top_max]->link[0], *right = up[top_max]->link[1];
if (left != NULL && right != NULL)
{
uint64_t left_right_max = left->max < right->max ? right->max : left->max;
up[top_max]->max = up[top_max]->interval->high < left_right_max ? left_right_max : up[top_max]->interval->high;
}
else if (left != NULL && right == NULL)
{
up[top_max]->max = up[top_max]->interval->high < left->max ? left->max : up[top_max]->interval->high;
}
else if (left == NULL && right != NULL)
{
up[top_max]->max = up[top_max]->interval->high < right->max ? right->max : up[top_max]->interval->high;
}
else
{
up[top_max]->max = up[top_max]->interval->high;
}
}
/* Walk back up the search path */
while (--top >= 0 && !done)
{
/* Update balance factors */
up[top]->balance += upd[top] != 0 ? -1 : +1;
/* Terminate or rebalance as necessary */
if (abs(up[top]->balance) == 1)
{
break;
}
else if (abs(up[top]->balance) > 1)
{
remove_balance(up[top], upd[top], done);
/* Fix parent */
if (top != 0)
{
up[top - 1]->link[upd[top - 1]] = up[top];
}
else
{
tree->root = up[0];
}
}
}
--tree->size;
}
return 1;
}
size_t itree_size(itree_t *tree)
{
return tree->size;
}
itreetrav_t *itreetnew(void)
{
return (itreetrav_t *)malloc(sizeof(itreetrav_t));
}
void itreetdelete(itreetrav_t *trav)
{
free(trav);
}
/*
First step in traversal,
handles min and max
*/
static interval_t *start(itreetrav_t *trav, itree_t *tree, int dir)
{
trav->tree = tree;
trav->it = tree->root;
trav->top = 0;
/* Build a path to work with */
if (trav->it != NULL)
{
while (trav->it->link[dir] != NULL)
{
trav->path[trav->top++] = trav->it;
trav->it = trav->it->link[dir];
}
}
#ifdef DEBUG
if (trav->it)
printf("[%.1f, %.1f] (%d) (%.1f)\n", trav->it->interval->low, trav->it->interval->high, *(int *)trav->it->interval->data, trav->it->max);
#endif
return trav->it == NULL ? NULL : trav->it->interval;
}
/*
Subsequent traversal steps,
handles ascending and descending
*/
static interval_t *move(itreetrav_t *trav, int dir)
{
if (trav->it->link[dir] != NULL)
{
/* Continue down this branch */
trav->path[trav->top++] = trav->it;
trav->it = trav->it->link[dir];
while (trav->it->link[!dir] != NULL)
{
trav->path[trav->top++] = trav->it;
trav->it = trav->it->link[!dir];
}
}
else
{
/* Move to the next branch */
itreenode_t *last;
do
{
if (trav->top == 0)
{
trav->it = NULL;
{
break;
}
}
last = trav->it;
trav->it = trav->path[--trav->top];
} while (last == trav->it->link[dir]);
}
#ifdef DEBUG
if (trav->it)
printf("[%.1f, %.1f] (%d) (%.1f)\n", trav->it->interval->low, trav->it->interval->high, *(int *)trav->it->interval->data, trav->it->max);
#endif
return trav->it == NULL ? NULL : trav->it->interval;
}
interval_t *itreetfirst(itreetrav_t *trav, itree_t *tree)
{
return start(trav, tree, 0); /* Min value */
}
interval_t *itreetlast(itreetrav_t *trav, itree_t *tree)
{
return start(trav, tree, 1); /* Max value */
}
interval_t *itreetnext(itreetrav_t *trav)
{
return move(trav, 1); /* Toward larger items */
}
interval_t *itreetprev(itreetrav_t *trav)
{
return move(trav, 0); /* Toward smaller items */
}

77
deps/interval_tree/itree.h vendored Normal file
View File

@@ -0,0 +1,77 @@
/*
* Libitree: an interval tree library in C
*
* Copyright (C) 2018 Alessandro Vullo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _INTERVAL_TREE_H_
#define _INTERVAL_TREE_H_
/*
Interval Tree library
This is an adaptation of the AVL balanced tree C library
created by Julienne Walker which can be found here:
http://www.eternallyconfuzzled.com/Libraries.aspx
*/
#ifdef __cplusplus
extern "C"
{
#endif
#include "interval.h"
#include "interval_list.h"
/* Opaque types */
typedef struct itree itree_t;
typedef struct itreetrav itreetrav_t;
/* User-defined interval data item handling */
typedef void *(*dup_f)(void *p);
typedef void (*rel_f)(void *p);
/* Interval tree functions */
itree_t *itree_new(dup_f dup, rel_f rel);
void itree_delete(itree_t *tree);
// Find the first interval containing the specified interval
interval_t *itree_find(itree_t *tree, interval_t *interval);
ilist_t *itree_findall(itree_t *tree, interval_t *interval);
int itree_insert(itree_t *tree, interval_t *interval);
// Delete the first interval contained by the specified interval
int itree_remove(itree_t *tree, interval_t *interval);
size_t itree_size(itree_t *tree);
/* Tree traversal functions */
itreetrav_t *itreetnew(void);
void itreetdelete(itreetrav_t *trav);
interval_t *itreetfirst(itreetrav_t *trav, itree_t *tree);
interval_t *itreetlast(itreetrav_t *trav, itree_t *tree);
interval_t *itreetnext(itreetrav_t *trav);
interval_t *itreetprev(itreetrav_t *trav);
#ifdef __cplusplus
}
#endif
#endif /* _INTERVAL_TREE_H_ */

View File

@@ -0,0 +1,5 @@
add_executable(gtest_interval_tree gtest_interval_tree.cpp)
target_link_libraries(gtest_interval_tree interval_tree gtest)
include(GoogleTest)
gtest_discover_tests(gtest_interval_tree)

View File

@@ -0,0 +1,336 @@
#include <gtest/gtest.h>
#include "itree.h"
void *my_dup(void *p)
{
return p ? strdup((const char *)p) : NULL;
}
void my_rel(void *p)
{
if (p)
{
free(p);
}
}
// find overlap
#if 1
TEST(INTERVAL_TREE, FIND)
{
itree_t *tree;
interval_t *result;
interval_t query;
interval_t segment;
// new
tree = itree_new(my_dup, my_rel);
EXPECT_TRUE(tree != nullptr);
EXPECT_TRUE(itree_size(tree) == 0);
// insert
segment = {
.low = 5,
.high = 9,
.data = (void *)"Hello",
};
EXPECT_TRUE(itree_insert(tree, &segment) == 1);
EXPECT_TRUE(itree_size(tree) == 1);
// find
query = {
.low = 5,
.high = 5,
};
result = itree_find(tree, &query);
EXPECT_TRUE(result != nullptr);
EXPECT_TRUE(result->low == 5);
EXPECT_TRUE(result->high == 9);
EXPECT_STREQ((const char *)result->data, "Hello");
// find
query = {
.low = 6,
.high = 8,
};
result = itree_find(tree, &query);
EXPECT_TRUE(result != nullptr);
EXPECT_TRUE(result->low == 5);
EXPECT_TRUE(result->high == 9);
EXPECT_STREQ((const char *)result->data, "Hello");
// find
query = {
.low = 5,
.high = 9,
};
result = itree_find(tree, &query);
EXPECT_TRUE(result != nullptr);
EXPECT_TRUE(result->low == 5);
EXPECT_TRUE(result->high == 9);
EXPECT_STREQ((const char *)result->data, "Hello");
// find
query = {
.low = 9,
.high = 9,
};
result = itree_find(tree, &query);
EXPECT_TRUE(result != nullptr);
EXPECT_TRUE(result->low == 5);
EXPECT_TRUE(result->high == 9);
EXPECT_STREQ((const char *)result->data, "Hello");
// find
query = {
.low = 1,
.high = 14,
};
result = itree_find(tree, &query);
EXPECT_TRUE(result != nullptr);
EXPECT_TRUE(result->low == 5);
EXPECT_TRUE(result->high == 9);
EXPECT_STREQ((const char *)result->data, "Hello");
// not found
query = {
.low = 1,
.high = 4,
};
result = itree_find(tree, &query);
EXPECT_TRUE(result == nullptr);
// not found
query = {
.low = 10,
.high = 14,
};
result = itree_find(tree, &query);
itree_delete(tree);
}
#endif
#if 1
TEST(INTERVAL_TREE, DELETE1)
{
itree_t *tree;
interval_t query;
interval_t segment;
// new
tree = itree_new(my_dup, my_rel);
EXPECT_TRUE(tree != nullptr);
EXPECT_TRUE(itree_size(tree) == 0);
// insert
segment = {
.low = 5,
.high = 9,
.data = (void *)"Hello",
};
EXPECT_TRUE(itree_insert(tree, &segment) == 1);
EXPECT_TRUE(itree_size(tree) == 1);
// delete
query = {
.low = 5,
.high = 5,
};
EXPECT_TRUE(itree_remove(tree, &query) == 0);
EXPECT_TRUE(itree_size(tree) == 1);
// delete
query = {
.low = 9,
.high = 9,
};
EXPECT_TRUE(itree_remove(tree, &query) == 0);
EXPECT_TRUE(itree_size(tree) == 1);
// delete
query = {
.low = 5,
.high = 9,
};
EXPECT_TRUE(itree_remove(tree, &query) == 1);
EXPECT_TRUE(itree_size(tree) == 0);
itree_delete(tree);
}
#endif
#if 1
TEST(INTERVAL_TREE, DELETE2)
{
itree_t *tree;
interval_t query;
interval_t segment;
// new
tree = itree_new(my_dup, my_rel);
EXPECT_TRUE(tree != nullptr);
EXPECT_TRUE(itree_size(tree) == 0);
// insert
segment = {
.low = 5,
.high = 9,
.data = (void *)"Hello",
};
EXPECT_TRUE(itree_insert(tree, &segment) == 1);
EXPECT_TRUE(itree_size(tree) == 1);
// insert
segment = {
.low = 15,
.high = 19,
.data = (void *)"World",
};
EXPECT_TRUE(itree_insert(tree, &segment) == 1);
EXPECT_TRUE(itree_size(tree) == 2);
// delete
query = {
.low = 1,
.high = 20,
};
EXPECT_TRUE(itree_remove(tree, &query) == 1);
EXPECT_TRUE(itree_size(tree) == 1);
// delete
query = {
.low = 1,
.high = 20,
};
EXPECT_TRUE(itree_remove(tree, &query) == 1);
EXPECT_TRUE(itree_size(tree) == 0);
itree_delete(tree);
}
#endif
#if 1
TEST(INTERVAL_TREE, REPEAT1)
{
itree_t *tree;
interval_t segment;
interval_t query;
// new
tree = itree_new(my_dup, my_rel);
EXPECT_TRUE(tree != nullptr);
EXPECT_TRUE(itree_size(tree) == 0);
// insert
segment = {
.low = 5,
.high = 9,
.data = (void *)"Hello",
};
EXPECT_TRUE(itree_insert(tree, &segment) == 1);
EXPECT_TRUE(itree_size(tree) == 1);
// insert
segment = {
.low = 5,
.high = 9,
.data = (void *)"World",
};
EXPECT_TRUE(itree_insert(tree, &segment) == 1);
EXPECT_TRUE(itree_size(tree) == 2);
// remove
query = {
.low = 5,
.high = 9,
};
EXPECT_TRUE(itree_remove(tree, &query) == 1);
EXPECT_TRUE(itree_size(tree) == 1);
EXPECT_TRUE(itree_remove(tree, &query) == 1);
EXPECT_TRUE(itree_size(tree) == 0);
itree_delete(tree);
}
#endif
#if 1 // repeat, return the fist one
TEST(INTERVAL_TREE, REPEAT2)
{
itree_t *tree;
ilist_t *list;
ilisttrav_t *trav;
interval_t *result;
interval_t query;
interval_t segment;
// new
tree = itree_new(my_dup, my_rel);
EXPECT_TRUE(tree != nullptr);
EXPECT_TRUE(itree_size(tree) == 0);
// insert
segment = {
.low = 5,
.high = 9,
.data = (void *)"Hello",
};
EXPECT_TRUE(itree_insert(tree, &segment) == 1);
EXPECT_TRUE(itree_size(tree) == 1);
// insert
segment = {
.low = 5,
.high = 9,
.data = (void *)"World",
};
EXPECT_TRUE(itree_insert(tree, &segment) == 1);
EXPECT_TRUE(itree_size(tree) == 2);
// find
query = {
.low = 5,
.high = 9,
};
result = itree_find(tree, &query);
EXPECT_TRUE(result != nullptr);
EXPECT_TRUE(result->low == 5);
EXPECT_TRUE(result->high == 9);
EXPECT_STREQ((const char *)result->data, "Hello");
// find all, free the repeat
query = {
.low = 5,
.high = 9,
};
list = itree_findall(tree, &query);
EXPECT_TRUE(list != nullptr);
EXPECT_TRUE(ilist_size(list) == 2);
trav = ilisttrav_new(list);
EXPECT_TRUE(trav != nullptr);
result = (interval_t *)ilisttrav_first(trav);
EXPECT_TRUE(result != nullptr);
EXPECT_TRUE(result->low == 5);
EXPECT_TRUE(result->high == 9);
EXPECT_STREQ((const char *)result->data, "Hello");
result = (interval_t *)ilisttrav_next(trav);
EXPECT_TRUE(result != nullptr);
EXPECT_TRUE(result->low == 5);
EXPECT_TRUE(result->high == 9);
EXPECT_STREQ((const char *)result->data, "World");
ilisttrav_delete(trav);
ilist_delete(list);
itree_delete(tree);
}
#endif
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -958,19 +958,21 @@ static inline const char *parse_udp(struct packet *pkt, const char *data, uint16
struct udphdr *hdr = (struct udphdr *)data; struct udphdr *hdr = (struct udphdr *)data;
SET_LAYER(pkt, layer, LAYER_TYPE_UDP, sizeof(struct udphdr), data, len); SET_LAYER(pkt, layer, LAYER_TYPE_UDP, sizeof(struct udphdr), data, len);
switch (udp_hdr_get_dst_port(hdr)) if (udp_hdr_get_dst_port(hdr) == 4789)
{ {
// TESTED // TESTED
// VXLAN_DPORT // VXLAN_DPORT 4789
case 4789:
return parse_vxlan(pkt, layer->pld_ptr, layer->pld_len); return parse_vxlan(pkt, layer->pld_ptr, layer->pld_len);
// TESTED
// GTP1U_PORT
case 2152:
return parse_gtpv1_u(pkt, layer->pld_ptr, layer->pld_len);
default:
return layer->pld_ptr;
} }
if (udp_hdr_get_dst_port(hdr) == 2152 || udp_hdr_get_src_port(hdr) == 2152)
{
// TESTED
// GTP1U_PORT 2152
return parse_gtpv1_u(pkt, layer->pld_ptr, layer->pld_len);
}
return layer->pld_ptr;
} }
static inline const char *parse_tcp(struct packet *pkt, const char *data, uint16_t len) static inline const char *parse_tcp(struct packet *pkt, const char *data, uint16_t len)