Property definitions

combinations $ CombinationIterator :: defaultinit
private class CombinationIterator[E]
	super Iterator[SequenceRead[E]]
	var product: CombinationCollection[E]

	var iterators = new Array[Iterator[E]]
	var indices = new Array[Int]

	var are_sorted: Bool is noinit
	var are_unique: Bool is noinit

	init
	do
		are_sorted = product.are_sorted
		are_unique = product.are_unique

		for rank in [0..product.repeat[ do
			reset_iterator(rank)
		end
	end

	redef var is_ok = true

	redef fun item
	do
		var len = product.repeat
		var res = new Array[E].with_capacity(len)
		for i in [0..len[ do
			var it = iterators[i]
			res.add(it.item)
		end
		return res
	end

	redef fun next
	do
		var rank = product.repeat - 1

		loop
			var it = iterators[rank]

			if are_unique and not are_sorted then
				var idx = indices[rank] + 1
				it.next
				var adv = next_free(rank, idx)
				for i in [idx..adv[ do it.next
				indices[rank] = adv
			else
				it.next
				indices[rank] += 1
			end

			if it.is_ok then break
			if rank == 0 then
				is_ok = false
				return
			end
			rank -= 1
		end

		for r in [rank+1..product.repeat[ do
			reset_iterator(r)
		end
	end

	fun next_free(rank: Int, start: Int): Int
	do
		loop
			for i in [0..rank[ do
				if indices[i] == start then
					start += 1
					continue label
				end
			end
			break label
		end label
		return start
	end

	fun reset_iterator(rank: Int): Iterator[E]
	do
		var it = product.collection.iterator
		iterators[rank] = it
		var skip = 0

		if (not are_sorted and not are_unique) or rank == 0 then
			# DO NOTHING
		else if are_sorted and are_unique then
			skip = indices[rank-1] + 1
		else if are_sorted then
			skip = indices[rank-1]
		else
			skip = next_free(rank, 0)
		end

		for i in [0..skip[ do it.next
		indices[rank] = skip
		if not it.is_ok then is_ok = false
		return it
	end

	fun need_skip: Bool
	do
		if not are_sorted and not are_unique then
			return false
		else if are_sorted and are_unique then
			var max = -1
			for i in indices do
				if i <= max then return true
				max = i
			end
			return false
		else if are_sorted then
			var max = -1
			for i in indices do
				if i < max then return true
				max = i
			end
			return false
		else
			# are_unique
			for i in indices do
				if indices.count(i) > 1 then return true
			end
			return false
		end
	end
end
lib/combinations/combinations.nit:313,1--439,3