Add interval tree
This commit is contained in:
1
deps/CMakeLists.txt
vendored
1
deps/CMakeLists.txt
vendored
@@ -1,3 +1,4 @@
|
||||
add_subdirectory(timeout)
|
||||
add_subdirectory(dablooms)
|
||||
add_subdirectory(toml)
|
||||
add_subdirectory(interval_tree)
|
||||
4
deps/dablooms/test/CMakeLists.txt
vendored
4
deps/dablooms/test/CMakeLists.txt
vendored
@@ -1,7 +1,3 @@
|
||||
###############################################################################
|
||||
# gtest
|
||||
###############################################################################
|
||||
|
||||
add_executable(gtest_dablooms gtest_dablooms.cpp)
|
||||
target_link_libraries(gtest_dablooms dablooms gtest)
|
||||
|
||||
|
||||
4
deps/interval_tree/CMakeLists.txt
vendored
Normal file
4
deps/interval_tree/CMakeLists.txt
vendored
Normal 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
71
deps/interval_tree/interval.cpp
vendored
Normal 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
59
deps/interval_tree/interval.h
vendored
Normal 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
277
deps/interval_tree/interval_list.cpp
vendored
Normal 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
57
deps/interval_tree/interval_list.h
vendored
Normal 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
629
deps/interval_tree/itree.cpp
vendored
Normal 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
77
deps/interval_tree/itree.h
vendored
Normal 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_ */
|
||||
5
deps/interval_tree/test/CMakeLists.txt
vendored
Normal file
5
deps/interval_tree/test/CMakeLists.txt
vendored
Normal 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)
|
||||
336
deps/interval_tree/test/gtest_interval_tree.cpp
vendored
Normal file
336
deps/interval_tree/test/gtest_interval_tree.cpp
vendored
Normal 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();
|
||||
}
|
||||
@@ -958,19 +958,21 @@ static inline const char *parse_udp(struct packet *pkt, const char *data, uint16
|
||||
struct udphdr *hdr = (struct udphdr *)data;
|
||||
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
|
||||
// VXLAN_DPORT
|
||||
case 4789:
|
||||
// VXLAN_DPORT 4789
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user