/*
Ranged integer class by M Phillips - 2007.

This code is provided as is with no warranties or guarantees of
any kind.

Please send an email to M Phillips (mbp2@i4free.co.nz)
  - if you use this file in a released product, or
  - if you find any bugs, or
  - if you have any suggestions
*/

#ifndef RANGED_INTEGER_H
#define RANGED_INTEGER_H

#include <climits>
#include <limits>
#include <stdexcept>

// compile-time asserts (failure results in error C2118: negative subscript)
#ifndef C_ASSERT
#define ASSERT_CONCAT_(a, b) a##b
#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
#define C_ASSERT(e) typedef char ASSERT_CONCAT(assert_line_, __LINE__)[(e)?1:-1]
#endif

#define OUT_OF_RANGE_EXCEPTION std::out_of_range("Out of range")

template <int MINRANGE = (std::numeric_limits<int>::min)(), int MAXRANGE = (std::numeric_limits<int>::max)()>
class rangedInteger {
	C_ASSERT(MINRANGE != INT_MIN || MAXRANGE != INT_MAX);

	int value;

public:
	operator int() const {
		return value;
	}
	rangedInteger() : value(MINRANGE) {
	}
	rangedInteger(int val) : value(val) {
		if (value < MINRANGE || value > MAXRANGE) throw OUT_OF_RANGE_EXCEPTION;
	}
	rangedInteger(const rangedInteger &r) : value(r.value) {
		if (value < MINRANGE || value > MAXRANGE) throw OUT_OF_RANGE_EXCEPTION;
	}
	const rangedInteger& operator = (const rangedInteger &r) {
		if (r.value < MINRANGE || r.value > MAXRANGE) throw OUT_OF_RANGE_EXCEPTION;
		value = r.value;
		return *this;
	}
	const rangedInteger& operator += (int r) {
		int tempvalue = value;
		tempvalue += r;
		if (tempvalue < MINRANGE || tempvalue > MAXRANGE) throw OUT_OF_RANGE_EXCEPTION;
		value = tempvalue;
		return *this;
	}
	const rangedInteger& operator -= (int r) {
		int tempvalue = value;
		tempvalue -= r;
		if (tempvalue < MINRANGE || tempvalue > MAXRANGE) throw OUT_OF_RANGE_EXCEPTION;
		value = tempvalue;
		return *this;
	}
	const rangedInteger& operator *= (int r) {
		int tempvalue = value;
		tempvalue *= r;
		if (tempvalue < MINRANGE || tempvalue > MAXRANGE) throw OUT_OF_RANGE_EXCEPTION;
		value = tempvalue;
		return *this;
	}
	const rangedInteger& operator /= (int r) {
		int tempvalue = value;
		tempvalue /= r;
		if (tempvalue < MINRANGE || tempvalue > MAXRANGE) throw OUT_OF_RANGE_EXCEPTION;
		value = tempvalue;
		return *this;
	}
	const rangedInteger& operator >>= (int r) {
		int tempvalue = value;
		tempvalue >>= r;
		if (tempvalue < MINRANGE || tempvalue > MAXRANGE) throw OUT_OF_RANGE_EXCEPTION;
		value = tempvalue;
		return *this;
	}
	const rangedInteger& operator <<= (int r) {
		int tempvalue = value;
		tempvalue <<= r;
		if (tempvalue < MINRANGE || tempvalue > MAXRANGE) throw OUT_OF_RANGE_EXCEPTION;
		value = tempvalue;
		return *this;
	}
	const rangedInteger& operator |= (int r) {
		int tempvalue = value;
		tempvalue |= r;
		if (tempvalue < MINRANGE || tempvalue > MAXRANGE) throw OUT_OF_RANGE_EXCEPTION;
		value = tempvalue;
		return *this;
	}
	const rangedInteger& operator &= (int r) {
		int tempvalue = value;
		tempvalue &= r;
		if (tempvalue < MINRANGE || tempvalue > MAXRANGE) throw OUT_OF_RANGE_EXCEPTION;
		value = tempvalue;
		return *this;
	}
	const rangedInteger& operator ^= (int r) {
		int tempvalue = value;
		tempvalue ^= r;
		if (tempvalue < MINRANGE || tempvalue > MAXRANGE) throw OUT_OF_RANGE_EXCEPTION;
		value = tempvalue;
		return *this;
	}
	const rangedInteger operator++ (int) {	// Post Increment operator
		rangedInteger result = *this;
		++*this;
		return result;
	}
	const rangedInteger& operator++ () {	// Pre Increment operator
		if (value+1 < MINRANGE || value+1 > MAXRANGE) throw OUT_OF_RANGE_EXCEPTION;
		++value;
		return *this;
	}
	const rangedInteger operator-- (int) {	// Post Decrement operator
		rangedInteger result = *this;
		--*this;
		return result;
	}
	const rangedInteger& operator-- () {	// Pre Decrement operator
		if (value-1 < MINRANGE || value-1 > MAXRANGE) throw OUT_OF_RANGE_EXCEPTION;
		--value;
		return *this;
	}
};

#endif

