Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request for Comments: Added UnicodeBuilder #205

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions hpy/debug/src/autogen_debug_ctx_init.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions hpy/debug/src/autogen_debug_wrappers.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions hpy/devel/include/common/runtime/ctx_unicodebuilder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifndef HPY_COMMON_RUNTIME_UNICODEBUILDER_H
#define HPY_COMMON_RUNTIME_UNICODEBUILDER_H

#include <Python.h>
#include "hpy.h"
#include "common/hpytype.h"


_HPy_HIDDEN HPyUnicodeBuilder ctx_UnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t capacity);
_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);


#endif /* HPY_COMMON_RUNTIME_UNICODEBUILDER_H */
26 changes: 26 additions & 0 deletions hpy/devel/include/cpython/hpy.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ typedef struct { PyObject *_o; } HPy;
typedef struct { Py_ssize_t _lst; } HPyListBuilder;
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;

Expand Down Expand Up @@ -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_unicodebuilder.h"
#include "../common/runtime/ctx_tracker.h"
#include "../common/runtime/ctx_tuple.h"
#include "../common/runtime/ctx_tuplebuilder.h"
Expand Down Expand Up @@ -433,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, const char *item)
{
return ctx_UnicodeBuilder_Add(ctx, builder, 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 */
4 changes: 4 additions & 0 deletions hpy/devel/include/universal/autogen_ctx.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions hpy/devel/include/universal/autogen_trampolines.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions hpy/devel/include/universal/hpy.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ typedef struct _HPy_s { HPy_ssize_t _i; } HPy;
typedef struct { HPy_ssize_t _lst; } HPyListBuilder;
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;

Expand Down
101 changes: 101 additions & 0 deletions hpy/devel/src/runtime/ctx_unicodebuilder.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#include <stddef.h>
#include <string.h>
#include <Python.h>
#include "hpy.h"

#ifdef HPY_UNIVERSAL_ABI
// for _h2py and _py2h
# include "handles.h"
#endif

static const Py_ssize_t HPYUNICODEBUILDER_INITIAL_CAPACITY = 1024;

typedef struct {
Py_ssize_t capacity; // allocated handles
Py_ssize_t length;
char *buf;
} _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, 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 the trailing 0

bp = malloc(sizeof(_PyUnicodeBuilder_s));
if (bp == NULL) {
HPyErr_NoMemory(ctx);
return _pb2hb(0);
}

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, const char *item)
{
_PyUnicodeBuilder_s *bp = _hb2pb(builder);
// 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;
}
}
strncpy((bp->buf + bp->length), item, (bp->capacity - bp->length));
bp->length += len;
return 0;
}

_HPy_HIDDEN HPy
ctx_UnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder)
{
_PyUnicodeBuilder_s *bp = _hb2pb(builder);
HPy h_result = HPyUnicode_FromString(ctx, bp->buf);
free(bp->buf);
free(bp);
return h_result;
}

_HPy_HIDDEN void
ctx_UnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder)
{
_PyUnicodeBuilder_s *bp = _hb2pb(builder);
free(bp->buf);
free(bp);
}
4 changes: 4 additions & 0 deletions hpy/tools/autogen/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,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,
Expand Down
6 changes: 6 additions & 0 deletions hpy/tools/autogen/public_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ typedef int size_t;
typedef int HPyFunc_Signature;
typedef int cpy_PyObject;
typedef int HPyListBuilder;
typedef int HPyUnicodeBuilder;
typedef int HPyTupleBuilder;
typedef int HPyTracker;
typedef int HPy_RichCmpOp;
Expand Down Expand Up @@ -282,6 +283,11 @@ 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, HPy_ssize_t size);
int HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, const char *item);
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,
HPy_ssize_t index, HPy h_item);
Expand Down
4 changes: 4 additions & 0 deletions hpy/universal/src/autogen_ctx_def.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions hpy/universal/src/ctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_unicodebuilder.h"
#include "common/runtime/ctx_tracker.h"
#include "common/runtime/ctx_tuple.h"
#include "common/runtime/ctx_tuplebuilder.h"
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def get_scm_config():
'hpy/devel/src/runtime/ctx_listbuilder.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',
Expand Down
23 changes: 23 additions & 0 deletions test/test_hpyunicodebuilder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from .support import HPyTest

class TestString(HPyTest):
def test_unicode_builder(self):
mod = self.make_module("""
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;
}
HPyUnicodeBuilder_Add(ctx, builder, "hello ");
HPyUnicodeBuilder_Add(ctx, builder, "world");
HPyUnicodeBuilder_Add(ctx, builder, "!");
HPy h_string = HPyUnicodeBuilder_Build(ctx, builder);
return h_string;
}
@EXPORT(f)
@INIT
""")
assert mod.f() == "hello world!"