util.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*-----------------------------------------------------------------------------
  2. | Copyright (c) 2013-2019, Nucleic Development Team.
  3. |
  4. | Distributed under the terms of the Modified BSD License.
  5. |
  6. | The full license is in the file LICENSE, distributed with this software.
  7. |----------------------------------------------------------------------------*/
  8. #pragma once
  9. #include <map>
  10. #include <string>
  11. #include <cppy/cppy.h>
  12. #include <kiwi/kiwi.h>
  13. #include "types.h"
  14. namespace kiwisolver
  15. {
  16. inline bool
  17. convert_to_double( PyObject* obj, double& out )
  18. {
  19. if( PyFloat_Check( obj ) )
  20. {
  21. out = PyFloat_AS_DOUBLE( obj );
  22. return true;
  23. }
  24. if( PyLong_Check( obj ) )
  25. {
  26. out = PyLong_AsDouble( obj );
  27. if( out == -1.0 && PyErr_Occurred() )
  28. return false;
  29. return true;
  30. }
  31. cppy::type_error( obj, "float, int, or long" );
  32. return false;
  33. }
  34. inline bool
  35. convert_pystr_to_str( PyObject* value, std::string& out )
  36. {
  37. out = PyUnicode_AsUTF8( value );
  38. return true;
  39. }
  40. inline bool
  41. convert_to_strength( PyObject* value, double& out )
  42. {
  43. if( PyUnicode_Check( value ) )
  44. {
  45. std::string str;
  46. if( !convert_pystr_to_str( value, str ) )
  47. return false;
  48. if( str == "required" )
  49. out = kiwi::strength::required;
  50. else if( str == "strong" )
  51. out = kiwi::strength::strong;
  52. else if( str == "medium" )
  53. out = kiwi::strength::medium;
  54. else if( str == "weak" )
  55. out = kiwi::strength::weak;
  56. else
  57. {
  58. PyErr_Format(
  59. PyExc_ValueError,
  60. "string strength must be 'required', 'strong', 'medium', "
  61. "or 'weak', not '%s'",
  62. str.c_str()
  63. );
  64. return false;
  65. }
  66. return true;
  67. }
  68. if( !convert_to_double( value, out ) )
  69. return false;
  70. return true;
  71. }
  72. inline bool
  73. convert_to_relational_op( PyObject* value, kiwi::RelationalOperator& out )
  74. {
  75. if( !PyUnicode_Check( value ) )
  76. {
  77. cppy::type_error( value, "str" );
  78. return false;
  79. }
  80. std::string str;
  81. if( !convert_pystr_to_str( value, str ) )
  82. return false;
  83. if( str == "==" )
  84. out = kiwi::OP_EQ;
  85. else if( str == "<=" )
  86. out = kiwi::OP_LE;
  87. else if( str == ">=" )
  88. out = kiwi::OP_GE;
  89. else
  90. {
  91. PyErr_Format(
  92. PyExc_ValueError,
  93. "relational operator must be '==', '<=', or '>=', not '%s'",
  94. str.c_str()
  95. );
  96. return false;
  97. }
  98. return true;
  99. }
  100. inline PyObject*
  101. make_terms( const std::map<PyObject*, double>& coeffs )
  102. {
  103. typedef std::map<PyObject*, double>::const_iterator iter_t;
  104. cppy::ptr terms( PyTuple_New( coeffs.size() ) );
  105. if( !terms )
  106. return 0;
  107. Py_ssize_t size = PyTuple_GET_SIZE( terms.get() );
  108. for( Py_ssize_t i = 0; i < size; ++i ) // zero tuple for safe early return
  109. PyTuple_SET_ITEM( terms.get(), i, 0 );
  110. Py_ssize_t i = 0;
  111. iter_t it = coeffs.begin();
  112. iter_t end = coeffs.end();
  113. for( ; it != end; ++it, ++i )
  114. {
  115. PyObject* pyterm = PyType_GenericNew( Term::TypeObject, 0, 0 );
  116. if( !pyterm )
  117. return 0;
  118. Term* term = reinterpret_cast<Term*>( pyterm );
  119. term->variable = cppy::incref( it->first );
  120. term->coefficient = it->second;
  121. PyTuple_SET_ITEM( terms.get(), i, pyterm );
  122. }
  123. return terms.release();
  124. }
  125. inline PyObject*
  126. reduce_expression( PyObject* pyexpr ) // pyexpr must be an Expression
  127. {
  128. Expression* expr = reinterpret_cast<Expression*>( pyexpr );
  129. std::map<PyObject*, double> coeffs;
  130. Py_ssize_t size = PyTuple_GET_SIZE( expr->terms );
  131. for( Py_ssize_t i = 0; i < size; ++i )
  132. {
  133. PyObject* item = PyTuple_GET_ITEM( expr->terms, i );
  134. Term* term = reinterpret_cast<Term*>( item );
  135. coeffs[ term->variable ] += term->coefficient;
  136. }
  137. cppy::ptr terms( make_terms( coeffs ) );
  138. if( !terms )
  139. return 0;
  140. PyObject* pynewexpr = PyType_GenericNew( Expression::TypeObject, 0, 0 );
  141. if( !pynewexpr )
  142. return 0;
  143. Expression* newexpr = reinterpret_cast<Expression*>( pynewexpr );
  144. newexpr->terms = terms.release();
  145. newexpr->constant = expr->constant;
  146. return pynewexpr;
  147. }
  148. inline kiwi::Expression
  149. convert_to_kiwi_expression( PyObject* pyexpr ) // pyexpr must be an Expression
  150. {
  151. Expression* expr = reinterpret_cast<Expression*>( pyexpr );
  152. std::vector<kiwi::Term> kterms;
  153. Py_ssize_t size = PyTuple_GET_SIZE( expr->terms );
  154. for( Py_ssize_t i = 0; i < size; ++i )
  155. {
  156. PyObject* item = PyTuple_GET_ITEM( expr->terms, i );
  157. Term* term = reinterpret_cast<Term*>( item );
  158. Variable* var = reinterpret_cast<Variable*>( term->variable );
  159. kterms.push_back( kiwi::Term( var->variable, term->coefficient ) );
  160. }
  161. return kiwi::Expression( kterms, expr->constant );
  162. }
  163. inline const char*
  164. pyop_str( int op )
  165. {
  166. switch( op )
  167. {
  168. case Py_LT:
  169. return "<";
  170. case Py_LE:
  171. return "<=";
  172. case Py_EQ:
  173. return "==";
  174. case Py_NE:
  175. return "!=";
  176. case Py_GT:
  177. return ">";
  178. case Py_GE:
  179. return ">=";
  180. default:
  181. return "";
  182. }
  183. }
  184. } // namespace kiwisolver