src/ring.h

Fri, 06 Mar 2020 16:08:45 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Fri, 06 Mar 2020 16:08:45 +0200
changeset 68
ddb07bb6840c
parent 26
3a9e761e4faa
child 115
ed884a2fb009
permissions
-rw-r--r--

default to XZ

/*
 *  LDForge: LDraw parts authoring CAD
 *  Copyright (C) 2013 - 2020 Teemu Piippo
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

namespace iter
{
	namespace _imp
	{
		template<typename T, typename Tint>
		class RingAdapter;
	}

	template<typename T>
	_imp::RingAdapter<T, int> ring(T&& collection);

	template<typename T, typename Tint>
	_imp::RingAdapter<T, Tint> ring(T&& collection, Tint count);
}

/*
 * Implements a ring adapter over T. This class corrects indices given to the element-operator so that they're within bounds.
 * The maximum amount can be specified manually.
 *
 * Example:
 *
 *   int A[] = {10,20,30,40};
 *   ring(A)[0]  ==     A[0 % 4]    == A[0]
 *   ring(A)[5]  ==     A[5 % 4]    == A[1]
 *   ring(A)[-1] == ring(A)[-1 + 4] == A[3]
 */
template<typename T, typename Tint>
class iter::_imp::RingAdapter
{
private:
	// The private section must come first because _collection is used in decltype() below.
	T&& collection;
	const Tint count;

public:
	RingAdapter(T&& collection, Tint count) :
		collection {collection},
		count {count} {}

	decltype(collection[Tint{}]) operator[](Tint index)
	{
		if (count == 0)
		{
			// Argh! ...let the collection deal with this case.
			return this->collection[index];
		}
		else
		{
			index %= this->count;

			// Fix negative modulus...
			if (index < 0)
				index += this->count;

			return this->collection[index];
		}
	}

	Tint size() const
	{
		return this->count;
	}
};

/*
 * Convenience function for RingAdapter so that the template parameter does not have to be provided. The ring amount is assumed
 * to be the amount of elements in the collection.
 */
template<typename T>
iter::_imp::RingAdapter<T, int> iter::ring(T&& collection)
{
	return {collection, countof(collection)};
}

/*
 * Version of ring() that allows manual specification of the count.
 */
template<typename T, typename Tint>
iter::_imp::RingAdapter<T, Tint> iter::ring(T&& collection, Tint count)
{
	return {collection, count};
}

template<typename T, typename Tint>
int countof(const iter::_imp::RingAdapter<T, Tint>& ring)
{
	return ring.size();
}

mercurial