/* Swinder - Portable library for spreadsheet Copyright (C) 2003 Ariya Hidayat This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA */ #include "value.h" #include "ustring.h" #include namespace Swinder { // helper class for Value class ValueData { public: Value::Type type; // someday move to use union to reduce memory consumption bool b; int i; double f; UString s; // create empty data ValueData(){ count = 0; b = false; i = 0; f = 0.0; s = UString::null; type = Value::Empty; ref(); }; // destroys data ~ValueData(){ if( this == s_null ) s_null = 0; } void ref(){ count++; } // static empty data to be shared static ValueData* null() { if( !s_null) s_null = new ValueData; else s_null->ref(); return s_null; } // decrease reference count void unref() { --count; if( !count ) delete this; } // true if it's null (which is shared) bool isNull(){ return this == s_null; } unsigned count; // reference count private: static ValueData* s_null; }; } using namespace Swinder; // to be shared between all empty value ValueData* ValueData::s_null = 0; // static things Value ks_value_empty; Value ks_error_div0; Value ks_error_na; Value ks_error_name; Value ks_error_null; Value ks_error_num; Value ks_error_ref; Value ks_error_value; // create an empty value Value::Value() { d = ValueData::null(); } // destructor Value::~Value() { d->unref(); } // create value of certain type Value::Value( Value::Type _type ) { d = new ValueData; d->type = _type; } // copy constructor Value::Value( const Value& _value ) { d = ValueData::null(); assign( _value ); } // assignment operator Value& Value::operator=( const Value& _value ) { return assign( _value ); } // create a boolean value Value::Value( bool b ) { d = ValueData::null(); setValue( b ); } // create an integer value Value::Value( int i ) { d = ValueData::null(); setValue ( i ); } // create a floating-point value Value::Value( double f ) { d = ValueData::null(); setValue( f ); } // create a string value Value::Value( const UString& s ) { d = ValueData::null(); setValue( s ); } // assign value from other // shallow copy: only copy the data pointer Value& Value::assign( const Value& _value ) { d->unref(); d = _value.d; d->ref(); return *this; } // return type of the value Value::Type Value::type() const { return d ? d->type : Empty; } // set the value to boolean void Value::setValue( bool b ) { detach(); d->type = Boolean; d->b = b; } // get the value as boolean bool Value::asBoolean() const { bool result = false; if( type() == Value::Boolean ) result = d->b; return result; } // set the value to integer void Value::setValue( int i ) { detach(); d->type = Integer; d->i = i; } // get the value as integer int Value::asInteger() const { int result = 0; if( type() == Value::Integer ) result = d->i; if( type() == Value::Float ) result = static_cast(d->f); return result; } void Value::setValue( const Value& v ) { assign( v ); } // set the value as floating-point void Value::setValue( double f ) { detach(); d->type = Float; d->f = f; } // get the value as floating-point double Value::asFloat() const { double result = 0.0; if( type() == Value::Float ) result = d->f; if( type() == Value::Integer ) result = static_cast(d->i); return result; } // set the value as string void Value::setValue( const UString& s ) { detach(); d->type = String; d->s = s; } // get the value as string UString Value::asString() const { UString result; if( type() == Value::String ) result = d->s; return result; } // set error message void Value::setError( const UString& msg ) { detach(); d->type = Error; d->s = msg; } // get error message UString Value::errorMessage() const { UString result; if( type() == Value::Error ) result = d->s; return result; } // reference to empty value const Value& Value::empty() { return ks_value_empty; } // reference to #DIV/0! error const Value& Value::errorDIV0() { if( !ks_error_div0.isError() ) ks_error_div0.setError( UString("#DIV/0!") ); return ks_error_div0; } // reference to #N/A error const Value& Value::errorNA() { if( !ks_error_na.isError() ) ks_error_na.setError( UString("#N/A") ); return ks_error_na; } // reference to #NAME? error const Value& Value::errorNAME() { if( !ks_error_name.isError() ) ks_error_name.setError( UString("#NAME?") ); return ks_error_name; } // reference to #NUM! error const Value& Value::errorNUM() { if( !ks_error_num.isError() ) ks_error_num.setError( UString("#NUM!") ); return ks_error_num; } // reference to #NULL! error const Value& Value::errorNULL() { if( !ks_error_null.isError() ) ks_error_null.setError( UString("#NULL!") ); return ks_error_null; } // reference to #REF! error const Value& Value::errorREF() { if( !ks_error_ref.isError() ) ks_error_ref.setError( UString("#REF!") ); return ks_error_ref; } // reference to #VALUE! error const Value& Value::errorVALUE() { if( !ks_error_value.isError() ) ks_error_value.setError( UString("#VALUE!") ); return ks_error_value; } // detach, create deep copy of ValueData void Value::detach() { if( d->isNull() || ( d->count > 1 ) ) { ValueData* n; n = new ValueData; n->type = d->type; switch( n->type ) { case Empty: break; case Boolean: n->b = d->b; break; case Integer: n->i = d->i; break; case Float: n->f = d->f; break; case String: n->s = d->s; break; case Error: n->s = d->s; break; default: break; } d->unref(); d = n; } } std::ostream& Swinder::operator<<( std::ostream& s, Swinder::Value value ) { switch( value.type() ) { case Value::Empty: s << "Empty"; break; case Value::Boolean: s << "Boolean: " << (value.asBoolean()?"True":"False"); break; case Value::Integer: s << "Integer: " << value.asInteger(); break; case Value::Float: s << "Float: " << value.asFloat(); break; case Value::String: s << "String: " << value.asString().ascii(); break; case Value::Error: s << "Error: " << value.errorMessage().ascii(); break; default: break; }; return s; }