excit.c 42.4 KB
Newer Older
1
#include <stdlib.h>
Brice Videau's avatar
Brice Videau committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#include <excit.h>

struct excit_func_table_s {
	int (*alloc)(excit_t data);
	void (*free)(excit_t data);
	int (*copy)(excit_t dst, const excit_t src);
	int (*next)(excit_t data, excit_index_t *indexes);
	int (*peek)(const excit_t data, excit_index_t *indexes);
	int (*size)(const excit_t data, excit_index_t *size);
	int (*rewind)(excit_t data);
	int (*split)(const excit_t data, excit_index_t n,
		     excit_t *results);
	int (*nth)(const excit_t data, excit_index_t n,
		   excit_index_t *indexes);
	int (*n)(const excit_t data, const excit_index_t *indexes,
		 excit_index_t *n);
	int (*pos)(const excit_t iterator, excit_index_t *n);
19 20
};

Brice Videau's avatar
Brice Videau committed
21 22 23 24
struct excit_s {
	const struct excit_func_table_s *functions;
	excit_index_t dimension;
	enum excit_type_e type;
25 26 27 28 29 30
	void *data;
};

/*--------------------------------------------------------------------*/

struct slice_iterator_s {
Brice Videau's avatar
Brice Videau committed
31 32
	excit_t src;
	excit_t indexer;
33 34
};

Brice Videau's avatar
Brice Videau committed
35
static int slice_iterator_alloc(excit_t data)
36 37 38
{
	data->data = malloc(sizeof(struct slice_iterator_s));
	if (!data->data)
Brice Videau's avatar
Brice Videau committed
39
		return -EXCIT_ENOMEM;
40 41 42 43 44
	struct slice_iterator_s *iterator =
	    (struct slice_iterator_s *) data->data;

	iterator->src = NULL;
	iterator->indexer = NULL;
Brice Videau's avatar
Brice Videau committed
45
	return EXCIT_SUCCESS;
46 47
}

Brice Videau's avatar
Brice Videau committed
48
static void slice_iterator_free(excit_t data)
49 50 51 52
{
	struct slice_iterator_s *iterator =
	    (struct slice_iterator_s *) data->data;

Brice Videau's avatar
Brice Videau committed
53 54
	excit_free(iterator->src);
	excit_free(iterator->indexer);
55 56 57
	free(data->data);
}

Brice Videau's avatar
Brice Videau committed
58
static int slice_iterator_copy(excit_t dst, const excit_t src)
59 60 61 62 63
{
	const struct slice_iterator_s *iterator =
	    (const struct slice_iterator_s *) src->data;
	struct slice_iterator_s *result = (struct slice_iterator_s *) dst->data;

Brice Videau's avatar
Brice Videau committed
64
	result->src = excit_dup(iterator->src);
65
	if (!result->src)
Brice Videau's avatar
Brice Videau committed
66
		return -EXCIT_ENOMEM;
Brice Videau's avatar
Brice Videau committed
67
	result->indexer = excit_dup(iterator->indexer);
68
	if (!result->indexer) {
Brice Videau's avatar
Brice Videau committed
69
		excit_free(iterator->src);
Brice Videau's avatar
Brice Videau committed
70
		return -EXCIT_ENOMEM;
71
	}
Brice Videau's avatar
Brice Videau committed
72
	return EXCIT_SUCCESS;
73 74
}

Brice Videau's avatar
Brice Videau committed
75
static int slice_iterator_next(excit_t data, excit_index_t *indexes)
76 77 78
{
	struct slice_iterator_s *iterator =
	    (struct slice_iterator_s *) data->data;
Brice Videau's avatar
Brice Videau committed
79 80
	excit_index_t n;
	int err = excit_next(iterator->indexer, &n);
81 82 83

	if (err)
		return err;
Brice Videau's avatar
Brice Videau committed
84
	return excit_nth(iterator->src, n, indexes);
85 86
}

Brice Videau's avatar
Brice Videau committed
87 88
static int slice_iterator_peek(const excit_t data,
			       excit_index_t *indexes)
89 90 91
{
	const struct slice_iterator_s *iterator =
	    (const struct slice_iterator_s *)data->data;
Brice Videau's avatar
Brice Videau committed
92 93
	excit_index_t n;
	int err = excit_peek(iterator->indexer, &n);
94 95 96

	if (err)
		return err;
Brice Videau's avatar
Brice Videau committed
97
	return excit_nth(iterator->src, n, indexes);
98 99
}

Brice Videau's avatar
Brice Videau committed
100
static int slice_iterator_size(const excit_t data, excit_index_t *size)
101 102 103 104
{
	const struct slice_iterator_s *iterator =
	    (const struct slice_iterator_s *)data->data;

Brice Videau's avatar
Brice Videau committed
105
	return excit_size(iterator->indexer, size);
106 107
}

Brice Videau's avatar
Brice Videau committed
108
static int slice_iterator_rewind(excit_t data)
109 110 111 112
{
	struct slice_iterator_s *iterator =
	    (struct slice_iterator_s *) data->data;

Brice Videau's avatar
Brice Videau committed
113
	return excit_rewind(iterator->indexer);
114 115
}

Brice Videau's avatar
Brice Videau committed
116 117
static int slice_iterator_nth(const excit_t data, excit_index_t n,
			      excit_index_t *indexes)
118 119 120
{
	const struct slice_iterator_s *iterator =
	    (const struct slice_iterator_s *)data->data;
Brice Videau's avatar
Brice Videau committed
121 122
	excit_index_t p;
	int err = excit_nth(iterator->indexer, n, &p);
123 124 125

	if (err)
		return err;
Brice Videau's avatar
Brice Videau committed
126
	return excit_nth(iterator->src, p, indexes);
127 128
}

Brice Videau's avatar
Brice Videau committed
129 130 131
static int slice_iterator_n(const excit_t data,
			    const excit_index_t *indexes,
			    excit_index_t *n)
132 133 134
{
	const struct slice_iterator_s *iterator =
	    (const struct slice_iterator_s *)data->data;
Brice Videau's avatar
Brice Videau committed
135 136
	excit_index_t inner_n;
	int err = excit_n(iterator->src, indexes, &inner_n);
137 138 139

	if (err)
		return err;
Brice Videau's avatar
Brice Videau committed
140
	return excit_n(iterator->indexer, &inner_n, n);
141 142
}

Brice Videau's avatar
Brice Videau committed
143
static int slice_iterator_pos(const excit_t data, excit_index_t *n)
144 145 146 147
{
	const struct slice_iterator_s *iterator =
	    (const struct slice_iterator_s *)data->data;

Brice Videau's avatar
Brice Videau committed
148
	return excit_pos(iterator->indexer, n);
149 150
}

Brice Videau's avatar
Brice Videau committed
151 152
static int slice_iterator_split(const excit_t data, excit_index_t n,
				excit_t *results)
153 154 155
{
	const struct slice_iterator_s *iterator =
	    (const struct slice_iterator_s *)data->data;
Brice Videau's avatar
Brice Videau committed
156
	int err = excit_split(iterator->indexer, n, results);
157 158 159 160

	if (err)
		return err;
	if (!results)
Brice Videau's avatar
Brice Videau committed
161
		return EXCIT_SUCCESS;
162
	for (int i = 0; i < n; i++) {
Brice Videau's avatar
Brice Videau committed
163 164
		excit_t tmp;
		excit_t tmp2;
165 166

		tmp = results[i];
Brice Videau's avatar
Brice Videau committed
167
		results[i] = excit_alloc(EXCIT_SLICE);
168
		if (!results[i]) {
Brice Videau's avatar
Brice Videau committed
169
			excit_free(tmp);
Brice Videau's avatar
Brice Videau committed
170
			err = -EXCIT_ENOMEM;
171 172
			goto error;
		}
Brice Videau's avatar
Brice Videau committed
173
		tmp2 = excit_dup(iterator->src);
174
		if (!tmp2) {
Brice Videau's avatar
Brice Videau committed
175
			excit_free(tmp);
Brice Videau's avatar
Brice Videau committed
176
			err = -EXCIT_ENOMEM;
177 178
			goto error;
		}
Brice Videau's avatar
Brice Videau committed
179
		err = excit_slice_init(results[i], tmp, tmp2);
180
		if (err) {
Brice Videau's avatar
Brice Videau committed
181 182
			excit_free(tmp);
			excit_free(tmp2);
183 184 185
			goto error;
		}
	}
Brice Videau's avatar
Brice Videau committed
186
	return EXCIT_SUCCESS;
187 188
error:
	for (int i = 0; i < n; i++)
Brice Videau's avatar
Brice Videau committed
189
		excit_free(results[i]);
190 191 192
	return err;
}

Brice Videau's avatar
Brice Videau committed
193
static const struct excit_func_table_s excit_slice_func_table = {
194 195 196 197 198 199 200 201 202 203 204 205 206
	slice_iterator_alloc,
	slice_iterator_free,
	slice_iterator_copy,
	slice_iterator_next,
	slice_iterator_peek,
	slice_iterator_size,
	slice_iterator_rewind,
	slice_iterator_split,
	slice_iterator_nth,
	slice_iterator_n,
	slice_iterator_pos
};

Brice Videau's avatar
Brice Videau committed
207 208
int excit_slice_init(excit_t iterator, excit_t src,
			 excit_t indexer)
209
{
Brice Videau's avatar
Brice Videau committed
210
	if (!iterator || iterator->type != EXCIT_SLICE || !src || !indexer
211
	    || indexer->dimension != 1)
Brice Videau's avatar
Brice Videau committed
212
		return -EXCIT_EINVAL;
213 214
	struct slice_iterator_s *it =
	    (struct slice_iterator_s *) iterator->data;
Brice Videau's avatar
Brice Videau committed
215 216 217
	excit_index_t size_src;
	excit_index_t size_indexer;
	int err = excit_size(src, &size_src);
218 219 220

	if (err)
		return err;
Brice Videau's avatar
Brice Videau committed
221
	err = excit_size(indexer, &size_indexer);
222 223 224
	if (err)
		return err;
	if (size_indexer > size_src)
Brice Videau's avatar
Brice Videau committed
225
		return -EXCIT_EDOM;
226 227 228
	it->src = src;
	it->indexer = indexer;
	iterator->dimension = src->dimension;
Brice Videau's avatar
Brice Videau committed
229
	return EXCIT_SUCCESS;
230 231 232 233 234
}

/*--------------------------------------------------------------------*/

struct product_iterator_s {
Brice Videau's avatar
Brice Videau committed
235 236
	excit_index_t count;
	excit_t *iterators;
237 238
};

Brice Videau's avatar
Brice Videau committed
239
static int product_iterator_alloc(excit_t data)
240 241 242
{
	data->data = malloc(sizeof(struct product_iterator_s));
	if (!data->data)
Brice Videau's avatar
Brice Videau committed
243
		return -EXCIT_ENOMEM;
244 245 246 247 248
	struct product_iterator_s *iterator =
	    (struct product_iterator_s *) data->data;

	iterator->count = 0;
	iterator->iterators = NULL;
Brice Videau's avatar
Brice Videau committed
249
	return EXCIT_SUCCESS;
250 251
}

Brice Videau's avatar
Brice Videau committed
252
static void product_iterator_free(excit_t data)
253 254 255 256
{
	struct product_iterator_s *iterator =
	    (struct product_iterator_s *) data->data;
	if (iterator->iterators) {
Brice Videau's avatar
Brice Videau committed
257 258
		for (excit_index_t i = 0; i < iterator->count; i++)
			excit_free(iterator->iterators[i]);
259 260 261 262 263
		free(iterator->iterators);
	}
	free(data->data);
}

Brice Videau's avatar
Brice Videau committed
264
static int product_iterator_copy(excit_t dst, const excit_t src)
265 266 267 268 269 270 271
{
	const struct product_iterator_s *iterator =
	    (const struct product_iterator_s *)src->data;
	struct product_iterator_s *result =
	    (struct product_iterator_s *) dst->data;

	result->iterators =
Brice Videau's avatar
Brice Videau committed
272
	    (excit_t *) malloc(iterator->count * sizeof(excit_t));
273
	if (!result->iterators)
Brice Videau's avatar
Brice Videau committed
274
		return -EXCIT_ENOMEM;
Brice Videau's avatar
Brice Videau committed
275
	excit_index_t i;
276 277

	for (i = 0; i < iterator->count; i++) {
Brice Videau's avatar
Brice Videau committed
278
		result->iterators[i] = excit_dup(iterator->iterators[i]);
279 280 281 282 283 284
		if (!result->iterators[i]) {
			i--;
			goto error;
		}
	}
	result->count = iterator->count;
Brice Videau's avatar
Brice Videau committed
285
	return EXCIT_SUCCESS;
286 287 288 289 290 291
error:
	while (i >= 0) {
		free(result->iterators[i]);
		i--;
	}
	free(result->iterators);
Brice Videau's avatar
Brice Videau committed
292
	return -EXCIT_ENOMEM;
293 294
}

Brice Videau's avatar
Brice Videau committed
295
static int product_iterator_rewind(excit_t data)
296 297 298 299
{
	struct product_iterator_s *iterator =
	    (struct product_iterator_s *) data->data;

Brice Videau's avatar
Brice Videau committed
300 301
	for (excit_index_t i = 0; i < iterator->count; i++) {
		int err = excit_rewind(iterator->iterators[i]);
302 303 304 305

		if (err)
			return err;
	}
Brice Videau's avatar
Brice Videau committed
306
	return EXCIT_SUCCESS;
307 308
}

Brice Videau's avatar
Brice Videau committed
309 310
static int product_iterator_size(const excit_t data,
				 excit_index_t *size)
311 312 313
{
	const struct product_iterator_s *iterator =
	    (const struct product_iterator_s *) data->data;
Brice Videau's avatar
Brice Videau committed
314
	excit_index_t tmp_size = 0;
315 316

	if (!size)
Brice Videau's avatar
Brice Videau committed
317
		return -EXCIT_EINVAL;
318 319 320 321
	if (iterator->count == 0)
		*size = 0;
	else {
		*size = 1;
Brice Videau's avatar
Brice Videau committed
322
		for (excit_index_t i = 0; i < iterator->count; i++) {
323
			int err =
Brice Videau's avatar
Brice Videau committed
324
			    excit_size(iterator->iterators[i], &tmp_size);
325 326 327 328 329 330 331 332

			if (err) {
				*size = 0;
				return err;
			}
			*size *= tmp_size;
		}
	}
Brice Videau's avatar
Brice Videau committed
333
	return EXCIT_SUCCESS;
334 335
}

Brice Videau's avatar
Brice Videau committed
336 337
static int product_iterator_nth(const excit_t data, excit_index_t n,
				excit_index_t *indexes)
338
{
Brice Videau's avatar
Brice Videau committed
339
	excit_index_t size;
340 341 342 343 344
	int err = product_iterator_size(data, &size);

	if (err)
		return err;
	if (n < 0 || n >= size)
Brice Videau's avatar
Brice Videau committed
345
		return -EXCIT_EDOM;
346 347 348 349
	const struct product_iterator_s *iterator =
	    (const struct product_iterator_s *) data->data;

	if (indexes) {
Brice Videau's avatar
Brice Videau committed
350 351
		excit_index_t subsize = 0;
		excit_index_t offset = data->dimension;
352

Brice Videau's avatar
Brice Videau committed
353
		for (excit_index_t i = iterator->count - 1; i >= 0; i--) {
354
			offset -= iterator->iterators[i]->dimension;
Brice Videau's avatar
Brice Videau committed
355
			err = excit_size(iterator->iterators[i], &subsize);
356 357 358
			if (err)
				return err;
			err =
Brice Videau's avatar
Brice Videau committed
359
			    excit_nth(iterator->iterators[i], n % subsize,
360 361 362 363 364 365
					  indexes + offset);
			if (err)
				return err;
			n /= subsize;
		}
	}
Brice Videau's avatar
Brice Videau committed
366
	return EXCIT_SUCCESS;
367 368
}

Brice Videau's avatar
Brice Videau committed
369 370 371
static int product_iterator_n(const excit_t data,
			      const excit_index_t *indexes,
			      excit_index_t *n)
372 373 374 375 376
{
	const struct product_iterator_s *iterator =
	    (const struct product_iterator_s *) data->data;

	if (iterator->count == 0)
Brice Videau's avatar
Brice Videau committed
377
		return -EXCIT_EINVAL;
Brice Videau's avatar
Brice Videau committed
378 379 380 381
	excit_index_t offset = 0;
	excit_index_t product = 0;
	excit_index_t inner_n;
	excit_index_t subsize;
382

Brice Videau's avatar
Brice Videau committed
383
	for (excit_index_t i = 0; i < iterator->count; i++) {
384
		int err =
Brice Videau's avatar
Brice Videau committed
385
		    excit_n(iterator->iterators[i], indexes + offset,
386 387 388
				&inner_n);
		if (err)
			return err;
Brice Videau's avatar
Brice Videau committed
389
		err = excit_size(iterator->iterators[i], &subsize);
390 391 392 393 394 395 396 397
		if (err)
			return err;
		product *= subsize;
		product += inner_n;
		offset += iterator->iterators[i]->dimension;
	}
	if (n)
		*n = product;
Brice Videau's avatar
Brice Videau committed
398
	return EXCIT_SUCCESS;
399 400
}

Brice Videau's avatar
Brice Videau committed
401
static int product_iterator_pos(const excit_t data, excit_index_t *n)
402 403 404 405 406
{
	const struct product_iterator_s *iterator =
	    (const struct product_iterator_s *) data->data;

	if (iterator->count == 0)
Brice Videau's avatar
Brice Videau committed
407
		return -EXCIT_EINVAL;
Brice Videau's avatar
Brice Videau committed
408 409 410
	excit_index_t product = 0;
	excit_index_t inner_n;
	excit_index_t subsize;
411

Brice Videau's avatar
Brice Videau committed
412 413
	for (excit_index_t i = 0; i < iterator->count; i++) {
		int err = excit_pos(iterator->iterators[i], &inner_n);
414 415 416

		if (err)
			return err;
Brice Videau's avatar
Brice Videau committed
417
		err = excit_size(iterator->iterators[i], &subsize);
418 419 420 421 422 423 424
		if (err)
			return err;
		product *= subsize;
		product += inner_n;
	}
	if (n)
		*n = product;
Brice Videau's avatar
Brice Videau committed
425
	return EXCIT_SUCCESS;
426 427
}

Brice Videau's avatar
Brice Videau committed
428 429
static inline int product_iterator_peeknext_helper(excit_t data,
						   excit_index_t *indexes,
430 431 432 433 434 435
						   int next)
{
	struct product_iterator_s *iterator =
	    (struct product_iterator_s *) data->data;
	int err;
	int looped;
Brice Videau's avatar
Brice Videau committed
436 437 438
	excit_index_t i;
	excit_index_t *next_indexes;
	excit_index_t offset = data->dimension;
439 440

	if (iterator->count == 0)
Brice Videau's avatar
Brice Videau committed
441
		return -EXCIT_EINVAL;
442 443 444 445 446 447 448 449 450
	looped = next;
	for (i = iterator->count - 1; i > 0; i--) {
		if (indexes) {
			offset -= iterator->iterators[i]->dimension;
			next_indexes = indexes + offset;
		} else
			next_indexes = NULL;
		if (looped)
			err =
Brice Videau's avatar
Brice Videau committed
451
			    excit_cyclic_next(iterator->iterators[i],
452 453 454
						  next_indexes, &looped);
		else
			err =
Brice Videau's avatar
Brice Videau committed
455
			    excit_peek(iterator->iterators[i],
456 457 458 459 460 461 462 463 464 465
					   next_indexes);
		if (err)
			return err;
	}
	if (indexes) {
		offset -= iterator->iterators[i]->dimension;
		next_indexes = indexes + offset;
	} else
		next_indexes = NULL;
	if (looped)
Brice Videau's avatar
Brice Videau committed
466
		err = excit_next(iterator->iterators[0], next_indexes);
467
	else
Brice Videau's avatar
Brice Videau committed
468
		err = excit_peek(iterator->iterators[0], next_indexes);
469 470
	if (err)
		return err;
Brice Videau's avatar
Brice Videau committed
471
	return EXCIT_SUCCESS;
472 473
}

Brice Videau's avatar
Brice Videau committed
474 475
static int product_iterator_peek(const excit_t data,
				 excit_index_t *indexes)
476 477 478 479
{
	return product_iterator_peeknext_helper(data, indexes, 0);
}

Brice Videau's avatar
Brice Videau committed
480
static int product_iterator_next(excit_t data, excit_index_t *indexes)
481 482 483 484
{
	return product_iterator_peeknext_helper(data, indexes, 1);
}

Brice Videau's avatar
Brice Videau committed
485 486
static int product_iterator_split(const excit_t data, excit_index_t n,
				  excit_t *results)
487
{
Brice Videau's avatar
Brice Videau committed
488
	excit_index_t size;
489 490 491 492 493
	int err = product_iterator_size(data, &size);

	if (err)
		return err;
	if (size < n)
Brice Videau's avatar
Brice Videau committed
494
		return -EXCIT_EDOM;
495
	if (!results)
Brice Videau's avatar
Brice Videau committed
496
		return EXCIT_SUCCESS;
Brice Videau's avatar
Brice Videau committed
497
	excit_t range = excit_alloc(EXCIT_RANGE);
498 499

	if (!range)
Brice Videau's avatar
Brice Videau committed
500
		return -EXCIT_ENOMEM;
Brice Videau's avatar
Brice Videau committed
501
	err = excit_range_init(range, 0, size - 1, 1);
502 503
	if (err)
		goto error1;
Brice Videau's avatar
Brice Videau committed
504
	err = excit_split(range, n, results);
505 506 507
	if (err)
		goto error1;
	for (int i = 0; i < n; i++) {
Brice Videau's avatar
Brice Videau committed
508
		excit_t tmp, tmp2;
509

Brice Videau's avatar
Brice Videau committed
510
		tmp = excit_dup(data);
511 512 513
		if (!tmp)
			goto error2;
		tmp2 = results[i];
Brice Videau's avatar
Brice Videau committed
514
		results[i] = excit_alloc(EXCIT_SLICE);
515
		if (!results[i]) {
Brice Videau's avatar
Brice Videau committed
516
			excit_free(tmp2);
517 518
			goto error2;
		}
Brice Videau's avatar
Brice Videau committed
519
		err = excit_slice_init(results[i], tmp, tmp2);
520
		if (err) {
Brice Videau's avatar
Brice Videau committed
521
			excit_free(tmp2);
522 523 524
			goto error2;
		}
	}
Brice Videau's avatar
Brice Videau committed
525
	excit_free(range);
Brice Videau's avatar
Brice Videau committed
526
	return EXCIT_SUCCESS;
527 528
error2:
	for (int i = 0; i < n; i++)
Brice Videau's avatar
Brice Videau committed
529
		excit_free(results[i]);
530
error1:
Brice Videau's avatar
Brice Videau committed
531
	excit_free(range);
532 533 534
	return err;
}

Brice Videau's avatar
Brice Videau committed
535 536
int excit_product_count(const excit_t iterator,
			    excit_index_t *count)
537
{
Brice Videau's avatar
Brice Videau committed
538
	if (!iterator || iterator->type != EXCIT_PRODUCT || !count)
Brice Videau's avatar
Brice Videau committed
539
		return -EXCIT_EINVAL;
540
	*count = ((struct product_iterator_s *) iterator->data)->count;
Brice Videau's avatar
Brice Videau committed
541
	return EXCIT_SUCCESS;
542 543
}

Brice Videau's avatar
Brice Videau committed
544 545 546
int excit_product_split_dim(const excit_t iterator,
				excit_index_t dim, excit_index_t n,
				excit_t *results)
547
{
Brice Videau's avatar
Brice Videau committed
548
	if (!iterator || iterator->type != EXCIT_PRODUCT)
Brice Videau's avatar
Brice Videau committed
549
		return -EXCIT_EINVAL;
550
	if (n <= 0)
Brice Videau's avatar
Brice Videau committed
551
		return -EXCIT_EDOM;
Brice Videau's avatar
Brice Videau committed
552 553
	excit_index_t count;
	int err = excit_product_count(iterator, &count);
554 555 556 557

	if (err)
		return err;
	if (dim >= count)
Brice Videau's avatar
Brice Videau committed
558
		return -EXCIT_EDOM;
559 560 561
	struct product_iterator_s *product_iterator =
	    (struct product_iterator_s *) iterator->data;

Brice Videau's avatar
Brice Videau committed
562
	err = excit_split(product_iterator->iterators[dim], n, results);
563 564 565
	if (err)
		return err;
	if (!results)
Brice Videau's avatar
Brice Videau committed
566
		return EXCIT_SUCCESS;
567
	for (int i = 0; i < n; i++) {
Brice Videau's avatar
Brice Videau committed
568
		excit_t tmp = results[i];
569

Brice Videau's avatar
Brice Videau committed
570
		results[i] = excit_dup(iterator);
571
		if (!tmp) {
Brice Videau's avatar
Brice Videau committed
572
			excit_free(tmp);
Brice Videau's avatar
Brice Videau committed
573
			err = -EXCIT_ENOMEM;
574 575 576 577
			goto error;
		}
		struct product_iterator_s *new_product_iterator =
		    (struct product_iterator_s *) results[i]->data;
Brice Videau's avatar
Brice Videau committed
578
		excit_free(new_product_iterator->iterators[dim]);
579 580
		new_product_iterator->iterators[dim] = tmp;
	}
Brice Videau's avatar
Brice Videau committed
581
	return EXCIT_SUCCESS;
582 583
error:
	for (int i = 0; i < n; i++)
Brice Videau's avatar
Brice Videau committed
584
		excit_free(results[i]);
585 586 587
	return err;
}

Brice Videau's avatar
Brice Videau committed
588
int excit_product_add_copy(excit_t iterator, excit_t added_iterator)
589 590
{
	int err = 0;
Brice Videau's avatar
Brice Videau committed
591
	excit_t copy = excit_dup(added_iterator);
592 593

	if (!copy)
Brice Videau's avatar
Brice Videau committed
594
		return -EXCIT_EINVAL;
Brice Videau's avatar
Brice Videau committed
595
	err = excit_product_add(iterator, copy);
596
	if (err) {
Brice Videau's avatar
Brice Videau committed
597
		excit_free(added_iterator);
598 599
		return err;
	}
Brice Videau's avatar
Brice Videau committed
600
	return EXCIT_SUCCESS;
601 602
}

Brice Videau's avatar
Brice Videau committed
603
int excit_product_add(excit_t iterator, excit_t added_iterator)
604
{
Brice Videau's avatar
Brice Videau committed
605
	if (!iterator || iterator->type != EXCIT_PRODUCT || !iterator->data
606
	    || !added_iterator)
Brice Videau's avatar
Brice Videau committed
607
		return -EXCIT_EINVAL;
608 609 610

	struct product_iterator_s *product_iterator =
	    (struct product_iterator_s *) iterator->data;
Brice Videau's avatar
Brice Videau committed
611
	excit_index_t mew_count = product_iterator->count + 1;
612

Brice Videau's avatar
Brice Videau committed
613 614 615
	excit_t *new_its =
	    (excit_t *) realloc(product_iterator->iterators,
				    mew_count * sizeof(excit_t));
616
	if (!new_its)
Brice Videau's avatar
Brice Videau committed
617
		return -EXCIT_ENOMEM;
618 619 620 621
	product_iterator->iterators = new_its;
	product_iterator->iterators[product_iterator->count] = added_iterator;
	product_iterator->count = mew_count;
	iterator->dimension += added_iterator->dimension;
Brice Videau's avatar
Brice Videau committed
622
	return EXCIT_SUCCESS;
623 624
}

Brice Videau's avatar
Brice Videau committed
625
static const struct excit_func_table_s excit_product_func_table = {
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
	product_iterator_alloc,
	product_iterator_free,
	product_iterator_copy,
	product_iterator_next,
	product_iterator_peek,
	product_iterator_size,
	product_iterator_rewind,
	product_iterator_split,
	product_iterator_nth,
	product_iterator_n,
	product_iterator_pos
};

/*--------------------------------------------------------------------*/

struct circular_fifo_s {
Brice Videau's avatar
Brice Videau committed
642 643 644 645 646
	excit_index_t length;
	excit_index_t start;
	excit_index_t end;
	excit_index_t size;
	excit_index_t *buffer;
647 648 649
};

static void circular_fifo_add(struct circular_fifo_s *fifo,
Brice Videau's avatar
Brice Videau committed
650
			      excit_index_t elem)
651 652 653 654 655 656 657 658 659 660 661 662
{
	if (fifo->size == fifo->length) {
		fifo->start = (fifo->start + 1) % fifo->length;
		fifo->end = (fifo->end + 1) % fifo->length;
	} else {
		fifo->end = (fifo->end + 1) % fifo->length;
		fifo->size++;
	}
	fifo->buffer[fifo->end] = elem;
}

static void circular_fifo_dump(const struct circular_fifo_s *fifo,
Brice Videau's avatar
Brice Videau committed
663
			       excit_index_t *vals)
664
{
Brice Videau's avatar
Brice Videau committed
665 666
	excit_index_t i;
	excit_index_t j;
667 668 669 670 671 672 673 674

	for (i = 0, j = fifo->start; i < fifo->size; i++) {
		vals[i] = fifo->buffer[j];
		j = (j + 1) % fifo->length;
	}
}

struct cons_iterator_s {
Brice Videau's avatar
Brice Videau committed
675 676
	excit_t iterator;
	excit_index_t n;
677 678 679
	struct circular_fifo_s fifo;
};

Brice Videau's avatar
Brice Videau committed
680
static int cons_iterator_alloc(excit_t data)
681 682 683
{
	data->data = malloc(sizeof(struct cons_iterator_s));
	if (!data->data)
Brice Videau's avatar
Brice Videau committed
684
		return -EXCIT_ENOMEM;
685 686 687 688 689 690 691 692 693 694
	struct cons_iterator_s *iterator =
	    (struct cons_iterator_s *) data->data;

	iterator->iterator = NULL;
	iterator->n = 0;
	iterator->fifo.length = 0;
	iterator->fifo.start = 0;
	iterator->fifo.end = -1;
	iterator->fifo.size = 0;
	iterator->fifo.buffer = NULL;
Brice Videau's avatar
Brice Videau committed
695
	return EXCIT_SUCCESS;
696 697
}

Brice Videau's avatar
Brice Videau committed
698
static void cons_iterator_free(excit_t data)
699 700 701 702
{
	struct cons_iterator_s *iterator =
	    (struct cons_iterator_s *) data->data;

Brice Videau's avatar
Brice Videau committed
703
	excit_free(iterator->iterator);
704 705 706 707
	free(iterator->fifo.buffer);
	free(data->data);
}

Brice Videau's avatar
Brice Videau committed
708
static int cons_iterator_copy(excit_t ddst, const excit_t dsrc)
709 710 711 712
{
	struct cons_iterator_s *dst = (struct cons_iterator_s *) ddst->data;
	const struct cons_iterator_s *src =
	    (const struct cons_iterator_s *)dsrc->data;
Brice Videau's avatar
Brice Videau committed
713
	excit_t copy = excit_dup(src->iterator);
714 715

	if (!copy)
Brice Videau's avatar
Brice Videau committed
716
		return -EXCIT_EINVAL;
717 718 719 720 721 722 723
	dst->iterator = copy;
	dst->n = src->n;
	dst->fifo.length = src->fifo.length;
	dst->fifo.start = src->fifo.start;
	dst->fifo.end = src->fifo.end;
	dst->fifo.size = src->fifo.size;
	dst->fifo.buffer =
Brice Videau's avatar
Brice Videau committed
724 725
	    (excit_index_t *) malloc(src->fifo.length *
					 sizeof(excit_index_t));
726
	if (!dst->fifo.buffer) {
Brice Videau's avatar
Brice Videau committed
727
		excit_free(copy);
Brice Videau's avatar
Brice Videau committed
728
		return -EXCIT_ENOMEM;
729 730 731
	}
	for (int i = 0; i < dst->fifo.length; i++)
		dst->fifo.buffer[i] = src->fifo.buffer[i];
Brice Videau's avatar
Brice Videau committed
732
	return EXCIT_SUCCESS;
733 734
}

Brice Videau's avatar
Brice Videau committed
735
static int cons_iterator_size(const excit_t data, excit_index_t *size)
736 737 738
{
	const struct cons_iterator_s *iterator =
	    (const struct cons_iterator_s *)data->data;
Brice Videau's avatar
Brice Videau committed
739 740
	excit_index_t tmp_size = 0;
	int err = excit_size(iterator->iterator, &tmp_size);
741 742 743 744

	if (err)
		return err;
	*size = tmp_size - (iterator->n - 1);
Brice Videau's avatar
Brice Videau committed
745
	return EXCIT_SUCCESS;
746 747
}

Brice Videau's avatar
Brice Videau committed
748 749
static int cons_iterator_split(const excit_t data, excit_index_t n,
			       excit_t *results)
750
{
Brice Videau's avatar
Brice Videau committed
751
	excit_index_t size;
752 753 754 755 756
	int err = cons_iterator_size(data, &size);

	if (err)
		return err;
	if (size < n)
Brice Videau's avatar
Brice Videau committed
757
		return -EXCIT_EDOM;
758
	if (!results)
Brice Videau's avatar
Brice Videau committed
759
		return EXCIT_SUCCESS;
Brice Videau's avatar
Brice Videau committed
760
	excit_t range = excit_alloc(EXCIT_RANGE);
761 762

	if (!range)
Brice Videau's avatar
Brice Videau committed
763
		return -EXCIT_ENOMEM;
Brice Videau's avatar
Brice Videau committed
764
	err = excit_range_init(range, 0, size - 1, 1);
765 766
	if (err)
		goto error1;
Brice Videau's avatar
Brice Videau committed
767
	err = excit_split(range, n, results);
768 769 770 771 772
	if (err)
		goto error1;
	int i;

	for (i = 0; i < n; i++) {
Brice Videau's avatar
Brice Videau committed
773
		excit_t tmp, tmp2;
774

Brice Videau's avatar
Brice Videau committed
775
		tmp = excit_dup(data);
776 777 778
		if (!tmp)
			goto error2;
		tmp2 = results[i];
Brice Videau's avatar
Brice Videau committed
779
		results[i] = excit_alloc(EXCIT_SLICE);
780
		if (!results[i]) {
Brice Videau's avatar
Brice Videau committed
781
			excit_free(tmp2);
782 783
			goto error2;
		}
Brice Videau's avatar
Brice Videau committed
784
		err = excit_slice_init(results[i], tmp, tmp2);
785
		if (err) {
Brice Videau's avatar
Brice Videau committed
786
			excit_free(tmp2);
787 788 789
			goto error2;
		}
	}
Brice Videau's avatar
Brice Videau committed
790
	excit_free(range);
Brice Videau's avatar
Brice Videau committed
791
	return EXCIT_SUCCESS;
792 793
error2:
	for (; i >= 0; i--)
Brice Videau's avatar
Brice Videau committed
794
		excit_free(results[i]);
795
error1:
Brice Videau's avatar
Brice Videau committed
796
	excit_free(range);
797 798 799
	return err;
}

Brice Videau's avatar
Brice Videau committed
800 801
static int cons_iterator_nth(const excit_t data, excit_index_t n,
			     excit_index_t *indexes)
802
{
Brice Videau's avatar
Brice Videau committed
803
	excit_index_t size;
804 805 806 807 808
	int err = cons_iterator_size(data, &size);

	if (err)
		return err;
	if (n < 0 || n >= size)
Brice Videau's avatar
Brice Videau committed
809
		return -EXCIT_EDOM;
810 811 812 813 814 815 816
	const struct cons_iterator_s *iterator =
	    (const struct cons_iterator_s *) data->data;
	int dim = iterator->iterator->dimension;

	if (indexes) {
		for (int i = 0; i < iterator->n; i++) {
			err =
Brice Videau's avatar
Brice Videau committed
817
			    excit_nth(iterator->iterator, n + i,
818 819 820 821 822
					  indexes + dim * i);
			if (err)
				return err;
		}
	}
Brice Videau's avatar
Brice Videau committed
823
	return EXCIT_SUCCESS;
824 825
}

Brice Videau's avatar
Brice Videau committed
826 827 828
static int cons_iterator_n(const excit_t data,
			   const excit_index_t *indexes,
			   excit_index_t *n)
829 830 831
{
	const struct cons_iterator_s *iterator =
	    (const struct cons_iterator_s *) data->data;
Brice Videau's avatar
Brice Videau committed
832 833
	excit_index_t inner_n, inner_n_tmp;
	int err = excit_n(iterator->iterator, indexes, &inner_n);
834 835 836 837 838 839 840

	if (err)
		return err;
	int dim = iterator->iterator->dimension;

	for (int i = 1; i < iterator->n; i++) {
		err =
Brice Videau's avatar
Brice Videau committed
841
		    excit_n(iterator->iterator, indexes + dim * i,
842 843 844 845
				&inner_n_tmp);
		if (err)
			return err;
		if (inner_n_tmp != inner_n + 1)
Brice Videau's avatar
Brice Videau committed
846
			return -EXCIT_EINVAL;
847 848 849 850
		inner_n = inner_n_tmp;
	}
	if (n)
		*n = inner_n - (iterator->n - 1);
Brice Videau's avatar
Brice Videau committed
851
	return EXCIT_SUCCESS;
852 853
}

Brice Videau's avatar
Brice Videau committed
854
static int cons_iterator_pos(const excit_t data, excit_index_t *n)
855
{
Brice Videau's avatar
Brice Videau committed
856
	excit_index_t inner_n;
857 858
	const struct cons_iterator_s *iterator =
	    (const struct cons_iterator_s *) data->data;
Brice Videau's avatar
Brice Videau committed
859
	int err = excit_pos(iterator->iterator, &inner_n);
860 861 862 863 864

	if (err)
		return err;
	if (n)
		*n = inner_n - (iterator->n - 1);
Brice Videau's avatar
Brice Videau committed
865
	return EXCIT_SUCCESS;
866 867
}

Brice Videau's avatar
Brice Videau committed
868 869
static int cons_iterator_peek(const excit_t data,
			      excit_index_t *indexes)
870 871 872 873 874 875 876 877 878 879
{
	const struct cons_iterator_s *iterator =
	    (const struct cons_iterator_s *) data->data;
	int err;
	int dim = iterator->iterator->dimension;
	int n = iterator->n;

	if (indexes) {
		circular_fifo_dump(&iterator->fifo, indexes);
		err =
Brice Videau's avatar
Brice Videau committed
880
		    excit_peek(iterator->iterator, indexes + dim * (n - 1));
881
	} else
Brice Videau's avatar
Brice Videau committed
882
		err = excit_peek(iterator->iterator, NULL);
883 884
	if (err)
		return err;
Brice Videau's avatar
Brice Videau committed
885
	return EXCIT_SUCCESS;
886 887
}

Brice Videau's avatar
Brice Videau committed
888
static int cons_iterator_next(excit_t data, excit_index_t *indexes)
889 890 891 892 893 894 895 896 897 898
{
	struct cons_iterator_s *iterator =
	    (struct cons_iterator_s *) data->data;
	int err;
	int dim = iterator->iterator->dimension;
	int n = iterator->n;

	if (indexes) {
		circular_fifo_dump(&iterator->fifo, indexes);
		err =
Brice Videau's avatar
Brice Videau committed
899
		    excit_next(iterator->iterator, indexes + dim * (n - 1));
900
	} else
Brice Videau's avatar
Brice Videau committed
901
		err = excit_next(iterator->iterator, NULL);
902 903 904 905 906
	if (err)
		return err;
	if (indexes)
		for (int i = dim * (n - 1); i < dim * n; i++)
			circular_fifo_add(&iterator->fifo, indexes[i]);
Brice Videau's avatar
Brice Videau committed
907
	return EXCIT_SUCCESS;
908 909
}

Brice Videau's avatar
Brice Videau committed
910
static int cons_iterator_rewind(excit_t data)
911 912 913
{
	struct cons_iterator_s *iterator =
	    (struct cons_iterator_s *) data->data;
Brice Videau's avatar
Brice Videau committed
914
	int err = excit_rewind(iterator->iterator);
915 916 917 918 919 920 921 922 923 924 925

	if (err)
		return err;
	iterator->fifo.start = 0;
	iterator->fifo.end = -1;
	iterator->fifo.size = 0;

	for (int i = 0; i < iterator->n - 1; i++) {
		int err;

		err =
Brice Videau's avatar
Brice Videau committed
926
		    excit_next(iterator->iterator,
927 928 929 930 931 932 933
				   iterator->fifo.buffer +
				   iterator->iterator->dimension * i);
		if (err)
			return err;
		iterator->fifo.size += iterator->iterator->dimension;
		iterator->fifo.end += iterator->iterator->dimension;
	}
Brice Videau's avatar
Brice Videau committed
934
	return EXCIT_SUCCESS;
935 936
}

Brice Videau's avatar
Brice Videau committed
937 938
int excit_cons_init(excit_t iterator, excit_t src,
			excit_index_t n)
939
{
Brice Videau's avatar
Brice Videau committed
940
	excit_index_t src_size;
941 942
	int err;

Brice Videau's avatar
Brice Videau committed
943
	if (!iterator || iterator->type != EXCIT_CONS || !src || n <= 0)
Brice Videau's avatar
Brice Videau committed
944
		return -EXCIT_EINVAL;
Brice Videau's avatar
Brice Videau committed
945
	err = excit_size(src, &src_size);
946 947 948
	if (err)
		return err;
	if (src_size < n)
Brice Videau's avatar
Brice Videau committed
949
		return -EXCIT_EINVAL;
950 951 952 953
	struct cons_iterator_s *cons_iterator =
	    (struct cons_iterator_s *) iterator->data;

	free(cons_iterator->fifo.buffer);
Brice Videau's avatar
Brice Videau committed
954
	excit_free(cons_iterator->iterator);
955 956 957 958 959
	iterator->dimension = n * src->dimension;
	cons_iterator->iterator = src;
	cons_iterator->n = n;
	cons_iterator->fifo.length = src->dimension * (n - 1);
	cons_iterator->fifo.buffer =
Brice Videau's avatar
Brice Videau committed
960 961
	    (excit_index_t *) malloc(cons_iterator->fifo.length *
					 sizeof(excit_index_t));
962
	if (!cons_iterator->fifo.buffer)
Brice Videau's avatar
Brice Videau committed
963
		return -EXCIT_ENOMEM;
964 965 966 967 968
	err = cons_iterator_rewind(iterator);
	if (err) {
		free(cons_iterator->fifo.buffer);
		return err;
	}
Brice Videau's avatar
Brice Videau committed
969
	return EXCIT_SUCCESS;
970 971
}

Brice Videau's avatar
Brice Videau committed
972
static const struct excit_func_table_s excit_cons_func_table = {
973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988
	cons_iterator_alloc,
	cons_iterator_free,
	cons_iterator_copy,
	cons_iterator_next,
	cons_iterator_peek,
	cons_iterator_size,
	cons_iterator_rewind,
	cons_iterator_split,
	cons_iterator_nth,
	cons_iterator_n,
	cons_iterator_pos
};

/*--------------------------------------------------------------------*/

struct repeat_iterator_s {
Brice Videau's avatar
Brice Videau committed
989 990 991
	excit_t iterator;
	excit_index_t n;
	excit_index_t counter;
992 993
};

Brice Videau's avatar
Brice Videau committed
994
static int repeat_iterator_alloc(excit_t data)
995 996 997
{
	data->data = malloc(sizeof(struct repeat_iterator_s));
	if (!data->data)
Brice Videau's avatar
Brice Videau committed
998
		return -EXCIT_ENOMEM;
999 1000 1001 1002 1003 1004
	struct repeat_iterator_s *iterator =
	    (struct repeat_iterator_s *) data->data;

	iterator->iterator = NULL;
	iterator->n = 0;
	iterator->counter = 0;
Brice Videau's avatar
Brice Videau committed
1005
	return EXCIT_SUCCESS;
1006 1007
}

Brice Videau's avatar
Brice Videau committed
1008
static void repeat_iterator_free(excit_t data)
1009 1010 1011 1012
{
	struct repeat_iterator_s *iterator =
	    (struct repeat_iterator_s *) data->data;

Brice Videau's avatar
Brice Videau committed
1013
	excit_free(iterator->iterator);
1014 1015 1016
	free(data->data);
}

Brice Videau's avatar
Brice Videau committed
1017
static int repeat_iterator_copy(excit_t ddst, const excit_t dsrc)
1018 1019 1020 1021
{
	struct repeat_iterator_s *dst = (struct repeat_iterator_s *) ddst->data;
	const struct repeat_iterator_s *src =
	    (const struct repeat_iterator_s *)dsrc->data;
Brice Videau's avatar
Brice Videau committed
1022
	excit_t copy = excit_dup(src->iterator);
1023 1024

	if (!copy)
Brice Videau's avatar
Brice Videau committed
1025
		return -EXCIT_EINVAL;
1026 1027 1028
	dst->iterator = copy;
	dst->n = src->n;
	dst->counter = src->counter;
Brice Videau's avatar
Brice Videau committed
1029
	return EXCIT_SUCCESS;
1030 1031
}

Brice Videau's avatar
Brice Videau committed
1032 1033
static int repeat_iterator_peek(const excit_t data,
				excit_index_t *indexes)
1034 1035 1036 1037
{
	const struct repeat_iterator_s *iterator =
	    (const struct repeat_iterator_s *) data->data;

Brice Videau's avatar
Brice Videau committed
1038
	return excit_peek(iterator->iterator, indexes);
1039 1040
}

Brice Videau's avatar
Brice Videau committed
1041
static int repeat_iterator_next(excit_t data, excit_index_t *indexes)