⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cls_value.cpp

📁 orange源码 数据挖掘技术
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*
    This file is part of Orange.

    Orange is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Orange 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Orange; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Authors: Janez Demsar, Blaz Zupan, 1996--2002
    Contact: janez.demsar@fri.uni-lj.si
*/


#ifdef _MSC_VER
 #pragma warning (disable : 4786 4114 4018 4267 4244)
#endif

#include "cls_value.hpp"
#include "cls_orange.hpp"
#include "vars.hpp"
#include "stringvars.hpp"
#include "pythonvars.hpp"
#include "values.hpp"

#include "vectortemplates.hpp"

#include "externs.px"


#define CHECK_VARIABLE \
  if (!self->variable) PYERROR(PyExc_TypeError, "'variable' not set", PYNULL);

#define CHECK_SPECIAL_OTHER \
  if (self->value.isSpecial()) \
    PYERROR(PyExc_TypeError, "attribute value unknown", PYNULL); \
  if ((self->value.varType!=TValue::INTVAR) && (self->value.varType!=TValue::FLOATVAR)) \
    PYERROR(PyExc_TypeError, "attribute is not an ordinary discrete or continuous", PYNULL);



DATASTRUCTURE(Value, TPyValue, 0)
ABSTRACT(SomeValue, Orange)

/* Converts a value into an appropriate python variable.
   Behaves as convertToPythonNative(const TValue &, PVariable)
   when the variable is not given. */

PyObject *convertToPythonNative(const TValue &val)
{ return convertToPythonNative(val, PVariable()); }



/* Converts a value into an appropriate python variable.
   Behaves as convertToPythonNative(const TValue &, PVariable);
   variable can be there or not. */

PyObject *convertToPythonNative(const TPyValue *value)
{ return convertToPythonNative(value->value, value->variable); }



/* Converts a value into an appropriate python variable.
   If value is known (e.g. not DC, DK...)
    - continuous values are returned as ordinary python floats
    - discrete are returned as strings (variable is required)
    - string values are returned as strings
    - other values are return as ordinary orange objects
   If value is special 
    - if the variable is given, its val2str is used to get a string
    - if the variable is not given, '?', '~' and '.' are returned
      for DK, DC and other, respectively.

   FAILS if the value is discrete and variable is not given
*/

PyObject *convertToPythonNative(const TValue &val, PVariable var)
{
  if ((val.varType==TValue::FLOATVAR) && !val.isSpecial())
    return PyFloat_FromDouble(double(val.floatV));

  if (val.varType == PYTHONVAR) {
    PyObject *res = val.svalV ? ((TPythonValue &)(val.svalV.getReference())).value : Py_None;
    Py_INCREF(res);
    return res;
  }

  if ((val.varType == STRINGVAR) && val.svalV) {
    string s;
    val.svalV.AS(TStringValue)->val2str(s);
    return PyString_FromString(s.c_str());
  }

  if ((val.varType!=TValue::INTVAR) && val.svalV)
    return WrapOrange((const_cast<TValue &>(val)).svalV);

  if (var) { // && (val.varType == TValue::INTVAR || val.isSpecial)
    string vs;
    var->val2str(val, vs);
    return PyString_FromString(vs.c_str());
  }

  if (val.isSpecial())
    if (val.isDK())
      return PyString_FromString("?");
    else if (val.isDC()) 
      return PyString_FromString("~");
    else
      return PyString_FromString(".");

  PYERROR(PyExc_TypeError, "unknown value type", PYNULL);
}


/* The main routine for converting values from python to TValue.
   If arguments are given as a
   - Value, it is simply copied.
       The variable is checked if given.
   - SomeValue, it is copied as such.
       If the variable is discrete or continuous, SomeValue must
       be DiscDistribution or ContDistribution.
   - string, we convert it to a value
       The variable must be given unless the string is '?', '~'
       (in this case INTVAR is ocnstructed)
       We could return a StringValue here, but if user passes a
       string without descriptor it is more probable that he just
       forgot it. I doubt that many would construct StringValues.)
   - int - if variable is given and is discrete, an integer value
           is constructed. If the variable is derived from
           EnumVariable the range is also tested
         - if variable is given and is continuous, a continuous
           value is constructed
         - if variable is given and is of other type, an error is
           raised
         - if the variable is not given, an integer value is constructed
   - float - a continuous value is constructed.
       If the variable is given, it is checked that it is continuous
   - other types: if it can be converted to float and the variable is
       given and is continuous, a continuous value is constructed.
       Otherwise, an exception is raised.         
*/

bool convertFromPython(PyObject *args, TValue &value, PVariable var)
{
  if (PyOrValue_Check(args)) {
    if (var && PyValue_AS_Variable(args) && (PyValue_AS_Variable(args)!=var)) {
      PyErr_Format(PyExc_TypeError, "wrong attribute value (expected value of '%s', got value of '%s')", var->name.c_str(), PyValue_AS_Variable(args)->name.c_str());
      return false;
    }
    else
      value = PyValue_AS_Value(args);
    return true;
  }

  if (PyOrSomeValue_Check(args)) {
    if (var) {
      if ((var->varType==TValue::INTVAR) && !PyOrDiscDistribution_Check(args)) {
        PyErr_Format(PyExc_TypeError, "attribute '%s' expects DiscDistribution, '%s' given", var->name.c_str(), args->ob_type->tp_name);
        return false;
      }
      if ((var->varType==TValue::FLOATVAR) && !PyOrContDistribution_Check(args)) {
        PyErr_Format(PyExc_TypeError, "attribute '%s' expects ContDistribution, '%s' given", var->name.c_str(), args->ob_type->tp_name);
        return false;
      }
    }
    int vtype;
    if (PyOrDiscDistribution_Check(args))
      vtype = TValue::INTVAR;
    else if (PyOrContDistribution_Check(args))
      vtype = TValue::FLOATVAR;
    else if (PyOrStringValue_Check(args))
      vtype = STRINGVAR;
    else if (PyOrPythonValue_Check(args))
      vtype = PYTHONVAR;
    else
      raiseError("unknovn variable type");

    value = TValue(PyOrange_AsSomeValue(args), vtype);
    return true;
  }
  
  if (PyString_Check(args)) {
    char *str = PyString_AsString(args);
    if (var)
      var->str2val(str, value);
    else
      if (!strcmp(str, "?"))
        value = TValue(TValue::INTVAR, valueDK);
      else if (!strcmp(str, "~"))
        value = TValue(TValue::INTVAR, valueDC);
      else {
        PyErr_Format(PyExc_TypeError, "cannot convert '%s' to a value of an unknown attribute", str);
        return false;
      }
    return true;
  }

  if (var && var->varType == PYTHONVAR) {
    Py_INCREF(args);
    value = TValue(mlnew TPythonValue(args), PYTHONVAR);
    return true;
  }
  
  if (PyInt_Check(args)) {
    int ii = int(PyInt_AsLong(args));

    if (var) {
      if (var->varType == TValue::FLOATVAR) {
        value = TValue(float(ii));
        return true;
      }

      if (var->varType == TValue::INTVAR) {
        if (var.is_derived_from(TEnumVariable)) {
          int nv = var.AS(TEnumVariable)->noOfValues();
          if (ii >= nv) {
            PyErr_Format(PyExc_TypeError, "value index %i out of range (0 - %i)", ii, nv-1);
            return false;
          }
        }

        value = TValue(ii);
        return true;
      }

      PyErr_Format(PyExc_TypeError,  "cannot convert an integer to a value of attribute '%s'", var->name.c_str());
      return false;
    }

    value = TValue(ii);
    return true;
  }

  if (PyFloat_Check(args)) {
    if (var && (var->varType != TValue::FLOATVAR)) {
      PyErr_Format(PyExc_TypeError,  "cannot convert a float to a value of attribute '%s'", var->name.c_str());
      return false;
    }

    value = TValue(float(PyFloat_AsDouble(args)));
    return true;
  }

  if (var && (var->varType == TValue::FLOATVAR)) {
    PyObject *pyfloat = PyNumber_Float(args);
    if (!pyfloat) {
      PyErr_Format(PyExc_TypeError, "cannot convert an object of type '%s' to value of attribute '%s'", args->ob_type->tp_name, var->name.c_str());
      return false;
    }

    value = TValue(float(PyFloat_AsDouble(pyfloat)));
    Py_DECREF(pyfloat);
    return true;
  }

  if (var)
    PyErr_Format(PyExc_TypeError,  "cannot convert an object of type '%s' to value of attribute '%s'", args->ob_type->tp_name, var->name.c_str());
  else
    PyErr_Format(PyExc_TypeError,  "cannot convert an object of type '%s' to value of attribute", args->ob_type->tp_name);

  return false;
}


/* Builds a TPyValue from arguments given in Python.
   See Value_FromArguments for details. */

bool convertFromPython(PyObject *args, TPyValue *&value)
{
  value = (TPyValue *)Value_FromArguments((PyTypeObject *)&PyOrValue_Type, args);
  return value!=NULL;
}



/* The main constructor for TPyValue.
   Gets a value and descriptor, allocates the memory and assigns fields. */

PyObject *Value_FromVariableValueType(PyTypeObject *type, PVariable var, const TValue &val)
{ 
  TPyValue *value = PyObject_GC_New(TPyValue, type);
  if (!value)
    return PYNULL;

  /* The below is needed since 'value' was allocated in C code, so it's
     constructor has never been called and the below fields (wrapped pointers)
     contain random data, which would lead to crash when trying to deallocate
     them. */
  value->value.svalV.init();
  value->variable.init();

  value->value = val;
  value->variable = var;

  PyObject_GC_Track(value);

  return (PyObject *)value;
}



/* Constructs a value from arguments in Python. Arguments must be given as a tuple
   with at least one element.
   - If the single element is a variable, a DK() value for that attribute is returned
   - Otherwise, it is converted using convertFromPython, without descriptor given

   If there are two elements
   - If one is variable, convertFromPython is used, passing the variable and the other
   - Otherwise, both must be integers and are used for varType and valueType.
*/

PyObject *Value_FromArguments(PyTypeObject *type, PyObject *args)
{   
  PyTRY
    PyObject *obj1;
    PyObject *obj2 = NULL;

    if (!PyArg_ParseTuple(args, "O|O:Value", &obj1, &obj2))
      return PYNULL;

    if (!obj2) {
      if (PyOrVariable_Check(obj1))
        return Value_FromVariableType(type, PyOrange_AsVariable(obj1));
      else {
        TValue val;
        return convertFromPython(obj1, val) ? Value_FromValueType(type, val) : PYNULL;
      }
    }

    TValue val;
    if (PyOrVariable_Check(obj1)) {
      const PVariable &var = PyOrange_AsVariable(obj1);
      return convertFromPython(obj2, val, var) ? Value_FromVariableValueType(type, var, val) : PYNULL;
    }
    else if (PyOrVariable_Check(obj2)) {
      const PVariable &var = PyOrange_AsVariable(obj2);
      return convertFromPython(obj1, val, var) ? Value_FromVariableValueType(type, var, val) : PYNULL;
    }
    else if (PyInt_Check(obj1) && PyInt_Check(obj2)) {
      int vartype = int(PyInt_AsLong(obj1));

      if (vartype == STRINGVAR)
        return Value_FromValueType(type, TValue(STRINGVAR, (signed char)PyInt_AsLong(obj2)));

      if (vartype > TValue::FLOATVAR) {
        PyErr_Format(PyExc_IndexError, "invalid value type (%i)", vartype);
        return PYNULL;
      }
        
      return Value_FromValueType(type, TValue((char)vartype, (signed char)PyInt_AsLong(obj2)));
    }

    PYERROR(PyExc_TypeError, "Value(): invalid arguments", PYNULL);
  PyCATCH
}




PyObject *Value_new(PyTypeObject *type, PyObject *args, PyObject *keywords)  BASED_ON(ROOT, "([Variable], [int | float | Value | ...])")
{ return Value_FromArguments(type, args); }


void Value_dealloc(TPyValue *self)
{ self->variable = PVariable();
  self->value.~TValue();

  if (PyObject_IsPointer(self)) {
    PyObject_GC_UnTrack((PyObject *)self);
    self->ob_type->tp_free((PyObject *)self); 
  }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -