Commit 4a114aaa authored by Kevin Modzelewski's avatar Kevin Modzelewski

Partially-templatize len

The exceptions thrown by len itself can now be either style,
though any exceptions thrown by any called functions (ex __len__)
will still get thrown as C++ exceptions and converted if needed.

Helps in a common case of "try calling len but don't worry if no
len was defined".
parent dfeff147
...@@ -732,12 +732,10 @@ exit: ...@@ -732,12 +732,10 @@ exit:
} }
extern "C" Py_ssize_t PyObject_Size(PyObject* o) noexcept { extern "C" Py_ssize_t PyObject_Size(PyObject* o) noexcept {
try { BoxedInt* r = lenInternal<ExceptionStyle::CAPI>(o, NULL);
return len(o)->n; if (!r)
} catch (ExcInfo e) {
setCAPIException(e);
return -1; return -1;
} return r->n;
} }
extern "C" PyObject* PyObject_GetIter(PyObject* o) noexcept { extern "C" PyObject* PyObject_GetIter(PyObject* o) noexcept {
......
...@@ -2592,13 +2592,20 @@ extern "C" BoxedInt* hash(Box* obj) { ...@@ -2592,13 +2592,20 @@ extern "C" BoxedInt* hash(Box* obj) {
return new BoxedInt(r); return new BoxedInt(r);
} }
extern "C" BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) { template <enum ExceptionStyle S> BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) {
static BoxedString* len_str = internStringImmortal("__len__"); static BoxedString* len_str = internStringImmortal("__len__");
if (S == CAPI) {
assert(!rewrite_args && "implement me");
rewrite_args = NULL;
}
// Corresponds to the first part of PyObject_Size: // Corresponds to the first part of PyObject_Size:
PySequenceMethods* m = obj->cls->tp_as_sequence; PySequenceMethods* m = obj->cls->tp_as_sequence;
if (m != NULL && m->sq_length != NULL && m->sq_length != slot_sq_length) { if (m != NULL && m->sq_length != NULL && m->sq_length != slot_sq_length) {
if (rewrite_args) { if (rewrite_args) {
assert(S == CXX);
RewriterVar* r_obj = rewrite_args->obj; RewriterVar* r_obj = rewrite_args->obj;
RewriterVar* r_cls = r_obj->getAttr(offsetof(Box, cls)); RewriterVar* r_cls = r_obj->getAttr(offsetof(Box, cls));
RewriterVar* r_m = r_cls->getAttr(offsetof(BoxedClass, tp_as_sequence)); RewriterVar* r_m = r_cls->getAttr(offsetof(BoxedClass, tp_as_sequence));
...@@ -2619,29 +2626,50 @@ extern "C" BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) { ...@@ -2619,29 +2626,50 @@ extern "C" BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) {
} }
int r = (*m->sq_length)(obj); int r = (*m->sq_length)(obj);
if (r == -1) if (r == -1) {
throwCAPIException(); if (S == CAPI)
return NULL;
else
throwCAPIException();
}
return (BoxedInt*)boxInt(r); return (BoxedInt*)boxInt(r);
} }
Box* rtn; Box* rtn;
if (rewrite_args) { try {
CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination); if (rewrite_args) {
rtn = callattrInternal0(obj, len_str, CLASS_ONLY, &crewrite_args, ArgPassSpec(0)); CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination);
if (!crewrite_args.out_success) rtn = callattrInternal0(obj, len_str, CLASS_ONLY, &crewrite_args, ArgPassSpec(0));
rewrite_args = NULL; if (!crewrite_args.out_success)
else if (rtn) rewrite_args = NULL;
rewrite_args->out_rtn = crewrite_args.out_rtn; else if (rtn)
} else { rewrite_args->out_rtn = crewrite_args.out_rtn;
rtn = callattrInternal0(obj, len_str, CLASS_ONLY, NULL, ArgPassSpec(0)); } else {
rtn = callattrInternal0(obj, len_str, CLASS_ONLY, NULL, ArgPassSpec(0));
}
} catch (ExcInfo e) {
if (S == CAPI) {
setCAPIException(e);
return NULL;
} else {
throw e;
}
} }
if (rtn == NULL) { if (rtn == NULL) {
raiseExcHelper(TypeError, "object of type '%s' has no len()", getTypeName(obj)); if (S == CAPI) {
PyErr_Format(TypeError, "object of type '%s' has no len()", getTypeName(obj));
return NULL;
} else
raiseExcHelper(TypeError, "object of type '%s' has no len()", getTypeName(obj));
} }
if (rtn->cls != int_cls) { if (rtn->cls != int_cls) {
raiseExcHelper(TypeError, "an integer is required"); if (S == CAPI) {
PyErr_Format(TypeError, "an integer is required");
return NULL;
} else
raiseExcHelper(TypeError, "an integer is required");
} }
if (rewrite_args) if (rewrite_args)
...@@ -2649,6 +2677,10 @@ extern "C" BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) { ...@@ -2649,6 +2677,10 @@ extern "C" BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) {
return static_cast<BoxedInt*>(rtn); return static_cast<BoxedInt*>(rtn);
} }
// force template instantiation:
template BoxedInt* lenInternal<CAPI>(Box*, LenRewriteArgs*);
template BoxedInt* lenInternal<CXX>(Box*, LenRewriteArgs*);
Box* lenCallInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* lenCallInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names) { Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names) {
if (argspec != ArgPassSpec(1)) if (argspec != ArgPassSpec(1))
...@@ -2656,7 +2688,7 @@ Box* lenCallInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, Arg ...@@ -2656,7 +2688,7 @@ Box* lenCallInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, Arg
if (rewrite_args) { if (rewrite_args) {
LenRewriteArgs lrewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination); LenRewriteArgs lrewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination);
Box* rtn = lenInternal(arg1, &lrewrite_args); Box* rtn = lenInternal<CXX>(arg1, &lrewrite_args);
if (!lrewrite_args.out_success) { if (!lrewrite_args.out_success) {
rewrite_args = 0; rewrite_args = 0;
} else { } else {
...@@ -2665,7 +2697,7 @@ Box* lenCallInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, Arg ...@@ -2665,7 +2697,7 @@ Box* lenCallInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, Arg
} }
return rtn; return rtn;
} }
return lenInternal(arg1, NULL); return lenInternal<CXX>(arg1, NULL);
} }
extern "C" BoxedInt* len(Box* obj) { extern "C" BoxedInt* len(Box* obj) {
...@@ -2674,7 +2706,7 @@ extern "C" BoxedInt* len(Box* obj) { ...@@ -2674,7 +2706,7 @@ extern "C" BoxedInt* len(Box* obj) {
static StatCounter slowpath_len("slowpath_len"); static StatCounter slowpath_len("slowpath_len");
slowpath_len.log(); slowpath_len.log();
return lenInternal(obj, NULL); return lenInternal<CXX>(obj, NULL);
} }
extern "C" i64 unboxedLen(Box* obj) { extern "C" i64 unboxedLen(Box* obj) {
...@@ -2691,14 +2723,14 @@ extern "C" i64 unboxedLen(Box* obj) { ...@@ -2691,14 +2723,14 @@ extern "C" i64 unboxedLen(Box* obj) {
if (rewriter.get()) { if (rewriter.get()) {
// rewriter->trap(); // rewriter->trap();
LenRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination()); LenRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination());
lobj = lenInternal(obj, &rewrite_args); lobj = lenInternal<CXX>(obj, &rewrite_args);
if (!rewrite_args.out_success) { if (!rewrite_args.out_success) {
rewriter.reset(NULL); rewriter.reset(NULL);
} else } else
r_boxed = rewrite_args.out_rtn; r_boxed = rewrite_args.out_rtn;
} else { } else {
lobj = lenInternal(obj, NULL); lobj = lenInternal<CXX>(obj, NULL);
} }
assert(lobj->cls == int_cls); assert(lobj->cls == int_cls);
......
...@@ -114,6 +114,8 @@ struct CallRewriteArgs; ...@@ -114,6 +114,8 @@ struct CallRewriteArgs;
Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
Box** args, const std::vector<BoxedString*>* keyword_names); Box** args, const std::vector<BoxedString*>* keyword_names);
struct LenRewriteArgs;
template <ExceptionStyle::ExceptionStyle S> BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args);
Box* lenCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* lenCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names); Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment