Download
97 lines 2.8 KiBCModified 2022-07-23 raw
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
#include <stdint.h>

#include "types.h"
#include "gc.h"

int64_t RANGE_MIN = -999999999999999999;
int64_t RANGE_MAX = +999999999999999999;

range_t *range_new(int64_t first, int64_t next, int64_t last) {
    range_t *r = gc_alloc(sizeof(range_t));
    r->first = first;
    r->next = next;
    if (next != first && last != first) {
        int64_t len = (last - first) / (next - first);
        last = first + len * (next - first);
    }
    r->last = last;
    return r;
}

range_t *range_new_first_last(int64_t first, int64_t last) {
    range_t *r = gc_alloc(sizeof(range_t));
    r->first = first;
    r->next = first <= last ? first+1 : first-1;
    r->last = last;
    return r;
}

range_t *range_new_first_next(int64_t first, int64_t next) {
    range_t *r = gc_alloc(sizeof(range_t));
    r->first = first;
    r->next = next;
    r->last = next >= first ? RANGE_MAX : RANGE_MIN;
    return r;
}

int64_t range_len(range_t *r) {
    int64_t len = (r->last - r->first) / (r->next - r->first);
    return (len < 0) ? 0 : len + 1;
}

int64_t range_nth(range_t *r, int64_t n) {
    int64_t step = r->next - r->first;
    return r->first + (n-1)*step;
}

int64_t range_step(range_t *r) {
    return r->next - r->first;
}

range_t *range_backwards(range_t *src) {
    int64_t step = src->next - src->first;
    return range_new(src->last, src->last - step, src->first);
}

list_t *bl_list_slice(list_t *list, range_t *r, size_t list_item_size, bool allow_aliasing) {
    list_t *slice = gc_alloc(sizeof(list_t));
    int64_t first = r->first;
    int64_t step = r->next - r->first;
    if (step == 0) return slice;
    // printf("step: %ld\n", step);
    int64_t last = r->last;
    if (step > 0) {
        if (first > list->len) return slice;
        if (first < 1) {
            first = first % step;
            if (first < 1) first += step;
        }
        if (last > list->len) last = list->len;
        if (last < first) return slice;
    } else {
        if (first < 1) return slice;
        if (first > list->len) {
            first = list->len - (list->len % -step) + (first % -step);
            if (first > list->len) first += step;
        }
        if (last < 1) last = 1;
        if (last > first) return slice;
    }
    int64_t len = ((last+step) - first) / step;
    if (len <= 0) len = 0;
    slice->len = len;

    if (step == 1 && allow_aliasing) {
        slice->items = &list->items[first-1];
    } else if (len > 0) {
        void *p = gc_alloc(len * list_item_size);
        slice->items = p;
        void *src_items = list->items;
        int64_t actual_len = 0;
        for (int64_t i = first; step > 0 ? (i <= last) : (i >= last); i += step) {
            actual_len += 1;
            p = mempcpy(p, src_items + (i - 1)*list_item_size, list_item_size);
        }
    }
    return slice;
}