From 59333177cd4ddc52a5c6826730ed20dc436fa0d8 Mon Sep 17 00:00:00 2001 From: Alexander Patel Date: Tue, 15 Jun 2021 20:36:25 -0700 Subject: [PATCH] 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 --- src/pk_buffers.h | 24 +++++++++++++++++++----- src/pk_core.c | 3 +-- src/pk_var.c | 17 +++++++++++++++++ src/pk_var.h | 3 +++ tests/lang/basics.pk | 5 +++++ 5 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/pk_buffers.h b/src/pk_buffers.h index 901383b..ba1379f 100644 --- a/src/pk_buffers.h +++ b/src/pk_buffers.h @@ -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 diff --git a/src/pk_core.c b/src/pk_core.c index e2e9058..ba150ed 100644 --- a/src/pk_core.c +++ b/src/pk_core.c @@ -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; diff --git a/src/pk_var.c b/src/pk_var.c index 021a817..e189b40 100644 --- a/src/pk_var.c +++ b/src/pk_var.c @@ -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) { diff --git a/src/pk_var.h b/src/pk_var.h index 2e22cbf..8b6dca4 100644 --- a/src/pk_var.h +++ b/src/pk_var.h @@ -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, diff --git a/tests/lang/basics.pk b/tests/lang/basics.pk index b802bf6..c197c4f 100644 --- a/tests/lang/basics.pk +++ b/tests/lang/basics.pk @@ -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')