// rpimpl_var.h
// Copyright (c) Menno Rubingh 2016.  Web: [http://rubinghsoftware.de]
// 
// MR Mar 2016.
//
// VarTable:
// List of the variables (each of tye 'double'), used for the evaluation 
// of a RP expression.
// Used internally by the RPInterpreter implementation.
//


#ifndef _RPIMPL_VAR_H_
#define _RPIMPL_VAR_H_


#include "llgp_between.h"   //BETWEEN_II(), BETWEEN_IE().

#include <assert.h>


class VarTable
{
	static char const CMIN = 'a';
	static char const CMAX = 'z';
	static int  const NVAR  = (CMAX - CMIN + 1);

	double m_arr[NVAR];  //The values of each of the variables 'a'...'z'.
	
public:	
	// Class functions.
	static bool nameToIndex_scan(                //For scanning varname from expression string.
		char   iName,
		int *  oIndex )
	{
		if ( BETWEEN_II( CMIN, iName, CMAX ) )
		{
			*oIndex = iName - CMIN;
			return true;
		}
		return false;
	}
	static int nameToIndex_assert( char iName )  //For get/set of variable by client code.
	{
		int kIndex;
		bool f = nameToIndex_scan( iName, &kIndex );
		assert( f );
		return kIndex;
	}
	static char indexToName( int iIndex )        //For printing the variable.
	{
		assert( BETWEEN_IE( 0, iIndex, NVAR ) );
		return CMIN + iIndex;
		
	}

	static int getNVars( void )                  //Return the number of variables. For 
	{                                            // iterating over all variables by index.
		return NVAR;
	}


	
	// Clear all variables to value 0.0.
	void clear( void )
	{
		for ( int k = 0; k < NVAR; k++ ) { m_arr[k] = 0.0; }
	}

	// Constructor inits all variables to 0.0.
	VarTable( void )
	{
		clear();
	}



	// Get/Set variable by index.
	// This is how the variables are accessed during evaluation of the parsed expression.
	// Assert fails if index out of bounds.
	void putByIndex( int iIndex, double iVal )
	{
		assert( BETWEEN_IE( 0, iIndex, NVAR ) );
		m_arr[iIndex] = iVal;
	}
	double getByIndex( int iIndex ) const
	{
		assert( BETWEEN_IE( 0, iIndex, NVAR ) );
		return m_arr[iIndex];
	}
	
	// Get/Set variable by variable name (letter)..
	// This is how variables are accessed by client code.
	// Precondition is that iName is a valid variable letter, i.e. 'a'...'z'. Assert fails 
	// if this assumption is violated (to catch logical errors in client code).
	void putByName( char iName, double iVal )
	{
		int kIndex = nameToIndex_assert( iName );
		putByIndex( kIndex, iVal );
	}
	double getByName( char iName ) const
	{
		int kIndex = nameToIndex_assert( iName );
		return getByIndex( kIndex );
	}
};



#endif //_RPIMPL_VAR_H_