Skip to content

Commit 641fd47

Browse files
committed
uinvert fexpr
1 parent f63e503 commit 641fd47

File tree

6 files changed

+88
-59
lines changed

6 files changed

+88
-59
lines changed

src/core/expr/fexpr.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,9 @@ bool PyFExpr::nb__bool__() {
215215
" f.B != 0\n";
216216
}
217217

218-
oobj PyFExpr::nb__invert__() {
219-
return make_unexpr(dt::expr::Op::UINVERT, this);
220-
}
218+
// oobj PyFExpr::nb__invert__() {
219+
// return make_unexpr(dt::expr::Op::UINVERT, this);
220+
// }
221221

222222
oobj PyFExpr::nb__neg__() {
223223
return make_unexpr(dt::expr::Op::UMINUS, this);

src/core/expr/fexpr.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ class PyFExpr : public py::XObject<PyFExpr> {
163163
static py::oobj nb__sub__ (py::robj, py::robj);
164164
static py::oobj nb__mul__ (py::robj, py::robj);
165165
static py::oobj nb__floordiv__(py::robj, py::robj);
166+
static py::oobj nb__invert__ (py::robj);
166167
static py::oobj nb__truediv__ (py::robj, py::robj);
167168
static py::oobj nb__mod__ (py::robj, py::robj);
168169
static py::oobj nb__pow__ (py::robj, py::robj, py::robj);
@@ -172,7 +173,7 @@ class PyFExpr : public py::XObject<PyFExpr> {
172173
static py::oobj nb__lshift__ (py::robj, py::robj);
173174
static py::oobj nb__rshift__ (py::robj, py::robj);
174175
bool nb__bool__();
175-
py::oobj nb__invert__();
176+
//py::oobj nb__invert__();
176177
py::oobj nb__neg__();
177178
py::oobj nb__pos__();
178179

src/core/expr/funary/uinvert.cc

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//------------------------------------------------------------------------------
2-
// Copyright 2023 H2O.ai
2+
// Copyright 2022-2023 H2O.ai
33
//
44
// Permission is hereby granted, free of charge, to any person obtaining a
55
// copy of this software and associated documentation files (the "Software"),
@@ -20,69 +20,86 @@
2020
// IN THE SOFTWARE.
2121
//------------------------------------------------------------------------------
2222
#include "column/const.h"
23-
#include "documentation.h"
23+
#include "column/func_unary.h"
24+
#include "column/isna.h"
2425
#include "expr/fexpr_column.h"
25-
#include "expr/funary/umaker.h"
26+
#include "documentation.h"
27+
#include "expr/fexpr_func_unary.h"
2628
#include "expr/eval_context.h"
2729
#include "expr/workframe.h"
2830
#include "python/xargs.h"
29-
namespace dt
30-
{
31-
namespace expr
32-
{
31+
#include "stype.h"
32+
namespace dt {
33+
namespace expr {
3334

34-
FExpr_UINVERT::FExpr_UINVERT(ptrExpr &&arg) : arg_(std::move(arg))
35-
{}
3635

37-
std::string FExpr_UINVERT::repr() const
38-
{
39-
std::string out = "uinvert";
40-
out += '(';
41-
out += arg_->repr();
42-
out += ')';
43-
return out;
44-
}
36+
class FExpr_UInvert : public FExpr_FuncUnary {
37+
public:
38+
using FExpr_FuncUnary::FExpr_FuncUnary;
4539

46-
static Column make_isna_col(Column &&col)
47-
{
48-
switch (stype) {
49-
case SType::VOID: return umaker_ptr(new umaker_copy());
50-
case SType::BOOL: return umaker1<int8_t, int8_t>::make(op_invert_bool, SType::AUTO, SType::BOOL);
51-
case SType::INT8: return _uinvert<int8_t>();
52-
case SType::INT16: return _uinvert<int16_t>();
53-
case SType::INT32: return _uinvert<int32_t>();
54-
case SType::INT64: return _uinvert<int64_t>();
55-
default:
56-
throw TypeError() << "Cannot apply unary `operator ~` to a column with "
57-
"stype `" << stype << "`";
58-
}
59-
}
6040

61-
Workframe FExpr_UINVERT::evaluate_n(EvalContext &ctx) const
62-
{
63-
Workframe wf = arg_->evaluate_n(ctx);
41+
std::string name() const override {
42+
return "uinvert";
43+
}
6444

65-
for (size_t i = 0; i < wf.ncols(); ++i)
66-
{
67-
Column coli = make_isna_col(wf.retrieve_column(i));
68-
wf.replace_column(i, std::move(coli));
69-
}
45+
template <typename T>
46+
static inline T op_invert(T x) {
47+
return ~x;
48+
}
7049

71-
return wf;
50+
static inline int8_t op_invert_bool(int8_t x) {
51+
return !x;
7252
}
53+
54+
Column evaluate1(Column&& col) const override{
55+
SType stype = col.stype();
56+
Column col_out;
7357

74-
static py::oobj pyfn_isna(const py::XArgs &args)
75-
{
76-
auto uinvert = args[0].to_oobj();
77-
return PyFExpr::make(new FExpr_ISNA(as_fexpr(uinvert)));
58+
switch (stype) {
59+
case SType::VOID: return Column(new ConstNa_ColumnImpl(
60+
col.nrows(), SType::VOID
61+
));
62+
case SType::BOOL:
63+
col_out = Column(new FuncUnary1_ColumnImpl<int8_t, int8_t>(
64+
std::move(col), op_invert_bool, col.nrows(), SType::BOOL
65+
));
66+
break;
67+
case SType::INT8:
68+
col_out = Column(new FuncUnary1_ColumnImpl<int8_t, int8_t>(
69+
std::move(col), op_invert<int8_t>, col.nrows(), SType::INT8
70+
));
71+
break;
72+
case SType::INT16:
73+
col_out = Column(new FuncUnary1_ColumnImpl<int16_t, int16_t>(
74+
std::move(col), op_invert<int16_t>, col.nrows(), SType::INT16
75+
));
76+
break;
77+
case SType::INT32:
78+
case SType::DATE32:
79+
col_out = Column(new FuncUnary1_ColumnImpl<int32_t, int32_t>(
80+
std::move(col), op_invert<int32_t>, col.nrows(), SType::INT32
81+
));
82+
break;
83+
case SType::INT64:
84+
case SType::TIME64:
85+
col_out = Column(new FuncUnary1_ColumnImpl<int64_t, int64_t>(
86+
std::move(col), op_invert<int64_t>, col.nrows(), SType::INT64
87+
));
88+
break;;
89+
default:
90+
throw TypeError() << "Cannot apply unary `operator ~` to a column with "
91+
"stype `" << stype << "`";
92+
}
93+
if (stype == SType::DATE32 || stype == SType::TIME64) {
94+
col_out.cast_inplace(stype);
95+
}
96+
return col_out;
7897
}
98+
};
7999

80-
DECLARE_PYFN(&pyfn_isna)
81-
->name("uinvert")
82-
->docs(doc_math_isna)
83-
->arg_names({"cols"})
84-
->n_positional_args(1)
85-
->n_required_args(1);
100+
py::oobj PyFExpr::nb__invert__(py::robj lhs) {
101+
return PyFExpr::make(
102+
new FExpr_UInvert(as_fexpr(lhs)));
103+
}
86104

87-
}
88-
} // dt::expr
105+
}} // dt::expr

src/core/expr/funary/umaker.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ umaker_ptr resolve_op(Op opcode, SType stype)
6363
// Basic
6464
case Op::UPLUS: return resolve_op_uplus(stype);
6565
case Op::UMINUS: return resolve_op_uminus(stype);
66-
case Op::UINVERT: return resolve_op_uinvert(stype);
66+
//case Op::UINVERT: return resolve_op_uinvert(stype);
6767

6868
// Math: trigonometric
6969
case Op::SIN: return resolve_op_sin(stype);

src/core/expr/funary/umaker.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ umaker_ptr resolve_op(Op, SType);
8484
// Basic
8585
umaker_ptr resolve_op_uplus(SType);
8686
umaker_ptr resolve_op_uminus(SType);
87-
umaker_ptr resolve_op_uinvert(SType);
87+
//umaker_ptr resolve_op_uinvert(SType);
8888

8989
// Trigonometric
9090
umaker_ptr resolve_op_sin(SType);

src/core/python/xobject.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,17 @@ PyObject* _safe_unary(PyObject* self) noexcept {
519519
}
520520
}
521521

522+
template <py::oobj(*METH)(py::robj), int OP>
523+
PyObject* _safe_uunary(PyObject* self) noexcept {
524+
auto cl = dt::CallLogger::unaryfn(self, OP);
525+
try {
526+
return METH(py::robj(self)).release();
527+
} catch (const std::exception& e) {
528+
exception_to_python(e);
529+
return nullptr;
530+
}
531+
}
532+
522533

523534
template <py::oobj(*METH)(py::robj, py::robj), int OP>
524535
PyObject* _safe_binary(PyObject* self, PyObject* other) noexcept {
@@ -778,7 +789,7 @@ PyObject* _safe_cmp(PyObject* x, PyObject* y, int op) noexcept {
778789

779790

780791
#define METHOD__INVERT__(METH) \
781-
py::_safe_unary<CLASS_OF(METH), METH, dt::CallLogger::Op::__invert__>, \
792+
py::_safe_uunary<METH, dt::CallLogger::Op::__invert__>, \
782793
py::XTypeMaker::nb_invert_tag
783794

784795

0 commit comments

Comments
 (0)