Base: refactor QuantityPy class
This commit is contained in:
@@ -22,7 +22,12 @@
|
|||||||
|
|
||||||
#include "PreCompiled.h"
|
#include "PreCompiled.h"
|
||||||
#ifndef _PreComp_
|
#ifndef _PreComp_
|
||||||
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <optional>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Unit.h"
|
#include "Unit.h"
|
||||||
@@ -33,7 +38,7 @@
|
|||||||
|
|
||||||
#include "UnitPy.h"
|
#include "UnitPy.h"
|
||||||
|
|
||||||
using namespace Base;
|
using Base::Quantity;
|
||||||
|
|
||||||
// returns a string which represents the object e.g. when printed in python
|
// returns a string which represents the object e.g. when printed in python
|
||||||
std::string QuantityPy::representation() const
|
std::string QuantityPy::representation() const
|
||||||
@@ -181,84 +186,128 @@ PyObject* QuantityPy::getUserPreferred(PyObject* /*args*/) const
|
|||||||
|
|
||||||
PyObject* QuantityPy::getValueAs(PyObject* args) const
|
PyObject* QuantityPy::getValueAs(PyObject* args) const
|
||||||
{
|
{
|
||||||
Quantity quant;
|
auto tryQuantity = [&]() -> std::optional<Quantity> {
|
||||||
quant.setInvalid();
|
|
||||||
|
|
||||||
// first try Quantity
|
|
||||||
if (!quant.isValid()) {
|
|
||||||
PyObject* object {};
|
PyObject* object {};
|
||||||
if (PyArg_ParseTuple(args, "O!", &(QuantityPy::Type), &object)) {
|
if (!PyArg_ParseTuple(args, "O!", &(QuantityPy::Type), &object)) {
|
||||||
quant = *static_cast<QuantityPy*>(object)->getQuantityPtr();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!quant.isValid()) {
|
return *getQuantityPtr();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto tryUnit = [&]() -> std::optional<Quantity> {
|
||||||
PyObject* object {};
|
PyObject* object {};
|
||||||
PyErr_Clear();
|
if (!PyArg_ParseTuple(args, "O!", &(UnitPy::Type), &object)) {
|
||||||
if (PyArg_ParseTuple(args, "O!", &(UnitPy::Type), &object)) {
|
return std::nullopt;
|
||||||
quant.setUnit(*static_cast<UnitPy*>(object)->getUnitPtr());
|
|
||||||
quant.setValue(1.0);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!quant.isValid()) {
|
return Quantity {1.0, *static_cast<UnitPy*>(object)->getUnitPtr()};
|
||||||
|
};
|
||||||
|
|
||||||
|
auto tryUnitAndValue = [&]() -> std::optional<Quantity> {
|
||||||
PyObject* object {};
|
PyObject* object {};
|
||||||
double value {};
|
double value {};
|
||||||
PyErr_Clear();
|
if (!PyArg_ParseTuple(args, "dO!", &value, &(UnitPy::Type), &object)) {
|
||||||
if (PyArg_ParseTuple(args, "dO!", &value, &(UnitPy::Type), &object)) {
|
return std::nullopt;
|
||||||
quant.setUnit(*static_cast<UnitPy*>(object)->getUnitPtr());
|
|
||||||
quant.setValue(value);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!quant.isValid()) {
|
return Quantity {value, *static_cast<UnitPy*>(object)->getUnitPtr()};
|
||||||
|
};
|
||||||
|
|
||||||
|
auto tryUnitPartsAndValue = [&]() -> std::optional<Quantity> {
|
||||||
double f = std::numeric_limits<double>::max();
|
double f = std::numeric_limits<double>::max();
|
||||||
int i1 = 0;
|
int i1 {0};
|
||||||
int i2 = 0;
|
int i2 {0};
|
||||||
int i3 = 0;
|
int i3 {0};
|
||||||
int i4 = 0;
|
int i4 {0};
|
||||||
int i5 = 0;
|
int i5 {0};
|
||||||
int i6 = 0;
|
int i6 {0};
|
||||||
int i7 = 0;
|
int i7 {0};
|
||||||
int i8 = 0;
|
int i8 {0};
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
if (PyArg_ParseTuple(args, "d|iiiiiiii", &f, &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8)) {
|
if (!PyArg_ParseTuple(args, "d|iiiiiiii", &f, &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8)) {
|
||||||
if (f < std::numeric_limits<double>::max()) {
|
return std::nullopt;
|
||||||
quant = Quantity(f,
|
}
|
||||||
Unit {static_cast<int8_t>(i1),
|
|
||||||
static_cast<int8_t>(i2),
|
if (f >= std::numeric_limits<double>::max()) {
|
||||||
static_cast<int8_t>(i3),
|
return std::nullopt;
|
||||||
static_cast<int8_t>(i4),
|
}
|
||||||
static_cast<int8_t>(i5),
|
|
||||||
static_cast<int8_t>(i6),
|
auto re = [](auto val) {
|
||||||
static_cast<int8_t>(i7),
|
return static_cast<int8_t>(val);
|
||||||
static_cast<int8_t>(i8)});
|
};
|
||||||
|
|
||||||
|
return Quantity {f, Unit {re(i1), re(i2), re(i3), re(i4), re(i5), re(i6), re(i7), re(i8)}};
|
||||||
|
};
|
||||||
|
|
||||||
|
auto tryString = [&]() -> std::optional<Quantity> {
|
||||||
|
char* string {};
|
||||||
|
if (!PyArg_ParseTuple(args, "et", "utf-8", &string)) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string str {string};
|
||||||
|
PyMem_Free(string);
|
||||||
|
return Quantity::parse(str);
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::vector<std::function<std::optional<Quantity>()>> funcs = {tryQuantity,
|
||||||
|
tryUnit,
|
||||||
|
tryUnitAndValue,
|
||||||
|
tryUnitPartsAndValue,
|
||||||
|
tryString};
|
||||||
|
|
||||||
|
auto tryFuncs = [&]() -> std::optional<Quantity> {
|
||||||
|
for (const auto& func : funcs) {
|
||||||
|
PyErr_Clear();
|
||||||
|
if (auto quant = func(); quant.has_value()) {
|
||||||
|
return quant;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto checkQuant = [&](const Quantity& quant) -> bool {
|
||||||
|
auto err = [&](const std::string& str) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, str.c_str());
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto* qPtr = getQuantityPtr();
|
||||||
|
if (!qPtr) {
|
||||||
|
err("QuantityPtr is null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto qpUnit = qPtr->getUnit();
|
||||||
|
if (qpUnit.isEmpty()) {
|
||||||
|
err("QuantityPtr returned empty unit");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto qUnit = quant.getUnit(); qUnit != qpUnit) {
|
||||||
|
err("Unit mismatch (`" + qUnit.getString() + "` != `" + qpUnit.getString() + "`)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const auto optQuant = tryFuncs();
|
||||||
|
if (!optQuant.has_value()) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Expected quantity, string, float or unit");
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!quant.isValid()) {
|
const auto quant = optQuant.value();
|
||||||
PyErr_Clear();
|
if (quant.isQuantity()) {
|
||||||
char* string {};
|
if (!checkQuant(quant)) {
|
||||||
if (PyArg_ParseTuple(args, "et", "utf-8", &string)) {
|
return nullptr;
|
||||||
std::string str(string);
|
|
||||||
PyMem_Free(string);
|
|
||||||
quant = Quantity::parse(str);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!quant.isValid()) {
|
return new QuantityPy(new Quantity(getQuantityPtr()->getValue() / quant.getValue()));
|
||||||
PyErr_SetString(PyExc_TypeError, "Either quantity, string, float or unit expected");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getQuantityPtr()->getUnit() != quant.getUnit() && quant.isQuantity()) {
|
|
||||||
PyErr_SetString(PyExc_ValueError, "Unit mismatch");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
quant = Quantity(getQuantityPtr()->getValueAs(quant));
|
|
||||||
return new QuantityPy(new Quantity(quant));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* QuantityPy::__round__(PyObject* args) const
|
PyObject* QuantityPy::__round__(PyObject* args) const
|
||||||
|
|||||||
Reference in New Issue
Block a user