//
// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
//
// The contents of this file are covered under the licence agreement in the
// file "LICENCE" distributed with Cforall.
//
// Cost.h --
//
// Author           : Richard C. Bilson
// Created On       : Sun May 17 09:39:50 2015
// Last Modified By : Peter A. Buhr
// Last Modified On : Sat Jul 22 09:35:55 2017
// Update Count     : 5
//

#pragma once

#include <iostream>

namespace ResolvExpr {
	class Cost {
	  private:
		Cost( int unsafeCost, int polyCost, int safeCost, int referenceCost );

	  public:
		Cost & incUnsafe( int inc = 1 );
		Cost & incPoly( int inc = 1 );
		Cost & incSafe( int inc = 1 );
		Cost & incReference( int inc = 1 );

		int get_unsafeCost() const { return unsafeCost; }
		int get_polyCost() const { return polyCost; }
		int get_safeCost() const { return safeCost; }
		int get_referenceCost() const { return referenceCost; }

		Cost operator+( const Cost &other ) const;
		Cost operator-( const Cost &other ) const;
		Cost &operator+=( const Cost &other );
		bool operator<( const Cost &other ) const;
		bool operator==( const Cost &other ) const;
		bool operator!=( const Cost &other ) const;
		friend std::ostream &operator<<( std::ostream &os, const Cost &cost );

		static const Cost zero;
		static const Cost infinity;

		static const Cost unsafe;
		static const Cost poly;
		static const Cost safe;
		static const Cost reference;
	  private:
		int compare( const Cost &other ) const;

		int unsafeCost;
		int polyCost;
		int safeCost;
		int referenceCost;
	};

	inline Cost::Cost( int unsafeCost, int polyCost, int safeCost, int referenceCost ) : unsafeCost( unsafeCost ), polyCost( polyCost ), safeCost( safeCost ), referenceCost( referenceCost ) {}

	inline Cost & Cost::incUnsafe( int inc ) {
		if ( *this == infinity ) return *this;
		unsafeCost += inc;
		return *this;
	}

	inline Cost & Cost::incPoly( int inc ) {
		if ( *this == infinity ) return *this;
		polyCost += inc;
		return *this;
	}

	inline Cost & Cost::incSafe( int inc ) {
		if ( *this == infinity ) return *this;
		safeCost += inc;
		return *this;
	}

	inline Cost & Cost::incReference( int inc ) {
		if ( *this == infinity ) return *this;
		referenceCost += inc;
		return *this;
	}

	inline Cost Cost::operator+( const Cost &other ) const {
		if ( *this == infinity || other == infinity ) return infinity;
		return Cost( unsafeCost + other.unsafeCost, polyCost + other.polyCost, safeCost + other.safeCost, referenceCost + other.referenceCost );
	}

	inline Cost Cost::operator-( const Cost &other ) const {
		if ( *this == infinity || other == infinity ) return infinity;
		return Cost( unsafeCost - other.unsafeCost, polyCost - other.polyCost, safeCost - other.safeCost, referenceCost - other.referenceCost );
	}

	inline Cost &Cost::operator+=( const Cost &other ) {
		if ( *this == infinity ) return *this;
		if ( other == infinity ) {
			*this = infinity;
			return *this;
		}
		unsafeCost += other.unsafeCost;
		polyCost += other.polyCost;
		safeCost += other.safeCost;
		referenceCost += other.referenceCost;
		return *this;
	}

	inline bool Cost::operator<( const Cost &other ) const {
		if ( *this == infinity ) return false;
		if ( other == infinity ) return true;

		if ( unsafeCost > other.unsafeCost ) {
			return false;
		} else if ( unsafeCost < other.unsafeCost ) {
			return true;
		} else if ( polyCost > other.polyCost ) {
			return false;
		} else if ( polyCost < other.polyCost ) {
			return true;
		} else if ( safeCost > other.safeCost ) {
			return false;
		} else if ( safeCost < other.safeCost ) {
			return true;
		} else if ( referenceCost > other.referenceCost ) {
			return false;
		} else if ( referenceCost < other.referenceCost ) {
			return true;
		} else {
			return false;
		} // if
	}

	inline bool Cost::operator==( const Cost &other ) const {
		return unsafeCost == other.unsafeCost
			&& polyCost == other.polyCost
			&& safeCost == other.safeCost
			&& referenceCost == other.referenceCost;
	}

	inline bool Cost::operator!=( const Cost &other ) const {
		return !( *this == other );
	}

	inline std::ostream &operator<<( std::ostream &os, const Cost &cost ) {
		os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", " << cost.safeCost << ", " << cost.referenceCost << " )";
		return os;
	}
} // namespace ResolvExpr

// Local Variables: //
// tab-width: 4 //
// mode: c++ //
// compile-command: "make install" //
// End: //
