Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
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
4 changes: 2 additions & 2 deletions mypy/typeshed/stubs/librt/librt/vecs.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ T = TypeVar("T")

class vec(Generic[T]):
@overload
def __init__(self) -> None: ...
def __init__(self, *, capacity: i64 = ...) -> None: ...
@overload
def __init__(self, items: Iterable[T], /) -> None: ...
def __init__(self, items: Iterable[T], /, *, capacity: i64 = ...) -> None: ...
def __len__(self) -> i64: ...
@overload
def __getitem__(self, i: i64, /) -> T: ...
Expand Down
47 changes: 36 additions & 11 deletions mypyc/irbuild/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,10 +364,20 @@ def transform_call_expr(builder: IRBuilder, expr: CallExpr) -> Value:
):
item_type = builder.type_to_rtype(analyzed.types[0])
vec_type = RVec(item_type)
if len(expr.args) == 0:
return vec_create(builder.builder, vec_type, 0, expr.line)
elif len(expr.args) == 1 and expr.arg_kinds == [ARG_POS]:
return translate_vec_create_from_iterable(builder, vec_type, expr.args[0])
capacity = _get_vec_capacity(builder, expr)
if len(expr.args) == 0 or (len(expr.args) == 1 and expr.arg_kinds == [ARG_NAMED]):
# vec[T]() or vec[T](capacity=N)
return vec_create(builder.builder, vec_type, 0, expr.line, capacity=capacity)
elif (
len(expr.args) == 1
and expr.arg_kinds == [ARG_POS]
or len(expr.args) == 2
and expr.arg_kinds == [ARG_POS, ARG_NAMED]
Comment on lines +372 to +375
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formatting makes this expression a little confusing. add parenthesis so it's `elif ((... and ...) or (... and ...))?

):
# vec[T](items) or vec[T](items, capacity=N)
return translate_vec_create_from_iterable(
builder, vec_type, expr.args[0], capacity=capacity
)
callee = analyzed.expr # Unwrap type application

if isinstance(callee, MemberExpr):
Expand Down Expand Up @@ -561,8 +571,16 @@ def translate_super_method_call(builder: IRBuilder, expr: CallExpr, callee: Supe
return builder.builder.call(decl, arg_values, arg_kinds, arg_names, expr.line)


def _get_vec_capacity(builder: IRBuilder, expr: CallExpr) -> Value | None:
"""Extract the 'capacity' keyword argument value from a vec() call, or None."""
for i, (kind, name) in enumerate(zip(expr.arg_kinds, expr.arg_names)):
if kind == ARG_NAMED and name == "capacity":
return builder.accept(expr.args[i])
return None


def translate_vec_create_from_iterable(
builder: IRBuilder, vec_type: RVec, arg: Expression
builder: IRBuilder, vec_type: RVec, arg: Expression, *, capacity: Value | None = None
) -> Value:
line = arg.line
item_type = vec_type.item_type
Expand All @@ -581,28 +599,35 @@ def translate_vec_create_from_iterable(
if is_int64_rprimitive(other_type) or is_int_rprimitive(other_type):
length = builder.accept(other)
init = builder.accept(lst.items[0])
return vec_create_initialized(builder.builder, vec_type, length, init, line)
return vec_create_initialized(
builder.builder, vec_type, length, init, line, capacity=capacity
)
assert False, other_type
if isinstance(arg, ListExpr):
items = []
for item in arg.items:
value = builder.accept(item)
items.append(builder.coerce(value, item_type, line))
return vec_create_from_values(builder.builder, vec_type, items, line)
return vec_create_from_values(builder.builder, vec_type, items, line, capacity=capacity)
if isinstance(arg, ListComprehension):
return translate_vec_comprehension(builder, vec_type, arg.generator)
return vec_from_iterable(builder, vec_type, arg, line)
return translate_vec_comprehension(builder, vec_type, arg.generator, capacity=capacity)
return vec_from_iterable(builder, vec_type, arg, line, capacity=capacity)


def vec_from_iterable(
builder: IRBuilder, vec_type: RVec, iterable: Expression, line: int
builder: IRBuilder,
vec_type: RVec,
iterable: Expression,
line: int,
*,
capacity: Value | None = None,
) -> Value:
"""Construct a vec from an arbitrary iterable."""
# Translate it as a vec comprehension vec[t]([<name> for <name> in
# iterable]). This way we can use various special casing supported
# by for loops and comprehensions.
vec = Register(vec_type)
builder.assign(vec, vec_create(builder.builder, vec_type, 0, line), line)
builder.assign(vec, vec_create(builder.builder, vec_type, 0, line, capacity=capacity), line)
name = f"___tmp_{line}"
var = Var(name)
reg = builder.add_local(var, vec_type.item_type)
Expand Down
10 changes: 7 additions & 3 deletions mypyc/irbuild/for_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,9 @@ def gen_inner_stmts() -> None:
return builder.read(set_ops, gen.line)


def translate_vec_comprehension(builder: IRBuilder, vec_type: RVec, gen: GeneratorExpr) -> Value:
def translate_vec_comprehension(
builder: IRBuilder, vec_type: RVec, gen: GeneratorExpr, *, capacity: Value | None = None
) -> Value:
def set_item(x: Value, y: Value, z: Value, line: int) -> None:
vec_init_item_unsafe(builder.builder, x, y, z, line)

Expand All @@ -372,15 +374,17 @@ def set_item(x: Value, y: Value, z: Value, line: int) -> None:
builder,
gen,
empty_op_llbuilder=lambda length, line: vec_create(
builder.builder, vec_type, length, line
builder.builder, vec_type, length, line, capacity=capacity
),
set_item_op=set_item,
)
if val is not None:
return val

vec = Register(vec_type)
builder.assign(vec, vec_create(builder.builder, vec_type, 0, gen.line), gen.line)
builder.assign(
vec, vec_create(builder.builder, vec_type, 0, gen.line, capacity=capacity), gen.line
)
loop_params = list(zip(gen.indices, gen.sequences, gen.condlists, gen.is_async))

def gen_inner_stmts() -> None:
Expand Down
38 changes: 30 additions & 8 deletions mypyc/irbuild/vec.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,28 @@ def as_platform_int(builder: LowLevelIRBuilder, v: Value, line: int) -> Value:
return builder.coerce(v, c_pyssize_t_rprimitive, line)


def vec_create(builder: LowLevelIRBuilder, vtype: RVec, length: int | Value, line: int) -> Value:
def vec_create(
builder: LowLevelIRBuilder,
vtype: RVec,
length: int | Value,
line: int,
*,
capacity: Value | None = None,
) -> Value:
if isinstance(length, int):
length = Integer(length, c_pyssize_t_rprimitive)
length = as_platform_int(builder, length, line)
if capacity is not None:
capacity = as_platform_int(builder, capacity, line)
else:
capacity = length

item_type = vtype.item_type
api_name = vec_api_by_item_type.get(item_type)
if api_name is not None:
call = CallC(
f"{api_name}.alloc",
[length, length],
[length, capacity],
vtype,
False,
False,
Expand All @@ -110,7 +121,7 @@ def vec_create(builder: LowLevelIRBuilder, vtype: RVec, length: int | Value, lin
if depth == 0:
call = CallC(
"VecTApi.alloc",
[length, length, typeval],
[length, capacity, typeval],
vtype,
False,
False,
Expand All @@ -121,7 +132,7 @@ def vec_create(builder: LowLevelIRBuilder, vtype: RVec, length: int | Value, lin
else:
call = CallC(
"VecNestedApi.alloc",
[length, length, typeval, Integer(depth, int32_rprimitive)],
[length, capacity, typeval, Integer(depth, int32_rprimitive)],
vtype,
False,
False,
Expand All @@ -134,7 +145,13 @@ def vec_create(builder: LowLevelIRBuilder, vtype: RVec, length: int | Value, lin


def vec_create_initialized(
builder: LowLevelIRBuilder, vtype: RVec, length: int | Value, init: Value, line: int
builder: LowLevelIRBuilder,
vtype: RVec,
length: int | Value,
init: Value,
line: int,
*,
capacity: Value | None = None,
) -> Value:
"""Create vec with items initialized to the given value."""
if isinstance(length, int):
Expand All @@ -143,7 +160,7 @@ def vec_create_initialized(

item_type = vtype.item_type
init = builder.coerce(init, item_type, line)
vec = vec_create(builder, vtype, length, line)
vec = vec_create(builder, vtype, length, line, capacity=capacity)

items_start = vec_items(builder, vec)
step = step_size(item_type)
Expand All @@ -160,9 +177,14 @@ def vec_create_initialized(


def vec_create_from_values(
builder: LowLevelIRBuilder, vtype: RVec, values: list[Value], line: int
builder: LowLevelIRBuilder,
vtype: RVec,
values: list[Value],
line: int,
*,
capacity: Value | None = None,
) -> Value:
vec = vec_create(builder, vtype, len(values), line)
vec = vec_create(builder, vtype, len(values), line, capacity=capacity)
ptr = vec_items(builder, vec)
item_type = vtype.item_type
step = step_size(item_type)
Expand Down
17 changes: 11 additions & 6 deletions mypyc/lib-rt/vecs/librt_vecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,29 +96,34 @@ typedef struct {

static PyObject *vec_generic_alias_call(PyObject *self, PyObject *args, PyObject *kw)
{
static char *kwlist[] = {"", NULL};
static char *kwlist[] = {"", "capacity", NULL};
PyObject *init = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw, "|O:vec", kwlist, &init)) {
int64_t cap = 0;
if (!PyArg_ParseTupleAndKeywords(args, kw, "|OL:vec", kwlist, &init, &cap)) {
return NULL;
}
if (cap < 0) {
PyErr_SetString(PyExc_ValueError, "capacity must not be negative");
return NULL;
}
VecGenericAlias *p = (VecGenericAlias *)self;
if (p->depth == 0) {
if (init == NULL) {
VecT vec = VecT_New(0, 0, p->item_type);
VecT vec = VecT_New(0, cap, p->item_type);
if (VEC_IS_ERROR(vec))
return NULL;
return VecT_Box(vec, p->item_type);
} else {
return VecT_FromIterable(p->item_type, init);
return VecT_FromIterable(p->item_type, init, cap);
}
} else {
if (init == NULL) {
VecNested vec = VecNested_New(0, 0, p->item_type, p->depth);
VecNested vec = VecNested_New(0, cap, p->item_type, p->depth);
if (VEC_IS_ERROR(vec))
return NULL;
return VecNested_Box(vec);
} else {
return VecNested_FromIterable(p->item_type, p->depth, init);
return VecNested_FromIterable(p->item_type, p->depth, init, cap);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions mypyc/lib-rt/vecs/librt_vecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ static inline int VecT_ItemCheck(VecT v, PyObject *item, size_t item_type) {
}

VecT VecT_New(Py_ssize_t size, Py_ssize_t cap, size_t item_type);
PyObject *VecT_FromIterable(size_t item_type, PyObject *iterable);
PyObject *VecT_FromIterable(size_t item_type, PyObject *iterable, int64_t cap);
PyObject *VecT_Box(VecT vec, size_t item_type);
VecT VecT_Append(VecT vec, PyObject *x, size_t item_type);
VecT VecT_Remove(VecT vec, PyObject *x);
Expand All @@ -726,7 +726,7 @@ static inline int VecNested_Check(PyObject *o) {
}

VecNested VecNested_New(Py_ssize_t size, Py_ssize_t cap, size_t item_type, size_t depth);
PyObject *VecNested_FromIterable(size_t item_type, size_t depth, PyObject *iterable);
PyObject *VecNested_FromIterable(size_t item_type, size_t depth, PyObject *iterable, int64_t cap);
PyObject *VecNested_Box(VecNested);
VecNested VecNested_Append(VecNested vec, VecNestedBufItem x);
VecNested VecNested_Remove(VecNested vec, VecNestedBufItem x);
Expand Down
14 changes: 12 additions & 2 deletions mypyc/lib-rt/vecs/vec_nested.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ VecNested VecNested_ConvertFromNested(VecNestedBufItem item) {
}

VecNested VecNested_New(Py_ssize_t size, Py_ssize_t cap, size_t item_type, size_t depth) {
if (cap < 0) {
PyErr_SetString(PyExc_ValueError, "capacity must not be negative");
return vec_error();
}
if (cap < size)
cap = size;
VecNested vec = vec_alloc(cap, item_type, depth);
Expand Down Expand Up @@ -564,10 +568,16 @@ PyTypeObject VecNestedType = {
// TODO: free
};

PyObject *VecNested_FromIterable(size_t item_type, size_t depth, PyObject *iterable) {
VecNested v = vec_alloc(0, item_type, depth);
PyObject *VecNested_FromIterable(size_t item_type, size_t depth, PyObject *iterable, int64_t cap) {
VecNested v = vec_alloc(cap > 0 ? cap : 0, item_type, depth);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could remove the ternary expression here and just pass cap i think since cap < 0 is rejected before FromIterable is called. same in other FromIterable functions.

if (VEC_IS_ERROR(v))
return NULL;
if (cap > 0) {
for (int64_t i = 0; i < cap; i++) {
v.buf->items[i].len = -1;
v.buf->items[i].buf = NULL;
}
}
v.len = 0;

PyObject *iter = PyObject_GetIter(iterable);
Expand Down
12 changes: 10 additions & 2 deletions mypyc/lib-rt/vecs/vec_t.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ VecT VecT_ConvertFromNested(VecNestedBufItem item) {
}

VecT VecT_New(Py_ssize_t size, Py_ssize_t cap, size_t item_type) {
if (cap < 0) {
PyErr_SetString(PyExc_ValueError, "capacity must not be negative");
return vec_error();
}
if (cap < size)
cap = size;
VecT vec = vec_alloc(cap, item_type);
Expand Down Expand Up @@ -557,10 +561,14 @@ PyTypeObject VecTType = {
// TODO: free
};

PyObject *VecT_FromIterable(size_t item_type, PyObject *iterable) {
VecT v = vec_alloc(0, item_type);
PyObject *VecT_FromIterable(size_t item_type, PyObject *iterable, int64_t cap) {
VecT v = vec_alloc(cap > 0 ? cap : 0, item_type);
if (VEC_IS_ERROR(v))
return NULL;
if (cap > 0) {
for (int64_t i = 0; i < cap; i++)
v.buf->items[i] = NULL;
}
v.len = 0;

PyObject *iter = PyObject_GetIter(iterable);
Expand Down
26 changes: 19 additions & 7 deletions mypyc/lib-rt/vecs/vec_template.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,12 @@ VEC FUNC(ConvertFromNested)(VecNestedBufItem item) {
}

VEC FUNC(New)(Py_ssize_t size, Py_ssize_t cap) {
if (cap < 0) {
PyErr_SetString(PyExc_ValueError, "capacity must not be negative");
return vec_error();
}
if (cap < size)
size = cap;
cap = size;
VEC vec = vec_alloc(cap);
if (VEC_IS_ERROR(vec))
return vec;
Expand All @@ -96,10 +100,13 @@ VEC FUNC(New)(Py_ssize_t size, Py_ssize_t cap) {
return vec;
}

PyObject *FUNC(FromIterable)(PyObject *iterable) {
VEC v = vec_alloc(0);
PyObject *FUNC(FromIterable)(PyObject *iterable, int64_t cap) {
VEC v = vec_alloc(cap > 0 ? cap : 0);
if (VEC_IS_ERROR(v))
return NULL;
if (cap > 0) {
memset(v.buf->items, 0, sizeof(ITEM_C_TYPE) * cap);
}
v.len = 0;

PyObject *iter = PyObject_GetIter(iterable);
Expand Down Expand Up @@ -132,15 +139,20 @@ PyObject *FUNC(FromIterable)(PyObject *iterable) {
}

static PyObject *vec_new(PyTypeObject *self, PyObject *args, PyObject *kw) {
static char *kwlist[] = {"", NULL};
static char *kwlist[] = {"", "capacity", NULL};
PyObject *init = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw, "|O:vec", kwlist, &init)) {
int64_t cap = 0;
if (!PyArg_ParseTupleAndKeywords(args, kw, "|OL:vec", kwlist, &init, &cap)) {
return NULL;
}
if (cap < 0) {
PyErr_SetString(PyExc_ValueError, "capacity must not be negative");
return NULL;
}
if (init == NULL) {
return FUNC(Box)(FUNC(New)(0, 0));
return FUNC(Box)(FUNC(New)(0, cap));
} else {
return (PyObject *)FUNC(FromIterable)(init);
return (PyObject *)FUNC(FromIterable)(init, cap);
}
}

Expand Down
Loading
Loading