From 1943680fd5766c25f9c81f50980e63c5c4a9589e Mon Sep 17 00:00:00 2001 From: Christian Klein <167265+cklein@users.noreply.github.com> Date: Thu, 8 Apr 2021 22:29:55 +0200 Subject: [PATCH 1/4] Added StringBuilder --- hpy/debug/src/autogen_debug_ctx_init.h | 8 +++ hpy/debug/src/autogen_debug_wrappers.c | 20 ++++++ .../common/runtime/ctx_stringbuilder.h | 16 +++++ hpy/devel/include/cpython/hpy.h | 27 ++++++++ hpy/devel/include/universal/autogen_ctx.h | 4 ++ .../include/universal/autogen_trampolines.h | 16 +++++ hpy/devel/include/universal/hpy.h | 1 + hpy/devel/src/runtime/ctx_stringbuilder.c | 63 +++++++++++++++++++ hpy/tools/autogen/parse.py | 4 ++ hpy/tools/autogen/public_api.h | 7 +++ hpy/universal/src/autogen_ctx_def.h | 4 ++ hpy/universal/src/ctx.c | 1 + setup.py | 1 + test/test_hpystringbuilder.py | 23 +++++++ 14 files changed, 195 insertions(+) create mode 100644 hpy/devel/include/common/runtime/ctx_stringbuilder.h create mode 100644 hpy/devel/src/runtime/ctx_stringbuilder.c create mode 100644 test/test_hpystringbuilder.py diff --git a/hpy/debug/src/autogen_debug_ctx_init.h b/hpy/debug/src/autogen_debug_ctx_init.h index 79768a67e..baa2afb30 100644 --- a/hpy/debug/src/autogen_debug_ctx_init.h +++ b/hpy/debug/src/autogen_debug_ctx_init.h @@ -131,6 +131,10 @@ HPyListBuilder debug_ctx_ListBuilder_New(HPyContext *dctx, HPy_ssize_t initial_s void debug_ctx_ListBuilder_Set(HPyContext *dctx, HPyListBuilder builder, HPy_ssize_t index, DHPy h_item); DHPy debug_ctx_ListBuilder_Build(HPyContext *dctx, HPyListBuilder builder); void debug_ctx_ListBuilder_Cancel(HPyContext *dctx, HPyListBuilder builder); +HPyStringBuilder debug_ctx_StringBuilder_New(HPyContext *dctx); +void debug_ctx_StringBuilder_Append(HPyContext *dctx, HPyStringBuilder builder, DHPy h_item); +DHPy debug_ctx_StringBuilder_Build(HPyContext *dctx, HPyStringBuilder builder); +void debug_ctx_StringBuilder_Cancel(HPyContext *dctx, HPyStringBuilder builder); HPyTupleBuilder debug_ctx_TupleBuilder_New(HPyContext *dctx, HPy_ssize_t initial_size); void debug_ctx_TupleBuilder_Set(HPyContext *dctx, HPyTupleBuilder builder, HPy_ssize_t index, DHPy h_item); DHPy debug_ctx_TupleBuilder_Build(HPyContext *dctx, HPyTupleBuilder builder); @@ -339,6 +343,10 @@ static inline void debug_ctx_init_fields(HPyContext *dctx, HPyContext *uctx) dctx->ctx_ListBuilder_Set = &debug_ctx_ListBuilder_Set; dctx->ctx_ListBuilder_Build = &debug_ctx_ListBuilder_Build; dctx->ctx_ListBuilder_Cancel = &debug_ctx_ListBuilder_Cancel; + dctx->ctx_StringBuilder_New = &debug_ctx_StringBuilder_New; + dctx->ctx_StringBuilder_Append = &debug_ctx_StringBuilder_Append; + dctx->ctx_StringBuilder_Build = &debug_ctx_StringBuilder_Build; + dctx->ctx_StringBuilder_Cancel = &debug_ctx_StringBuilder_Cancel; dctx->ctx_TupleBuilder_New = &debug_ctx_TupleBuilder_New; dctx->ctx_TupleBuilder_Set = &debug_ctx_TupleBuilder_Set; dctx->ctx_TupleBuilder_Build = &debug_ctx_TupleBuilder_Build; diff --git a/hpy/debug/src/autogen_debug_wrappers.c b/hpy/debug/src/autogen_debug_wrappers.c index 55a42d3d7..461d2027c 100644 --- a/hpy/debug/src/autogen_debug_wrappers.c +++ b/hpy/debug/src/autogen_debug_wrappers.c @@ -592,6 +592,26 @@ void debug_ctx_ListBuilder_Cancel(HPyContext *dctx, HPyListBuilder builder) HPyListBuilder_Cancel(get_info(dctx)->uctx, builder); } +HPyStringBuilder debug_ctx_StringBuilder_New(HPyContext *dctx) +{ + return HPyStringBuilder_New(get_info(dctx)->uctx); +} + +void debug_ctx_StringBuilder_Append(HPyContext *dctx, HPyStringBuilder builder, DHPy h_item) +{ + HPyStringBuilder_Append(get_info(dctx)->uctx, builder, DHPy_unwrap(dctx, h_item)); +} + +DHPy debug_ctx_StringBuilder_Build(HPyContext *dctx, HPyStringBuilder builder) +{ + return DHPy_wrap(dctx, HPyStringBuilder_Build(get_info(dctx)->uctx, builder)); +} + +void debug_ctx_StringBuilder_Cancel(HPyContext *dctx, HPyStringBuilder builder) +{ + HPyStringBuilder_Cancel(get_info(dctx)->uctx, builder); +} + HPyTupleBuilder debug_ctx_TupleBuilder_New(HPyContext *dctx, HPy_ssize_t initial_size) { return HPyTupleBuilder_New(get_info(dctx)->uctx, initial_size); diff --git a/hpy/devel/include/common/runtime/ctx_stringbuilder.h b/hpy/devel/include/common/runtime/ctx_stringbuilder.h new file mode 100644 index 000000000..8467f37b1 --- /dev/null +++ b/hpy/devel/include/common/runtime/ctx_stringbuilder.h @@ -0,0 +1,16 @@ +#ifndef HPY_COMMON_RUNTIME_STRINGBUILDER_H +#define HPY_COMMON_RUNTIME_STRINGBUILDER_H + +#include +#include "hpy.h" +#include "common/hpytype.h" + + +_HPy_HIDDEN HPyStringBuilder ctx_StringBuilder_New(HPyContext *ctx); +_HPy_HIDDEN void ctx_StringBuilder_Append(HPyContext *ctx, HPyStringBuilder builder, + HPy h_item); +_HPy_HIDDEN HPy ctx_StringBuilder_Build(HPyContext *ctx, HPyStringBuilder builder); +_HPy_HIDDEN void ctx_StringBuilder_Cancel(HPyContext *ctx, HPyStringBuilder builder); + + +#endif /* HPY_COMMON_RUNTIME_STRINGBUILDER_H */ diff --git a/hpy/devel/include/cpython/hpy.h b/hpy/devel/include/cpython/hpy.h index da30575ca..46e284232 100644 --- a/hpy/devel/include/cpython/hpy.h +++ b/hpy/devel/include/cpython/hpy.h @@ -31,6 +31,7 @@ typedef struct { PyObject *_o; } HPy; typedef struct { Py_ssize_t _lst; } HPyListBuilder; +typedef struct { Py_ssize_t _lst; } HPyStringBuilder; typedef struct { Py_ssize_t _tup; } HPyTupleBuilder; typedef struct { void *_o; } HPyTracker; typedef Py_ssize_t HPy_ssize_t; @@ -280,6 +281,7 @@ HPy_AsPyObject(HPyContext *ctx, HPy h) #include "../common/runtime/ctx_object.h" #include "../common/runtime/ctx_type.h" #include "../common/runtime/ctx_listbuilder.h" +#include "../common/runtime/ctx_stringbuilder.h" #include "../common/runtime/ctx_tracker.h" #include "../common/runtime/ctx_tuple.h" #include "../common/runtime/ctx_tuplebuilder.h" @@ -378,6 +380,31 @@ HPyListBuilder_Cancel(HPyContext *ctx, HPyListBuilder builder) ctx_ListBuilder_Cancel(ctx, builder); } +HPyAPI_FUNC(HPyStringBuilder) +HPyStringBuilder_New(HPyContext *ctx) +{ + return ctx_StringBuilder_New(ctx); +} + +HPyAPI_FUNC(void) +HPyStringBuilder_Append(HPyContext *ctx, HPyStringBuilder builder, + HPy h_item) +{ + ctx_StringBuilder_Append(ctx, builder, h_item); +} + +HPyAPI_FUNC(HPy) +HPyStringBuilder_Build(HPyContext *ctx, HPyStringBuilder builder) +{ + return ctx_StringBuilder_Build(ctx, builder); +} + +HPyAPI_FUNC(void) +HPyStringBuilder_Cancel(HPyContext *ctx, HPyStringBuilder builder) +{ + ctx_StringBuilder_Cancel(ctx, builder); +} + HPyAPI_FUNC(HPyTupleBuilder) HPyTupleBuilder_New(HPyContext *ctx, HPy_ssize_t initial_size) { diff --git a/hpy/devel/include/universal/autogen_ctx.h b/hpy/devel/include/universal/autogen_ctx.h index 8863cee20..a9ce30500 100644 --- a/hpy/devel/include/universal/autogen_ctx.h +++ b/hpy/devel/include/universal/autogen_ctx.h @@ -210,6 +210,10 @@ struct _HPyContext_s { void (*ctx_ListBuilder_Set)(HPyContext *ctx, HPyListBuilder builder, HPy_ssize_t index, HPy h_item); HPy (*ctx_ListBuilder_Build)(HPyContext *ctx, HPyListBuilder builder); void (*ctx_ListBuilder_Cancel)(HPyContext *ctx, HPyListBuilder builder); + HPyStringBuilder (*ctx_StringBuilder_New)(HPyContext *ctx); + void (*ctx_StringBuilder_Append)(HPyContext *ctx, HPyStringBuilder builder, HPy h_item); + HPy (*ctx_StringBuilder_Build)(HPyContext *ctx, HPyStringBuilder builder); + void (*ctx_StringBuilder_Cancel)(HPyContext *ctx, HPyStringBuilder builder); HPyTupleBuilder (*ctx_TupleBuilder_New)(HPyContext *ctx, HPy_ssize_t initial_size); void (*ctx_TupleBuilder_Set)(HPyContext *ctx, HPyTupleBuilder builder, HPy_ssize_t index, HPy h_item); HPy (*ctx_TupleBuilder_Build)(HPyContext *ctx, HPyTupleBuilder builder); diff --git a/hpy/devel/include/universal/autogen_trampolines.h b/hpy/devel/include/universal/autogen_trampolines.h index 00203a27c..1dfaf489f 100644 --- a/hpy/devel/include/universal/autogen_trampolines.h +++ b/hpy/devel/include/universal/autogen_trampolines.h @@ -486,6 +486,22 @@ static inline void HPyListBuilder_Cancel(HPyContext *ctx, HPyListBuilder builder ctx->ctx_ListBuilder_Cancel ( ctx, builder ); } +static inline HPyStringBuilder HPyStringBuilder_New(HPyContext *ctx) { + return ctx->ctx_StringBuilder_New ( ctx ); +} + +static inline void HPyStringBuilder_Append(HPyContext *ctx, HPyStringBuilder builder, HPy h_item) { + ctx->ctx_StringBuilder_Append ( ctx, builder, h_item ); +} + +static inline HPy HPyStringBuilder_Build(HPyContext *ctx, HPyStringBuilder builder) { + return ctx->ctx_StringBuilder_Build ( ctx, builder ); +} + +static inline void HPyStringBuilder_Cancel(HPyContext *ctx, HPyStringBuilder builder) { + ctx->ctx_StringBuilder_Cancel ( ctx, builder ); +} + static inline HPyTupleBuilder HPyTupleBuilder_New(HPyContext *ctx, HPy_ssize_t initial_size) { return ctx->ctx_TupleBuilder_New ( ctx, initial_size ); } diff --git a/hpy/devel/include/universal/hpy.h b/hpy/devel/include/universal/hpy.h index b401dc240..f0c691f25 100644 --- a/hpy/devel/include/universal/hpy.h +++ b/hpy/devel/include/universal/hpy.h @@ -34,6 +34,7 @@ typedef intptr_t HPy_hash_t; the HPy structure contains an index in a global array. */ typedef struct _HPy_s { HPy_ssize_t _i; } HPy; typedef struct { HPy_ssize_t _lst; } HPyListBuilder; +typedef struct { HPy_ssize_t _lst; } HPyStringBuilder; typedef struct { HPy_ssize_t _tup; } HPyTupleBuilder; typedef struct { HPy_ssize_t _i; } HPyTracker; diff --git a/hpy/devel/src/runtime/ctx_stringbuilder.c b/hpy/devel/src/runtime/ctx_stringbuilder.c new file mode 100644 index 000000000..018f3c8c1 --- /dev/null +++ b/hpy/devel/src/runtime/ctx_stringbuilder.c @@ -0,0 +1,63 @@ +#include +#include +#include "hpy.h" + +#ifdef HPY_UNIVERSAL_ABI + // for _h2py and _py2h +# include "handles.h" +#endif + +#include + +_HPy_HIDDEN HPyStringBuilder +ctx_StringBuilder_New(HPyContext *ctx) +{ + PyObject *lst = PyList_New(0); + if (lst == NULL) + PyErr_Clear(); /* delay the MemoryError */ + return (HPyStringBuilder){(HPy_ssize_t)lst }; +} + +_HPy_HIDDEN void +ctx_StringBuilder_Append(HPyContext *ctx, HPyStringBuilder builder, HPy h_item) +{ + PyObject *lst = (PyObject *)builder._lst; + if (lst != NULL) { + PyObject *item = _h2py(h_item); + PyList_Append(lst, item); + } +} + +_HPy_HIDDEN HPy +ctx_StringBuilder_Build(HPyContext *ctx, HPyStringBuilder builder) +{ + PyObject *lst = (PyObject *)builder._lst; + if (lst == NULL) { + PyErr_NoMemory(); + return HPy_NULL; + } + builder._lst = 0; + PyObject *sep = PyUnicode_FromString(""); + PyObject *str = PyUnicode_Join(sep, lst); + Py_XDECREF(sep); + if(str == NULL) { + PyErr_NoMemory(); + return HPy_NULL; + } + Py_XDECREF(lst); + return _py2h(str); +} + +_HPy_HIDDEN void +ctx_StringBuilder_Cancel(HPyContext *ctx, HPyStringBuilder builder) +{ + PyObject *lst = (PyObject *)builder._lst; + if (lst == NULL) { + // we don't report the memory error here: the builder + // is being cancelled (so the result of the builder is not being used) + // and likely it's being cancelled during the handling of another error + return; + } + builder._lst = 0; + Py_XDECREF(lst); +} diff --git a/hpy/tools/autogen/parse.py b/hpy/tools/autogen/parse.py index 149ddf82f..980dbb6b1 100644 --- a/hpy/tools/autogen/parse.py +++ b/hpy/tools/autogen/parse.py @@ -210,6 +210,10 @@ def _visit_hpyslot_slot(self, node): 'HPyListBuilder_Set': None, 'HPyListBuilder_Build': None, 'HPyListBuilder_Cancel': None, + 'HPyStringBuilder_New': None, + 'HPyStringBuilder_Append': None, + 'HPyStringBuilder_Build': None, + 'HPyStringBuilder_Cancel': None, 'HPyTuple_FromArray': None, 'HPyTupleBuilder_New': None, 'HPyTupleBuilder_Set': None, diff --git a/hpy/tools/autogen/public_api.h b/hpy/tools/autogen/public_api.h index 34c0a1c67..4095ae35a 100644 --- a/hpy/tools/autogen/public_api.h +++ b/hpy/tools/autogen/public_api.h @@ -12,6 +12,7 @@ typedef int size_t; typedef int HPyFunc_Signature; typedef int cpy_PyObject; typedef int HPyListBuilder; +typedef int HPyStringBuilder; typedef int HPyTupleBuilder; typedef int HPyTracker; typedef int HPy_RichCmpOp; @@ -282,6 +283,12 @@ void HPyListBuilder_Set(HPyContext *ctx, HPyListBuilder builder, HPy HPyListBuilder_Build(HPyContext *ctx, HPyListBuilder builder); void HPyListBuilder_Cancel(HPyContext *ctx, HPyListBuilder builder); +HPyStringBuilder HPyStringBuilder_New(HPyContext *ctx); +void HPyStringBuilder_Append(HPyContext *ctx, HPyStringBuilder builder, + HPy h_item); +HPy HPyStringBuilder_Build(HPyContext *ctx, HPyStringBuilder builder); +void HPyStringBuilder_Cancel(HPyContext *ctx, HPyStringBuilder builder); + HPyTupleBuilder HPyTupleBuilder_New(HPyContext *ctx, HPy_ssize_t initial_size); void HPyTupleBuilder_Set(HPyContext *ctx, HPyTupleBuilder builder, HPy_ssize_t index, HPy h_item); diff --git a/hpy/universal/src/autogen_ctx_def.h b/hpy/universal/src/autogen_ctx_def.h index 614be60c3..7caf1e3c8 100644 --- a/hpy/universal/src/autogen_ctx_def.h +++ b/hpy/universal/src/autogen_ctx_def.h @@ -136,6 +136,10 @@ struct _HPyContext_s g_universal_ctx = { .ctx_ListBuilder_Set = &ctx_ListBuilder_Set, .ctx_ListBuilder_Build = &ctx_ListBuilder_Build, .ctx_ListBuilder_Cancel = &ctx_ListBuilder_Cancel, + .ctx_StringBuilder_New = &ctx_StringBuilder_New, + .ctx_StringBuilder_Append = &ctx_StringBuilder_Append, + .ctx_StringBuilder_Build = &ctx_StringBuilder_Build, + .ctx_StringBuilder_Cancel = &ctx_StringBuilder_Cancel, .ctx_TupleBuilder_New = &ctx_TupleBuilder_New, .ctx_TupleBuilder_Set = &ctx_TupleBuilder_Set, .ctx_TupleBuilder_Build = &ctx_TupleBuilder_Build, diff --git a/hpy/universal/src/ctx.c b/hpy/universal/src/ctx.c index 7cd371a47..1281e6d06 100644 --- a/hpy/universal/src/ctx.c +++ b/hpy/universal/src/ctx.c @@ -6,6 +6,7 @@ #include "common/runtime/ctx_module.h" #include "common/runtime/ctx_object.h" #include "common/runtime/ctx_listbuilder.h" +#include "common/runtime/ctx_stringbuilder.h" #include "common/runtime/ctx_tracker.h" #include "common/runtime/ctx_tuple.h" #include "common/runtime/ctx_tuplebuilder.h" diff --git a/setup.py b/setup.py index 991cee993..39694a42f 100644 --- a/setup.py +++ b/setup.py @@ -59,6 +59,7 @@ def get_scm_config(): 'hpy/devel/src/runtime/ctx_type.c', 'hpy/devel/src/runtime/ctx_tracker.c', 'hpy/devel/src/runtime/ctx_listbuilder.c', + 'hpy/devel/src/runtime/ctx_stringbuilder.c', 'hpy/devel/src/runtime/ctx_tuple.c', 'hpy/devel/src/runtime/ctx_tuplebuilder.c', 'hpy/debug/src/debug_ctx.c', diff --git a/test/test_hpystringbuilder.py b/test/test_hpystringbuilder.py new file mode 100644 index 000000000..39150ba20 --- /dev/null +++ b/test/test_hpystringbuilder.py @@ -0,0 +1,23 @@ +from .support import HPyTest + +class TestString(HPyTest): + def test_StringBuilder(self, hpy_abi): + mod = self.make_module(""" + HPyDef_METH(f, "f", f_impl, HPyFunc_O) + static HPy f_impl(HPyContext *ctx, HPy h_self, HPy h_arg) + { + HPyStringBuilder builder = HPyStringBuilder_New(ctx); + HPy h_s1 = HPyUnicode_FromString(ctx, "hello "); + HPy h_s2 = HPyUnicode_FromString(ctx, "!"); + HPyStringBuilder_Append(ctx, builder, h_s1); + HPyStringBuilder_Append(ctx, builder, h_arg); + HPyStringBuilder_Append(ctx, builder, h_s2); + HPy h_string = HPyStringBuilder_Build(ctx, builder); + HPy_Close(ctx, h_s1); + HPy_Close(ctx, h_s2); + return h_string; + } + @EXPORT(f) + @INIT + """) + assert mod.f("world") == "hello world!" From de2e78a79ac03789ef07582361ed069f0976e62e Mon Sep 17 00:00:00 2001 From: Christian Klein Date: Sun, 11 Apr 2021 12:52:16 +0200 Subject: [PATCH 2/4] Renamed StringBuilder to UnicodeBuilder --- hpy/debug/src/autogen_debug_ctx_init.h | 16 +++++++------- hpy/debug/src/autogen_debug_wrappers.c | 16 +++++++------- .../common/runtime/ctx_stringbuilder.h | 16 -------------- .../common/runtime/ctx_unicodebuilder.h | 16 ++++++++++++++ hpy/devel/include/cpython/hpy.h | 22 +++++++++---------- hpy/devel/include/universal/autogen_ctx.h | 8 +++---- .../include/universal/autogen_trampolines.h | 16 +++++++------- hpy/devel/include/universal/hpy.h | 2 +- ...x_stringbuilder.c => ctx_unicodebuilder.c} | 12 +++++----- hpy/tools/autogen/parse.py | 8 +++---- hpy/tools/autogen/public_api.h | 10 ++++----- hpy/universal/src/autogen_ctx_def.h | 8 +++---- hpy/universal/src/ctx.c | 2 +- setup.py | 2 +- test/test_hpystringbuilder.py | 12 +++++----- 15 files changed, 83 insertions(+), 83 deletions(-) delete mode 100644 hpy/devel/include/common/runtime/ctx_stringbuilder.h create mode 100644 hpy/devel/include/common/runtime/ctx_unicodebuilder.h rename hpy/devel/src/runtime/{ctx_stringbuilder.c => ctx_unicodebuilder.c} (78%) diff --git a/hpy/debug/src/autogen_debug_ctx_init.h b/hpy/debug/src/autogen_debug_ctx_init.h index baa2afb30..cbb856012 100644 --- a/hpy/debug/src/autogen_debug_ctx_init.h +++ b/hpy/debug/src/autogen_debug_ctx_init.h @@ -131,10 +131,10 @@ HPyListBuilder debug_ctx_ListBuilder_New(HPyContext *dctx, HPy_ssize_t initial_s void debug_ctx_ListBuilder_Set(HPyContext *dctx, HPyListBuilder builder, HPy_ssize_t index, DHPy h_item); DHPy debug_ctx_ListBuilder_Build(HPyContext *dctx, HPyListBuilder builder); void debug_ctx_ListBuilder_Cancel(HPyContext *dctx, HPyListBuilder builder); -HPyStringBuilder debug_ctx_StringBuilder_New(HPyContext *dctx); -void debug_ctx_StringBuilder_Append(HPyContext *dctx, HPyStringBuilder builder, DHPy h_item); -DHPy debug_ctx_StringBuilder_Build(HPyContext *dctx, HPyStringBuilder builder); -void debug_ctx_StringBuilder_Cancel(HPyContext *dctx, HPyStringBuilder builder); +HPyUnicodeBuilder debug_ctx_UnicodeBuilder_New(HPyContext *dctx); +void debug_ctx_UnicodeBuilder_Append(HPyContext *dctx, HPyUnicodeBuilder builder, DHPy h_item); +DHPy debug_ctx_UnicodeBuilder_Build(HPyContext *dctx, HPyUnicodeBuilder builder); +void debug_ctx_UnicodeBuilder_Cancel(HPyContext *dctx, HPyUnicodeBuilder builder); HPyTupleBuilder debug_ctx_TupleBuilder_New(HPyContext *dctx, HPy_ssize_t initial_size); void debug_ctx_TupleBuilder_Set(HPyContext *dctx, HPyTupleBuilder builder, HPy_ssize_t index, DHPy h_item); DHPy debug_ctx_TupleBuilder_Build(HPyContext *dctx, HPyTupleBuilder builder); @@ -343,10 +343,10 @@ static inline void debug_ctx_init_fields(HPyContext *dctx, HPyContext *uctx) dctx->ctx_ListBuilder_Set = &debug_ctx_ListBuilder_Set; dctx->ctx_ListBuilder_Build = &debug_ctx_ListBuilder_Build; dctx->ctx_ListBuilder_Cancel = &debug_ctx_ListBuilder_Cancel; - dctx->ctx_StringBuilder_New = &debug_ctx_StringBuilder_New; - dctx->ctx_StringBuilder_Append = &debug_ctx_StringBuilder_Append; - dctx->ctx_StringBuilder_Build = &debug_ctx_StringBuilder_Build; - dctx->ctx_StringBuilder_Cancel = &debug_ctx_StringBuilder_Cancel; + dctx->ctx_UnicodeBuilder_New = &debug_ctx_UnicodeBuilder_New; + dctx->ctx_UnicodeBuilder_Append = &debug_ctx_UnicodeBuilder_Append; + dctx->ctx_UnicodeBuilder_Build = &debug_ctx_UnicodeBuilder_Build; + dctx->ctx_UnicodeBuilder_Cancel = &debug_ctx_UnicodeBuilder_Cancel; dctx->ctx_TupleBuilder_New = &debug_ctx_TupleBuilder_New; dctx->ctx_TupleBuilder_Set = &debug_ctx_TupleBuilder_Set; dctx->ctx_TupleBuilder_Build = &debug_ctx_TupleBuilder_Build; diff --git a/hpy/debug/src/autogen_debug_wrappers.c b/hpy/debug/src/autogen_debug_wrappers.c index 461d2027c..98721a93b 100644 --- a/hpy/debug/src/autogen_debug_wrappers.c +++ b/hpy/debug/src/autogen_debug_wrappers.c @@ -592,24 +592,24 @@ void debug_ctx_ListBuilder_Cancel(HPyContext *dctx, HPyListBuilder builder) HPyListBuilder_Cancel(get_info(dctx)->uctx, builder); } -HPyStringBuilder debug_ctx_StringBuilder_New(HPyContext *dctx) +HPyUnicodeBuilder debug_ctx_UnicodeBuilder_New(HPyContext *dctx) { - return HPyStringBuilder_New(get_info(dctx)->uctx); + return HPyUnicodeBuilder_New(get_info(dctx)->uctx); } -void debug_ctx_StringBuilder_Append(HPyContext *dctx, HPyStringBuilder builder, DHPy h_item) +void debug_ctx_UnicodeBuilder_Append(HPyContext *dctx, HPyUnicodeBuilder builder, DHPy h_item) { - HPyStringBuilder_Append(get_info(dctx)->uctx, builder, DHPy_unwrap(dctx, h_item)); + HPyUnicodeBuilder_Append(get_info(dctx)->uctx, builder, DHPy_unwrap(dctx, h_item)); } -DHPy debug_ctx_StringBuilder_Build(HPyContext *dctx, HPyStringBuilder builder) +DHPy debug_ctx_UnicodeBuilder_Build(HPyContext *dctx, HPyUnicodeBuilder builder) { - return DHPy_wrap(dctx, HPyStringBuilder_Build(get_info(dctx)->uctx, builder)); + return DHPy_wrap(dctx, HPyUnicodeBuilder_Build(get_info(dctx)->uctx, builder)); } -void debug_ctx_StringBuilder_Cancel(HPyContext *dctx, HPyStringBuilder builder) +void debug_ctx_UnicodeBuilder_Cancel(HPyContext *dctx, HPyUnicodeBuilder builder) { - HPyStringBuilder_Cancel(get_info(dctx)->uctx, builder); + HPyUnicodeBuilder_Cancel(get_info(dctx)->uctx, builder); } HPyTupleBuilder debug_ctx_TupleBuilder_New(HPyContext *dctx, HPy_ssize_t initial_size) diff --git a/hpy/devel/include/common/runtime/ctx_stringbuilder.h b/hpy/devel/include/common/runtime/ctx_stringbuilder.h deleted file mode 100644 index 8467f37b1..000000000 --- a/hpy/devel/include/common/runtime/ctx_stringbuilder.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef HPY_COMMON_RUNTIME_STRINGBUILDER_H -#define HPY_COMMON_RUNTIME_STRINGBUILDER_H - -#include -#include "hpy.h" -#include "common/hpytype.h" - - -_HPy_HIDDEN HPyStringBuilder ctx_StringBuilder_New(HPyContext *ctx); -_HPy_HIDDEN void ctx_StringBuilder_Append(HPyContext *ctx, HPyStringBuilder builder, - HPy h_item); -_HPy_HIDDEN HPy ctx_StringBuilder_Build(HPyContext *ctx, HPyStringBuilder builder); -_HPy_HIDDEN void ctx_StringBuilder_Cancel(HPyContext *ctx, HPyStringBuilder builder); - - -#endif /* HPY_COMMON_RUNTIME_STRINGBUILDER_H */ diff --git a/hpy/devel/include/common/runtime/ctx_unicodebuilder.h b/hpy/devel/include/common/runtime/ctx_unicodebuilder.h new file mode 100644 index 000000000..5d00783b2 --- /dev/null +++ b/hpy/devel/include/common/runtime/ctx_unicodebuilder.h @@ -0,0 +1,16 @@ +#ifndef HPY_COMMON_RUNTIME_UNICODEBUILDER_H +#define HPY_COMMON_RUNTIME_UNICODEBUILDER_H + +#include +#include "hpy.h" +#include "common/hpytype.h" + + +_HPy_HIDDEN HPyUnicodeBuilder ctx_UnicodeBuilder_New(HPyContext *ctx); +_HPy_HIDDEN void ctx_UnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, + HPy h_item); +_HPy_HIDDEN HPy ctx_UnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder); +_HPy_HIDDEN void ctx_UnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder); + + +#endif /* HPY_COMMON_RUNTIME_UNICODEBUILDER_H */ diff --git a/hpy/devel/include/cpython/hpy.h b/hpy/devel/include/cpython/hpy.h index 46e284232..a6b76e862 100644 --- a/hpy/devel/include/cpython/hpy.h +++ b/hpy/devel/include/cpython/hpy.h @@ -31,7 +31,7 @@ typedef struct { PyObject *_o; } HPy; typedef struct { Py_ssize_t _lst; } HPyListBuilder; -typedef struct { Py_ssize_t _lst; } HPyStringBuilder; +typedef struct { Py_ssize_t _lst; } HPyUnicodeBuilder; typedef struct { Py_ssize_t _tup; } HPyTupleBuilder; typedef struct { void *_o; } HPyTracker; typedef Py_ssize_t HPy_ssize_t; @@ -281,7 +281,7 @@ HPy_AsPyObject(HPyContext *ctx, HPy h) #include "../common/runtime/ctx_object.h" #include "../common/runtime/ctx_type.h" #include "../common/runtime/ctx_listbuilder.h" -#include "../common/runtime/ctx_stringbuilder.h" +#include "../common/runtime/ctx_unicodebuilder.h" #include "../common/runtime/ctx_tracker.h" #include "../common/runtime/ctx_tuple.h" #include "../common/runtime/ctx_tuplebuilder.h" @@ -380,29 +380,29 @@ HPyListBuilder_Cancel(HPyContext *ctx, HPyListBuilder builder) ctx_ListBuilder_Cancel(ctx, builder); } -HPyAPI_FUNC(HPyStringBuilder) -HPyStringBuilder_New(HPyContext *ctx) +HPyAPI_FUNC(HPyUnicodeBuilder) +HPyUnicodeBuilder_New(HPyContext *ctx) { - return ctx_StringBuilder_New(ctx); + return ctx_UnicodeBuilder_New(ctx); } HPyAPI_FUNC(void) -HPyStringBuilder_Append(HPyContext *ctx, HPyStringBuilder builder, +HPyUnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) { - ctx_StringBuilder_Append(ctx, builder, h_item); + ctx_UnicodeBuilder_Append(ctx, builder, h_item); } HPyAPI_FUNC(HPy) -HPyStringBuilder_Build(HPyContext *ctx, HPyStringBuilder builder) +HPyUnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder) { - return ctx_StringBuilder_Build(ctx, builder); + return ctx_UnicodeBuilder_Build(ctx, builder); } HPyAPI_FUNC(void) -HPyStringBuilder_Cancel(HPyContext *ctx, HPyStringBuilder builder) +HPyUnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder) { - ctx_StringBuilder_Cancel(ctx, builder); + ctx_UnicodeBuilder_Cancel(ctx, builder); } HPyAPI_FUNC(HPyTupleBuilder) diff --git a/hpy/devel/include/universal/autogen_ctx.h b/hpy/devel/include/universal/autogen_ctx.h index a9ce30500..b3f8c5d5e 100644 --- a/hpy/devel/include/universal/autogen_ctx.h +++ b/hpy/devel/include/universal/autogen_ctx.h @@ -210,10 +210,10 @@ struct _HPyContext_s { void (*ctx_ListBuilder_Set)(HPyContext *ctx, HPyListBuilder builder, HPy_ssize_t index, HPy h_item); HPy (*ctx_ListBuilder_Build)(HPyContext *ctx, HPyListBuilder builder); void (*ctx_ListBuilder_Cancel)(HPyContext *ctx, HPyListBuilder builder); - HPyStringBuilder (*ctx_StringBuilder_New)(HPyContext *ctx); - void (*ctx_StringBuilder_Append)(HPyContext *ctx, HPyStringBuilder builder, HPy h_item); - HPy (*ctx_StringBuilder_Build)(HPyContext *ctx, HPyStringBuilder builder); - void (*ctx_StringBuilder_Cancel)(HPyContext *ctx, HPyStringBuilder builder); + HPyUnicodeBuilder (*ctx_UnicodeBuilder_New)(HPyContext *ctx); + void (*ctx_UnicodeBuilder_Append)(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item); + HPy (*ctx_UnicodeBuilder_Build)(HPyContext *ctx, HPyUnicodeBuilder builder); + void (*ctx_UnicodeBuilder_Cancel)(HPyContext *ctx, HPyUnicodeBuilder builder); HPyTupleBuilder (*ctx_TupleBuilder_New)(HPyContext *ctx, HPy_ssize_t initial_size); void (*ctx_TupleBuilder_Set)(HPyContext *ctx, HPyTupleBuilder builder, HPy_ssize_t index, HPy h_item); HPy (*ctx_TupleBuilder_Build)(HPyContext *ctx, HPyTupleBuilder builder); diff --git a/hpy/devel/include/universal/autogen_trampolines.h b/hpy/devel/include/universal/autogen_trampolines.h index 1dfaf489f..ec29dc766 100644 --- a/hpy/devel/include/universal/autogen_trampolines.h +++ b/hpy/devel/include/universal/autogen_trampolines.h @@ -486,20 +486,20 @@ static inline void HPyListBuilder_Cancel(HPyContext *ctx, HPyListBuilder builder ctx->ctx_ListBuilder_Cancel ( ctx, builder ); } -static inline HPyStringBuilder HPyStringBuilder_New(HPyContext *ctx) { - return ctx->ctx_StringBuilder_New ( ctx ); +static inline HPyUnicodeBuilder HPyUnicodeBuilder_New(HPyContext *ctx) { + return ctx->ctx_UnicodeBuilder_New ( ctx ); } -static inline void HPyStringBuilder_Append(HPyContext *ctx, HPyStringBuilder builder, HPy h_item) { - ctx->ctx_StringBuilder_Append ( ctx, builder, h_item ); +static inline void HPyUnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) { + ctx->ctx_UnicodeBuilder_Append ( ctx, builder, h_item ); } -static inline HPy HPyStringBuilder_Build(HPyContext *ctx, HPyStringBuilder builder) { - return ctx->ctx_StringBuilder_Build ( ctx, builder ); +static inline HPy HPyUnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder) { + return ctx->ctx_UnicodeBuilder_Build ( ctx, builder ); } -static inline void HPyStringBuilder_Cancel(HPyContext *ctx, HPyStringBuilder builder) { - ctx->ctx_StringBuilder_Cancel ( ctx, builder ); +static inline void HPyUnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder) { + ctx->ctx_UnicodeBuilder_Cancel ( ctx, builder ); } static inline HPyTupleBuilder HPyTupleBuilder_New(HPyContext *ctx, HPy_ssize_t initial_size) { diff --git a/hpy/devel/include/universal/hpy.h b/hpy/devel/include/universal/hpy.h index f0c691f25..8fec06c85 100644 --- a/hpy/devel/include/universal/hpy.h +++ b/hpy/devel/include/universal/hpy.h @@ -34,7 +34,7 @@ typedef intptr_t HPy_hash_t; the HPy structure contains an index in a global array. */ typedef struct _HPy_s { HPy_ssize_t _i; } HPy; typedef struct { HPy_ssize_t _lst; } HPyListBuilder; -typedef struct { HPy_ssize_t _lst; } HPyStringBuilder; +typedef struct { HPy_ssize_t _lst; } HPyUnicodeBuilder; typedef struct { HPy_ssize_t _tup; } HPyTupleBuilder; typedef struct { HPy_ssize_t _i; } HPyTracker; diff --git a/hpy/devel/src/runtime/ctx_stringbuilder.c b/hpy/devel/src/runtime/ctx_unicodebuilder.c similarity index 78% rename from hpy/devel/src/runtime/ctx_stringbuilder.c rename to hpy/devel/src/runtime/ctx_unicodebuilder.c index 018f3c8c1..2cf9d9925 100644 --- a/hpy/devel/src/runtime/ctx_stringbuilder.c +++ b/hpy/devel/src/runtime/ctx_unicodebuilder.c @@ -9,17 +9,17 @@ #include -_HPy_HIDDEN HPyStringBuilder -ctx_StringBuilder_New(HPyContext *ctx) +_HPy_HIDDEN HPyUnicodeBuilder +ctx_UnicodeBuilder_New(HPyContext *ctx) { PyObject *lst = PyList_New(0); if (lst == NULL) PyErr_Clear(); /* delay the MemoryError */ - return (HPyStringBuilder){(HPy_ssize_t)lst }; + return (HPyUnicodeBuilder){(HPy_ssize_t)lst }; } _HPy_HIDDEN void -ctx_StringBuilder_Append(HPyContext *ctx, HPyStringBuilder builder, HPy h_item) +ctx_UnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) { PyObject *lst = (PyObject *)builder._lst; if (lst != NULL) { @@ -29,7 +29,7 @@ ctx_StringBuilder_Append(HPyContext *ctx, HPyStringBuilder builder, HPy h_item) } _HPy_HIDDEN HPy -ctx_StringBuilder_Build(HPyContext *ctx, HPyStringBuilder builder) +ctx_UnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder) { PyObject *lst = (PyObject *)builder._lst; if (lst == NULL) { @@ -49,7 +49,7 @@ ctx_StringBuilder_Build(HPyContext *ctx, HPyStringBuilder builder) } _HPy_HIDDEN void -ctx_StringBuilder_Cancel(HPyContext *ctx, HPyStringBuilder builder) +ctx_UnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder) { PyObject *lst = (PyObject *)builder._lst; if (lst == NULL) { diff --git a/hpy/tools/autogen/parse.py b/hpy/tools/autogen/parse.py index 980dbb6b1..072d1ee87 100644 --- a/hpy/tools/autogen/parse.py +++ b/hpy/tools/autogen/parse.py @@ -210,10 +210,10 @@ def _visit_hpyslot_slot(self, node): 'HPyListBuilder_Set': None, 'HPyListBuilder_Build': None, 'HPyListBuilder_Cancel': None, - 'HPyStringBuilder_New': None, - 'HPyStringBuilder_Append': None, - 'HPyStringBuilder_Build': None, - 'HPyStringBuilder_Cancel': None, + 'HPyUnicodeBuilder_New': None, + 'HPyUnicodeBuilder_Append': None, + 'HPyUnicodeBuilder_Build': None, + 'HPyUnicodeBuilder_Cancel': None, 'HPyTuple_FromArray': None, 'HPyTupleBuilder_New': None, 'HPyTupleBuilder_Set': None, diff --git a/hpy/tools/autogen/public_api.h b/hpy/tools/autogen/public_api.h index 4095ae35a..74703b048 100644 --- a/hpy/tools/autogen/public_api.h +++ b/hpy/tools/autogen/public_api.h @@ -12,7 +12,7 @@ typedef int size_t; typedef int HPyFunc_Signature; typedef int cpy_PyObject; typedef int HPyListBuilder; -typedef int HPyStringBuilder; +typedef int HPyUnicodeBuilder; typedef int HPyTupleBuilder; typedef int HPyTracker; typedef int HPy_RichCmpOp; @@ -283,11 +283,11 @@ void HPyListBuilder_Set(HPyContext *ctx, HPyListBuilder builder, HPy HPyListBuilder_Build(HPyContext *ctx, HPyListBuilder builder); void HPyListBuilder_Cancel(HPyContext *ctx, HPyListBuilder builder); -HPyStringBuilder HPyStringBuilder_New(HPyContext *ctx); -void HPyStringBuilder_Append(HPyContext *ctx, HPyStringBuilder builder, +HPyUnicodeBuilder HPyUnicodeBuilder_New(HPyContext *ctx); +void HPyUnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item); -HPy HPyStringBuilder_Build(HPyContext *ctx, HPyStringBuilder builder); -void HPyStringBuilder_Cancel(HPyContext *ctx, HPyStringBuilder builder); +HPy HPyUnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder); +void HPyUnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder); HPyTupleBuilder HPyTupleBuilder_New(HPyContext *ctx, HPy_ssize_t initial_size); void HPyTupleBuilder_Set(HPyContext *ctx, HPyTupleBuilder builder, diff --git a/hpy/universal/src/autogen_ctx_def.h b/hpy/universal/src/autogen_ctx_def.h index 7caf1e3c8..1bf11c027 100644 --- a/hpy/universal/src/autogen_ctx_def.h +++ b/hpy/universal/src/autogen_ctx_def.h @@ -136,10 +136,10 @@ struct _HPyContext_s g_universal_ctx = { .ctx_ListBuilder_Set = &ctx_ListBuilder_Set, .ctx_ListBuilder_Build = &ctx_ListBuilder_Build, .ctx_ListBuilder_Cancel = &ctx_ListBuilder_Cancel, - .ctx_StringBuilder_New = &ctx_StringBuilder_New, - .ctx_StringBuilder_Append = &ctx_StringBuilder_Append, - .ctx_StringBuilder_Build = &ctx_StringBuilder_Build, - .ctx_StringBuilder_Cancel = &ctx_StringBuilder_Cancel, + .ctx_UnicodeBuilder_New = &ctx_UnicodeBuilder_New, + .ctx_UnicodeBuilder_Append = &ctx_UnicodeBuilder_Append, + .ctx_UnicodeBuilder_Build = &ctx_UnicodeBuilder_Build, + .ctx_UnicodeBuilder_Cancel = &ctx_UnicodeBuilder_Cancel, .ctx_TupleBuilder_New = &ctx_TupleBuilder_New, .ctx_TupleBuilder_Set = &ctx_TupleBuilder_Set, .ctx_TupleBuilder_Build = &ctx_TupleBuilder_Build, diff --git a/hpy/universal/src/ctx.c b/hpy/universal/src/ctx.c index 1281e6d06..f23d6eb7c 100644 --- a/hpy/universal/src/ctx.c +++ b/hpy/universal/src/ctx.c @@ -6,7 +6,7 @@ #include "common/runtime/ctx_module.h" #include "common/runtime/ctx_object.h" #include "common/runtime/ctx_listbuilder.h" -#include "common/runtime/ctx_stringbuilder.h" +#include "common/runtime/ctx_unicodebuilder.h" #include "common/runtime/ctx_tracker.h" #include "common/runtime/ctx_tuple.h" #include "common/runtime/ctx_tuplebuilder.h" diff --git a/setup.py b/setup.py index 39694a42f..b3b1fb0b2 100644 --- a/setup.py +++ b/setup.py @@ -59,9 +59,9 @@ def get_scm_config(): 'hpy/devel/src/runtime/ctx_type.c', 'hpy/devel/src/runtime/ctx_tracker.c', 'hpy/devel/src/runtime/ctx_listbuilder.c', - 'hpy/devel/src/runtime/ctx_stringbuilder.c', 'hpy/devel/src/runtime/ctx_tuple.c', 'hpy/devel/src/runtime/ctx_tuplebuilder.c', + 'hpy/devel/src/runtime/ctx_unicodebuilder.c', 'hpy/debug/src/debug_ctx.c', 'hpy/debug/src/debug_ctx_cpython.c', 'hpy/debug/src/debug_handles.c', diff --git a/test/test_hpystringbuilder.py b/test/test_hpystringbuilder.py index 39150ba20..9b79bd341 100644 --- a/test/test_hpystringbuilder.py +++ b/test/test_hpystringbuilder.py @@ -1,18 +1,18 @@ from .support import HPyTest class TestString(HPyTest): - def test_StringBuilder(self, hpy_abi): + def test_UnicodeBuilder(self, hpy_abi): mod = self.make_module(""" HPyDef_METH(f, "f", f_impl, HPyFunc_O) static HPy f_impl(HPyContext *ctx, HPy h_self, HPy h_arg) { - HPyStringBuilder builder = HPyStringBuilder_New(ctx); + HPyUnicodeBuilder builder = HPyUnicodeBuilder_New(ctx); HPy h_s1 = HPyUnicode_FromString(ctx, "hello "); HPy h_s2 = HPyUnicode_FromString(ctx, "!"); - HPyStringBuilder_Append(ctx, builder, h_s1); - HPyStringBuilder_Append(ctx, builder, h_arg); - HPyStringBuilder_Append(ctx, builder, h_s2); - HPy h_string = HPyStringBuilder_Build(ctx, builder); + HPyUnicodeBuilder_Append(ctx, builder, h_s1); + HPyUnicodeBuilder_Append(ctx, builder, h_arg); + HPyUnicodeBuilder_Append(ctx, builder, h_s2); + HPy h_string = HPyUnicodeBuilder_Build(ctx, builder); HPy_Close(ctx, h_s1); HPy_Close(ctx, h_s2); return h_string; From cd4c539934404fdf03e03c47126a8d7ae1171e9f Mon Sep 17 00:00:00 2001 From: Christian Klein <167265+cklein@users.noreply.github.com> Date: Sun, 11 Apr 2021 13:30:35 +0200 Subject: [PATCH 3/4] Implementation with a preallocated list The idea turned out to be very closely related to HPyTracker, so I blatantly stole some code there. --- hpy/debug/src/autogen_debug_ctx_init.h | 6 +- hpy/debug/src/autogen_debug_wrappers.c | 8 +- .../common/runtime/ctx_unicodebuilder.h | 6 +- hpy/devel/include/cpython/hpy.h | 51 +++++---- hpy/devel/include/universal/autogen_ctx.h | 4 +- .../include/universal/autogen_trampolines.h | 8 +- hpy/devel/include/universal/hpy.h | 2 +- hpy/devel/src/runtime/ctx_unicodebuilder.c | 102 +++++++++++++----- hpy/tools/autogen/parse.py | 8 +- hpy/tools/autogen/public_api.h | 5 +- hpy/universal/src/autogen_ctx_def.h | 2 +- test/test_hpystringbuilder.py | 23 ---- test/test_hpyunicodebuilder.py | 51 +++++++++ 13 files changed, 173 insertions(+), 103 deletions(-) delete mode 100644 test/test_hpystringbuilder.py create mode 100644 test/test_hpyunicodebuilder.py diff --git a/hpy/debug/src/autogen_debug_ctx_init.h b/hpy/debug/src/autogen_debug_ctx_init.h index cbb856012..cc1acd862 100644 --- a/hpy/debug/src/autogen_debug_ctx_init.h +++ b/hpy/debug/src/autogen_debug_ctx_init.h @@ -131,8 +131,8 @@ HPyListBuilder debug_ctx_ListBuilder_New(HPyContext *dctx, HPy_ssize_t initial_s void debug_ctx_ListBuilder_Set(HPyContext *dctx, HPyListBuilder builder, HPy_ssize_t index, DHPy h_item); DHPy debug_ctx_ListBuilder_Build(HPyContext *dctx, HPyListBuilder builder); void debug_ctx_ListBuilder_Cancel(HPyContext *dctx, HPyListBuilder builder); -HPyUnicodeBuilder debug_ctx_UnicodeBuilder_New(HPyContext *dctx); -void debug_ctx_UnicodeBuilder_Append(HPyContext *dctx, HPyUnicodeBuilder builder, DHPy h_item); +HPyUnicodeBuilder debug_ctx_UnicodeBuilder_New(HPyContext *dctx, HPy_ssize_t size); +int debug_ctx_UnicodeBuilder_Add(HPyContext *dctx, HPyUnicodeBuilder builder, DHPy h_item); DHPy debug_ctx_UnicodeBuilder_Build(HPyContext *dctx, HPyUnicodeBuilder builder); void debug_ctx_UnicodeBuilder_Cancel(HPyContext *dctx, HPyUnicodeBuilder builder); HPyTupleBuilder debug_ctx_TupleBuilder_New(HPyContext *dctx, HPy_ssize_t initial_size); @@ -344,7 +344,7 @@ static inline void debug_ctx_init_fields(HPyContext *dctx, HPyContext *uctx) dctx->ctx_ListBuilder_Build = &debug_ctx_ListBuilder_Build; dctx->ctx_ListBuilder_Cancel = &debug_ctx_ListBuilder_Cancel; dctx->ctx_UnicodeBuilder_New = &debug_ctx_UnicodeBuilder_New; - dctx->ctx_UnicodeBuilder_Append = &debug_ctx_UnicodeBuilder_Append; + dctx->ctx_UnicodeBuilder_Add = &debug_ctx_UnicodeBuilder_Add; dctx->ctx_UnicodeBuilder_Build = &debug_ctx_UnicodeBuilder_Build; dctx->ctx_UnicodeBuilder_Cancel = &debug_ctx_UnicodeBuilder_Cancel; dctx->ctx_TupleBuilder_New = &debug_ctx_TupleBuilder_New; diff --git a/hpy/debug/src/autogen_debug_wrappers.c b/hpy/debug/src/autogen_debug_wrappers.c index 98721a93b..f0affd025 100644 --- a/hpy/debug/src/autogen_debug_wrappers.c +++ b/hpy/debug/src/autogen_debug_wrappers.c @@ -592,14 +592,14 @@ void debug_ctx_ListBuilder_Cancel(HPyContext *dctx, HPyListBuilder builder) HPyListBuilder_Cancel(get_info(dctx)->uctx, builder); } -HPyUnicodeBuilder debug_ctx_UnicodeBuilder_New(HPyContext *dctx) +HPyUnicodeBuilder debug_ctx_UnicodeBuilder_New(HPyContext *dctx, HPy_ssize_t size) { - return HPyUnicodeBuilder_New(get_info(dctx)->uctx); + return HPyUnicodeBuilder_New(get_info(dctx)->uctx, size); } -void debug_ctx_UnicodeBuilder_Append(HPyContext *dctx, HPyUnicodeBuilder builder, DHPy h_item) +int debug_ctx_UnicodeBuilder_Add(HPyContext *dctx, HPyUnicodeBuilder builder, DHPy h_item) { - HPyUnicodeBuilder_Append(get_info(dctx)->uctx, builder, DHPy_unwrap(dctx, h_item)); + return HPyUnicodeBuilder_Add(get_info(dctx)->uctx, builder, DHPy_unwrap(dctx, h_item)); } DHPy debug_ctx_UnicodeBuilder_Build(HPyContext *dctx, HPyUnicodeBuilder builder) diff --git a/hpy/devel/include/common/runtime/ctx_unicodebuilder.h b/hpy/devel/include/common/runtime/ctx_unicodebuilder.h index 5d00783b2..ce7ad975a 100644 --- a/hpy/devel/include/common/runtime/ctx_unicodebuilder.h +++ b/hpy/devel/include/common/runtime/ctx_unicodebuilder.h @@ -6,9 +6,9 @@ #include "common/hpytype.h" -_HPy_HIDDEN HPyUnicodeBuilder ctx_UnicodeBuilder_New(HPyContext *ctx); -_HPy_HIDDEN void ctx_UnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, - HPy h_item); +_HPy_HIDDEN HPyUnicodeBuilder ctx_UnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t capacity); +_HPy_HIDDEN int ctx_UnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, + HPy h_item); _HPy_HIDDEN HPy ctx_UnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder); _HPy_HIDDEN void ctx_UnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder); diff --git a/hpy/devel/include/cpython/hpy.h b/hpy/devel/include/cpython/hpy.h index a6b76e862..b60305026 100644 --- a/hpy/devel/include/cpython/hpy.h +++ b/hpy/devel/include/cpython/hpy.h @@ -31,9 +31,9 @@ typedef struct { PyObject *_o; } HPy; typedef struct { Py_ssize_t _lst; } HPyListBuilder; -typedef struct { Py_ssize_t _lst; } HPyUnicodeBuilder; typedef struct { Py_ssize_t _tup; } HPyTupleBuilder; typedef struct { void *_o; } HPyTracker; +typedef struct { void *_o; } HPyUnicodeBuilder; typedef Py_ssize_t HPy_ssize_t; typedef Py_hash_t HPy_hash_t; @@ -380,31 +380,6 @@ HPyListBuilder_Cancel(HPyContext *ctx, HPyListBuilder builder) ctx_ListBuilder_Cancel(ctx, builder); } -HPyAPI_FUNC(HPyUnicodeBuilder) -HPyUnicodeBuilder_New(HPyContext *ctx) -{ - return ctx_UnicodeBuilder_New(ctx); -} - -HPyAPI_FUNC(void) -HPyUnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, - HPy h_item) -{ - ctx_UnicodeBuilder_Append(ctx, builder, h_item); -} - -HPyAPI_FUNC(HPy) -HPyUnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder) -{ - return ctx_UnicodeBuilder_Build(ctx, builder); -} - -HPyAPI_FUNC(void) -HPyUnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder) -{ - ctx_UnicodeBuilder_Cancel(ctx, builder); -} - HPyAPI_FUNC(HPyTupleBuilder) HPyTupleBuilder_New(HPyContext *ctx, HPy_ssize_t initial_size) { @@ -460,4 +435,28 @@ HPyTracker_Close(HPyContext *ctx, HPyTracker ht) ctx_Tracker_Close(ctx, ht); } +HPyAPI_FUNC(HPyUnicodeBuilder) +HPyUnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t size) +{ + return ctx_UnicodeBuilder_New(ctx, size); +} + +HPyAPI_FUNC(int) +HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) +{ + return ctx_UnicodeBuilder_Add(ctx, builder, h_item); +} + +HPyAPI_FUNC(HPy) +HPyUnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder) +{ + return ctx_UnicodeBuilder_Build(ctx, builder); +} + +HPyAPI_FUNC(void) +HPyUnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder) +{ + ctx_UnicodeBuilder_Cancel(ctx, builder); +} + #endif /* !HPy_CPYTHON_H */ diff --git a/hpy/devel/include/universal/autogen_ctx.h b/hpy/devel/include/universal/autogen_ctx.h index b3f8c5d5e..22aa45996 100644 --- a/hpy/devel/include/universal/autogen_ctx.h +++ b/hpy/devel/include/universal/autogen_ctx.h @@ -210,8 +210,8 @@ struct _HPyContext_s { void (*ctx_ListBuilder_Set)(HPyContext *ctx, HPyListBuilder builder, HPy_ssize_t index, HPy h_item); HPy (*ctx_ListBuilder_Build)(HPyContext *ctx, HPyListBuilder builder); void (*ctx_ListBuilder_Cancel)(HPyContext *ctx, HPyListBuilder builder); - HPyUnicodeBuilder (*ctx_UnicodeBuilder_New)(HPyContext *ctx); - void (*ctx_UnicodeBuilder_Append)(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item); + HPyUnicodeBuilder (*ctx_UnicodeBuilder_New)(HPyContext *ctx, HPy_ssize_t size); + int (*ctx_UnicodeBuilder_Add)(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item); HPy (*ctx_UnicodeBuilder_Build)(HPyContext *ctx, HPyUnicodeBuilder builder); void (*ctx_UnicodeBuilder_Cancel)(HPyContext *ctx, HPyUnicodeBuilder builder); HPyTupleBuilder (*ctx_TupleBuilder_New)(HPyContext *ctx, HPy_ssize_t initial_size); diff --git a/hpy/devel/include/universal/autogen_trampolines.h b/hpy/devel/include/universal/autogen_trampolines.h index ec29dc766..b5999941c 100644 --- a/hpy/devel/include/universal/autogen_trampolines.h +++ b/hpy/devel/include/universal/autogen_trampolines.h @@ -486,12 +486,12 @@ static inline void HPyListBuilder_Cancel(HPyContext *ctx, HPyListBuilder builder ctx->ctx_ListBuilder_Cancel ( ctx, builder ); } -static inline HPyUnicodeBuilder HPyUnicodeBuilder_New(HPyContext *ctx) { - return ctx->ctx_UnicodeBuilder_New ( ctx ); +static inline HPyUnicodeBuilder HPyUnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t size) { + return ctx->ctx_UnicodeBuilder_New ( ctx, size ); } -static inline void HPyUnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) { - ctx->ctx_UnicodeBuilder_Append ( ctx, builder, h_item ); +static inline int HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) { + return ctx->ctx_UnicodeBuilder_Add ( ctx, builder, h_item ); } static inline HPy HPyUnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder) { diff --git a/hpy/devel/include/universal/hpy.h b/hpy/devel/include/universal/hpy.h index 8fec06c85..1ec11ff1e 100644 --- a/hpy/devel/include/universal/hpy.h +++ b/hpy/devel/include/universal/hpy.h @@ -34,9 +34,9 @@ typedef intptr_t HPy_hash_t; the HPy structure contains an index in a global array. */ typedef struct _HPy_s { HPy_ssize_t _i; } HPy; typedef struct { HPy_ssize_t _lst; } HPyListBuilder; -typedef struct { HPy_ssize_t _lst; } HPyUnicodeBuilder; typedef struct { HPy_ssize_t _tup; } HPyTupleBuilder; typedef struct { HPy_ssize_t _i; } HPyTracker; +typedef struct { HPy_ssize_t _i; } HPyUnicodeBuilder; typedef struct _HPyContext_s HPyContext; diff --git a/hpy/devel/src/runtime/ctx_unicodebuilder.c b/hpy/devel/src/runtime/ctx_unicodebuilder.c index 2cf9d9925..5716b3652 100644 --- a/hpy/devel/src/runtime/ctx_unicodebuilder.c +++ b/hpy/devel/src/runtime/ctx_unicodebuilder.c @@ -7,57 +7,101 @@ # include "handles.h" #endif -#include +static const Py_ssize_t HPYUNICODEBUILDER_INITIAL_CAPACITY = 5; + +typedef struct { + Py_ssize_t capacity; // allocated handles + Py_ssize_t length; // used handles + PyObject *list; +} _PyUnicodeBuilder_s; + +#ifdef HPY_UNIVERSAL_ABI +static inline _PyUnicodeBuilder_s *_hb2pb(HPyUnicodeBuilder ht) { + return (_PyUnicodeBuilder_s *) (ht)._i; +} +static inline HPyUnicodeBuilder _pb2hb(_PyUnicodeBuilder_s *bp) { + return (HPyUnicodeBuilder) {(HPy_ssize_t) (bp)}; +} +#else +static inline _PyUnicodeBuilder_s *_hb2pb(HPyUnicodeBuilder ht) { + return (_PyUnicodeBuilder_s *) (ht)._o; +} +static inline HPyUnicodeBuilder _pb2hb(_PyUnicodeBuilder_s *bp) { + return (HPyUnicodeBuilder) {(void *) (bp)}; +} +#endif _HPy_HIDDEN HPyUnicodeBuilder -ctx_UnicodeBuilder_New(HPyContext *ctx) +ctx_UnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t capacity) { - PyObject *lst = PyList_New(0); - if (lst == NULL) - PyErr_Clear(); /* delay the MemoryError */ - return (HPyUnicodeBuilder){(HPy_ssize_t)lst }; + _PyUnicodeBuilder_s *bp; + if (capacity == 0) { + capacity = HPYUNICODEBUILDER_INITIAL_CAPACITY; + } + capacity++; // always reserve space for an extra handle, see the docs, analogue to HPyTracker + + bp = malloc(sizeof(_PyUnicodeBuilder_s)); + if (bp == NULL) { + HPyErr_NoMemory(ctx); + return _pb2hb(0); + } + + bp->list = PyList_New(capacity); + if (bp->list == NULL) { + free(bp); + HPyErr_NoMemory(ctx); + return _pb2hb(0); + } + bp->capacity = capacity; + bp->length = 0; + return _pb2hb(bp); } -_HPy_HIDDEN void -ctx_UnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) +_HPy_HIDDEN int +ctx_UnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) { - PyObject *lst = (PyObject *)builder._lst; - if (lst != NULL) { - PyObject *item = _h2py(h_item); - PyList_Append(lst, item); + if(!HPyUnicode_Check(ctx, h_item)) { + HPyErr_SetString(ctx, ctx->h_TypeError, "Argument must be of type HPyUnicode"); + return -1; + } + + _PyUnicodeBuilder_s *bp = _hb2pb(builder); + PyObject *item = _h2py(h_item); + + // XXX: For the initial PoC we don't care about reallocation + if (bp->capacity <= bp->length) { + return -1; } + Py_INCREF(item); + PyList_SET_ITEM(bp->list, bp->length++, item); + return 0; } _HPy_HIDDEN HPy ctx_UnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder) { - PyObject *lst = (PyObject *)builder._lst; - if (lst == NULL) { - PyErr_NoMemory(); - return HPy_NULL; - } - builder._lst = 0; + _PyUnicodeBuilder_s *bp = _hb2pb(builder); + PyObject *list = PyList_GetSlice(bp->list, 0, bp->length); + PyObject *sep = PyUnicode_FromString(""); - PyObject *str = PyUnicode_Join(sep, lst); + PyObject *str = PyUnicode_Join(sep, list); Py_XDECREF(sep); + if(str == NULL) { PyErr_NoMemory(); return HPy_NULL; } - Py_XDECREF(lst); + + Py_XDECREF(bp->list); + Py_XDECREF(list); + free(bp); return _py2h(str); } _HPy_HIDDEN void ctx_UnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder) { - PyObject *lst = (PyObject *)builder._lst; - if (lst == NULL) { - // we don't report the memory error here: the builder - // is being cancelled (so the result of the builder is not being used) - // and likely it's being cancelled during the handling of another error - return; - } - builder._lst = 0; - Py_XDECREF(lst); + _PyUnicodeBuilder_s *bp = _hb2pb(builder); + Py_XDECREF(bp->list); + free(bp); } diff --git a/hpy/tools/autogen/parse.py b/hpy/tools/autogen/parse.py index 072d1ee87..365147007 100644 --- a/hpy/tools/autogen/parse.py +++ b/hpy/tools/autogen/parse.py @@ -210,10 +210,6 @@ def _visit_hpyslot_slot(self, node): 'HPyListBuilder_Set': None, 'HPyListBuilder_Build': None, 'HPyListBuilder_Cancel': None, - 'HPyUnicodeBuilder_New': None, - 'HPyUnicodeBuilder_Append': None, - 'HPyUnicodeBuilder_Build': None, - 'HPyUnicodeBuilder_Cancel': None, 'HPyTuple_FromArray': None, 'HPyTupleBuilder_New': None, 'HPyTupleBuilder_Set': None, @@ -223,6 +219,10 @@ def _visit_hpyslot_slot(self, node): 'HPyTracker_Add': None, 'HPyTracker_ForgetAll': None, 'HPyTracker_Close': None, + 'HPyUnicodeBuilder_New': None, + 'HPyUnicodeBuilder_Add': None, + 'HPyUnicodeBuilder_Build': None, + 'HPyUnicodeBuilder_Cancel': None, '_HPy_Dump': None, 'HPy_Type': 'PyObject_Type', 'HPy_TypeCheck': None, diff --git a/hpy/tools/autogen/public_api.h b/hpy/tools/autogen/public_api.h index 74703b048..f77c951b5 100644 --- a/hpy/tools/autogen/public_api.h +++ b/hpy/tools/autogen/public_api.h @@ -283,9 +283,8 @@ void HPyListBuilder_Set(HPyContext *ctx, HPyListBuilder builder, HPy HPyListBuilder_Build(HPyContext *ctx, HPyListBuilder builder); void HPyListBuilder_Cancel(HPyContext *ctx, HPyListBuilder builder); -HPyUnicodeBuilder HPyUnicodeBuilder_New(HPyContext *ctx); -void HPyUnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, - HPy h_item); +HPyUnicodeBuilder HPyUnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t size); +int HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item); HPy HPyUnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder); void HPyUnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder); diff --git a/hpy/universal/src/autogen_ctx_def.h b/hpy/universal/src/autogen_ctx_def.h index 1bf11c027..c537790ca 100644 --- a/hpy/universal/src/autogen_ctx_def.h +++ b/hpy/universal/src/autogen_ctx_def.h @@ -137,7 +137,7 @@ struct _HPyContext_s g_universal_ctx = { .ctx_ListBuilder_Build = &ctx_ListBuilder_Build, .ctx_ListBuilder_Cancel = &ctx_ListBuilder_Cancel, .ctx_UnicodeBuilder_New = &ctx_UnicodeBuilder_New, - .ctx_UnicodeBuilder_Append = &ctx_UnicodeBuilder_Append, + .ctx_UnicodeBuilder_Add = &ctx_UnicodeBuilder_Add, .ctx_UnicodeBuilder_Build = &ctx_UnicodeBuilder_Build, .ctx_UnicodeBuilder_Cancel = &ctx_UnicodeBuilder_Cancel, .ctx_TupleBuilder_New = &ctx_TupleBuilder_New, diff --git a/test/test_hpystringbuilder.py b/test/test_hpystringbuilder.py deleted file mode 100644 index 9b79bd341..000000000 --- a/test/test_hpystringbuilder.py +++ /dev/null @@ -1,23 +0,0 @@ -from .support import HPyTest - -class TestString(HPyTest): - def test_UnicodeBuilder(self, hpy_abi): - mod = self.make_module(""" - HPyDef_METH(f, "f", f_impl, HPyFunc_O) - static HPy f_impl(HPyContext *ctx, HPy h_self, HPy h_arg) - { - HPyUnicodeBuilder builder = HPyUnicodeBuilder_New(ctx); - HPy h_s1 = HPyUnicode_FromString(ctx, "hello "); - HPy h_s2 = HPyUnicode_FromString(ctx, "!"); - HPyUnicodeBuilder_Append(ctx, builder, h_s1); - HPyUnicodeBuilder_Append(ctx, builder, h_arg); - HPyUnicodeBuilder_Append(ctx, builder, h_s2); - HPy h_string = HPyUnicodeBuilder_Build(ctx, builder); - HPy_Close(ctx, h_s1); - HPy_Close(ctx, h_s2); - return h_string; - } - @EXPORT(f) - @INIT - """) - assert mod.f("world") == "hello world!" diff --git a/test/test_hpyunicodebuilder.py b/test/test_hpyunicodebuilder.py new file mode 100644 index 000000000..6b30285d1 --- /dev/null +++ b/test/test_hpyunicodebuilder.py @@ -0,0 +1,51 @@ +from .support import HPyTest + +class TestString(HPyTest): + def test_unicode_builder(self): + mod = self.make_module(""" + HPyDef_METH(f, "f", f_impl, HPyFunc_O) + static HPy f_impl(HPyContext *ctx, HPy h_self, HPy h_arg) + { + HPyUnicodeBuilder builder = HPyUnicodeBuilder_New(ctx, 0); + if(HPy_IsNull(builder)) { + HPyErr_SetString(ctx, ctx->h_RuntimeError, "Could not create HPyUnicodeBuilder"); + return HPy_NULL; + } + HPy h_s1 = HPyUnicode_FromString(ctx, "hello "); + HPy h_s2 = HPyUnicode_FromString(ctx, "!"); + HPyUnicodeBuilder_Add(ctx, builder, h_s1); + HPyUnicodeBuilder_Add(ctx, builder, h_arg); + HPyUnicodeBuilder_Add(ctx, builder, h_s2); + HPy h_string = HPyUnicodeBuilder_Build(ctx, builder); + HPy_Close(ctx, h_s1); + HPy_Close(ctx, h_s2); + return h_string; + } + @EXPORT(f) + @INIT + """) + assert mod.f("world") == "hello world!" + + def test_type_error(self): + mod = self.make_module(""" + HPyDef_METH(f, "f", f_impl, HPyFunc_O) + static HPy f_impl(HPyContext *ctx, HPy h_self, HPy h_arg) + { + HPyUnicodeBuilder builder = HPyUnicodeBuilder_New(ctx, 0); + if(HPy_IsNull(builder)) { + HPyErr_SetString(ctx, ctx->h_RuntimeError, "Could not create HPyUnicodeBuilder"); + return HPy_NULL; + } + HPy h_long = HPyLong_FromLong(ctx, 42); + HPyUnicodeBuilder_Add(ctx, builder, h_long); + HPy_Close(ctx, h_long); + HPyUnicodeBuilder_Cancel(ctx, builder); + return HPy_NULL; + } + @EXPORT(f) + @INIT + """) + import pytest + with pytest.raises(TypeError) as exc_info: + mod.f("world") + assert exc_info.match("Argument must be of type HPyUnicode") From c2ed4f2f3f34639cb878f7b4d9d97b7e68c1a458 Mon Sep 17 00:00:00 2001 From: Christian Klein <167265+cklein@users.noreply.github.com> Date: Tue, 13 Apr 2021 18:28:25 +0200 Subject: [PATCH 4/4] Changed UnicodeBuilders to operate on a c string instead of a list of Python strings --- hpy/debug/src/autogen_debug_ctx_init.h | 2 +- hpy/debug/src/autogen_debug_wrappers.c | 4 +- .../common/runtime/ctx_unicodebuilder.h | 3 +- hpy/devel/include/cpython/hpy.h | 4 +- hpy/devel/include/universal/autogen_ctx.h | 2 +- .../include/universal/autogen_trampolines.h | 4 +- hpy/devel/src/runtime/ctx_unicodebuilder.c | 62 +++++++++---------- hpy/tools/autogen/public_api.h | 2 +- test/test_hpyunicodebuilder.py | 40 ++---------- 9 files changed, 44 insertions(+), 79 deletions(-) diff --git a/hpy/debug/src/autogen_debug_ctx_init.h b/hpy/debug/src/autogen_debug_ctx_init.h index cc1acd862..11f991a14 100644 --- a/hpy/debug/src/autogen_debug_ctx_init.h +++ b/hpy/debug/src/autogen_debug_ctx_init.h @@ -132,7 +132,7 @@ void debug_ctx_ListBuilder_Set(HPyContext *dctx, HPyListBuilder builder, HPy_ssi DHPy debug_ctx_ListBuilder_Build(HPyContext *dctx, HPyListBuilder builder); void debug_ctx_ListBuilder_Cancel(HPyContext *dctx, HPyListBuilder builder); HPyUnicodeBuilder debug_ctx_UnicodeBuilder_New(HPyContext *dctx, HPy_ssize_t size); -int debug_ctx_UnicodeBuilder_Add(HPyContext *dctx, HPyUnicodeBuilder builder, DHPy h_item); +int debug_ctx_UnicodeBuilder_Add(HPyContext *dctx, HPyUnicodeBuilder builder, const char *item); DHPy debug_ctx_UnicodeBuilder_Build(HPyContext *dctx, HPyUnicodeBuilder builder); void debug_ctx_UnicodeBuilder_Cancel(HPyContext *dctx, HPyUnicodeBuilder builder); HPyTupleBuilder debug_ctx_TupleBuilder_New(HPyContext *dctx, HPy_ssize_t initial_size); diff --git a/hpy/debug/src/autogen_debug_wrappers.c b/hpy/debug/src/autogen_debug_wrappers.c index f0affd025..486e16295 100644 --- a/hpy/debug/src/autogen_debug_wrappers.c +++ b/hpy/debug/src/autogen_debug_wrappers.c @@ -597,9 +597,9 @@ HPyUnicodeBuilder debug_ctx_UnicodeBuilder_New(HPyContext *dctx, HPy_ssize_t siz return HPyUnicodeBuilder_New(get_info(dctx)->uctx, size); } -int debug_ctx_UnicodeBuilder_Add(HPyContext *dctx, HPyUnicodeBuilder builder, DHPy h_item) +int debug_ctx_UnicodeBuilder_Add(HPyContext *dctx, HPyUnicodeBuilder builder, const char *item) { - return HPyUnicodeBuilder_Add(get_info(dctx)->uctx, builder, DHPy_unwrap(dctx, h_item)); + return HPyUnicodeBuilder_Add(get_info(dctx)->uctx, builder, item); } DHPy debug_ctx_UnicodeBuilder_Build(HPyContext *dctx, HPyUnicodeBuilder builder) diff --git a/hpy/devel/include/common/runtime/ctx_unicodebuilder.h b/hpy/devel/include/common/runtime/ctx_unicodebuilder.h index ce7ad975a..5b7924369 100644 --- a/hpy/devel/include/common/runtime/ctx_unicodebuilder.h +++ b/hpy/devel/include/common/runtime/ctx_unicodebuilder.h @@ -7,8 +7,7 @@ _HPy_HIDDEN HPyUnicodeBuilder ctx_UnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t capacity); -_HPy_HIDDEN int ctx_UnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, - HPy h_item); +_HPy_HIDDEN int ctx_UnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, const char *item); _HPy_HIDDEN HPy ctx_UnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder); _HPy_HIDDEN void ctx_UnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder); diff --git a/hpy/devel/include/cpython/hpy.h b/hpy/devel/include/cpython/hpy.h index b60305026..27e0c6b92 100644 --- a/hpy/devel/include/cpython/hpy.h +++ b/hpy/devel/include/cpython/hpy.h @@ -442,9 +442,9 @@ HPyUnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t size) } HPyAPI_FUNC(int) -HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) +HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, const char *item) { - return ctx_UnicodeBuilder_Add(ctx, builder, h_item); + return ctx_UnicodeBuilder_Add(ctx, builder, item); } HPyAPI_FUNC(HPy) diff --git a/hpy/devel/include/universal/autogen_ctx.h b/hpy/devel/include/universal/autogen_ctx.h index 22aa45996..a90643fd7 100644 --- a/hpy/devel/include/universal/autogen_ctx.h +++ b/hpy/devel/include/universal/autogen_ctx.h @@ -211,7 +211,7 @@ struct _HPyContext_s { HPy (*ctx_ListBuilder_Build)(HPyContext *ctx, HPyListBuilder builder); void (*ctx_ListBuilder_Cancel)(HPyContext *ctx, HPyListBuilder builder); HPyUnicodeBuilder (*ctx_UnicodeBuilder_New)(HPyContext *ctx, HPy_ssize_t size); - int (*ctx_UnicodeBuilder_Add)(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item); + int (*ctx_UnicodeBuilder_Add)(HPyContext *ctx, HPyUnicodeBuilder builder, const char *item); HPy (*ctx_UnicodeBuilder_Build)(HPyContext *ctx, HPyUnicodeBuilder builder); void (*ctx_UnicodeBuilder_Cancel)(HPyContext *ctx, HPyUnicodeBuilder builder); HPyTupleBuilder (*ctx_TupleBuilder_New)(HPyContext *ctx, HPy_ssize_t initial_size); diff --git a/hpy/devel/include/universal/autogen_trampolines.h b/hpy/devel/include/universal/autogen_trampolines.h index b5999941c..c52b785a5 100644 --- a/hpy/devel/include/universal/autogen_trampolines.h +++ b/hpy/devel/include/universal/autogen_trampolines.h @@ -490,8 +490,8 @@ static inline HPyUnicodeBuilder HPyUnicodeBuilder_New(HPyContext *ctx, HPy_ssize return ctx->ctx_UnicodeBuilder_New ( ctx, size ); } -static inline int HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) { - return ctx->ctx_UnicodeBuilder_Add ( ctx, builder, h_item ); +static inline int HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, const char *item) { + return ctx->ctx_UnicodeBuilder_Add ( ctx, builder, item ); } static inline HPy HPyUnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder) { diff --git a/hpy/devel/src/runtime/ctx_unicodebuilder.c b/hpy/devel/src/runtime/ctx_unicodebuilder.c index 5716b3652..ea96f3ba7 100644 --- a/hpy/devel/src/runtime/ctx_unicodebuilder.c +++ b/hpy/devel/src/runtime/ctx_unicodebuilder.c @@ -1,4 +1,5 @@ #include +#include #include #include "hpy.h" @@ -7,12 +8,12 @@ # include "handles.h" #endif -static const Py_ssize_t HPYUNICODEBUILDER_INITIAL_CAPACITY = 5; +static const Py_ssize_t HPYUNICODEBUILDER_INITIAL_CAPACITY = 1024; typedef struct { Py_ssize_t capacity; // allocated handles - Py_ssize_t length; // used handles - PyObject *list; + Py_ssize_t length; + char *buf; } _PyUnicodeBuilder_s; #ifdef HPY_UNIVERSAL_ABI @@ -36,9 +37,10 @@ ctx_UnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t capacity) { _PyUnicodeBuilder_s *bp; if (capacity == 0) { + // TODO: default value or raise a ValueError? capacity = HPYUNICODEBUILDER_INITIAL_CAPACITY; } - capacity++; // always reserve space for an extra handle, see the docs, analogue to HPyTracker + capacity++; // always reserve space for the trailing 0 bp = malloc(sizeof(_PyUnicodeBuilder_s)); if (bp == NULL) { @@ -46,34 +48,37 @@ ctx_UnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t capacity) return _pb2hb(0); } - bp->list = PyList_New(capacity); - if (bp->list == NULL) { + bp->buf = calloc(1, capacity); + if (bp == NULL) { free(bp); HPyErr_NoMemory(ctx); return _pb2hb(0); } + bp->capacity = capacity; bp->length = 0; return _pb2hb(bp); } _HPy_HIDDEN int -ctx_UnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) +ctx_UnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, const char *item) { - if(!HPyUnicode_Check(ctx, h_item)) { - HPyErr_SetString(ctx, ctx->h_TypeError, "Argument must be of type HPyUnicode"); - return -1; - } - _PyUnicodeBuilder_s *bp = _hb2pb(builder); - PyObject *item = _h2py(h_item); - - // XXX: For the initial PoC we don't care about reallocation - if (bp->capacity <= bp->length) { - return -1; + // TODO: Should we trust the user to submit a 0 terminated string? + // The alternative would be to use strnlen and have a maximum allowed length for s + int len = strlen(item); + if(bp->length + len >= bp->capacity) { + // TODO: Have a better reallocation strategy + int new_size = bp->capacity + len + 1; + bp->buf = realloc(bp->buf, new_size); + if(bp->buf == NULL) { + free(bp); + HPyErr_NoMemory(ctx); + return -1; + } } - Py_INCREF(item); - PyList_SET_ITEM(bp->list, bp->length++, item); + strncpy((bp->buf + bp->length), item, (bp->capacity - bp->length)); + bp->length += len; return 0; } @@ -81,27 +86,16 @@ _HPy_HIDDEN HPy ctx_UnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder) { _PyUnicodeBuilder_s *bp = _hb2pb(builder); - PyObject *list = PyList_GetSlice(bp->list, 0, bp->length); - - PyObject *sep = PyUnicode_FromString(""); - PyObject *str = PyUnicode_Join(sep, list); - Py_XDECREF(sep); - - if(str == NULL) { - PyErr_NoMemory(); - return HPy_NULL; - } - - Py_XDECREF(bp->list); - Py_XDECREF(list); + HPy h_result = HPyUnicode_FromString(ctx, bp->buf); + free(bp->buf); free(bp); - return _py2h(str); + return h_result; } _HPy_HIDDEN void ctx_UnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder) { _PyUnicodeBuilder_s *bp = _hb2pb(builder); - Py_XDECREF(bp->list); + free(bp->buf); free(bp); } diff --git a/hpy/tools/autogen/public_api.h b/hpy/tools/autogen/public_api.h index f77c951b5..d68bf0994 100644 --- a/hpy/tools/autogen/public_api.h +++ b/hpy/tools/autogen/public_api.h @@ -284,7 +284,7 @@ HPy HPyListBuilder_Build(HPyContext *ctx, HPyListBuilder builder); void HPyListBuilder_Cancel(HPyContext *ctx, HPyListBuilder builder); HPyUnicodeBuilder HPyUnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t size); -int HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item); +int HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, const char *item); HPy HPyUnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder); void HPyUnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder); diff --git a/test/test_hpyunicodebuilder.py b/test/test_hpyunicodebuilder.py index 6b30285d1..8bb1f9c4d 100644 --- a/test/test_hpyunicodebuilder.py +++ b/test/test_hpyunicodebuilder.py @@ -3,49 +3,21 @@ class TestString(HPyTest): def test_unicode_builder(self): mod = self.make_module(""" - HPyDef_METH(f, "f", f_impl, HPyFunc_O) - static HPy f_impl(HPyContext *ctx, HPy h_self, HPy h_arg) + HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS) + static HPy f_impl(HPyContext *ctx, HPy h_self) { HPyUnicodeBuilder builder = HPyUnicodeBuilder_New(ctx, 0); if(HPy_IsNull(builder)) { HPyErr_SetString(ctx, ctx->h_RuntimeError, "Could not create HPyUnicodeBuilder"); return HPy_NULL; } - HPy h_s1 = HPyUnicode_FromString(ctx, "hello "); - HPy h_s2 = HPyUnicode_FromString(ctx, "!"); - HPyUnicodeBuilder_Add(ctx, builder, h_s1); - HPyUnicodeBuilder_Add(ctx, builder, h_arg); - HPyUnicodeBuilder_Add(ctx, builder, h_s2); + HPyUnicodeBuilder_Add(ctx, builder, "hello "); + HPyUnicodeBuilder_Add(ctx, builder, "world"); + HPyUnicodeBuilder_Add(ctx, builder, "!"); HPy h_string = HPyUnicodeBuilder_Build(ctx, builder); - HPy_Close(ctx, h_s1); - HPy_Close(ctx, h_s2); return h_string; } @EXPORT(f) @INIT """) - assert mod.f("world") == "hello world!" - - def test_type_error(self): - mod = self.make_module(""" - HPyDef_METH(f, "f", f_impl, HPyFunc_O) - static HPy f_impl(HPyContext *ctx, HPy h_self, HPy h_arg) - { - HPyUnicodeBuilder builder = HPyUnicodeBuilder_New(ctx, 0); - if(HPy_IsNull(builder)) { - HPyErr_SetString(ctx, ctx->h_RuntimeError, "Could not create HPyUnicodeBuilder"); - return HPy_NULL; - } - HPy h_long = HPyLong_FromLong(ctx, 42); - HPyUnicodeBuilder_Add(ctx, builder, h_long); - HPy_Close(ctx, h_long); - HPyUnicodeBuilder_Cancel(ctx, builder); - return HPy_NULL; - } - @EXPORT(f) - @INIT - """) - import pytest - with pytest.raises(TypeError) as exc_info: - mod.f("world") - assert exc_info.match("Argument must be of type HPyUnicode") + assert mod.f() == "hello world!"