Jelajahi Sumber

Added list.join() method and its unit test.

Marco Bambini 8 tahun lalu
induk
melakukan
ed10308edb
2 mengubah file dengan 58 tambahan dan 0 penghapusan
  1. 48 0
      src/runtime/gravity_core.c
  2. 10 0
      test/list_join.gravity

+ 48 - 0
src/runtime/gravity_core.c

@@ -762,6 +762,53 @@ static bool list_loop (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, ui
 	RETURN_VALUE(VALUE_FROM_INT(t2-t1), rindex);
 }
 
+static bool list_join (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+	gravity_list_t *list = VALUE_AS_LIST(GET_VALUE(0));
+	const char *sep = NULL;
+	if ((nargs > 1) && VALUE_ISA_STRING(GET_VALUE(1))) sep = VALUE_AS_CSTRING(GET_VALUE(1));
+	
+	// create a new empty buffer
+	uint32_t alloc = (uint32_t) (marray_size(list->array) * 64);
+	uint32_t len = 0;
+	uint32_t seplen = (sep) ? VALUE_AS_STRING(GET_VALUE(1))->len : 0;
+	char *buffer = mem_alloc(alloc);
+	assert(buffer);
+	
+	register gravity_int_t n = marray_size(list->array);
+	register gravity_int_t i = 0;
+	
+	// traverse list and append each item
+	while (i < n) {
+		gravity_value_t value = convert_value2string(vm, marray_get(list->array, i));
+		if (VALUE_ISA_ERROR(value)) RETURN_VALUE(value, rindex);
+		
+		const char *s2 = VALUE_AS_STRING(value)->s;
+		uint32_t req = VALUE_AS_STRING(value)->len;
+		uint32_t free = alloc - len;
+		
+		// check if buffer needs to be reallocated
+		if (free < req + seplen) {
+			buffer = mem_realloc(buffer, (alloc * 2) + req + seplen);
+			alloc += alloc + req + seplen;
+		}
+		
+		// copy s2 to into buffer
+		memcpy(buffer+len, s2, req);
+		len += req;
+		
+		// check for separator string
+		if (i+1 < n && seplen) {
+			memcpy(buffer+len, sep, seplen);
+			len += seplen;
+		}
+		
+		++i;
+	}
+	
+	gravity_string_t *result = gravity_string_new(vm, buffer, len, alloc);
+	RETURN_VALUE(VALUE_FROM_OBJECT(result), rindex);
+}
+
 // MARK: - Map Class -
 
 static bool map_count (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
@@ -1668,6 +1715,7 @@ static void gravity_core_init (void) {
 	gravity_class_bind(gravity_class_list, GRAVITY_INTERNAL_LOADAT_NAME, NEW_CLOSURE_VALUE(list_loadat));
 	gravity_class_bind(gravity_class_list, GRAVITY_INTERNAL_STOREAT_NAME, NEW_CLOSURE_VALUE(list_storeat));
 	gravity_class_bind(gravity_class_list, GRAVITY_INTERNAL_LOOP_NAME, NEW_CLOSURE_VALUE(list_loop));
+	gravity_class_bind(gravity_class_list, "join", NEW_CLOSURE_VALUE(list_join));
 	gravity_class_bind(gravity_class_list, "push", NEW_CLOSURE_VALUE(list_push));
 	gravity_class_bind(gravity_class_list, "pop", NEW_CLOSURE_VALUE(list_pop));
 	gravity_class_bind(gravity_class_list, "contains", NEW_CLOSURE_VALUE(list_contains));

+ 10 - 0
test/list_join.gravity

@@ -0,0 +1,10 @@
+#unittest {
+	name: "List join.";
+	error: NONE;
+	result: "1,2,3,4,5";
+};
+
+func main() {
+	var list = [1,2,3,4,5];
+	return list.join(",");
+}