Skip to content

Commit 68df196

Browse files
committed
Changed UnicodeBuilders to operate on a c string instead of a list of Python strings
1 parent cd4c539 commit 68df196

File tree

9 files changed

+44
-79
lines changed

9 files changed

+44
-79
lines changed

hpy/debug/src/autogen_debug_ctx_init.h

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

hpy/debug/src/autogen_debug_wrappers.c

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

hpy/devel/include/common/runtime/ctx_unicodebuilder.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77

88

99
_HPy_HIDDEN HPyUnicodeBuilder ctx_UnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t capacity);
10-
_HPy_HIDDEN int ctx_UnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder,
11-
HPy h_item);
10+
_HPy_HIDDEN int ctx_UnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, const char *item);
1211
_HPy_HIDDEN HPy ctx_UnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder);
1312
_HPy_HIDDEN void ctx_UnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder);
1413

hpy/devel/include/cpython/hpy.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -442,9 +442,9 @@ HPyUnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t size)
442442
}
443443

444444
HPyAPI_FUNC(int)
445-
HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item)
445+
HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, const char *item)
446446
{
447-
return ctx_UnicodeBuilder_Add(ctx, builder, h_item);
447+
return ctx_UnicodeBuilder_Add(ctx, builder, item);
448448
}
449449

450450
HPyAPI_FUNC(HPy)

hpy/devel/include/universal/autogen_ctx.h

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

hpy/devel/include/universal/autogen_trampolines.h

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+28-34
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <stddef.h>
2+
#include <string.h>
23
#include <Python.h>
34
#include "hpy.h"
45

@@ -7,12 +8,12 @@
78
# include "handles.h"
89
#endif
910

10-
static const Py_ssize_t HPYUNICODEBUILDER_INITIAL_CAPACITY = 5;
11+
static const Py_ssize_t HPYUNICODEBUILDER_INITIAL_CAPACITY = 1024;
1112

1213
typedef struct {
1314
Py_ssize_t capacity; // allocated handles
14-
Py_ssize_t length; // used handles
15-
PyObject *list;
15+
Py_ssize_t length;
16+
char *buf;
1617
} _PyUnicodeBuilder_s;
1718

1819
#ifdef HPY_UNIVERSAL_ABI
@@ -36,72 +37,65 @@ ctx_UnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t capacity)
3637
{
3738
_PyUnicodeBuilder_s *bp;
3839
if (capacity == 0) {
40+
// TODO: default value or raise a ValueError?
3941
capacity = HPYUNICODEBUILDER_INITIAL_CAPACITY;
4042
}
41-
capacity++; // always reserve space for an extra handle, see the docs, analogue to HPyTracker
43+
capacity++; // always reserve space for the trailing 0
4244

4345
bp = malloc(sizeof(_PyUnicodeBuilder_s));
4446
if (bp == NULL) {
4547
HPyErr_NoMemory(ctx);
4648
return _pb2hb(0);
4749
}
4850

49-
bp->list = PyList_New(capacity);
50-
if (bp->list == NULL) {
51+
bp->buf = malloc(capacity);
52+
if (bp == NULL) {
5153
free(bp);
5254
HPyErr_NoMemory(ctx);
5355
return _pb2hb(0);
5456
}
57+
5558
bp->capacity = capacity;
5659
bp->length = 0;
5760
return _pb2hb(bp);
5861
}
5962

6063
_HPy_HIDDEN int
61-
ctx_UnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item)
64+
ctx_UnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, const char *s)
6265
{
63-
if(!HPyUnicode_Check(ctx, h_item)) {
64-
HPyErr_SetString(ctx, ctx->h_TypeError, "Argument must be of type HPyUnicode");
65-
return -1;
66-
}
67-
6866
_PyUnicodeBuilder_s *bp = _hb2pb(builder);
69-
PyObject *item = _h2py(h_item);
70-
71-
// XXX: For the initial PoC we don't care about reallocation
72-
if (bp->capacity <= bp->length) {
73-
return -1;
67+
// TODO: Should we trust the user to submit a 0 terminated string?
68+
// The alternative would be to use strnlen and have a maximum allowed length for s
69+
int len = strlen(s);
70+
if(bp->length + length >= bp->capacity) {
71+
// TODO: Have a better reallocation strategy
72+
int new_size = bp->capacity + length + 1;
73+
bp->buf = realloc(bp->buf, new_size);
74+
if(bp->buf == NULL) {
75+
free(bp);
76+
HPyErr_NoMemory(ctx);
77+
return -1;
78+
}
7479
}
75-
Py_INCREF(item);
76-
PyList_SET_ITEM(bp->list, bp->length++, item);
80+
strncpy((bp->buf + bp->length), s, len);
81+
bp->length += len;
7782
return 0;
7883
}
7984

8085
_HPy_HIDDEN HPy
8186
ctx_UnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder)
8287
{
8388
_PyUnicodeBuilder_s *bp = _hb2pb(builder);
84-
PyObject *list = PyList_GetSlice(bp->list, 0, bp->length);
85-
86-
PyObject *sep = PyUnicode_FromString("");
87-
PyObject *str = PyUnicode_Join(sep, list);
88-
Py_XDECREF(sep);
89-
90-
if(str == NULL) {
91-
PyErr_NoMemory();
92-
return HPy_NULL;
93-
}
94-
95-
Py_XDECREF(bp->list);
96-
Py_XDECREF(list);
89+
HPy h_result = HPyUnicode_FromString(ctx, bp->buf);
90+
free(bp->buf);
9791
free(bp);
98-
return _py2h(str);
92+
return h_result;
9993
}
10094

10195
_HPy_HIDDEN void
10296
ctx_UnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder)
10397
{
10498
_PyUnicodeBuilder_s *bp = _hb2pb(builder);
105-
Py_XDECREF(bp->list);
99+
free(bp->buf);
106100
free(bp);
107101
}

hpy/tools/autogen/public_api.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ HPy HPyListBuilder_Build(HPyContext *ctx, HPyListBuilder builder);
284284
void HPyListBuilder_Cancel(HPyContext *ctx, HPyListBuilder builder);
285285

286286
HPyUnicodeBuilder HPyUnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t size);
287-
int HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item);
287+
int HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, const char *s);
288288
HPy HPyUnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder);
289289
void HPyUnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder);
290290

test/test_hpyunicodebuilder.py

+6-34
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,21 @@
33
class TestString(HPyTest):
44
def test_unicode_builder(self):
55
mod = self.make_module("""
6-
HPyDef_METH(f, "f", f_impl, HPyFunc_O)
7-
static HPy f_impl(HPyContext *ctx, HPy h_self, HPy h_arg)
6+
HPyDef_METH(f, "f", f_impl, HPyFunc_NOARGS)
7+
static HPy f_impl(HPyContext *ctx, HPy h_self)
88
{
99
HPyUnicodeBuilder builder = HPyUnicodeBuilder_New(ctx, 0);
1010
if(HPy_IsNull(builder)) {
1111
HPyErr_SetString(ctx, ctx->h_RuntimeError, "Could not create HPyUnicodeBuilder");
1212
return HPy_NULL;
1313
}
14-
HPy h_s1 = HPyUnicode_FromString(ctx, "hello ");
15-
HPy h_s2 = HPyUnicode_FromString(ctx, "!");
16-
HPyUnicodeBuilder_Add(ctx, builder, h_s1);
17-
HPyUnicodeBuilder_Add(ctx, builder, h_arg);
18-
HPyUnicodeBuilder_Add(ctx, builder, h_s2);
14+
HPyUnicodeBuilder_Add(ctx, builder, "hello ");
15+
HPyUnicodeBuilder_Add(ctx, builder, "world");
16+
HPyUnicodeBuilder_Add(ctx, builder, "!");
1917
HPy h_string = HPyUnicodeBuilder_Build(ctx, builder);
20-
HPy_Close(ctx, h_s1);
21-
HPy_Close(ctx, h_s2);
2218
return h_string;
2319
}
2420
@EXPORT(f)
2521
@INIT
2622
""")
27-
assert mod.f("world") == "hello world!"
28-
29-
def test_type_error(self):
30-
mod = self.make_module("""
31-
HPyDef_METH(f, "f", f_impl, HPyFunc_O)
32-
static HPy f_impl(HPyContext *ctx, HPy h_self, HPy h_arg)
33-
{
34-
HPyUnicodeBuilder builder = HPyUnicodeBuilder_New(ctx, 0);
35-
if(HPy_IsNull(builder)) {
36-
HPyErr_SetString(ctx, ctx->h_RuntimeError, "Could not create HPyUnicodeBuilder");
37-
return HPy_NULL;
38-
}
39-
HPy h_long = HPyLong_FromLong(ctx, 42);
40-
HPyUnicodeBuilder_Add(ctx, builder, h_long);
41-
HPy_Close(ctx, h_long);
42-
HPyUnicodeBuilder_Cancel(ctx, builder);
43-
return HPy_NULL;
44-
}
45-
@EXPORT(f)
46-
@INIT
47-
""")
48-
import pytest
49-
with pytest.raises(TypeError) as exc_info:
50-
mod.f("world")
51-
assert exc_info.match("Argument must be of type HPyUnicode")
23+
assert mod.f() == "hello world!"

0 commit comments

Comments
 (0)