//--------------------------------------------------------------------------- IValue& Value::operator+=(const IValue &val) { if (IsScalar() && val.IsScalar()) { // Scalar/Scalar addition m_val += val.GetComplex(); m_cType = (m_val.imag()==0) ? ( (m_val.real()==(int)m_val.real()) ? 'i' : 'f' ) : 'c'; } else if (IsMatrix() && val.IsMatrix()) { // Matrix/Matrix addition assert(m_pvVal); *m_pvVal += val.GetArray(); } else if (IsString() && val.IsString()) { // string/string addition assert(m_psVal); *m_psVal += val.GetString(); } else { // Type conflict throw ParserError(ErrorContext(ecTYPE_CONFLICT_FUN, -1, _T("+"), GetType(), val.GetType(), 2)); } return *this; }
/** \brief Assign a value with multiplication \param val The value to multiply to this When multiplying to values with each value representing a matrix type the result is checked whether it is a 1 x 1 matrix. If so the value is "unboxed" and stored directly in this value object. It is no longer treated as a matrix internally. */ IValue& Value::operator*=(const IValue &val) { if (IsScalar() && val.IsScalar()) { // Scalar/Scalar multiplication m_val *= val.GetComplex(); m_cType = (m_val.imag()==0) ? ( (m_val.real()==(int)m_val.real()) ? 'i' : 'f' ) : 'c'; } else if (IsMatrix() && val.IsMatrix()) { // Matrix/Matrix addition assert(m_pvVal); *m_pvVal *= val.GetArray(); // The result may actually be a scalar value, i.e. the scalar product of // two vectors. if (m_pvVal->GetCols()==1 && m_pvVal->GetRows()==1) { Assign(m_pvVal->At(0,0)); } } else if ( IsMatrix() && val.IsScalar() ) { *m_pvVal *= val; } else if ( IsScalar() * val.IsMatrix() ) { // transform this into a matrix and multiply with rhs Value prod = val * (*this); Assign(prod); } else { // Type conflict ErrorContext errc(ecTYPE_CONFLICT_FUN, -1, _T("*")); errc.Type1 = GetType(); errc.Type2 = 'm'; //val.GetType(); errc.Arg = 2; throw ParserError(errc); } return *this; }
//--------------------------------------------------------------------------- IValue& Value::At(int nRow, int nCol) { if (IsMatrix()) { if (nRow>=m_pvVal->GetRows() || nCol>=m_pvVal->GetCols() || nRow<0 || nCol<0) throw ParserError( ErrorContext(ecINDEX_OUT_OF_BOUNDS, -1, GetIdent()) ); return m_pvVal->At(nRow, nCol); } else if (nRow==0 && nCol==0) { return *this; } else throw ParserError( ErrorContext(ecINDEX_OUT_OF_BOUNDS) ); }
bool SetPropertyFromNode( const TreeNode& node, Property::Value& value, const Replacement& replacer ) { bool done = false; // some values are ambiguous as we have no Property::Type but can be disambiguated in the json // Currently Rotations and Rectangle must always be disambiguated when a type isnt available if( Disambiguated( node, value, replacer ) ) { done = true; } else { if( node.Size() ) { // our current heuristic for deciding an array is actually a vector and not say a map // is to check if the values are all floats bool allNumbers = true; for(TreeConstIter iter = node.CBegin(); iter != node.CEnd(); ++iter) { OptionalFloat f = IsFloat((*iter).second); if(!f) { allNumbers = false; break; } } if( allNumbers ) { // prefer finding vectors over presuming composite Property::Array... if( OptionalMatrix v = IsMatrix(node) ) { value = *v; done = true; } else if( OptionalMatrix3 v = IsMatrix3(node) ) { value = *v; done = true; } else if( OptionalVector4 v = IsVector4(node) ) { value = *v; done = true; } else if( OptionalVector3 v = IsVector3(node) ) { value = *v; done = true; } else if( OptionalVector2 v = IsVector2(node) ) { value = *v; done = true; } else if( 4 == node.Size() ) { if( OptionalVector4 v = IsVector4(node) ) { value = *v; done = true; } } else { value = Property::Value(Property::ARRAY); Property::Array* array = value.GetArray(); if( array ) { for(TreeConstIter iter = node.CBegin(); iter != node.CEnd(); ++iter) { Property::Value childValue; if( SetPropertyFromNode( (*iter).second, childValue, replacer ) ) { array->PushBack( childValue ); done = true; } } } } } if(!done) { // presume an array or map // container of size 1 TreeNode::ConstIterator iter = node.CBegin(); // its seems legal with current json parser for a map to have an empty key // but here we take that to mean the structure is a list if( ((*iter).first) == 0 ) { value = Property::Value(Property::ARRAY); Property::Array* array = value.GetArray(); if( array ) { for(unsigned int i = 0; i < node.Size(); ++i, ++iter) { Property::Value childValue; if( SetPropertyFromNode( (*iter).second, childValue, replacer ) ) { array->PushBack( childValue ); done = true; } } } } else { value = Property::Value(Property::MAP); Property::Map* map = value.GetMap(); if( map ) { for(unsigned int i = 0; i < node.Size(); ++i, ++iter) { Property::Value childValue; if( SetPropertyFromNode( (*iter).second, childValue, replacer ) ) { map->Insert( (*iter).first, childValue ); done = true; } } } } } // if!done } // if node.size() else // if( 0 == node.size() ) { // no children so either one of bool, float, integer, string OptionalBoolean aBool = replacer.IsBoolean(node); OptionalInteger anInt = replacer.IsInteger(node); OptionalFloat aFloat = replacer.IsFloat(node); OptionalString aString = replacer.IsString(node); if(aBool) { // a bool is also an int but here we presume int if(anInt) { value = *anInt; done = true; } else { value = *aBool; done = true; } } else { // Note: These are both floats and strings // {"value":"123"} // {"value":123} // This means we can't have a string with purely numeric content without disambiguation. if(aFloat) { value = *aFloat; done = true; } else if(anInt) { value = *anInt; done = true; } else { // string always succeeds with the current json parser so its last value = *aString; done = true; } } // if aBool } // if( node.size() ) } // if Disambiguated() return done; } // bool SetPropertyFromNode( const TreeNode& node, Property::Value& value )