pk_core: implement list addition

This commit implements list addition. A new list is allocated, and
the contents of l1 and l2 are concatenated onto the list.

This is done by extending the buffer template macro to support a
`concat` operation, which given an `other` buffer, appends all
elements of the `other` buffer to the end of the `self` buffer.
Allocations are done as needed.

We implement this additional operation, since the alternative would
be to call `reserve()` for each `write()` operation, which doesn't
seem ideal.

Issue: #55
This commit is contained in:
Alexander Patel 2021-06-15 20:36:25 -07:00
parent 5f6f66517f
commit 59333177cd
5 changed files with 45 additions and 7 deletions

View File

@ -37,13 +37,17 @@
/* Fill the buffer at the end of it with provided data if the capacity */ \
/* isn't enough using VM's realloc function. */ \
void pk##m_name##BufferFill(pk##m_name##Buffer* self, PKVM* vm, \
m_type data, int count); \
m_type data, int count); \
\
/* Write to the buffer with provided data at the end of the buffer.*/ \
void pk##m_name##BufferWrite(pk##m_name##Buffer* self, \
PKVM* vm, m_type data); \
PKVM* vm, m_type data); \
\
/* Concatenate the contents of another buffer at the end of this buffer.*/ \
void pk##m_name##BufferConcat(pk##m_name##Buffer* self, PKVM* vm, \
pk##m_name##Buffer* other); \
// The buffer "template" implementation of diferent types.
// The buffer "template" implementation of different types.
#define DEFINE_BUFFER(m_name, m_type) \
void pk##m_name##BufferInit(pk##m_name##Buffer* self) { \
self->data = NULL; \
@ -71,7 +75,7 @@
} \
\
void pk##m_name##BufferFill(pk##m_name##Buffer* self, PKVM* vm, \
m_type data, int count) { \
m_type data, int count) { \
\
pk##m_name##BufferReserve(self, vm, self->count + count); \
\
@ -81,8 +85,18 @@
} \
\
void pk##m_name##BufferWrite(pk##m_name##Buffer* self, \
PKVM* vm, m_type data) { \
PKVM* vm, m_type data) { \
pk##m_name##BufferFill(self, vm, data, 1); \
} \
\
void pk##m_name##BufferConcat(pk##m_name##Buffer* self, PKVM* vm, \
pk##m_name##Buffer* other) { \
pk##m_name##BufferReserve(self, vm, self->count + other->count); \
\
memcpy(self->data + self->count, \
other->data, \
other->count * sizeof(m_type)); \
self->count += other->count; \
}
#endif // BUFFERS_TEMPLATE_H

View File

@ -1068,8 +1068,7 @@ Var varAdd(PKVM* vm, Var v1, Var v2) {
case OBJ_LIST:
{
if (o2->type == OBJ_LIST) {
List* l1 = (List*)o1, * l2 = (List*)o2;
TODO;
return VAR_OBJ(listJoin(vm, (List*)o1, (List*)o2));
}
} break;

View File

@ -1272,6 +1272,23 @@ String* stringJoin(PKVM* vm, String* str1, String* str2) {
return string;
}
List* listJoin(PKVM* vm, List* l1, List* l2) {
// Optimize end case.
if (l1->elements.count == 0) return l2;
if (l2->elements.count == 0) return l1;
size_t size = (size_t)l1->elements.count + (size_t)l2->elements.count;
List* list = newList(vm, size);
vmPushTempRef(vm, &list->_super);
pkVarBufferConcat(&list->elements, vm, &l1->elements);
pkVarBufferConcat(&list->elements, vm, &l2->elements);
vmPopTempRef(vm);
return list;
}
uint32_t scriptAddName(Script* self, PKVM* vm, const char* name,
uint32_t length) {

View File

@ -548,6 +548,9 @@ String* stringFormat(PKVM* vm, const char* fmt, ...);
// Which would be faster than using "@@" format.
String* stringJoin(PKVM* vm, String* str1, String* str2);
// Create a new list by joining the 2 given list and return the result.
List* listJoin(PKVM* vm, List* l1, List* l2);
// Add the name (string literal) to the string buffer if not already exists and
// return it's index in the buffer.
uint32_t scriptAddName(Script* self, PKVM* vm, const char* name,

View File

@ -21,6 +21,11 @@ assert(0xffffffffffffffff == 18446744073709551615)
l1 = [1, false, null, func print('hello') end]
assert(is_null(l1[2]))
l1[1] = true; assert(l1[1])
l1 = [] + [] ; assert(l1.length == 0)
l1 = [] + [1]; assert(l1.length == 1); assert(l1[0] == 1)
l1 = [1] + []; assert(l1.length == 1); assert(l1[0] == 1)
l2 = l1 + [1,2,3]; assert(l2.length == 4); assert(l2 == [1,1,2,3])
l3 = l2 + l1 + l2; assert(l3 == [1,1,2,3,1,1,1,2,3])
## Builtin functions tests.
assert(to_string(42) == '42')