range.c 4.14 KB
Newer Older
1
#include "dev/excit.h"
2 3
#include "range.h"

4
static int range_it_alloc(excit_t data)
5
{
6 7 8 9 10 11 12
	struct range_it_s *it = (struct range_it_s *)data->data;

	it->v = 0;
	it->first = 0;
	it->last = -1;
	it->step = 1;
	return EXCIT_SUCCESS;
13 14
}

15
static void range_it_free(excit_t data)
16 17 18
{
}

19
static int range_it_copy(excit_t ddst, const excit_t dsrc)
20
{
21 22 23 24 25 26 27 28
	struct range_it_s *dst = (struct range_it_s *)ddst->data;
	const struct range_it_s *src = (const struct range_it_s *)dsrc->data;

	dst->v = src->v;
	dst->first = src->first;
	dst->last = src->last;
	dst->step = src->step;
	return EXCIT_SUCCESS;
29 30
}

31
static int range_it_rewind(excit_t data)
32
{
33 34 35 36
	struct range_it_s *it = (struct range_it_s *)data->data;

	it->v = it->first;
	return EXCIT_SUCCESS;
37 38
}

39
static int range_it_peek(const excit_t data, ssize_t *val)
40
{
41 42 43 44 45 46 47 48 49 50 51 52 53
	struct range_it_s *it = (struct range_it_s *)data->data;

	if (it->step < 0) {
		if (it->v < it->last)
			return EXCIT_STOPIT;
	} else if (it->step > 0) {
		if (it->v > it->last)
			return EXCIT_STOPIT;
	} else
		return -EXCIT_EINVAL;
	if (val)
		*val = it->v;
	return EXCIT_SUCCESS;
54 55
}

56
static int range_it_next(excit_t data, ssize_t *val)
57
{
58 59 60 61 62 63 64
	struct range_it_s *it = (struct range_it_s *)data->data;
	int err = range_it_peek(data, val);

	if (err)
		return err;
	it->v += it->step;
	return EXCIT_SUCCESS;
65 66
}

67
static int range_it_size(const excit_t data, ssize_t *size)
68
{
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
	const struct range_it_s *it = (struct range_it_s *)data->data;

	if (it->step < 0)
		if (it->first < it->last)
			*size = 0;
		else
			*size = 1 + (it->first - it->last) / (-it->step);
	else if (it->step > 0)
		if (it->first > it->last)
			*size = 0;
		else
			*size = 1 + (it->last - it->first) / (it->step);
	else
		return -EXCIT_EINVAL;
	return EXCIT_SUCCESS;
84 85
}

86
static int range_it_nth(const excit_t data, ssize_t n, ssize_t *val)
87
{
88 89 90 91 92 93 94 95 96 97 98 99
	ssize_t size;
	int err = range_it_size(data, &size);

	if (err)
		return err;
	if (n < 0 || n >= size)
		return -EXCIT_EDOM;
	if (val) {
		struct range_it_s *it = (struct range_it_s *)data->data;
		*val = it->first + n * it->step;
	}
	return EXCIT_SUCCESS;
100 101
}

102
static int range_it_rank(const excit_t data, const ssize_t *val, ssize_t *n)
103
{
104 105 106 107 108 109 110 111 112 113 114 115 116
	ssize_t size;
	int err = range_it_size(data, &size);

	if (err)
		return err;
	const struct range_it_s *it = (struct range_it_s *)data->data;
	ssize_t pos = (*val - it->first) / it->step;

	if (pos < 0 || pos >= size || it->first + pos * it->step != *val)
		return -EXCIT_EINVAL;
	if (n)
		*n = pos;
	return EXCIT_SUCCESS;
117 118
}

119
static int range_it_pos(const excit_t data, ssize_t *n)
120
{
121 122
	ssize_t val;
	int err = range_it_peek(data, &val);
123

124 125 126
	if (err)
		return err;
	const struct range_it_s *it = (struct range_it_s *)data->data;
127

128 129 130
	if (n)
		*n = (val - it->first) / it->step;
	return EXCIT_SUCCESS;
131 132
}

133
static int range_it_split(const excit_t data, ssize_t n, excit_t *results)
134
{
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
	const struct range_it_s *it = (struct range_it_s *)data->data;
	ssize_t size;
	int err = range_it_size(data, &size);

	if (err)
		return err;
	int block_size = size / n;

	if (block_size <= 0)
		return -EXCIT_EDOM;
	if (!results)
		return EXCIT_SUCCESS;
	ssize_t new_last = it->last;
	ssize_t new_first;
	int i;

	for (i = n - 1; i >= 0; i--) {
		block_size = size / (i + 1);
		results[i] = excit_alloc(EXCIT_RANGE);
		if (!results[i]) {
			err = -EXCIT_ENOMEM;
			goto error;
		}
		new_first = new_last - (block_size - 1) * it->step;
		err =
		    excit_range_init(results[i], new_first, new_last, it->step);
		if (err) {
			excit_free(results[i]);
			goto error;
		}
		new_last = new_first - it->step;
		size = size - block_size;
	}
	return EXCIT_SUCCESS;
169
error:
170 171 172 173
	i += 1;
	for (; i < n; i++)
		excit_free(results[i]);
	return err;
174 175 176 177 178
}

int excit_range_init(excit_t it, ssize_t first, ssize_t last, ssize_t step)
{
	struct range_it_s *range_it;
179 180 181 182 183

	if (!it || it->type != EXCIT_RANGE)
		return -EXCIT_EINVAL;
	it->dimension = 1;
	range_it = (struct range_it_s *)it->data;
184 185 186 187 188 189 190
	range_it->first = first;
	range_it->v = first;
	range_it->last = last;
	range_it->step = step;
	return EXCIT_SUCCESS;
}

191 192 193 194 195 196 197 198 199 200 201 202 203
struct excit_func_table_s excit_range_func_table = {
	range_it_alloc,
	range_it_free,
	range_it_copy,
	range_it_next,
	range_it_peek,
	range_it_size,
	range_it_rewind,
	range_it_split,
	range_it_nth,
	range_it_rank,
	range_it_pos
};
Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
204