ModuloCounter.h 3.96 KB
/*
 * ModuloCounter.h
 *
 *  Created on: 8 mar 2019
 *      Author: mariuszo
 */

#ifndef MODULOCOUNTER_H_
#define MODULOCOUNTER_H_
/*
#include <type_traits>
#include <limits>
#include <atomic>
#include <assert.h>
*/
template <typename T, class Enable = void> class ModuloCounter {};
template <typename T> class ModuloCounter<T, typename std::enable_if<std::numeric_limits<T>::is_integer>::type> {
	T m_value;
	T m_limit;
public:
	ModuloCounter(const T& value=-1, const T& modulo=0):m_value(value), m_limit(modulo-1){
		assert(m_limit>=-1);
		assert(m_limit==-1 || (m_value>=0 && m_value<=m_limit));
	}

	inline void operator()(const T& value, const T& modulo) {
		m_value=value;
		m_limit=modulo-1;
		assert(m_limit>=0);
		assert(m_value>=0 && m_value<=m_limit);
	}

	T& operator=(const T& value){
		assert(m_limit>=0);
		assert(m_value>=0 && m_value<=m_limit);
		m_value=value;
		return m_value;
	}

	inline T& operator++(){
		assert(m_limit>=0);
		if (m_value!=m_limit)
			m_value++;
		else
			m_value=0;
		return m_value;
	}
	inline T& operator--(){
		assert(m_limit>=0);
		if (m_value!=0)
			m_value--;
		else
			m_value=m_limit;
		return m_value;
	}

	inline T operator++(int){
		assert(m_limit>=0);
		const T orgvalue(m_value);
		++(*this);
		return orgvalue;
	}
	inline T operator--(int){
		assert(m_limit>=0);
		const T orgvalue(m_value);
		--(*this);
		return orgvalue;
	}
	inline const T& val() const{
		return m_value;
	}
	inline T prev() const {
		assert(m_limit>=0);
		if (m_value!=0)
			return m_value-1;
		else
			return m_limit;
	}
	inline static T prev(const T& value, const T& modulo) {
		assert(modulo>0);
		assert(value>=0 && value<modulo);
		if (value!=0)
			return value-1;
		else
			return modulo-1;
	}
	inline T next() const {
		assert(m_limit>=0);
		if (m_value!=m_limit)
			return m_value+1;
		else
			return 0;
	}
	inline static T next(const T& value, const T& modulo) {
		assert(modulo>0);
		assert(value>=0 && value<modulo);
		if (value!=modulo-1)
			return value+1;
		else
			return 0;
	}
};

template <typename T, class Enable = void> class AtomicModuloCounter {};
template <typename T> class AtomicModuloCounter<T, typename std::enable_if<std::numeric_limits<T>::is_integer>::type> {
	std::atomic<T> m_value;
	T m_limit;
	AtomicModuloCounter& operator=(const AtomicModuloCounter&) = delete;
	AtomicModuloCounter& operator=(const AtomicModuloCounter&) volatile = delete;
public:
	AtomicModuloCounter(const T& value=-1, const T& modulo=0):m_value(value), m_limit(modulo-1){
		assert(m_limit>=-1);
		assert(m_limit==-1 || (m_value>=0 && m_value<=m_limit));
	}

	inline void operator()(const T& value, const T& modulo) {
		m_value=value;
		m_limit=modulo-1;
		assert(m_limit>=0);
		assert(m_value>=0 && m_value<=m_limit);
	}

	T& operator=(const T& value){
		assert(m_limit>=0);
		assert(m_value>=0 && m_value<=m_limit);
		return m_value=value;
	}

	inline T operator++(){
		assert(m_limit>=0);
		T val=m_value.load(std::memory_order_relaxed);
		T newval;
		do {
		    newval=(val!=m_limit)?val+1:0;
		} while (!m_value.compare_exchange_weak(val, newval, std::memory_order_release, std::memory_order_relaxed));
		return newval;
	}
	inline T operator--(){
		assert(m_limit>=0);
		T val=m_value.load(std::memory_order_relaxed);
		T newval;
		do {
		    newval=(val!=0)?val-1:m_limit;
		} while (!m_value.compare_exchange_weak(val, newval, std::memory_order_release, std::memory_order_relaxed));
		return newval;
	}

	inline T operator++(T){
		assert(m_limit>=0);
		T val=m_value.load(std::memory_order_relaxed);
		do {
		} while (!m_value.compare_exchange_weak(val, (val!=m_limit)?val+1:0, std::memory_order_release, std::memory_order_relaxed));
		return val;
	}
	inline T operator--(T){
		assert(m_limit>=0);
		T val=m_value.load(std::memory_order_relaxed);
		do {
		} while (!m_value.compare_exchange_weak(val, (val!=0)?val-1:m_limit, std::memory_order_release, std::memory_order_relaxed));
		return val;
	}
	inline const T val() const{
		return m_value.load(std::memory_order_acquire);
	}
};

#endif /* MODULOCOUNTER_H_ */