2008-07-22 23:28:28 +00:00
|
|
|
/*
|
2014-01-19 01:09:44 +00:00
|
|
|
* This file Copyright (C) 2008-2014 Mnemosyne LLC
|
2007-08-14 20:45:23 +00:00
|
|
|
*
|
2014-01-21 03:10:30 +00:00
|
|
|
* It may be used under the GNU GPL versions 2 or 3
|
2014-01-19 01:09:44 +00:00
|
|
|
* or any future license endorsed by Mnemosyne LLC.
|
2007-08-18 17:19:49 +00:00
|
|
|
*
|
2008-07-22 23:28:28 +00:00
|
|
|
*/
|
2007-08-14 20:45:23 +00:00
|
|
|
|
|
|
|
#include <string.h> /* memmove */
|
|
|
|
|
|
|
|
#include "ptrarray.h"
|
2017-06-08 07:24:12 +00:00
|
|
|
#include "tr-assert.h"
|
2007-08-14 20:45:23 +00:00
|
|
|
#include "utils.h"
|
|
|
|
|
2010-02-15 16:44:02 +00:00
|
|
|
#define FLOOR 32
|
2007-08-14 20:45:23 +00:00
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
tr_ptrArray const TR_PTR_ARRAY_INIT = TR_PTR_ARRAY_INIT_STATIC;
|
2008-12-29 08:54:36 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
void tr_ptrArrayDestruct(tr_ptrArray* p, PtrArrayForeachFunc func)
|
2007-08-14 20:45:23 +00:00
|
|
|
{
|
2017-06-08 07:24:12 +00:00
|
|
|
TR_ASSERT(p != NULL);
|
|
|
|
TR_ASSERT(p->items != NULL || p->n_items == 0);
|
2008-12-29 08:54:36 +00:00
|
|
|
|
2017-04-30 16:25:26 +00:00
|
|
|
if (func != NULL)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
tr_ptrArrayForeach(p, func);
|
|
|
|
}
|
2008-12-29 08:54:36 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_free(p->items);
|
2008-12-29 08:54:36 +00:00
|
|
|
}
|
2007-08-14 20:45:23 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
void tr_ptrArrayForeach(tr_ptrArray* t, PtrArrayForeachFunc func)
|
2007-08-14 20:45:23 +00:00
|
|
|
{
|
2017-06-08 07:24:12 +00:00
|
|
|
TR_ASSERT(t != NULL);
|
|
|
|
TR_ASSERT(t->items != NULL || t->n_items == 0);
|
|
|
|
TR_ASSERT(func != NULL);
|
2007-09-30 23:55:49 +00:00
|
|
|
|
2017-05-13 22:38:31 +00:00
|
|
|
for (int i = 0; i < t->n_items; ++i)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
func(t->items[i]);
|
|
|
|
}
|
2007-09-30 23:55:49 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
void** tr_ptrArrayPeek(tr_ptrArray* t, int* size)
|
2007-08-14 20:45:23 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
*size = t->n_items;
|
|
|
|
return t->items;
|
2007-08-14 20:45:23 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
int tr_ptrArrayInsert(tr_ptrArray* t, void* ptr, int pos)
|
2007-08-14 20:45:23 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
if (t->n_items >= t->n_alloc)
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
t->n_alloc = MAX(FLOOR, t->n_alloc * 2);
|
|
|
|
t->items = tr_renew(void*, t->items, t->n_alloc);
|
2007-08-14 20:45:23 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (pos < 0 || pos > t->n_items)
|
|
|
|
{
|
|
|
|
pos = t->n_items;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memmove(t->items + pos + 1, t->items + pos, sizeof(void*) * (t->n_items - pos));
|
|
|
|
}
|
2007-08-14 20:45:23 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
t->items[pos] = ptr;
|
|
|
|
t->n_items++;
|
|
|
|
return pos;
|
2007-08-14 20:45:23 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
void* tr_ptrArrayPop(tr_ptrArray* t)
|
2008-01-31 02:24:43 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
void* ret = NULL;
|
2008-01-31 02:24:43 +00:00
|
|
|
|
2017-04-30 16:25:26 +00:00
|
|
|
if (t->n_items != 0)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
ret = t->items[--t->n_items];
|
|
|
|
}
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
return ret;
|
2008-01-31 02:24:43 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
void tr_ptrArrayErase(tr_ptrArray* t, int begin, int end)
|
2007-08-14 20:45:23 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
if (end < 0)
|
|
|
|
{
|
|
|
|
end = t->n_items;
|
|
|
|
}
|
2012-12-13 01:47:40 +00:00
|
|
|
|
2017-06-08 07:24:12 +00:00
|
|
|
TR_ASSERT(begin >= 0);
|
|
|
|
TR_ASSERT(begin < end);
|
|
|
|
TR_ASSERT(end <= t->n_items);
|
2007-08-14 20:45:23 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
memmove(t->items + begin, t->items + end, sizeof(void*) * (t->n_items - end));
|
2007-08-14 20:45:23 +00:00
|
|
|
|
2017-04-30 16:30:03 +00:00
|
|
|
t->n_items -= end - begin;
|
2007-08-14 20:45:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
***
|
|
|
|
**/
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
int tr_ptrArrayLowerBound(tr_ptrArray const* t, void const* ptr, int (* compare)(void const*, void const*), bool* exact_match)
|
2011-06-24 18:25:56 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
int pos = -1;
|
|
|
|
bool match = false;
|
2011-06-24 18:25:56 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (t->n_items == 0)
|
2011-06-24 18:25:56 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
pos = 0;
|
2011-06-24 18:25:56 +00:00
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
else
|
2011-06-24 18:25:56 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
int first = 0;
|
|
|
|
int last = t->n_items - 1;
|
2011-06-24 18:25:56 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
for (;;)
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2017-04-20 16:02:19 +00:00
|
|
|
int const half = (last - first) / 2;
|
|
|
|
int const c = compare(t->items[first + half], ptr);
|
2012-12-13 01:47:40 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (c < 0)
|
2012-12-13 01:47:40 +00:00
|
|
|
{
|
2017-04-20 16:02:19 +00:00
|
|
|
int const new_first = first + half + 1;
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
if (new_first > last)
|
2012-12-13 01:47:40 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
pos = new_first;
|
|
|
|
break;
|
2011-06-24 18:25:56 +00:00
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
first = new_first;
|
2011-06-24 18:25:56 +00:00
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
else if (c > 0)
|
2012-12-13 01:47:40 +00:00
|
|
|
{
|
2017-04-20 16:02:19 +00:00
|
|
|
int const new_last = first + half - 1;
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
if (new_last < first)
|
2012-12-13 01:47:40 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
pos = first;
|
|
|
|
break;
|
2011-06-24 18:25:56 +00:00
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
last = new_last;
|
2011-06-24 18:25:56 +00:00
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
else
|
2012-12-13 01:47:40 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
match = true;
|
|
|
|
pos = first + half;
|
|
|
|
break;
|
2011-06-24 18:25:56 +00:00
|
|
|
}
|
2007-08-14 20:45:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (exact_match != NULL)
|
|
|
|
{
|
|
|
|
*exact_match = match;
|
|
|
|
}
|
2012-12-13 01:47:40 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
return pos;
|
2007-09-28 15:05:42 +00:00
|
|
|
}
|
|
|
|
|
2017-06-08 07:24:12 +00:00
|
|
|
#ifndef TR_ENABLE_ASSERTS
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
#define assertArrayIsSortedAndUnique(array, compare) /* no-op */
|
|
|
|
#define assertIndexIsSortedAndUnique(array, pos, compare) /* no-op */
|
|
|
|
|
2013-01-13 22:09:18 +00:00
|
|
|
#else
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
static void assertArrayIsSortedAndUnique(tr_ptrArray const* t, int (* compare)(void const*, void const*))
|
2007-09-28 15:05:42 +00:00
|
|
|
{
|
2017-05-13 22:38:31 +00:00
|
|
|
for (int i = 0; i < t->n_items - 2; ++i)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2017-06-08 07:24:12 +00:00
|
|
|
TR_ASSERT(compare(t->items[i], t->items[i + 1]) < 0);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2011-06-24 18:25:56 +00:00
|
|
|
}
|
2007-08-14 20:45:23 +00:00
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
static void assertIndexIsSortedAndUnique(tr_ptrArray const* t, int pos, int (* compare)(void const*, void const*))
|
2013-01-13 22:09:18 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
if (pos > 0)
|
|
|
|
{
|
2017-06-08 07:24:12 +00:00
|
|
|
TR_ASSERT(compare(t->items[pos - 1], t->items[pos]) < 0);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2013-01-13 22:09:18 +00:00
|
|
|
|
2017-04-30 16:25:26 +00:00
|
|
|
if (pos + 1 < t->n_items)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2017-06-08 07:24:12 +00:00
|
|
|
TR_ASSERT(compare(t->items[pos], t->items[pos + 1]) < 0);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2013-01-13 22:09:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
int tr_ptrArrayInsertSorted(tr_ptrArray* t, void* ptr, int (* compare)(void const*, void const*))
|
2007-08-14 20:45:23 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
int pos;
|
|
|
|
int ret;
|
|
|
|
assertArrayIsSortedAndUnique(t, compare);
|
2011-06-24 18:25:56 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
pos = tr_ptrArrayLowerBound(t, ptr, compare, NULL);
|
|
|
|
ret = tr_ptrArrayInsert(t, ptr, pos);
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
assertIndexIsSortedAndUnique(t, ret, compare);
|
|
|
|
return ret;
|
2007-08-14 20:45:23 +00:00
|
|
|
}
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
void* tr_ptrArrayFindSorted(tr_ptrArray* t, void const* ptr, int (* compare)(void const*, void const*))
|
2007-08-14 20:45:23 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
bool match = false;
|
2017-04-20 16:02:19 +00:00
|
|
|
int const pos = tr_ptrArrayLowerBound(t, ptr, compare, &match);
|
2017-04-19 12:04:45 +00:00
|
|
|
return match ? t->items[pos] : NULL;
|
2007-08-14 20:45:23 +00:00
|
|
|
}
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
static void* tr_ptrArrayRemoveSortedValue(tr_ptrArray* t, void const* ptr, int (* compare)(void const*, void const*))
|
2007-08-14 20:45:23 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
int pos;
|
|
|
|
bool match;
|
|
|
|
void* ret = NULL;
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
assertArrayIsSortedAndUnique(t, compare);
|
2013-01-13 22:09:18 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
pos = tr_ptrArrayLowerBound(t, ptr, compare, &match);
|
2012-12-13 01:47:40 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (match)
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
ret = t->items[pos];
|
2017-06-08 07:24:12 +00:00
|
|
|
TR_ASSERT(compare(ret, ptr) == 0);
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_ptrArrayErase(t, pos, pos + 1);
|
2007-08-14 20:45:23 +00:00
|
|
|
}
|
2012-12-13 01:47:40 +00:00
|
|
|
|
2017-06-13 02:24:09 +00:00
|
|
|
TR_ASSERT(ret == NULL || compare(ret, ptr) == 0);
|
2017-04-19 12:04:45 +00:00
|
|
|
return ret;
|
2007-08-14 20:45:23 +00:00
|
|
|
}
|
2013-08-17 17:20:31 +00:00
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
void tr_ptrArrayRemoveSortedPointer(tr_ptrArray* t, void const* ptr, int (* compare)(void const*, void const*))
|
2013-08-17 17:20:31 +00:00
|
|
|
{
|
2017-06-13 02:24:09 +00:00
|
|
|
void* removed = tr_ptrArrayRemoveSortedValue(t, ptr, compare);
|
|
|
|
|
2017-06-08 07:24:12 +00:00
|
|
|
#ifndef TR_ENABLE_ASSERTS
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2017-06-13 02:24:09 +00:00
|
|
|
(void)removed;
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2013-08-17 17:20:31 +00:00
|
|
|
#else
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2017-06-08 07:24:12 +00:00
|
|
|
TR_ASSERT(removed != NULL);
|
|
|
|
TR_ASSERT(removed == ptr);
|
|
|
|
TR_ASSERT(tr_ptrArrayFindSorted(t, ptr, compare) == NULL);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2013-08-17 17:20:31 +00:00
|
|
|
#endif
|
|
|
|
}
|