mirror of https://github.com/arendst/Tasmota.git
208 lines
5.3 KiB
C
208 lines
5.3 KiB
C
|
/********************************************************************
|
||
|
** Copyright (c) 2018-2020 Guan Wenliang
|
||
|
** This file is part of the Berry default interpreter.
|
||
|
** skiars@qq.com, https://github.com/Skiars/berry
|
||
|
** See Copyright Notice in the LICENSE file or at
|
||
|
** https://github.com/Skiars/berry/blob/master/LICENSE
|
||
|
********************************************************************/
|
||
|
#include "be_list.h"
|
||
|
#include "be_mem.h"
|
||
|
#include "be_gc.h"
|
||
|
#include "be_vm.h"
|
||
|
#include "be_vector.h"
|
||
|
#include "be_exec.h"
|
||
|
#include <string.h>
|
||
|
|
||
|
#define datasize(size) ((size) * sizeof(bvalue))
|
||
|
|
||
|
blist* be_list_new(bvm *vm)
|
||
|
{
|
||
|
bgcobject *gco = be_gcnew(vm, BE_LIST, blist);
|
||
|
blist *list = cast_list(gco);
|
||
|
if (list) {
|
||
|
list->count = 0;
|
||
|
list->capacity = 2;
|
||
|
var_setlist(vm->top, list);
|
||
|
be_incrtop(vm);
|
||
|
list->data = be_malloc(vm, datasize(list->capacity));
|
||
|
be_stackpop(vm, 1);
|
||
|
}
|
||
|
return list;
|
||
|
}
|
||
|
|
||
|
void be_list_delete(bvm *vm, blist *list)
|
||
|
{
|
||
|
be_free(vm, list->data, datasize(list->capacity));
|
||
|
be_free(vm, list, sizeof(blist));
|
||
|
}
|
||
|
|
||
|
blist* be_list_copy(bvm *vm, blist *original)
|
||
|
{
|
||
|
bgcobject *gco = be_gcnew(vm, BE_LIST, blist);
|
||
|
blist *list = cast_list(gco);
|
||
|
if (list) {
|
||
|
size_t size = datasize(original->capacity);
|
||
|
list->count = original->count;
|
||
|
list->capacity = original->capacity;
|
||
|
var_setlist(vm->top, list);
|
||
|
be_incrtop(vm);
|
||
|
list->data = be_malloc(vm, size);
|
||
|
be_stackpop(vm, 1);
|
||
|
memcpy(list->data, original->data, size);
|
||
|
}
|
||
|
return list;
|
||
|
}
|
||
|
|
||
|
bvalue* be_list_index(blist *list, int index)
|
||
|
{
|
||
|
if (index < 0) {
|
||
|
index = list->count + index;
|
||
|
}
|
||
|
if (index < 0 || index >= list->count) {
|
||
|
return NULL;
|
||
|
}
|
||
|
return be_list_at(list, index);
|
||
|
}
|
||
|
|
||
|
bvalue* be_list_push(bvm *vm, blist *list, bvalue *value)
|
||
|
{
|
||
|
bvalue *slot;
|
||
|
if (list->count >= list->capacity) {
|
||
|
int newcap = be_nextsize(list->capacity);
|
||
|
list->data = be_realloc(vm, list->data,
|
||
|
datasize(list->capacity), datasize(newcap));
|
||
|
list->capacity = newcap;
|
||
|
}
|
||
|
slot = list->data + list->count++;
|
||
|
if (value != NULL) {
|
||
|
*slot = *value;
|
||
|
}
|
||
|
return slot;
|
||
|
}
|
||
|
|
||
|
bvalue* be_list_insert(bvm *vm, blist *list, int index, bvalue *value)
|
||
|
{
|
||
|
int i;
|
||
|
bvalue *data;
|
||
|
if (index < 0) {
|
||
|
index = list->count + index;
|
||
|
}
|
||
|
if (index < 0 || index > list->count) {
|
||
|
return NULL;
|
||
|
}
|
||
|
if (list->count >= list->capacity) {
|
||
|
int newcap = be_nextsize(list->capacity);
|
||
|
list->data = be_realloc(vm, list->data,
|
||
|
datasize(list->capacity), datasize(newcap));
|
||
|
list->capacity = newcap;
|
||
|
}
|
||
|
data = list->data;
|
||
|
for (i = list->count++; i > index; --i) {
|
||
|
data[i] = data[i - 1];
|
||
|
}
|
||
|
data = list->data + index;
|
||
|
if (value != NULL) {
|
||
|
*data = *value;
|
||
|
}
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
int be_list_remove(bvm *vm, blist *list, int index)
|
||
|
{
|
||
|
int i;
|
||
|
bvalue *data;
|
||
|
(void)vm;
|
||
|
if (index < 0) {
|
||
|
index = list->count + index;
|
||
|
}
|
||
|
if (index < 0 || index >= list->count) {
|
||
|
return bfalse;
|
||
|
}
|
||
|
data = list->data;
|
||
|
list->count--;
|
||
|
for (i = index; i < list->count; ++i) {
|
||
|
data[i] = data[i + 1];
|
||
|
}
|
||
|
return btrue;
|
||
|
}
|
||
|
|
||
|
void be_list_resize(bvm *vm, blist *list, int count)
|
||
|
{
|
||
|
if (count != list->count) {
|
||
|
int newcap = be_nextsize(count);
|
||
|
if (newcap > list->capacity) {
|
||
|
bvalue *v, *end;
|
||
|
list->data = be_realloc(vm, list->data,
|
||
|
datasize(list->capacity), datasize(newcap));
|
||
|
list->capacity = newcap;
|
||
|
v = list->data + list->count;
|
||
|
end = list->data + count;
|
||
|
while (v < end) {
|
||
|
var_setnil(v++);
|
||
|
}
|
||
|
}
|
||
|
list->count = count;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void be_list_merge(bvm *vm, blist *list, const blist *other)
|
||
|
{
|
||
|
int dst_len = list->count;
|
||
|
int src_len = other->count;
|
||
|
int length = src_len + dst_len;
|
||
|
if (length != 0) {
|
||
|
int newcap = be_nextsize(length);
|
||
|
if (newcap > list->capacity) {
|
||
|
list->data = be_realloc(vm, list->data,
|
||
|
datasize(list->capacity), datasize(newcap));
|
||
|
list->capacity = newcap;
|
||
|
}
|
||
|
memcpy(list->data + dst_len, other->data, src_len * sizeof(bvalue));
|
||
|
list->count = length;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void be_list_reverse(blist *list)
|
||
|
{
|
||
|
bvalue *left = list->data;
|
||
|
bvalue *right = left + list->count - 1;
|
||
|
for (; left < right; ++left, --right) {
|
||
|
bvalue temp = *left;
|
||
|
*left = *right;
|
||
|
*right = temp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void be_list_pool_init(bvm *vm, blist *list)
|
||
|
{
|
||
|
bvalue *head;
|
||
|
be_list_resize(vm, list, 0);
|
||
|
head = be_list_push(vm, list, NULL);
|
||
|
var_setint(head, 0);
|
||
|
}
|
||
|
|
||
|
int be_list_pool_alloc(bvm *vm, blist *list, bvalue *src)
|
||
|
{
|
||
|
bvalue *head = be_list_data(list), *node;
|
||
|
int id = var_toidx(head); /* get the first free node */
|
||
|
if (id) {
|
||
|
node = head + id;
|
||
|
head->v.i = var_toint(node); /* link the next free node to head */
|
||
|
} else {
|
||
|
id = be_list_count(list);
|
||
|
node = be_list_push(vm, list, NULL);
|
||
|
}
|
||
|
*node = *src;
|
||
|
return id;
|
||
|
}
|
||
|
|
||
|
void be_list_pool_free(blist *list, int id)
|
||
|
{
|
||
|
bvalue *head = be_list_data(list);
|
||
|
bvalue *node = head + id;
|
||
|
be_assert(id > 0 && id < list->count);
|
||
|
/* insert a new free node to head */
|
||
|
*node = *head;
|
||
|
head->v.i = id;
|
||
|
}
|