Skip to content

Commit

Permalink
#341 fix issue pushing collections with complex element types
Browse files Browse the repository at this point in the history
SanderMertens committed Jul 4, 2018

Verified

This commit was signed with the committer’s verified signature.
TarikGul Tarik Gul
1 parent 3948dc2 commit a735ee3
Showing 2 changed files with 70 additions and 24 deletions.
26 changes: 21 additions & 5 deletions include/store/rw.h
Original file line number Diff line number Diff line change
@@ -36,15 +36,31 @@
* can be accessed. This "opens" the scope of the complex value, which
* allows iteration over the members/elements in that scope. It also will
* make field expressions relative to that scope. Pushing/popping scopes
* is analogous to the `()` and `[]` operators in cortoscript, as can be
* is analogous to the `{}` and `[]` operators in cortoscript, as can be
* seen in this example:
*
* `Line l = {start:{x:10, 20}, stop.x:30, stop.y:40}`
*
* In this example, each `{` corresponds with a push, and each `}`
* corresponds with a pop. The example also illustrates how to set single
* fields in nested scopes without pushing/popping. This can be done in
* the reader/writer API with the `field` function.
* This cortoscript example is equivalent to the following code:
*
```
corto_rw rw = corto_rw_init(Line_o, l_o);
corto_rw_push(&rw);
corto_rw_field(&rw, "start");
corto_rw_push(&rw);
corto_rw_field(&rw, "x");
corto_rw_set_int(&rw, 10);
corto_rw_next(&rw);
corto_rw_set_int(&rw, 20);
corto_rw_pop(&rw);
corto_rw_next(&rw);
corto_rw_field(&rw, "stop.x");
corto_rw_set_int(&rw, 30);
corto_rw_next(&rw); // not strictly necessary because the next call is rw_field
corto_rw_field(&rw, "stop.y");
corto_rw_set_int(&rw, 40);
corto_rw_pop(&rw);
```
*
* Note that this is an UNSTABLE API.
*/
68 changes: 49 additions & 19 deletions src/store/rw.c
Original file line number Diff line number Diff line change
@@ -29,13 +29,21 @@ bool corto_type_is_collection(
}

static
bool corto_type_is_complex(
bool corto_type_is_complex_nonref(
corto_type type)
{
return !type->reference &&
(type->kind == CORTO_COMPOSITE || type->kind == CORTO_COLLECTION);
}

static
bool corto_type_is_complex(
corto_type type)
{
return
(type->kind == CORTO_COMPOSITE || type->kind == CORTO_COLLECTION);
}

static
bool corto_type_is_growable(
corto_type type)
@@ -205,7 +213,7 @@ int32_t corto_rw_count(
corto_rw *this)
{
if (!this->current) {
if (corto_type_is_complex(this->rw_type)) {
if (corto_type_is_complex_nonref(this->rw_type)) {
/* Complex values have no values in the root scope */
return 0;
} else {
@@ -485,35 +493,35 @@ int16_t corto_rw_push(
corto_rw *this,
bool as_collection)
{
corto_type cur_type = NULL;
corto_type cur_type = NULL, cur_scope_type = NULL;
void *cur_ptr = NULL;
corto_rw_scope *scope = NULL;
bool is_collection = false;
cur_type = corto_rw_get_type(this);
bool is_complex = corto_type_is_complex(cur_type);

if (!this->current) {
cur_type = this->rw_type;
if (this->current) {
cur_scope_type = this->current->scope_type;
}

/* Ignore if the type is a reference type for the root scope */
if (cur_type->kind != CORTO_COMPOSITE &&
cur_type->kind != CORTO_COLLECTION)
{
corto_throw(
"cannot push scope for non-complex type '%s'", cur_type);
goto error;
}
} else {
cur_type = corto_rw_get_type(this);
if (!corto_type_is_complex(cur_type)) {
if (!is_complex) {
corto_throw(
"cannot open scope for non-complex type '%s'",
corto_fullpath(NULL, cur_type));
goto error;
} else if (is_complex && cur_type->reference) {
if (this->current) {
corto_throw(
"cannot push scope for non-complex type '%s'", cur_type);
"cannot open scope for reference type '%s'",
corto_fullpath(NULL, cur_type));
goto error;
}
}

is_collection = corto_type_is_collection(cur_type);

if (as_collection && !is_collection) {
corto_throw("cannot push scope of type '%s' as collection",
corto_throw("cannot open scope of non-collection type '%s' as collection",
corto_fullpath(NULL, cur_type));
goto error;
}
@@ -526,6 +534,23 @@ int16_t corto_rw_push(
cur_ptr = this->current->field.ptr;
}

/* If this is the first element to be pushed of a type that requires an
* allocation, create it. Subsequent elements will be created when the
* application calls corto_rw_next or equivalent. */
if (cur_scope_type && corto_type_is_collection(cur_scope_type)) {
corto_collection col_type = corto_collection(cur_scope_type);
if (col_type->kind != CORTO_ARRAY) {
if (!corto_rw_count(this) && corto_collection_requires_alloc(cur_type)) {
corto_rw_append(this);
cur_ptr = corto_rw_get_ptr(this);
}
} else if (!cur_ptr) {
/* If collection type is array, the pointer of the first element is
* equal to the pointer of the array */
cur_ptr = this->current->scope_ptr;
}
}

scope->scope_type = cur_type;
scope->scope_ptr = cur_ptr;
scope->parent = this->current;
@@ -653,7 +678,7 @@ int32_t corto_rw_get_index(
corto_rw *this)
{
if (!this->current) {
if (corto_type_is_complex(this->rw_type)) {
if (corto_type_is_complex_nonref(this->rw_type)) {
/* Indicate that index cannot be interpreted, as root scope doesn't
* have any complex values that can be initialized */
return -1;
@@ -700,6 +725,11 @@ uintptr_t corto_rw_set_value(
corto_type type = corto_rw_get_type(this);
void *ptr = corto_rw_get_ptr(this);

if (!ptr) {
corto_throw("no value to assign");
goto error;
}

corto_value field = corto_value_pointer(ptr, type);

if (corto_value_binaryOp(CORTO_ASSIGN, &field, value, NULL)) {

0 comments on commit a735ee3

Please sign in to comment.