diff -r 918b6c0f8b5b -r ed9685f44ab3 src/ring.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ring.h Sat Dec 14 22:36:06 2019 +0200 @@ -0,0 +1,109 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 - 2018 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 . + */ + +#pragma once + +namespace iter +{ + namespace _imp + { + template + class RingAdapter; + } + + template + _imp::RingAdapter ring(T& collection); + + template + _imp::RingAdapter ring(T& collection, int 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 +class iter::_imp::RingAdapter +{ +private: + // The private section must come first because _collection is used in decltype() below. + T& collection; + const int count; + +public: + RingAdapter(T& collection, int count) : + collection {collection}, + count {count} {} + + template + decltype(collection[IndexType()]) operator[](IndexType 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]; + } + } + + int 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 +iter::_imp::RingAdapter iter::ring(T& collection) +{ + return {collection, countof(collection)}; +} + +/* + * Version of ring() that allows manual specification of the count. + */ +template +iter::_imp::RingAdapter iter::ring(T& collection, int count) +{ + return {collection, count}; +} + +template +int countof(const iter::_imp::RingAdapter& ring) +{ + return ring.size(); +}