excit.c 36.5 KB
Newer Older
1
#include <stdlib.h>
2 3
#include <excit.h>

Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
4
#define CASE(val) case val: return #val; break
5

Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
6
const char *excit_type_name(enum excit_type_e type)
7
{
8
	switch (type) {
Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
9 10 11 12 13 14 15 16
		CASE(EXCIT_RANGE);
		CASE(EXCIT_CONS);
		CASE(EXCIT_REPEAT);
		CASE(EXCIT_HILBERT2D);
		CASE(EXCIT_PRODUCT);
		CASE(EXCIT_SLICE);
		CASE(EXCIT_USER);
		CASE(EXCIT_TYPE_MAX);
17 18 19 20 21
	default:
		return NULL;
	}
}

Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
22
const char *excit_error_name(enum excit_error_e err)
23
{
24
	switch (err) {
Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
25 26 27 28 29 30 31
		CASE(EXCIT_SUCCESS);
		CASE(EXCIT_STOPIT);
		CASE(EXCIT_ENOMEM);
		CASE(EXCIT_EINVAL);
		CASE(EXCIT_EDOM);
		CASE(EXCIT_ENOTSUP);
		CASE(EXCIT_ERROR_MAX);
32 33 34 35 36 37 38
	default:
		return NULL;
	}
}

#undef CASE

39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
struct excit_s {
	struct excit_func_table_s *func_table;
	ssize_t dimension;
	enum excit_type_e type;
	void *data;
};

int excit_set_dimension(excit_t it, ssize_t dimension)
{
	if (!it)
		return -EXCIT_EINVAL;
	if (it->type != EXCIT_USER)
		return -EXCIT_ENOTSUP;
	it->dimension = dimension;
	return EXCIT_SUCCESS;
}

int excit_get_data(excit_t it, void **data)
{
	if (!it)
		return -EXCIT_EINVAL;
	if (it->type != EXCIT_USER)
		return -EXCIT_ENOTSUP;
	*data = it->data;
	return EXCIT_SUCCESS;
}

int excit_set_func_table(excit_t it, struct excit_func_table_s *func_table)
{
	if (!it)
		return -EXCIT_EINVAL;
	it->func_table = func_table;
	return EXCIT_SUCCESS;
}

int excit_get_func_table(excit_t it, struct excit_func_table_s **func_table)
{
	if (!it)
		return -EXCIT_EINVAL;
	*func_table = it->func_table;
	return EXCIT_SUCCESS;
}

82 83
/*--------------------------------------------------------------------*/

84
struct slice_it_s {
85 86
	excit_t src;
	excit_t indexer;
87 88
};

89
static int slice_it_alloc(excit_t data)
90
{
91
	struct slice_it_s *it = (struct slice_it_s *) data->data;
92

93 94
	it->src = NULL;
	it->indexer = NULL;
Brice Videau's avatar
Brice Videau committed
95
	return EXCIT_SUCCESS;
96 97
}

98
static void slice_it_free(excit_t data)
99
{
100
	struct slice_it_s *it = (struct slice_it_s *) data->data;
101

102 103
	excit_free(it->src);
	excit_free(it->indexer);
104 105
}

106
static int slice_it_copy(excit_t dst, const excit_t src)
107
{
108 109
	const struct slice_it_s *it = (const struct slice_it_s *) src->data;
	struct slice_it_s *result = (struct slice_it_s *) dst->data;
110

111
	result->src = excit_dup(it->src);
112
	if (!result->src)
Brice Videau's avatar
Brice Videau committed
113
		return -EXCIT_ENOMEM;
114
	result->indexer = excit_dup(it->indexer);
115
	if (!result->indexer) {
116
		excit_free(it->src);
Brice Videau's avatar
Brice Videau committed
117
		return -EXCIT_ENOMEM;
118
	}
Brice Videau's avatar
Brice Videau committed
119
	return EXCIT_SUCCESS;
120 121
}

122
static int slice_it_next(excit_t data, ssize_t *indexes)
123
{
124 125 126
	struct slice_it_s *it = (struct slice_it_s *) data->data;
	ssize_t n;
	int err = excit_next(it->indexer, &n);
127 128 129

	if (err)
		return err;
130
	return excit_nth(it->src, n, indexes);
131 132
}

133
static int slice_it_peek(const excit_t data, ssize_t *indexes)
134
{
135 136 137
	const struct slice_it_s *it = (const struct slice_it_s *)data->data;
	ssize_t n;
	int err = excit_peek(it->indexer, &n);
138 139 140

	if (err)
		return err;
141
	return excit_nth(it->src, n, indexes);
142 143
}

144
static int slice_it_size(const excit_t data, ssize_t *size)
145
{
146
	const struct slice_it_s *it = (const struct slice_it_s *)data->data;
147

148
	return excit_size(it->indexer, size);
149 150
}

151
static int slice_it_rewind(excit_t data)
152
{
153
	struct slice_it_s *it = (struct slice_it_s *) data->data;
154

155
	return excit_rewind(it->indexer);
156 157
}

158
static int slice_it_nth(const excit_t data, ssize_t n, ssize_t *indexes)
159
{
160 161 162
	const struct slice_it_s *it = (const struct slice_it_s *)data->data;
	ssize_t p;
	int err = excit_nth(it->indexer, n, &p);
163 164 165

	if (err)
		return err;
166
	return excit_nth(it->src, p, indexes);
167 168
}

169
static int slice_it_rank(const excit_t data, const ssize_t *indexes, ssize_t *n)
170
{
171 172
	const struct slice_it_s *it = (const struct slice_it_s *)data->data;
	ssize_t inner_n;
173
	int err = excit_rank(it->src, indexes, &inner_n);
174 175 176

	if (err)
		return err;
177
	return excit_rank(it->indexer, &inner_n, n);
178 179
}

180
static int slice_it_pos(const excit_t data, ssize_t *n)
181
{
182
	const struct slice_it_s *it = (const struct slice_it_s *)data->data;
183

184
	return excit_pos(it->indexer, n);
185 186
}

187
static int slice_it_split(const excit_t data, ssize_t n, excit_t *results)
188
{
189 190
	const struct slice_it_s *it = (const struct slice_it_s *)data->data;
	int err = excit_split(it->indexer, n, results);
191 192 193 194

	if (err)
		return err;
	if (!results)
Brice Videau's avatar
Brice Videau committed
195
		return EXCIT_SUCCESS;
196
	for (int i = 0; i < n; i++) {
197 198
		excit_t tmp;
		excit_t tmp2;
199 200

		tmp = results[i];
201
		results[i] = excit_alloc(EXCIT_SLICE);
202
		if (!results[i]) {
203
			excit_free(tmp);
Brice Videau's avatar
Brice Videau committed
204
			err = -EXCIT_ENOMEM;
205 206
			goto error;
		}
207
		tmp2 = excit_dup(it->src);
208
		if (!tmp2) {
209
			excit_free(tmp);
Brice Videau's avatar
Brice Videau committed
210
			err = -EXCIT_ENOMEM;
211 212
			goto error;
		}
213
		err = excit_slice_init(results[i], tmp, tmp2);
214
		if (err) {
215 216
			excit_free(tmp);
			excit_free(tmp2);
217 218 219
			goto error;
		}
	}
Brice Videau's avatar
Brice Videau committed
220
	return EXCIT_SUCCESS;
221 222
error:
	for (int i = 0; i < n; i++)
223
		excit_free(results[i]);
224 225 226
	return err;
}

227
static struct excit_func_table_s excit_slice_func_table = {
228 229 230 231 232 233 234 235 236
	slice_it_alloc,
	slice_it_free,
	slice_it_copy,
	slice_it_next,
	slice_it_peek,
	slice_it_size,
	slice_it_rewind,
	slice_it_split,
	slice_it_nth,
237
	slice_it_rank,
238
	slice_it_pos
239 240
};

241
int excit_slice_init(excit_t it, excit_t src, excit_t indexer)
242
{
243 244
	if (!it || it->type != EXCIT_SLICE || !src || !indexer
		|| indexer->dimension != 1)
Brice Videau's avatar
Brice Videau committed
245
		return -EXCIT_EINVAL;
246 247 248
	struct slice_it_s *slice_it = (struct slice_it_s *) it->data;
	ssize_t size_src;
	ssize_t size_indexer;
249
	int err = excit_size(src, &size_src);
250 251 252

	if (err)
		return err;
253
	err = excit_size(indexer, &size_indexer);
254 255 256
	if (err)
		return err;
	if (size_indexer > size_src)
Brice Videau's avatar
Brice Videau committed
257
		return -EXCIT_EDOM;
258 259 260
	slice_it->src = src;
	slice_it->indexer = indexer;
	it->dimension = src->dimension;
Brice Videau's avatar
Brice Videau committed
261
	return EXCIT_SUCCESS;
262 263 264 265
}

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

266 267 268
struct prod_it_s {
	ssize_t count;
	excit_t *its;
269 270
};

271
static int prod_it_alloc(excit_t data)
272
{
273
	struct prod_it_s *it = (struct prod_it_s *) data->data;
274

275 276
	it->count = 0;
	it->its = NULL;
Brice Videau's avatar
Brice Videau committed
277
	return EXCIT_SUCCESS;
278 279
}

280
static void prod_it_free(excit_t data)
281
{
282
	struct prod_it_s *it = (struct prod_it_s *) data->data;
283

284 285 286 287
	if (it->its) {
		for (ssize_t i = 0; i < it->count; i++)
			excit_free(it->its[i]);
		free(it->its);
288 289 290
	}
}

291
static int prod_it_copy(excit_t dst, const excit_t src)
292
{
293 294
	const struct prod_it_s *it = (const struct prod_it_s *)src->data;
	struct prod_it_s *result = (struct prod_it_s *) dst->data;
295

296 297
	result->its = (excit_t *) malloc(it->count * sizeof(excit_t));
	if (!result->its)
Brice Videau's avatar
Brice Videau committed
298
		return -EXCIT_ENOMEM;
299
	ssize_t i;
300

301 302 303
	for (i = 0; i < it->count; i++) {
		result->its[i] = excit_dup(it->its[i]);
		if (!result->its[i]) {
304 305 306 307
			i--;
			goto error;
		}
	}
308
	result->count = it->count;
Brice Videau's avatar
Brice Videau committed
309
	return EXCIT_SUCCESS;
310 311
error:
	while (i >= 0) {
312
		free(result->its[i]);
313 314
		i--;
	}
315
	free(result->its);
Brice Videau's avatar
Brice Videau committed
316
	return -EXCIT_ENOMEM;
317 318
}

319
static int prod_it_rewind(excit_t data)
320
{
321
	struct prod_it_s *it = (struct prod_it_s *) data->data;
322

323 324
	for (ssize_t i = 0; i < it->count; i++) {
		int err = excit_rewind(it->its[i]);
325 326 327 328

		if (err)
			return err;
	}
Brice Videau's avatar
Brice Videau committed
329
	return EXCIT_SUCCESS;
330 331
}

332
static int prod_it_size(const excit_t data, ssize_t *size)
333
{
334 335
	const struct prod_it_s *it = (const struct prod_it_s *) data->data;
	ssize_t tmp_size = 0;
336 337

	if (!size)
Brice Videau's avatar
Brice Videau committed
338
		return -EXCIT_EINVAL;
339
	if (it->count == 0)
340 341 342
		*size = 0;
	else {
		*size = 1;
343 344
		for (ssize_t i = 0; i < it->count; i++) {
			int err = excit_size(it->its[i], &tmp_size);
345 346 347 348 349 350 351 352

			if (err) {
				*size = 0;
				return err;
			}
			*size *= tmp_size;
		}
	}
Brice Videau's avatar
Brice Videau committed
353
	return EXCIT_SUCCESS;
354 355
}

356
static int prod_it_nth(const excit_t data, ssize_t n, ssize_t *indexes)
357
{
358 359
	ssize_t size;
	int err = prod_it_size(data, &size);
360 361 362 363

	if (err)
		return err;
	if (n < 0 || n >= size)
Brice Videau's avatar
Brice Videau committed
364
		return -EXCIT_EDOM;
365
	const struct prod_it_s *it = (const struct prod_it_s *) data->data;
366 367

	if (indexes) {
368 369
		ssize_t subsize = 0;
		ssize_t offset = data->dimension;
370

371 372 373
		for (ssize_t i = it->count - 1; i >= 0; i--) {
			offset -= it->its[i]->dimension;
			err = excit_size(it->its[i], &subsize);
374 375
			if (err)
				return err;
376 377
			err = excit_nth(it->its[i], n % subsize,
					indexes + offset);
378 379 380 381 382
			if (err)
				return err;
			n /= subsize;
		}
	}
Brice Videau's avatar
Brice Videau committed
383
	return EXCIT_SUCCESS;
384 385
}

386
static int prod_it_rank(const excit_t data, const ssize_t *indexes, ssize_t *n)
387
{
388
	const struct prod_it_s *it = (const struct prod_it_s *) data->data;
389

390
	if (it->count == 0)
Brice Videau's avatar
Brice Videau committed
391
		return -EXCIT_EINVAL;
392 393 394 395 396 397
	ssize_t offset = 0;
	ssize_t product = 0;
	ssize_t inner_n;
	ssize_t subsize;

	for (ssize_t i = 0; i < it->count; i++) {
398
		int err = excit_rank(it->its[i], indexes + offset, &inner_n);
Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
399

400 401
		if (err)
			return err;
402
		err = excit_size(it->its[i], &subsize);
403 404 405 406
		if (err)
			return err;
		product *= subsize;
		product += inner_n;
407
		offset += it->its[i]->dimension;
408 409 410
	}
	if (n)
		*n = product;
Brice Videau's avatar
Brice Videau committed
411
	return EXCIT_SUCCESS;
412 413
}

414
static int prod_it_pos(const excit_t data, ssize_t *n)
415
{
416
	const struct prod_it_s *it = (const struct prod_it_s *) data->data;
417

418
	if (it->count == 0)
Brice Videau's avatar
Brice Videau committed
419
		return -EXCIT_EINVAL;
420 421 422
	ssize_t product = 0;
	ssize_t inner_n;
	ssize_t subsize;
423

424 425
	for (ssize_t i = 0; i < it->count; i++) {
		int err = excit_pos(it->its[i], &inner_n);
426 427 428

		if (err)
			return err;
429
		err = excit_size(it->its[i], &subsize);
430 431 432 433 434 435 436
		if (err)
			return err;
		product *= subsize;
		product += inner_n;
	}
	if (n)
		*n = product;
Brice Videau's avatar
Brice Videau committed
437
	return EXCIT_SUCCESS;
438 439
}

440 441
static inline int prod_it_peeknext_helper(excit_t data, ssize_t *indexes,
					  int next)
442
{
443
	struct prod_it_s *it = (struct prod_it_s *) data->data;
444 445
	int err;
	int looped;
446 447 448
	ssize_t i;
	ssize_t *next_indexes;
	ssize_t offset = data->dimension;
449

450
	if (it->count == 0)
Brice Videau's avatar
Brice Videau committed
451
		return -EXCIT_EINVAL;
452
	looped = next;
453
	for (i = it->count - 1; i > 0; i--) {
454
		if (indexes) {
455
			offset -= it->its[i]->dimension;
456 457 458 459
			next_indexes = indexes + offset;
		} else
			next_indexes = NULL;
		if (looped)
460 461
			err = excit_cyclic_next(it->its[i], next_indexes,
						&looped);
462
		else
463
			err = excit_peek(it->its[i], next_indexes);
464 465 466 467
		if (err)
			return err;
	}
	if (indexes) {
468
		offset -= it->its[i]->dimension;
469 470 471 472
		next_indexes = indexes + offset;
	} else
		next_indexes = NULL;
	if (looped)
473
		err = excit_next(it->its[0], next_indexes);
474
	else
475
		err = excit_peek(it->its[0], next_indexes);
476 477
	if (err)
		return err;
Brice Videau's avatar
Brice Videau committed
478
	return EXCIT_SUCCESS;
479 480
}

481
static int prod_it_peek(const excit_t data, ssize_t *indexes)
482
{
483
	return prod_it_peeknext_helper(data, indexes, 0);
484 485
}

486
static int prod_it_next(excit_t data, ssize_t *indexes)
487
{
488
	return prod_it_peeknext_helper(data, indexes, 1);
489 490
}

491
static int prod_it_split(const excit_t data, ssize_t n, excit_t *results)
492
{
493 494
	ssize_t size;
	int err = prod_it_size(data, &size);
495 496 497 498

	if (err)
		return err;
	if (size < n)
Brice Videau's avatar
Brice Videau committed
499
		return -EXCIT_EDOM;
500
	if (!results)
Brice Videau's avatar
Brice Videau committed
501
		return EXCIT_SUCCESS;
502
	excit_t range = excit_alloc(EXCIT_RANGE);
503 504

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

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

540
int excit_product_count(const excit_t it, ssize_t *count)
541
{
542
	if (!it || it->type != EXCIT_PRODUCT || !count)
Brice Videau's avatar
Brice Videau committed
543
		return -EXCIT_EINVAL;
544
	*count = ((struct prod_it_s *) it->data)->count;
Brice Videau's avatar
Brice Videau committed
545
	return EXCIT_SUCCESS;
546 547
}

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

	if (err)
		return err;
	if (dim >= count)
Brice Videau's avatar
Brice Videau committed
561
		return -EXCIT_EDOM;
562
	struct prod_it_s *prod_it = (struct prod_it_s *) it->data;
563

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

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

590
int excit_product_add_copy(excit_t it, excit_t added_it)
591 592
{
	int err = 0;
593
	excit_t copy = excit_dup(added_it);
594 595

	if (!copy)
Brice Videau's avatar
Brice Videau committed
596
		return -EXCIT_EINVAL;
597
	err = excit_product_add(it, copy);
598
	if (err) {
599
		excit_free(added_it);
600 601
		return err;
	}
Brice Videau's avatar
Brice Videau committed
602
	return EXCIT_SUCCESS;
603 604
}

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

611 612
	struct prod_it_s *prod_it = (struct prod_it_s *) it->data;
	ssize_t mew_count = prod_it->count + 1;
613

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

625
static struct excit_func_table_s excit_prod_func_table = {
626 627 628 629 630 631 632 633 634
	prod_it_alloc,
	prod_it_free,
	prod_it_copy,
	prod_it_next,
	prod_it_peek,
	prod_it_size,
	prod_it_rewind,
	prod_it_split,
	prod_it_nth,
635
	prod_it_rank,
636
	prod_it_pos
637 638 639 640 641
};

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

struct circular_fifo_s {
642 643 644 645 646
	ssize_t length;
	ssize_t start;
	ssize_t end;
	ssize_t size;
	ssize_t *buffer;
647 648
};

649
static void circular_fifo_add(struct circular_fifo_s *fifo, ssize_t elem)
650 651 652 653 654 655 656 657 658 659 660
{
	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;
}

Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
661
static void circular_fifo_dump(const struct circular_fifo_s *fifo,
662
			       ssize_t *vals)
663
{
664 665
	ssize_t i;
	ssize_t j;
666 667 668 669 670 671 672

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

673 674 675
struct cons_it_s {
	excit_t it;
	ssize_t n;
676 677 678
	struct circular_fifo_s fifo;
};

679
static int cons_it_alloc(excit_t data)
680
{
681 682 683 684 685 686 687 688 689
	struct cons_it_s *it = (struct cons_it_s *) data->data;

	it->it = NULL;
	it->n = 0;
	it->fifo.length = 0;
	it->fifo.start = 0;
	it->fifo.end = -1;
	it->fifo.size = 0;
	it->fifo.buffer = NULL;
Brice Videau's avatar
Brice Videau committed
690
	return EXCIT_SUCCESS;
691 692
}

693
static void cons_it_free(excit_t data)
694
{
695
	struct cons_it_s *it = (struct cons_it_s *) data->data;
696

697 698
	excit_free(it->it);
	free(it->fifo.buffer);
699 700
}

701
static int cons_it_copy(excit_t ddst, const excit_t dsrc)
702
{
703 704 705
	struct cons_it_s *dst = (struct cons_it_s *) ddst->data;
	const struct cons_it_s *src = (const struct cons_it_s *)dsrc->data;
	excit_t copy = excit_dup(src->it);
706 707

	if (!copy)
Brice Videau's avatar
Brice Videau committed
708
		return -EXCIT_EINVAL;
709
	dst->it = copy;
710 711 712 713 714 715
	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 =
716
	    (ssize_t *) malloc(src->fifo.length * sizeof(ssize_t));
717
	if (!dst->fifo.buffer) {
718
		excit_free(copy);
Brice Videau's avatar
Brice Videau committed
719
		return -EXCIT_ENOMEM;
720 721 722
	}
	for (int i = 0; i < dst->fifo.length; i++)
		dst->fifo.buffer[i] = src->fifo.buffer[i];
Brice Videau's avatar
Brice Videau committed
723
	return EXCIT_SUCCESS;
724 725
}

726
static int cons_it_size(const excit_t data, ssize_t *size)
727
{
728 729 730
	const struct cons_it_s *it = (const struct cons_it_s *)data->data;
	ssize_t tmp_size = 0;
	int err = excit_size(it->it, &tmp_size);
731 732 733

	if (err)
		return err;
734
	*size = tmp_size - (it->n - 1);
Brice Videau's avatar
Brice Videau committed
735
	return EXCIT_SUCCESS;
736 737
}

738
static int cons_it_split(const excit_t data, ssize_t n, excit_t *results)
739
{
740 741
	ssize_t size;
	int err = cons_it_size(data, &size);
742 743 744 745

	if (err)
		return err;
	if (size < n)
Brice Videau's avatar
Brice Videau committed
746
		return -EXCIT_EDOM;
747
	if (!results)
Brice Videau's avatar
Brice Videau committed
748
		return EXCIT_SUCCESS;
749
	excit_t range = excit_alloc(EXCIT_RANGE);
750 751

	if (!range)
Brice Videau's avatar
Brice Videau committed
752
		return -EXCIT_ENOMEM;
753
	err = excit_range_init(range, 0, size - 1, 1);
754 755
	if (err)
		goto error1;
756
	err = excit_split(range, n, results);
757 758 759 760 761
	if (err)
		goto error1;
	int i;

	for (i = 0; i < n; i++) {
762
		excit_t tmp, tmp2;
763

764
		tmp = excit_dup(data);
765 766 767
		if (!tmp)
			goto error2;
		tmp2 = results[i];
768
		results[i] = excit_alloc(EXCIT_SLICE);
769
		if (!results[i]) {
770
			excit_free(tmp2);
771 772
			goto error2;
		}
773
		err = excit_slice_init(results[i], tmp, tmp2);
774
		if (err) {
775
			excit_free(tmp2);
776 777 778
			goto error2;
		}
	}
779
	excit_free(range);
Brice Videau's avatar
Brice Videau committed
780
	return EXCIT_SUCCESS;
781 782
error2:
	for (; i >= 0; i--)
783
		excit_free(results[i]);
784
error1:
785
	excit_free(range);
786 787 788
	return err;
}

789
static int cons_it_nth(const excit_t data, ssize_t n, ssize_t *indexes)
790
{
791 792
	ssize_t size;
	int err = cons_it_size(data, &size);
793 794 795 796

	if (err)
		return err;
	if (n < 0 || n >= size)
Brice Videau's avatar
Brice Videau committed
797
		return -EXCIT_EDOM;
798 799
	const struct cons_it_s *it = (const struct cons_it_s *) data->data;
	int dim = it->it->dimension;
800 801

	if (indexes) {
802 803
		for (int i = 0; i < it->n; i++) {
			err = excit_nth(it->it, n + i, indexes + dim * i);
804 805 806 807
			if (err)
				return err;
		}
	}
Brice Videau's avatar
Brice Videau committed
808
	return EXCIT_SUCCESS;
809 810
}

811
static int cons_it_rank(const excit_t data, const ssize_t *indexes, ssize_t *n)
812
{
813 814
	const struct cons_it_s *it = (const struct cons_it_s *) data->data;
	ssize_t inner_n, inner_n_tmp;
815
	int err = excit_rank(it->it, indexes, &inner_n);
816 817 818

	if (err)
		return err;
819
	int dim = it->it->dimension;
820

821
	for (int i = 1; i < it->n; i++) {
822
		err = excit_rank(it->it, indexes + dim * i, &inner_n_tmp);
823 824 825
		if (err)
			return err;
		if (inner_n_tmp != inner_n + 1)
Brice Videau's avatar
Brice Videau committed
826
			return -EXCIT_EINVAL;
827 828 829
		inner_n = inner_n_tmp;
	}
	if (n)
830
		*n = inner_n - (it->n - 1);
Brice Videau's avatar
Brice Videau committed
831
	return EXCIT_SUCCESS;
832 833
}

834
static int cons_it_pos(const excit_t data, ssize_t *n)
835
{
836 837 838
	ssize_t inner_n;
	const struct cons_it_s *it = (const struct cons_it_s *) data->data;
	int err = excit_pos(it->it, &inner_n);
839 840 841 842

	if (err)
		return err;
	if (n)
843
		*n = inner_n - (it->n - 1);
Brice Videau's avatar
Brice Videau committed
844
	return EXCIT_SUCCESS;
845 846
}

847
static int cons_it_peek(const excit_t data, ssize_t *indexes)
848
{
849
	const struct cons_it_s *it = (const struct cons_it_s *) data->data;
850
	int err;
851 852
	int dim = it->it->dimension;
	int n = it->n;
853 854

	if (indexes) {
855 856
		circular_fifo_dump(&it->fifo, indexes);
		err = excit_peek(it->it, indexes + dim * (n - 1));
857
	} else
858
		err = excit_peek(it->it, NULL);
859 860
	if (err)
		return err;
Brice Videau's avatar
Brice Videau committed
861
	return EXCIT_SUCCESS;
862 863
}

864
static int cons_it_next(excit_t data, ssize_t *indexes)
865
{
866
	struct cons_it_s *it = (struct cons_it_s *) data->data;
867
	int err;
868 869
	int dim = it->it->dimension;
	int n = it->n;
870 871

	if (indexes) {
872 873
		circular_fifo_dump(&it->fifo, indexes);
		err = excit_next(it->it, indexes + dim * (n - 1));
874
	} else
875
		err = excit_next(it->it, NULL);
876 877 878 879
	if (err)
		return err;
	if (indexes)
		for (int i = dim * (n - 1); i < dim * n; i++)
880
			circular_fifo_add(&it->fifo, indexes[i]);
Brice Videau's avatar
Brice Videau committed
881
	return EXCIT_SUCCESS;
882 883
}

884
static int cons_it_rewind(excit_t data)
885
{
886 887
	struct cons_it_s *it = (struct cons_it_s *) data->data;
	int err = excit_rewind(it->it);
888 889 890

	if (err)
		return err;
891 892 893
	it->fifo.start = 0;
	it->fifo.end = -1;
	it->fifo.size = 0;
894

895
	for (int i = 0; i < it->n - 1; i++) {
896 897 898
		int err;

		err =
899
		    excit_next(it->it, it->fifo.buffer + it->it->dimension * i);
900 901
		if (err)
			return err;
902 903
		it->fifo.size += it->it->dimension;
		it->fifo.end += it->it->dimension;
904
	}
Brice Videau's avatar
Brice Videau committed
905
	return EXCIT_SUCCESS;
906 907
}

908
int excit_cons_init(excit_t it, excit_t src, ssize_t n)
909
{
910
	ssize_t src_size;
911 912
	int err;

913
	if (!it || it->type != EXCIT_CONS || !src || n <= 0)
Brice Videau's avatar
Brice Videau committed
914
		return -EXCIT_EINVAL;
915
	err = excit_size(src, &src_size);
916 917 918
	if (err)
		return err;
	if (src_size < n)
Brice Videau's avatar
Brice Videau committed
919
		return -EXCIT_EINVAL;
920 921 922 923 924 925 926 927 928 929 930
	struct cons_it_s *cons_it = (struct cons_it_s *) it->data;

	free(cons_it->fifo.buffer);
	excit_free(cons_it->it);
	it->dimension = n * src->dimension;
	cons_it->it = src;
	cons_it->n = n;
	cons_it->fifo.length = src->dimension * (n - 1);
	cons_it->fifo.buffer =
	    (ssize_t *) malloc(cons_it->fifo.length * sizeof(ssize_t));
	if (!cons_it->fifo.buffer)
Brice Videau's avatar
Brice Videau committed
931
		return -EXCIT_ENOMEM;
932
	err = cons_it_rewind(it);
933
	if (err) {
934
		free(cons_it->fifo.buffer);
935 936
		return err;
	}
Brice Videau's avatar
Brice Videau committed
937
	return EXCIT_SUCCESS;
938 939
}

940
static struct excit_func_table_s excit_cons_func_table = {
941 942 943 944 945 946 947 948 949
	cons_it_alloc,
	cons_it_free,
	cons_it_copy,
	cons_it_next,
	cons_it_peek,
	cons_it_size,
	cons_it_rewind,
	cons_it_split,
	cons_it_nth,
950
	cons_it_rank,
951
	cons_it_pos
952 953 954 955
};

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

956 957 958 959
struct repeat_it_s {
	excit_t it;
	ssize_t n;
	ssize_t counter;
960 961
};

962
static int repeat_it_alloc(excit_t data)
963
{
964
	struct repeat_it_s *it = (struct repeat_it_s *) data->data;
965

966 967 968
	it->it = NULL;
	it->n = 0;
	it->counter = 0;
Brice Videau's avatar
Brice Videau committed
969
	return EXCIT_SUCCESS;
970 971
}

972
static void repeat_it_free(excit_t data)
973
{
974
	struct repeat_it_s *it = (struct repeat_it_s *) data->data;
975

976
	excit_free(it->it);
977 978
}

979
static int repeat_it_copy(excit_t ddst, const excit_t dsrc)
980
{
981 982 983
	struct repeat_it_s *dst = (struct repeat_it_s *) ddst->data;
	const struct repeat_it_s *src = (const struct repeat_it_s *)dsrc->data;
	excit_t copy = excit_dup(src->it);
984 985

	if (!copy)
Brice Videau's avatar
Brice Videau committed
986
		return -EXCIT_EINVAL;
987
	dst->it = copy;
988 989
	dst->n = src->n;
	dst->counter = src->counter;
Brice Videau's avatar
Brice Videau committed
990
	return EXCIT_SUCCESS;
991 992
}

993
static int repeat_it_peek(const excit_t data, ssize_t *indexes)
994
{
995
	const struct repeat_it_s *it = (const struct repeat_it_s *) data->data;
996

997
	return excit_peek(it->it, indexes);
998 999
}

1000
static int repeat_it_next(excit_t data, ssize_t *indexes)
1001
{
1002
	struct repeat_it_s *it = (struct repeat_it_s *) data->data;
1003

1004 1005 1006 1007 1008
	it->counter++;
	if (it->counter < it->n)
		return excit_peek(it->it, indexes);
	it->counter = 0;
	return excit_next(it->it, indexes);
1009 1010
}

1011
static int repeat_it_size(const excit_t data, ssize_t *size)
1012
{
1013 1014
	const struct repeat_it_s *it = (const struct repeat_it_s *) data->data;
	int err = excit_size(it->it, size);
1015 1016 1017

	if (err)
		return err;
1018
	*size *= it->n;
Brice Videau's avatar
Brice Videau committed
1019
	return EXCIT_SUCCESS;
1020 1021
}

1022
static int repeat_it_rewind(excit_t data)
1023
{
1024
	struct repeat_it_s *it = (struct repeat_it_s *) data->data;
1025

1026 1027
	it->counter = 0;
	return excit_rewind(it->it);
1028 1029
}

1030
static int repeat_it_nth(const excit_t data, ssize_t n, ssize_t *val)
1031
{
1032 1033
	ssize_t size;
	int err = repeat_it_size(data, &size);
1034 1035 1036 1037

	if (err)
		return err;
	if (n < 0 || n >= size)
Brice Videau's avatar
Brice Videau committed
1038
		return -EXCIT_EDOM;
1039
	const struct repeat_it_s *it = (const struct repeat_it_s *) data->data;
1040

1041