summaryrefslogtreecommitdiffstats
path: root/tools/apriori/rangesort.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/apriori/rangesort.c')
-rw-r--r--tools/apriori/rangesort.c317
1 files changed, 317 insertions, 0 deletions
diff --git a/tools/apriori/rangesort.c b/tools/apriori/rangesort.c
new file mode 100644
index 0000000..b0295e8
--- /dev/null
+++ b/tools/apriori/rangesort.c
@@ -0,0 +1,317 @@
+#include <common.h>
+#include <debug.h>
+#include <rangesort.h>
+
+#define PARALLEL_ARRAY_SIZE (5)
+
+struct range_list_t {
+ range_t *array;
+#ifdef DEBUG
+ int is_sorted;
+#endif
+ int array_length;
+ int num_ranges;
+};
+
+range_list_t* init_range_list(void) {
+ range_list_t *ranges = (range_list_t *)MALLOC(sizeof(range_list_t));
+
+ ranges->array = (range_t *)MALLOC(PARALLEL_ARRAY_SIZE*sizeof(range_t));
+ ranges->array_length = PARALLEL_ARRAY_SIZE;
+ ranges->num_ranges = 0;
+#ifdef DEBUG
+ ranges->is_sorted = 0;
+#endif
+ return ranges;
+}
+
+void destroy_range_list(range_list_t *ranges) {
+ int idx;
+ for (idx = 0; idx < ranges->num_ranges; idx++) {
+ if (ranges->array[idx].user_dtor) {
+ ASSERT(ranges->array[idx].user);
+ ranges->array[idx].user_dtor(ranges->array[idx].user);
+ }
+ }
+ FREE(ranges->array);
+ FREE(ranges);
+}
+
+static inline int CONTAINS(range_t *container, range_t *contained) {
+ return container->start <= contained->start && contained->length &&
+ (container->start + container->length >
+ contained->start + contained->length);
+}
+
+static inline int IN_RANGE(range_t *range, GElf_Off point) {
+ return
+ range->start <= point &&
+ point < (range->start + range->length);
+}
+
+static inline int INTERSECT(range_t *left, range_t *right) {
+ return
+ (IN_RANGE(left, right->start) &&
+ IN_RANGE(right, left->start + left->length)) ||
+ (IN_RANGE(right, left->start) &&
+ IN_RANGE(left, right->start + right->length));
+}
+
+static int range_cmp_for_search(const void *l, const void *r) {
+ range_t *left = (range_t *)l, *right = (range_t *)r;
+ if (INTERSECT(left, right) ||
+ CONTAINS(left, right) ||
+ CONTAINS(right, left)) {
+ return 0;
+ }
+ return left->start - right->start;
+}
+
+static inline void run_checks(const void *l, const void *r) {
+ range_t *left = (range_t *)l, *right = (range_t *)r;
+ if (CONTAINS(left, right)) {
+ if (left->err_fn)
+ left->err_fn(ERROR_CONTAINS, left, right);
+ FAILIF(1, "Range sorting error: [%lld, %lld) contains [%lld, %lld)!\n",
+ left->start, left->start + left->length,
+ right->start, right->start + right->length);
+ }
+ if (CONTAINS(right, left)) {
+ if (right->err_fn)
+ right->err_fn(ERROR_CONTAINS, left, right);
+ FAILIF(1, "Range sorting error: [%lld, %lld) contains [%lld, %lld)!\n",
+ right->start, right->start + right->length,
+ left->start, left->start + left->length);
+ }
+ if (INTERSECT(left, right)) {
+ if (left->err_fn)
+ left->err_fn(ERROR_OVERLAPS, left, right);
+ FAILIF(1, "Range sorting error: [%lld, %lld)and [%lld, %lld) intersect!\n",
+ left->start, left->start + left->length,
+ right->start, right->start + right->length);
+ }
+}
+
+static int range_cmp(const void *l, const void *r) {
+ run_checks(l, r);
+ range_t *left = (range_t *)l, *right = (range_t *)r;
+ return left->start - right->start;
+}
+
+void add_unique_range_nosort(
+ range_list_t *ranges,
+ GElf_Off start,
+ GElf_Off length,
+ void *user,
+ void (*err_fn)(range_error_t, range_t *, range_t *),
+ void (*user_dtor)(void * ))
+{
+ if (ranges->num_ranges == ranges->array_length) {
+ ranges->array_length += PARALLEL_ARRAY_SIZE;
+ ranges->array = REALLOC(ranges->array,
+ ranges->array_length*sizeof(range_t));
+ }
+ ranges->array[ranges->num_ranges].start = start;
+ ranges->array[ranges->num_ranges].length = length;
+ ranges->array[ranges->num_ranges].user = user;
+ ranges->array[ranges->num_ranges].err_fn = err_fn;
+ ranges->array[ranges->num_ranges].user_dtor = user_dtor;
+ ranges->num_ranges++;
+}
+
+range_list_t *sort_ranges(range_list_t *ranges) {
+ if (ranges->num_ranges > 1)
+ qsort(ranges->array, ranges->num_ranges, sizeof(range_t), range_cmp);
+ ranges->is_sorted = 1;
+ return ranges;
+}
+
+range_t *find_range(range_list_t *ranges, GElf_Off value) {
+#if 1
+ int i;
+ for (i = 0; i < ranges->num_ranges; i++) {
+ if (ranges->array[i].start <= value &&
+ value < ranges->array[i].start + ranges->array[i].length)
+ return ranges->array + i;
+ }
+ return NULL;
+#else
+ ASSERT(ranges->is_sorted); /* The range list must be sorted */
+ range_t lookup;
+ lookup.start = value;
+ lookup.length = 0;
+ return
+ (range_t *)bsearch(&lookup,
+ ranges->array, ranges->num_ranges, sizeof(range_t),
+ range_cmp_for_search);
+#endif
+}
+
+int get_num_ranges(const range_list_t *ranges)
+{
+ return ranges->num_ranges;
+}
+
+range_t *get_sorted_ranges(const range_list_t *ranges, int *num_ranges) {
+ ASSERT(ranges->is_sorted); /* The range list must be sorted */
+ if (num_ranges) {
+ *num_ranges = ranges->num_ranges;
+ }
+ return ranges->array;
+}
+
+GElf_Off get_last_address(const range_list_t *ranges) {
+ ASSERT(ranges->num_ranges);
+ return
+ ranges->array[ranges->num_ranges-1].start +
+ ranges->array[ranges->num_ranges-1].length;
+}
+
+static void handle_range_error(range_error_t err,
+ range_t *left, range_t *right) {
+ switch (err) {
+ case ERROR_CONTAINS:
+ ERROR("ERROR: section (%lld, %lld bytes) contains "
+ "section (%lld, %lld bytes)\n",
+ left->start, left->length,
+ right->start, right->length);
+ break;
+ case ERROR_OVERLAPS:
+ ERROR("ERROR: Section (%lld, %lld bytes) intersects "
+ "section (%lld, %lld bytes)\n",
+ left->start, left->length,
+ right->start, right->length);
+ break;
+ default:
+ ASSERT(!"Unknown range error code!");
+ }
+
+ FAILIF(1, "Range error.\n");
+}
+
+static void destroy_contiguous_range_info(void *user) {
+ contiguous_range_info_t *info = (contiguous_range_info_t *)user;
+ FREE(info->ranges);
+ FREE(info);
+}
+
+static void handle_contiguous_range_error(range_error_t err,
+ range_t *left,
+ range_t *right)
+{
+ contiguous_range_info_t *left_data =
+ (contiguous_range_info_t *)left->user;
+ ASSERT(left_data);
+ contiguous_range_info_t *right_data =
+ (contiguous_range_info_t *)right->user;
+ ASSERT(right_data);
+
+ PRINT("Contiguous-range overlap error. Printing contained ranges:\n");
+ int cnt;
+ PRINT("\tLeft ranges:\n");
+ for (cnt = 0; cnt < left_data->num_ranges; cnt++) {
+ PRINT("\t\t[%lld, %lld)\n",
+ left_data->ranges[cnt].start,
+ left_data->ranges[cnt].start + left_data->ranges[cnt].length);
+ }
+ PRINT("\tRight ranges:\n");
+ for (cnt = 0; cnt < right_data->num_ranges; cnt++) {
+ PRINT("\t\t[%lld, %lld)\n",
+ right_data->ranges[cnt].start,
+ right_data->ranges[cnt].start + right_data->ranges[cnt].length);
+ }
+
+ handle_range_error(err, left, right);
+}
+
+range_list_t* get_contiguous_ranges(const range_list_t *input)
+{
+ ASSERT(input);
+ FAILIF(!input->is_sorted,
+ "get_contiguous_ranges(): input range list is not sorted!\n");
+
+ range_list_t* ret = init_range_list();
+ int num_ranges;
+ range_t *ranges = get_sorted_ranges(input, &num_ranges);
+
+ int end_idx = 0;
+ while (end_idx < num_ranges) {
+ int start_idx = end_idx++;
+ int old_end_idx = start_idx;
+ int total_length = ranges[start_idx].length;
+ while (end_idx < num_ranges) {
+ if (ranges[old_end_idx].start + ranges[old_end_idx].length !=
+ ranges[end_idx].start)
+ break;
+ old_end_idx = end_idx++;
+ total_length += ranges[old_end_idx].length;
+ }
+
+ contiguous_range_info_t *user =
+ (contiguous_range_info_t *)MALLOC(sizeof(contiguous_range_info_t));
+ user->num_ranges = end_idx - start_idx;
+ user->ranges = (range_t *)MALLOC(user->num_ranges * sizeof(range_t));
+ int i;
+ for (i = 0; i < end_idx - start_idx; i++)
+ user->ranges[i] = ranges[start_idx + i];
+ add_unique_range_nosort(ret,
+ ranges[start_idx].start,
+ total_length,
+ user,
+ handle_contiguous_range_error,
+ destroy_contiguous_range_info);
+ }
+
+ return ret;
+}
+
+range_list_t* subtract_ranges(const range_list_t *r, const range_list_t *s)
+{
+ ASSERT(r); ASSERT(r->is_sorted);
+ ASSERT(s); ASSERT(s->is_sorted);
+
+ range_list_t *result = init_range_list();
+
+ int r_num_ranges, r_idx;
+ range_t *r_ranges = get_sorted_ranges(r, &r_num_ranges);
+ ASSERT(r_ranges);
+
+ int s_num_ranges, s_idx;
+ range_t *s_ranges = get_sorted_ranges(s, &s_num_ranges);
+ ASSERT(s_ranges);
+
+ s_idx = 0;
+ for (r_idx = 0; r_idx < r_num_ranges; r_idx++) {
+ GElf_Off last_start = r_ranges[r_idx].start;
+ for (; s_idx < s_num_ranges; s_idx++) {
+ if (CONTAINS(&r_ranges[r_idx], &s_ranges[s_idx])) {
+ if (last_start ==
+ r_ranges[r_idx].start + r_ranges[r_idx].length) {
+ break;
+ }
+ if (last_start == s_ranges[s_idx].start) {
+ last_start += s_ranges[s_idx].length;
+ continue;
+ }
+ INFO("Adding subtracted range [%lld, %lld)\n",
+ last_start,
+ s_ranges[s_idx].start);
+ add_unique_range_nosort(
+ result,
+ last_start,
+ s_ranges[s_idx].start - last_start,
+ NULL,
+ NULL,
+ NULL);
+ last_start = s_ranges[s_idx].start + s_ranges[s_idx].length;
+ } else {
+ ASSERT(!INTERSECT(&r_ranges[r_idx], &s_ranges[s_idx]));
+ break;
+ }
+ } /* while (s_idx < s_num_ranges) */
+ } /* for (r_idx = 0; r_idx < r_num_ranges; r_idx++) */
+
+ return result;
+}
+
+