blob: 76c70d2ac8432a59c5823bed33e1c3afd47d9597 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
#include <proton/object.h>
#include <stdlib.h>
#include <assert.h>
struct pn_list_t {
const pn_class_t *clazz;
size_t capacity;
size_t size;
void **elements;
};
size_t pn_list_size(pn_list_t *list)
{
assert(list);
return list->size;
}
void *pn_list_get(pn_list_t *list, int index)
{
assert(list); assert(list->size);
return list->elements[index % list->size];
}
void pn_list_set(pn_list_t *list, int index, void *value)
{
assert(list); assert(list->size);
void *old = list->elements[index % list->size];
pn_class_decref(list->clazz, old);
list->elements[index % list->size] = value;
pn_class_incref(list->clazz, value);
}
static void pni_list_ensure(pn_list_t *list, size_t capacity)
{
assert(list);
if (list->capacity < capacity) {
size_t newcap = list->capacity;
while (newcap < capacity) { newcap *= 2; }
list->elements = (void **) realloc(list->elements, newcap * sizeof(void *));
assert(list->elements);
list->capacity = newcap;
}
}
int pn_list_add(pn_list_t *list, void *value)
{
assert(list);
pni_list_ensure(list, list->size + 1);
list->elements[list->size++] = value;
pn_class_incref(list->clazz, value);
return 0;
}
void *pn_list_pop(pn_list_t *list)
{
assert(list);
if (list->size) {
return list->elements[--list->size];
} else {
return NULL;
}
}
ssize_t pn_list_index(pn_list_t *list, void *value)
{
for (size_t i = 0; i < list->size; i++) {
if (pn_class_equals(list->clazz, list->elements[i], value)) {
return i;
}
}
return -1;
}
bool pn_list_remove(pn_list_t *list, void *value)
{
assert(list);
ssize_t idx = pn_list_index(list, value);
if (idx < 0) {
return false;
} else {
pn_list_del(list, idx, 1);
}
return true;
}
void pn_list_del(pn_list_t *list, int index, int n)
{
assert(list);
if (!list->size) { return; }
index %= list->size;
for (int i = 0; i < n; i++) {
pn_class_decref(list->clazz, list->elements[index + i]);
}
size_t slide = list->size - (index + n);
for (size_t i = 0; i < slide; i++) {
list->elements[index + i] = list->elements[index + n + i];
}
list->size -= n;
}
void pn_list_clear(pn_list_t *list)
{
assert(list);
pn_list_del(list, 0, list->size);
}
void pn_list_minpush(pn_list_t *list, void *value)
{
assert(list);
pn_list_add(list, value);
// we use one based indexing for the heap
void **heap = list->elements - 1;
int now = list->size;
while (now > 1 && pn_class_compare(list->clazz, heap[now/2], value) > 0) {
heap[now] = heap[now/2];
now /= 2;
}
heap[now] = value;
}
void *pn_list_minpop(pn_list_t *list)
{
assert(list);
// we use one based indexing for the heap
void **heap = list->elements - 1;
void *min = heap[1];
void *last = pn_list_pop(list);
int size = pn_list_size(list);
int now, child;
for (now = 1; now*2 <= size; now = child) {
child = now*2;
if (child != size && pn_class_compare(list->clazz, heap[child], heap[child + 1]) > 0) {
child++;
}
if (pn_class_compare(list->clazz, last, heap[child]) > 0) {
heap[now] = heap[child];
} else {
break;
}
}
heap[now] = last;
return min;
}
typedef struct {
pn_list_t *list;
size_t index;
} pni_list_iter_t;
static void *pni_list_next(void *ctx)
{
pni_list_iter_t *iter = (pni_list_iter_t *) ctx;
if (iter->index < pn_list_size(iter->list)) {
return pn_list_get(iter->list, iter->index++);
} else {
return NULL;
}
}
void pn_list_iterator(pn_list_t *list, pn_iterator_t *iter)
{
pni_list_iter_t *liter = (pni_list_iter_t *) pn_iterator_start(iter, pni_list_next, sizeof(pni_list_iter_t));
liter->list = list;
liter->index = 0;
}
static void pn_list_finalize(void *object)
{
assert(object);
pn_list_t *list = (pn_list_t *) object;
for (size_t i = 0; i < list->size; i++) {
pn_class_decref(list->clazz, pn_list_get(list, i));
}
free(list->elements);
}
static uintptr_t pn_list_hashcode(void *object)
{
assert(object);
pn_list_t *list = (pn_list_t *) object;
uintptr_t hash = 1;
for (size_t i = 0; i < list->size; i++) {
hash = hash * 31 + pn_hashcode(pn_list_get(list, i));
}
return hash;
}
static intptr_t pn_list_compare(void *oa, void *ob)
{
assert(oa); assert(ob);
pn_list_t *a = (pn_list_t *) oa;
pn_list_t *b = (pn_list_t *) ob;
size_t na = pn_list_size(a);
size_t nb = pn_list_size(b);
if (na != nb) {
return nb - na;
} else {
for (size_t i = 0; i < na; i++) {
intptr_t delta = pn_compare(pn_list_get(a, i), pn_list_get(b, i));
if (delta) return delta;
}
}
return 0;
}
static int pn_list_inspect(void *obj, pn_string_t *dst)
{
assert(obj);
pn_list_t *list = (pn_list_t *) obj;
int err = pn_string_addf(dst, "[");
if (err) return err;
size_t n = pn_list_size(list);
for (size_t i = 0; i < n; i++) {
if (i > 0) {
err = pn_string_addf(dst, ", ");
if (err) return err;
}
err = pn_class_inspect(list->clazz, pn_list_get(list, i), dst);
if (err) return err;
}
return pn_string_addf(dst, "]");
}
#define pn_list_initialize NULL
pn_list_t *pn_list(const pn_class_t *clazz, size_t capacity)
{
static const pn_class_t list_clazz = PN_CLASS(pn_list);
pn_list_t *list = (pn_list_t *) pn_class_new(&list_clazz, sizeof(pn_list_t));
list->clazz = clazz;
list->capacity = capacity ? capacity : 16;
list->elements = (void **) malloc(list->capacity * sizeof(void *));
list->size = 0;
return list;
}