Tasmota/lib/libesp32/berry/src/be_list.c

208 lines
5.3 KiB
C
Raw Normal View History

/********************************************************************
** 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;
}