bool CDatum::IsEqual (CDatum dValue) const // IsEqual // // Returns TRUE if the values are equal { switch (GetBasicType()) { case typeNil: return dValue.IsNil(); case typeTrue: return !dValue.IsNil(); case typeInteger32: case typeInteger64: case typeIntegerIP: case typeDouble: return (dValue.IsNumber() && CNumberValue(*this).Compare(dValue) == 0); case typeString: return (dValue.GetBasicType() == typeString && strEquals(*this, dValue)); case typeDateTime: return (dValue.GetBasicType() == typeDateTime && ((const CDateTime &)*this == (const CDateTime &)dValue)); // LATER case typeArray: case typeBinary: case typeStruct: case typeSymbol: return false; default: ASSERT(false); return false; } }
int CDatum::DefaultCompare (void *pCtx, const CDatum &dKey1, const CDatum &dKey2) // DefaultCompare // // Default comparison routine used for sorting. Returns: // // -1: If dKey1 < dKey2 // 0: If dKey1 == dKey2 // 1: If dKey1 > dKey2 // // NOTES: // // Nil == "" // Nil == {} // Nil == () // "abc" != "ABC" { int i; // If both are the same datatype, then compare CDatum::Types iType1 = dKey1.GetBasicType(); CDatum::Types iType2 = dKey2.GetBasicType(); // If both types are equal, then compare if (iType1 == iType2) { switch (iType1) { case CDatum::typeNil: case CDatum::typeTrue: return 0; case CDatum::typeInteger32: if ((int)dKey1 > (int)dKey2) return 1; else if ((int)dKey1 < (int)dKey2) return -1; else return 0; case CDatum::typeInteger64: if ((DWORDLONG)dKey1 > (DWORDLONG)dKey2) return 1; else if ((DWORDLONG)dKey1 < (DWORDLONG)dKey2) return -1; else return 0; case CDatum::typeDouble: if ((double)dKey1 > (double)dKey2) return 1; else if ((double)dKey1 < (double)dKey2) return -1; else return 0; case CDatum::typeIntegerIP: return KeyCompare((const CIPInteger &)dKey1, (const CIPInteger &)dKey2); case CDatum::typeString: return KeyCompare((const CString &)dKey1, (const CString &)dKey2); case CDatum::typeDateTime: return ((const CDateTime &)dKey1).Compare((const CDateTime &)dKey2); case CDatum::typeArray: if (dKey1.GetCount() > dKey2.GetCount()) return 1; else if (dKey1.GetCount() < dKey2.GetCount()) return -1; else { for (i = 0; i < dKey1.GetCount(); i++) { CDatum dItem1 = dKey1.GetElement(i); CDatum dItem2 = dKey2.GetElement(i); int iItemCompare = CDatum::DefaultCompare(pCtx, dItem1, dItem2); if (iItemCompare != 0) return iItemCompare; } return 0; } case CDatum::typeStruct: if (dKey1.GetCount() > dKey2.GetCount()) return 1; else if (dKey1.GetCount() < dKey2.GetCount()) return -1; else { for (i = 0; i < dKey1.GetCount(); i++) { CString sItemKey1 = dKey1.GetKey(i); CString sItemKey2 = dKey2.GetKey(i); int iKeyCompare = KeyCompare(sItemKey1, sItemKey2); if (iKeyCompare != 0) return iKeyCompare; CDatum dItem1 = dKey1.GetElement(i); CDatum dItem2 = dKey2.GetElement(i); int iItemCompare = CDatum::DefaultCompare(pCtx, dItem1, dItem2); if (iItemCompare != 0) return iItemCompare; } return 0; } // LATER: Not yet supported default: return 0; } } // If one of the types is nil, then compare else if (iType1 == CDatum::typeNil || iType2 == CDatum::typeNil) { CDatum dNonNil; int iResult; if (iType2 == CDatum::typeNil) { dNonNil = dKey1; Swap(iType1, iType2); iResult = 1; } else { dNonNil = dKey2; iResult = -1; } switch (iType2) { case CDatum::typeString: if (((const CString &)dNonNil).IsEmpty()) return 0; else return iResult; case CDatum::typeArray: case CDatum::typeStruct: if (dNonNil.GetCount() == 0) return 0; else return iResult; default: // nil is always less return iResult; } } // If one of the types is a number, then compare as numbers else if (dKey1.IsNumber() || dKey2.IsNumber()) { CNumberValue Number1(dKey1); CNumberValue Number2(dKey2); if (Number1.IsValidNumber() && Number2.IsValidNumber()) return Number1.Compare(Number2); else if (Number1.IsValidNumber()) return 1; else if (Number2.IsValidNumber()) return -1; else return 0; } // Otherwise, cannot compare else return 0; }
CDatum::Types CDatum::GetNumberType (int *retiValue, CDatum *retdConverted) const // GetNumberType // // Returns the most appropriate number type for the datum and optimistically // returns the value if the type is integer. // // The number type is the best number type that the datum can be cast // to without loss of data, following this order (from most preferable to // least): // // typeInteger32 // typeDouble // typeIntegerIP // // If the original datum is a string then we try to parse it and return the // best number type. retdConverted will be a datum representing the parsed // number. // // If the value cannot be converted to a number we return typeUnknown. { // Pre-init if (retdConverted) *retdConverted = *this; switch (m_dwData & AEON_TYPE_MASK) { case AEON_TYPE_STRING: { if (m_dwData == 0) { if (retiValue) *retiValue = 0; return typeInteger32; } else { CDatum dNumberValue; if (!CDatum::CreateFromStringValue(*this, &dNumberValue) || !dNumberValue.IsNumber()) return typeUnknown; if (retdConverted) *retdConverted = dNumberValue; return dNumberValue.GetNumberType(retiValue); } } case AEON_TYPE_NUMBER: switch (m_dwData & AEON_NUMBER_TYPE_MASK) { case AEON_NUMBER_CONSTANT: { switch (m_dwData) { case constTrue: if (retiValue) *retiValue = 1; return typeInteger32; default: ASSERT(false); return typeUnknown; } } case AEON_NUMBER_28BIT: if (retiValue) *retiValue = ((int)(m_dwData & AEON_NUMBER_MASK) >> 4); return typeInteger32; case AEON_NUMBER_32BIT: if (retiValue) *retiValue = (int)g_IntAlloc.Get(GetNumberIndex()); return typeInteger32; case AEON_NUMBER_DOUBLE: return typeDouble; default: ASSERT(false); return typeUnknown; } case AEON_TYPE_COMPLEX: return raw_GetComplex()->GetNumberType(retiValue); default: ASSERT(false); return typeUnknown; } }