text: /***************************************************************
   *
   * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
   * University of Wisconsin-Madison, WI.
   * 
   * Licensed under the Apache License, Version 2.0 (the "License"); you
   * may not use this file except in compliance with the License.  You may
   * obtain a copy of the License at
   * 
   *    http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   ***************************************************************/
  
  
  #ifndef __CLASSAD_VALUE_H__
  #define __CLASSAD_VALUE_H__
  
  #include "classad/common.h"
  #include "classad/util.h"
  #include "classad/classad_stl.h"
  
  #define REFACTOR_FACTOR	// factor actually stored in the value class, but exposed only through literal class
  
  namespace classad {
  
  class Literal;
  class ExprList;
  class ClassAd;
  
  /// Represents the result of an evaluation.
  class Value 
  {
  	public:
  			/// Value types
  		enum ValueType {
  												NULL_VALUE          = 0,
  		/** The error value */ 					ERROR_VALUE         = 1<<0,
  		/** The undefined value */ 				UNDEFINED_VALUE     = 1<<1,
  		/** A boolean value (false, true)*/ 	BOOLEAN_VALUE 		= 1<<2,
  		/** An integer value */ 				INTEGER_VALUE       = 1<<3,
  		/** A real value */ 					REAL_VALUE          = 1<<4,
  		/** A relative time value */ 			RELATIVE_TIME_VALUE = 1<<5,
  		/** An absolute time value */ 			ABSOLUTE_TIME_VALUE = 1<<6,
  		/** A string value */ 					STRING_VALUE        = 1<<7,
  		/** A classad value */ 					CLASSAD_VALUE       = 1<<8,
  		/** A list value (not owned here)*/	            LIST_VALUE 			= 1<<9,
  		/** A list value (owned via shared_ptr)*/     	SLIST_VALUE 		= 1<<10,
  		/** Mask of types that need _Clear*/ VALUE_OWNS_POINTER = ABSOLUTE_TIME_VALUE | STRING_VALUE | SLIST_VALUE,
  		};
  
  			/// Number factors
  		enum NumberFactor {
  	    /** No factor specified */  NO_FACTOR= 0,
  		/** Byte factor */          B_FACTOR = 1,
  		/** Kilo factor */          K_FACTOR = 2,
  		/** Mega factor */          M_FACTOR = 3,
  		/** Giga factor */          G_FACTOR = 4,
  		/** Terra factor*/          T_FACTOR = 5
  		};
  
   
  		/// Values of number multiplication factors
  		static const double ScaleFactor[];
  
  		/// Constructor
  		Value()
  			: classadValue(NULL)
  			, valueType(UNDEFINED_VALUE)
  		#ifdef REFACTOR_FACTOR
  			, factor(NO_FACTOR)
  		#endif
  		{}
  
  		/// Copy Constructor
  		Value(const Value &value)
  			: classadValue(NULL)
  			, valueType(UNDEFINED_VALUE)
  		#ifdef REFACTOR_FACTOR
  			, factor(NO_FACTOR)
  		#endif
  		{
  			CopyFrom(value);
  			return;
  		}
  
  		/// Destructor
  		~Value() { _Clear(); }
  
  		/// Assignment operator
  		Value& operator=(const Value &value) {
  			if (this != &value) {
  				CopyFrom(value);
  			}
  			return *this;
  		}
  
  		/** Discards the previous value and sets the value to UNDEFINED */
  		void Clear (void) {
  			if (valueType & VALUE_OWNS_POINTER) { _Clear(); }
  			classadValue = NULL; // This clears the entire union.
  			valueType 	= UNDEFINED_VALUE;
  		#ifdef REFACTOR_FACTOR
  			factor = NO_FACTOR;
  		#endif
  		}
  
  		/** Copies the value of another value object.
  			@param v The value copied from.
  		*/
  		void CopyFrom( const Value &v );
  
  		/** Sets a boolean value; previous value discarded.
  			@param b The boolean value.
  		*/
  		void SetBooleanValue(bool b);
  
  		/** Sets a real value; previous value discarded.
  			@param r The real value.
  		*/
  		void SetRealValue(double r);
  
  		/** Sets an integer value; previous value discarded.
  			@param i The integer value.
  		*/
  		void SetIntegerValue(long long i);
  
  		/** Sets the undefined value; previous value discarded.
  		*/
  		void SetUndefinedValue(void);
  
  		/** Sets the error value; previous value discarded.
  		*/
  		void SetErrorValue(void);
  
  		/** Sets an expression list value; previous value discarded. Unlike the
  			version of this function that takes a raw ExprList pointer, this one
  			takes (shared) ownership over the list.  This list will be deleted
  			when the last copy of this shared_ptr goes away.
  			@param l The list value.
  		*/
  		void SetListValue(classad_shared_ptr<ExprList> l);
  
  		/** Sets an expression list value; previous value discarded. Unlike the
  			version of this function that takes a shared_ptr, you still own the ExprList:: it 
  			is not owned by the Value class, so it is your responsibility to delete it. 
  			@param l The list value.
  		*/
  		void SetListValue(ExprList* l);
  
  		/** Sets a ClassAd value; previous value discarded. You still own the ClassA:, it 
              is not owned by the Value class, so it is your responsibility to delete it. 
  			@param c The ClassAd value.
  		*/
  		void SetClassAdValue(ClassAd* c);	
  
  		/** Sets a string value; previous value discarded.
  			@param str The string value.
  		*/
  		void SetStringValue( const std::string &str );
  
  		/** Sets a string value; previous value discarded. The string is copied
              so you may feel free to delete the original if you wish. 
  			@param str The string value.
  		*/
  		void SetStringValue( const char *str );
  		void SetStringValue( const char *str, size_t cch );
  
  		/** Sets an absolute time value in seconds since the UNIX epoch, & the 
              time zone it's measured in.
  			@param secs - Absolute Time Literal(seconds since the UNIX epoch, timezone offset) .
  		*/
  		void SetAbsoluteTimeValue( abstime_t secs );
  
  		/** Sets a relative time value.
  			@param secs Number of seconds.
  		*/
  		void SetRelativeTimeValue( time_t secs );
  		void SetRelativeTimeValue( double secs );
  
  		/** Gets the type of the value.
  			@return The value type.
  			@see ValueType
  		*/
  		inline ValueType GetType() const { return valueType; }
  
  		/** Checks if the value is boolean.
  			@param b The boolean value if the value is boolean.
  			@return true iff the value is boolean.
  		*/
  		inline bool IsBooleanValue(bool& b) const;
  		/** Checks if the value is boolean.
  			@return true iff the value is boolean.
  		*/	
  		inline bool IsBooleanValue() const;
  
  		/** Checks if the value is boolean or something considered
  			equivalent by implicit conversion (e.g. a number), if
  			old ClassAd evaluation semantics are being used. If they're
  			not being used, this method behaves like IsBooleanValue().
  			@param b The boolean value if return is true.
  			@return true iff the value is boolean or equivalent
  		 */
  		bool IsBooleanValueEquiv(bool &b) const;
  
  		/** Checks if the value is integral.
  			@param i The integer value if the value is integer.
  			If the type of i is smaller than a long long, the value
  			may be truncated.
  			@return true iff the value is an integer.
  		*/
  		inline bool IsIntegerValue(int &i) const;
  		inline bool IsIntegerValue(long &i) const;
  		inline bool IsIntegerValue(long long &i) const;
  		/** Checks if the value is integral.
  			@return true iff the value is an integer.
  		*/
  		inline bool IsIntegerValue() const;
  		/** Checks if the value is real.
  			@param r The real value if the value is real.
  			@return true iff the value is real.
  		*/	
  		inline bool IsRealValue(double &r) const; 	
  		/** Checks if the value is real.
  			@return true iff the value is real.
  		*/
  		inline bool IsRealValue() const;
  		/** Checks if the value is a string.  
  			@param str A reference to a string object, which is filled with the
  				string value.
  			@return true iff the value is a string.
  		*/
  		bool IsStringValue( std::string &str ) const; 	
  		/** Checks if the value is a string.  
  			@param str A reference to a C string, which will point to the 
  				string value.  This pointer must <b>not</b> be deallocated or
  				tampered with.
  			@return true iff the value is a string.
  		*/
  		bool IsStringValue( const char *&str ) const; 	
  		/** Checks if the value is a string and provides a copy of it in a buffer you provide
  			@param str A buffer to hold the string value.
  			@param len The size of the buffer.
  			@return true iff the value is a string.
  		*/
  		bool IsStringValue( char *str, int len ) const; 	
  		/** Returns length of the string instead of the string
              @param size This is filled in with the size of the string
  			@return true iff the value is string.
  		*/
          inline bool IsStringValue( int &size ) const;
  		/** Checks if the value is a string.
  			@return true iff the value is string.
  		*/
  		inline bool IsStringValue() const;
  		/** Checks if the value is an expression list.
  			@param l The expression list if the value is an expression list.
  			@return true iff the value is an expression list.
  		*/
  		inline bool IsListValue(const ExprList*& l) const;
  		/** Checks if the value is an expression list. The ExprList returned is 
  			the original list put into the Value, so you only own it if you own 
  			the original.  If the original was put into this Value as a shared_ptr,
  			the shared_ptr still owns it (i.e. don't delete this pointer or
  			make a new shared_ptr for it).  Consider using IsSListValue() instead.
  			@param l The expression list if the value is an expression list. 
  			@return true iff the value is an expression list.
  		*/
  		inline bool IsListValue(ExprList*& l);
  		/** Checks if the value is an expression list.
  			@param l A shared_ptr to the expression list if the value is an expression list.
  			         Note that if the list was not set via a shared_ptr, a copy of the
  			         list will be made and this Value will convert from type LIST_VALUE
  			         to SLIST_VALUE as a side-effect.
  			@return true iff the value is an expression list
  		*/
  		bool IsSListValue(classad_shared_ptr<ExprList>& l);
  		/** Checks if the value is an expression list.
  			@return true iff the value is an expression list.
  		*/
  		inline bool IsListValue() const;
  		/** Checks if the value is a ClassAd.
  			@param c The ClassAd if the value is a ClassAd.
  			@return true iff the value is a ClassAd.
  		*/
  		inline bool IsClassAdValue(const ClassAd *&c) const; 
  		/** Checks if the value is a ClassAd. The ClassAd returned is 
              the original list put into the ClassAd, so you only own it if you own 
              the original.
  			@param c The ClassAd if the value is a ClassAd.
  			@return true iff the value is a ClassAd.
  		*/
  		inline bool IsClassAdValue(ClassAd *&c) const; 
  		/** Checks if the value is a ClassAd. 
  			@return true iff the value is a ClassAd value.
  		*/
  		inline bool IsClassAdValue() const;
  		/** Checks if the value is the undefined value.
  			@return true iff the value if the undefined value.
  		*/
  		inline bool IsUndefinedValue() const;
  		/** Checks if the value is the error value.
  			@return true iff the value if the error value.
  		*/
  		inline bool IsErrorValue() const;
  		/** Checks if the value is exceptional.
  			@return true iff the value is either undefined or error.
  		*/
  		inline bool IsExceptional() const;
  		/** Checks if the value is numerical.
  			This includes booleans, which can be used in arithmetic.
  			@return true iff the value is a number
  		*/
  		bool IsNumber () const;
  		/** Checks if the value is numerical. If the value is a real, it is 
  				converted to an integer through truncation.
  				If the value is a boolean, it is converted to 0 (for False)
  				or 1 (for True).
  			@param i The integer value of the value if the value is a number.
  			If the type of i is smaller than a long long, the value
  			may be truncated.
  			@return true iff the value is a number
  		*/
  		bool IsNumber (int &i) const;
  		bool IsNumber (long &i) const;
  		bool IsNumber (long long &i) const;
  		/** Checks if the value is numerical. If the value is an integer, it 
  				is promoted to a real.
  				If the value is a bollean, it is converted to 0.0 (for False)
  				or 1.0 (for True).
  			@param r The real value of the value if the value is a number.
  			@return true iff the value is a number
  		*/
  		bool IsNumber (double &r) const;
  		/** Checks if the value is an absolute time value.
  			@return true iff the value is an absolute time value.
  		*/
  		bool IsAbsoluteTimeValue( ) const;
  		/** Checks if the value is an absolute time value.
  			@param secs - Absolute time literal (Number of seconds since the UNIX epoch,timezone offset).
  			@return true iff the value is an absolute time value.
  		*/
  		bool IsAbsoluteTimeValue( abstime_t& secs ) const;
  		/** Checks if the value is a relative time value.
  			@return true iff the value is a relative time value
  		*/
  		bool IsRelativeTimeValue( ) const;
  		/** Checks if the value is a relative time value.
  			@param secs Number of seconds
  			@return true iff the value is a relative time value
  		*/
  		bool IsRelativeTimeValue( double& secs ) const;
  		bool IsRelativeTimeValue( time_t& secs ) const;
  
          bool SameAs(const Value &otherValue) const;
  
          friend bool operator==(const Value &value1, const Value &value2);
  
  		friend std::ostream& operator<<(std::ostream &stream, Value &value);
  
  	private:
  		void _Clear();
  
  		friend class Literal;
  		friend class ClassAd;
  		friend class ExprTree;
  
  		union {
  			bool			booleanValue;
  			long long		integerValue;
  			double 			realValue;
  			ExprList        *listValue;
  			classad_shared_ptr<ExprList> *slistValue;
  			ClassAd			*classadValue;
  			double			relTimeValueSecs;
  			abstime_t		*absTimeValueSecs;
  			std::string		*strValue;
  		};
  
  		ValueType 		valueType;	// the type of the value
  #ifdef REFACTOR_FACTOR
  		NumberFactor	factor;		// the type of the value
  		void ApplyFactor();
  #endif
  };
  
  bool convertValueToRealValue(const Value value, Value &realValue);
  bool convertValueToIntegerValue(const Value value, Value &integerValue);
  bool convertValueToStringValue(const Value value, Value &stringValue);
  
  // implementations of the inlined functions
  inline bool Value::
  IsBooleanValue( bool& b ) const
  {
  	b = booleanValue;
  	return( valueType == BOOLEAN_VALUE );
  }
  
  inline bool Value::
  IsBooleanValue() const
  {
  	return( valueType == BOOLEAN_VALUE );
  }
  
  inline bool Value::
  IsIntegerValue (int &i) const
  {
      i = (int)integerValue;
      return (valueType == INTEGER_VALUE);
  }  
  
  inline bool Value::
  IsIntegerValue (long &i) const
  {
      i = (long)integerValue;
      return (valueType == INTEGER_VALUE);
  }  
  
  inline bool Value::
  IsIntegerValue (long long &i) const
  {
      i = integerValue;
      return (valueType == INTEGER_VALUE);
  }  
  
  inline bool Value::
  IsIntegerValue () const
  {
      return (valueType == INTEGER_VALUE);
  }  
  
  inline bool Value::
  IsRealValue (double &r) const
  {
      r = realValue;
      return (valueType == REAL_VALUE);
  }  
  
  inline bool Value::
  IsRealValue () const
  {
      return (valueType == REAL_VALUE);
  }  
  
  inline bool Value::
  IsListValue( const ExprList *&l) const
  {
      if (valueType == LIST_VALUE) {
          l = listValue;
          return true;
      } else if (valueType == SLIST_VALUE) {
          l = slistValue->get();
          return true;
      } else {
          return false;
      }
  }
  
  inline bool Value::
  IsListValue( ExprList *&l)
  {
      if (valueType == LIST_VALUE) {
          l = listValue;
          return true;
      } else if (valueType == SLIST_VALUE) {
          l = slistValue->get();
          return true;
      } else {
          return false;
      }
  }
  
  inline bool Value::
  IsListValue () const
  {
  	return (valueType == LIST_VALUE || valueType == SLIST_VALUE);
  }
  
  
  inline bool Value::
  IsStringValue() const
  {
      return (valueType == STRING_VALUE);
  }
  
  
  inline bool Value::
  IsStringValue( const char *&s ) const
  {
  	// We want to be careful not to copy it in here. 
  	// People may accumulate in the "s" after this call,
  	// So it best to only touch it if it exists.
  	// (Example: the strcat classad function)
  	if (valueType == STRING_VALUE) {
  		s = strValue->c_str( );
  		return true;
  	} else {
  		return false;
  	}
  }
  
  inline bool Value::
  IsStringValue( char *s, int len ) const
  {
  	if( valueType == STRING_VALUE ) {
  		strncpy( s, strValue->c_str( ), len );
  		return( true );
  	}
  	return( false );
  }
  
  inline bool Value::
  IsStringValue( std::string &s ) const
  {
  	if ( valueType == STRING_VALUE ) {
  		s = *strValue;
  		return true;
  	} else {
  		return false;
  	}
  }
  
  inline bool Value::
  IsStringValue( int &size ) const
  {
      if (valueType == STRING_VALUE) {
          size = (int)strValue->size();
          return true;
      } else {
          size = -1;
          return false;
      }
  }
  
  inline bool Value::
  IsClassAdValue(const ClassAd *&ad) const
  {
  	if ( valueType == CLASSAD_VALUE ) {
  		ad = classadValue;
  		return true;
  	} else {
  		return false;
  	}
  }
  
  inline bool Value::
  IsClassAdValue(ClassAd *&ad) const
  {
  	if ( valueType == CLASSAD_VALUE ) {
  		ad = classadValue;
  		return true;
  	} else {
  		return false;
  	}
  }
  
  inline bool Value:: 
  IsClassAdValue() const
  {
  	return( valueType == CLASSAD_VALUE );	
  }
  
  inline bool Value::
  IsUndefinedValue (void) const
  { 
  	return (valueType == UNDEFINED_VALUE);
  }
  
  inline bool Value::
  IsErrorValue(void) const
  { 
  	return (valueType == ERROR_VALUE); 
  }
  
  inline bool Value::
  IsExceptional(void) const
  {
  	return( valueType == UNDEFINED_VALUE || valueType == ERROR_VALUE );
  }
  
  inline bool Value::
  IsAbsoluteTimeValue( ) const
  {
  	return( valueType == ABSOLUTE_TIME_VALUE );
  }
  
  inline bool Value::
  IsAbsoluteTimeValue( abstime_t &secs ) const
  {
  	if ( valueType == ABSOLUTE_TIME_VALUE ) {
  		secs = *absTimeValueSecs;
  		return true;
  	} else {
  		return false;
  	}
  }
  
  inline bool Value::
  IsRelativeTimeValue( ) const
  {
  	return( valueType == RELATIVE_TIME_VALUE );
  }
  
  inline bool Value::
  IsRelativeTimeValue( double &secs ) const
  {
  	secs = relTimeValueSecs;
  	return( valueType == RELATIVE_TIME_VALUE );
  }
  inline bool Value::
  IsRelativeTimeValue( time_t &secs ) const
  {
  	secs = (int) relTimeValueSecs;
  	return( valueType == RELATIVE_TIME_VALUE );
  }
  inline bool Value::
  IsNumber( ) const
  {
  	return( valueType==INTEGER_VALUE || valueType==REAL_VALUE );
  }
  } // classad
  
  #endif//__CLASSAD_VALUE_H__
  