📄 cls_value.cpp
字号:
}
int Value_traverse(TPyValue *self, visitproc visit, void *arg)
{ PVISIT(self->variable);
PVISIT(self->value.svalV);
return 0;
}
void Value_clear(TPyValue *self)
{ self->variable=PVariable();
self->value.~TValue();
}
/* Returns a string representations for a value.
- If descriptor is given, its val2str should take care of everything
- If the value is special, we know that to do
- If value is
- FLOATVAR, convert a floatV
- INTVAR, print a intV in brackets
- else if svalV is given, it should take care of itself
- else, we return "###"
*/
char *pvs = NULL;
const char *TPyValue2string(TPyValue *self)
{ if (self->variable) {
string str;
self->variable->val2str(self->value, str);
pvs = (char *)realloc(pvs, str.size()+1);
strcpy(pvs, str.c_str());
}
else {
if (self->value.isDK())
return "?";
if (self->value.isDC())
return "~";
if (self->value.isSpecial())
return ".";
pvs = (char *)realloc(pvs, 16);
if (self->value.varType==TValue::FLOATVAR)
sprintf(pvs, "%f", self->value.floatV);
else if (self->value.varType==TValue::INTVAR)
sprintf(pvs, "<%i>", self->value.intV);
else if (self->value.svalV) {
string str;
self->value.svalV->val2str(str);
pvs = (char *)realloc(pvs, str.size()+1);
strcpy(pvs, str.c_str());
}
else
return "###";
}
return pvs;
}
/* Compares two values. The first is always TPyValue.
Comparisons of discrete are based on intV not on string representations
If both are TPyValue, the values must be of same type
- If both are special, they are equal/different if the valueType is
equal/different. Operators >, <, <= and >= are not defined.
- If only one is special, it's an error
- If they are discrete and descriptors are known but different,
each value's string representation is compared to the other's,
both comparisons are made and must give the same result.
If not, it's an error.
- Otherwise, intV's r floatV's are compared
If the other is an integer, it can be compared with discrete and
continuous attributes
If the other is a float, it can be compared with continuous attrs.
If the first value is special and the other is string "~" or "?",
they are compared as described above.
Otherwise, the descriptor for the first value must be known and is
used to convert the second value (if possible). The values are
then compared by the same rules as if both were PyValues
(except that both obviously have the same descriptor).
*/
#define errUndefinedIf(cond) if (cond) PYERROR(PyExc_TypeError, "Value.compare: cannot compare with undefined values", PYNULL);
PyObject *richcmp_from_sign(const int &i, const int &op)
{ int cmp;
switch (op) {
case Py_LT: cmp = (i<0); break;
case Py_LE: cmp = (i<=0); break;
case Py_EQ: cmp = (i==0); break;
case Py_NE: cmp = (i!=0); break;
case Py_GT: cmp = (i>0); break;
case Py_GE: cmp = (i>=0); break;
default:
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
PyObject *res;
if (cmp)
res = Py_True;
else
res = Py_False;
Py_INCREF(res);
return res;
}
PyObject *Value_richcmp(TPyValue *i, PyObject *j, int op)
{
PyTRY
const TValue &val1 = i->value;
if (PyOrValue_Check(j)) {
const TValue &val2 = PyValue_AS_Value(j);
if (val1.varType != val2.varType)
PYERROR(PyExc_TypeError, "Value.compare: can't compare values of different types", PYNULL)
if (val1.isSpecial() || val2.isSpecial())
if ((op==Py_EQ) || (op==Py_NE)) {
PyObject *res = (val1.valueType==val2.valueType) == (op==Py_EQ) ? Py_True : Py_False;
Py_INCREF(res);
return res;
}
else {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
// Nominal values of different attributes are treated separately
PVariable &var1 = i->variable;
PVariable &var2 = PyValue_AS_Variable(j);
if ((val1.varType==TValue::INTVAR) && var1 && var2 && (var1 != var2)) {
TValue tempval;
string tempstr;
var2->val2str(val2, tempstr);
if (var1->str2val_try(tempstr, tempval)) {
int cmp1 = val1.compare(tempval);
var1->val2str(val1, tempstr);
if (var2->str2val_try(tempstr, tempval)) {
int cmp2 = tempval.compare(val2);
bool err = true;
switch (op) {
case Py_LE:
case Py_GE: err = ((cmp1*cmp2) == -1); break;
case Py_LT:
case Py_GT: err = (cmp1!=cmp2); break;
case Py_EQ:
case Py_NE: err = ((cmp1==0) != (cmp2==0)); break;
}
if (err)
PYERROR(PyExc_TypeError, "Value.compare: values are of different types and have different orders", PYNULL);
}
return richcmp_from_sign(cmp1, op);
}
var1->val2str(val1, tempstr);
if (var2->str2val_try(tempstr, tempval))
return richcmp_from_sign(tempval.compare(val2), op);
PYERROR(PyExc_TypeError, "Value.compare: values are of different types and cannot be compared", PYNULL);
}
// Not nominal OR both values or of the same attribute
return richcmp_from_sign(val1.compare(val2), op);
}
if (PyInt_Check(j)) {
errUndefinedIf(val1.isSpecial());
if (val1.varType==TValue::INTVAR)
return richcmp_from_sign(val1.intV - (int)PyInt_AsLong(j), op);
else if (val1.varType==TValue::FLOATVAR)
return richcmp_from_sign(sign(val1.floatV - (int)PyInt_AsLong(j)), op);
}
else if (PyFloat_Check(j)) {
errUndefinedIf(val1.isSpecial());
if (val1.varType==TValue::FLOATVAR)
return richcmp_from_sign(sign(val1.floatV - (float)PyFloat_AsDouble(j)), op);
}
else if (PyString_Check(j) && val1.isSpecial() && ((op==Py_EQ) || (op==Py_NE))) {
char *s = PyString_AsString(j);
PyObject *res = NULL;
if (!strcmp(s, "~"))
res = (val1.valueType==valueDC) == (op==Py_EQ) ? Py_True : Py_False;
else if (!strcmp(s, "?"))
res = (val1.valueType==valueDK) == (op==Py_EQ) ? Py_True : Py_False;
if (res) {
Py_INCREF(res);
return res;
}
}
if (i->variable) {
TValue val2;
if (!convertFromPython(j, val2, i->variable))
return PYNULL;
if (val1.isSpecial() || val2.isSpecial())
if ((op==Py_EQ) || (op==Py_NE)) {
PyObject *res = (val1.valueType==val2.valueType) == (op==Py_EQ) ? Py_True : Py_False;
Py_INCREF(res);
return res;
}
else {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
return richcmp_from_sign(val1.compare(val2), op);
}
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
PyCATCH
}
#undef errUndefinedIf
PyObject *Value_str(TPyValue *self)
{ PyTRY
return PyString_FromString(TPyValue2string(self));
PyCATCH
}
PyObject *Value_repr(TPyValue *self)
{ PyTRY
if (self->variable)
return PyString_FromFormat("<orange.Value '%s'='%s'>", self->variable->name.c_str(), TPyValue2string(self));
else
return PyString_FromFormat("<orange.Value '%s'>", TPyValue2string(self));
PyCATCH
}
bool checkSpecial(TPyValue *self, char *casttype)
{
if (self->value.isSpecial()) {
if (self->variable && self->variable->name.length())
PyErr_Format(PyExc_TypeError, "value of '%s' is unknown and cannot be %s", self->variable->name.c_str(), casttype);
else
PyErr_Format(PyExc_TypeError, "attribute value is unknown and cannot be %s", casttype);
return false;
}
return true;
}
PyObject *Value_int(TPyValue *self)
{ PyTRY
if (!checkSpecial(self, "cast to an integer"))
return PYNULL;
return Py_BuildValue("i", (self->value.varType==TValue::INTVAR) ? self->value.intV : int(self->value.floatV));
PyCATCH
}
PyObject *Value_long(TPyValue *self)
{ PyTRY
if (!checkSpecial(self, "cast to a long integer"))
return PYNULL;
return Py_BuildValue("l", (self->value.varType==TValue::INTVAR) ? long(self->value.intV) : long(self->value.floatV));
PyCATCH
}
PyObject *Value_float(TPyValue *self)
{ PyTRY
if (!checkSpecial(self, "cast to a float"))
return PYNULL;
return Py_BuildValue("f", (self->value.varType==TValue::INTVAR) ? float(self->value.intV) : self->value.floatV);
PyCATCH
}
inline bool checkForNumerical(const TValue &val1, const TValue &val2, const char *op)
{
if (val1.isSpecial() || val2.isSpecial())
PYERROR(PyExc_TypeError, "cannot %s unknown values", false);
if ((val1.varType!=TValue::FLOATVAR) || (val2.varType!=TValue::FLOATVAR))
PYERROR(PyExc_TypeError, "cannot %s non-continuous values", false);
return true;
}
#define VALUEOP(opname,FUN,opverb) \
PyObject *Value_##opname(TPyValue *self, PyObject *other) \
{ PyTRY \
const TValue &val1 = self->value; \
\
if (PyOrValue_Check(other)) { \
const TValue &val2 = PyValue_AS_Value(other); \
return checkForNumerical(val1, val2, opverb) ? PyFloat_FromDouble(val1.floatV FUN val2.floatV) : PYNULL; \
} \
\
TValue val2; \
return convertFromPython(other, val2, self->variable) && checkForNumerical(val1, val2, opverb) ? PyFloat_FromDouble(val1.floatV FUN val2.floatV) : PYNULL; \
PyCATCH \
}
PyObject *Value_add(TPyValue *self, PyObject *other);
PyObject *Value_sub(TPyValue *self, PyObject *other);
PyObject *Value_mul(TPyValue *self, PyObject *other);
PyObject *Value_div(TPyValue *self, PyObject *other);
VALUEOP(add,+,"sum")
VALUEOP(sub,-,"subtract")
VALUEOP(mul,*,"multiply")
VALUEOP(div,/,"divide")
PyObject *Value_pow(TPyValue *self, PyObject *other, PyObject *)
{ PyTRY
const TValue &val1 = self->value;
if (!val1.isSpecial() && (val1.varType==TValue::FLOATVAR) && (val1.floatV<=0))
PYERROR(PyExc_TypeError, "negative base value", false);
if (PyOrValue_Check(other)) {
const TValue &val2 = PyValue_AS_Value(other);
return checkForNumerical(val1, val2, "add") ? PyFloat_FromDouble(exp(val2.floatV*log(val1.floatV))) : PYNULL;
}
else {
TValue val2;
return convertFromPython(other, val2, self->variable)
&& checkForNumerical(val1, val2, "add")
? PyFloat_FromDouble(exp(val2.floatV*log(val1.floatV)))
: PYNULL;
}
PyCATCH
}
PyObject *Value_neg(TPyValue *self)
{ PyTRY
if (!checkSpecial(self, "negated"))
return PYNULL;
const TValue &val1 = self->value;
if (val1.varType!=TValue::FLOATVAR)
PYERROR(PyExc_TypeError, "cannot negate non-continuous value", false);
return PyFloat_FromDouble(-val1.floatV);
PyCATCH
}
PyObject *Value_abs(TPyValue *self)
{ PyTRY
if (self->value.isSpecial())
if (self->variable && self->variable->name.length()) {
PyErr_Format(PyExc_TypeError, "cannot compute an absolute value of '%s' since its value is unknown", self->variable->name.c_str());
return PYNULL;
}
else
PYERROR(PyExc_TypeError, "cannot compute an absolute value of attribute since its value is unknown", PYNULL);
const TValue &val1 = self->value;
if (val1.varType!=TValue::FLOATVAR)
PYERROR(PyExc_TypeError, "cannot compute abs of non-continuous value", false);
return PyFloat_FromDouble(fabs(val1.floatV));
PyCATCH
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -