895 lines
20 KiB
C
895 lines
20 KiB
C
/* EINA - EFL data type library
|
|
* Copyright (C) 2002-2008 Carsten Haitzler, Vincent Torri
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library;
|
|
* if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "eina_config.h"
|
|
#include "eina_private.h"
|
|
#include "eina_log.h"
|
|
|
|
/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
|
|
#include "eina_safety_checks.h"
|
|
#include "eina_inlist.h"
|
|
|
|
/* FIXME: TODO please, refactor this :) */
|
|
|
|
/*============================================================================*
|
|
* Local *
|
|
*============================================================================*/
|
|
|
|
/**
|
|
* @cond LOCAL
|
|
*/
|
|
|
|
#define EINA_INLIST_SORT_STACK_SIZE 32
|
|
|
|
typedef struct _Eina_Iterator_Inlist Eina_Iterator_Inlist;
|
|
typedef struct _Eina_Accessor_Inlist Eina_Accessor_Inlist;
|
|
|
|
struct _Eina_Iterator_Inlist
|
|
{
|
|
Eina_Iterator iterator;
|
|
const Eina_Inlist *head;
|
|
const Eina_Inlist *current;
|
|
};
|
|
|
|
struct _Eina_Accessor_Inlist
|
|
{
|
|
Eina_Accessor accessor;
|
|
|
|
const Eina_Inlist *head;
|
|
const Eina_Inlist *current;
|
|
|
|
unsigned int index;
|
|
};
|
|
|
|
struct _Eina_Inlist_Sorted_State
|
|
{
|
|
Eina_Inlist *jump_table[EINA_INLIST_JUMP_SIZE];
|
|
|
|
unsigned short jump_limit;
|
|
int jump_div;
|
|
|
|
int inserted;
|
|
};
|
|
|
|
static Eina_Bool
|
|
eina_inlist_iterator_next(Eina_Iterator_Inlist *it, void **data)
|
|
{
|
|
if (!it->current)
|
|
return EINA_FALSE;
|
|
|
|
if (data)
|
|
*data = (void *)it->current;
|
|
|
|
it->current = it->current->next;
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static Eina_Inlist *
|
|
eina_inlist_iterator_get_container(Eina_Iterator_Inlist *it)
|
|
{
|
|
return (Eina_Inlist *)it->head;
|
|
}
|
|
|
|
static void
|
|
eina_inlist_iterator_free(Eina_Iterator_Inlist *it)
|
|
{
|
|
free(it);
|
|
}
|
|
|
|
static Eina_Bool
|
|
eina_inlist_accessor_get_at(Eina_Accessor_Inlist *it,
|
|
unsigned int idx,
|
|
void **data)
|
|
{
|
|
const Eina_Inlist *over;
|
|
unsigned int middle;
|
|
unsigned int i;
|
|
|
|
if (it->index == idx)
|
|
over = it->current;
|
|
else if (idx > it->index)
|
|
/* Looking after current. */
|
|
for (i = it->index, over = it->current;
|
|
i < idx && over;
|
|
++i, over = over->next)
|
|
;
|
|
else
|
|
{
|
|
middle = it->index >> 1;
|
|
|
|
if (idx > middle)
|
|
/* Looking backward from current. */
|
|
for (i = it->index, over = it->current;
|
|
i > idx && over;
|
|
--i, over = over->prev)
|
|
;
|
|
else
|
|
/* Looking from the start. */
|
|
for (i = 0, over = it->head;
|
|
i < idx && over;
|
|
++i, over = over->next)
|
|
;
|
|
}
|
|
|
|
if (!over)
|
|
return EINA_FALSE;
|
|
|
|
it->current = over;
|
|
it->index = idx;
|
|
|
|
if (data)
|
|
*data = (void *)over;
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static Eina_Inlist *
|
|
eina_inlist_accessor_get_container(Eina_Accessor_Inlist *it)
|
|
{
|
|
return (Eina_Inlist *)it->head;
|
|
}
|
|
|
|
static void
|
|
eina_inlist_accessor_free(Eina_Accessor_Inlist *it)
|
|
{
|
|
free(it);
|
|
}
|
|
|
|
static Eina_Inlist *
|
|
eina_inlist_sort_merge(Eina_Inlist *a, Eina_Inlist *b, Eina_Compare_Cb func)
|
|
{
|
|
Eina_Inlist *first, *last;
|
|
|
|
if (func(a, b) < 0)
|
|
a = (last = first = a)->next;
|
|
else
|
|
b = (last = first = b)->next;
|
|
|
|
while (a && b)
|
|
if (func(a, b) < 0)
|
|
a = (last = last->next = a)->next;
|
|
else
|
|
b = (last = last->next = b)->next;
|
|
|
|
last->next = a ? a : b;
|
|
|
|
return first;
|
|
}
|
|
|
|
static Eina_Inlist *
|
|
eina_inlist_sort_rebuild_prev(Eina_Inlist *list)
|
|
{
|
|
Eina_Inlist *prev = NULL;
|
|
|
|
for (; list; list = list->next)
|
|
{
|
|
list->prev = prev;
|
|
prev = list;
|
|
}
|
|
|
|
return prev;
|
|
}
|
|
|
|
static void
|
|
_eina_inlist_sorted_state_compact(Eina_Inlist_Sorted_State *state)
|
|
{
|
|
unsigned short i, j;
|
|
|
|
/* compress the jump table */
|
|
state->jump_div *= 2;
|
|
state->jump_limit /= 2;
|
|
|
|
for (i = 2, j = 1;
|
|
i < EINA_INLIST_JUMP_SIZE;
|
|
i += 2, j++)
|
|
state->jump_table[j] = state->jump_table[i];
|
|
}
|
|
|
|
/**
|
|
* @endcond
|
|
*/
|
|
|
|
|
|
/*============================================================================*
|
|
* Global *
|
|
*============================================================================*/
|
|
|
|
/*============================================================================*
|
|
* API *
|
|
*============================================================================*/
|
|
|
|
EAPI Eina_Inlist *
|
|
eina_inlist_append(Eina_Inlist *list, Eina_Inlist *new_l)
|
|
{
|
|
Eina_Inlist *l;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(new_l, list);
|
|
|
|
new_l->next = NULL;
|
|
if (!list)
|
|
{
|
|
new_l->prev = NULL;
|
|
new_l->last = new_l;
|
|
return new_l;
|
|
}
|
|
|
|
if (list->last)
|
|
l = list->last;
|
|
else
|
|
for (l = list; (l) && (l->next); l = l->next)
|
|
;
|
|
|
|
l->next = new_l;
|
|
new_l->prev = l;
|
|
list->last = new_l;
|
|
return list;
|
|
}
|
|
|
|
EAPI Eina_Inlist *
|
|
eina_inlist_prepend(Eina_Inlist *list, Eina_Inlist *new_l)
|
|
{
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(new_l, list);
|
|
|
|
new_l->prev = NULL;
|
|
if (!list)
|
|
{
|
|
new_l->next = NULL;
|
|
new_l->last = new_l;
|
|
return new_l;
|
|
}
|
|
|
|
new_l->next = list;
|
|
list->prev = new_l;
|
|
new_l->last = list->last;
|
|
list->last = NULL;
|
|
return new_l;
|
|
}
|
|
|
|
EAPI Eina_Inlist *
|
|
eina_inlist_append_relative(Eina_Inlist *list,
|
|
Eina_Inlist *new_l,
|
|
Eina_Inlist *relative)
|
|
{
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(new_l, list);
|
|
|
|
if ((relative) && (list))
|
|
{
|
|
if (relative->next)
|
|
{
|
|
new_l->next = relative->next;
|
|
relative->next->prev = new_l;
|
|
}
|
|
else
|
|
new_l->next = NULL;
|
|
|
|
relative->next = new_l;
|
|
new_l->prev = relative;
|
|
if (!new_l->next)
|
|
list->last = new_l;
|
|
|
|
return list;
|
|
}
|
|
|
|
return eina_inlist_append(list, new_l);
|
|
}
|
|
|
|
EAPI Eina_Inlist *
|
|
eina_inlist_prepend_relative(Eina_Inlist *list,
|
|
Eina_Inlist *new_l,
|
|
Eina_Inlist *relative)
|
|
{
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(new_l, list);
|
|
|
|
if ((relative) && (list))
|
|
{
|
|
new_l->prev = relative->prev;
|
|
new_l->next = relative;
|
|
relative->prev = new_l;
|
|
if (new_l->prev)
|
|
{
|
|
new_l->prev->next = new_l;
|
|
/* new_l->next could not be NULL, as it was set to 'relative' */
|
|
assert(new_l->next);
|
|
return list;
|
|
}
|
|
else
|
|
{
|
|
/* new_l->next could not be NULL, as it was set to 'relative' */
|
|
assert(new_l->next);
|
|
|
|
new_l->last = list->last;
|
|
list->last = NULL;
|
|
return new_l;
|
|
}
|
|
}
|
|
|
|
return eina_inlist_prepend(list, new_l);
|
|
}
|
|
|
|
EAPI Eina_Inlist *
|
|
eina_inlist_remove(Eina_Inlist *list, Eina_Inlist *item)
|
|
{
|
|
Eina_Inlist *return_l;
|
|
|
|
/* checkme */
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(list, NULL);
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(item, list);
|
|
if (EINA_UNLIKELY((item != list) && (!item->prev) && (!item->next)))
|
|
{
|
|
EINA_LOG_ERR("safety check failed: item %p does not appear to be part of an inlist!", item);
|
|
return list;
|
|
}
|
|
|
|
if (item->next)
|
|
item->next->prev = item->prev;
|
|
|
|
if (item->prev)
|
|
{
|
|
item->prev->next = item->next;
|
|
return_l = list;
|
|
}
|
|
else
|
|
{
|
|
return_l = item->next;
|
|
if (return_l)
|
|
return_l->last = list->last;
|
|
}
|
|
|
|
if (item == list->last)
|
|
list->last = item->prev;
|
|
|
|
item->next = NULL;
|
|
item->prev = NULL;
|
|
return return_l;
|
|
}
|
|
|
|
EAPI Eina_Inlist *
|
|
eina_inlist_promote(Eina_Inlist *list, Eina_Inlist *item)
|
|
{
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(list, NULL);
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(item, list);
|
|
|
|
if (item == list)
|
|
return list;
|
|
|
|
if (item->next)
|
|
item->next->prev = item->prev;
|
|
|
|
item->prev->next = item->next;
|
|
|
|
if (list->last == item)
|
|
list->last = item->prev;
|
|
|
|
item->next = list;
|
|
item->prev = NULL;
|
|
item->last = list->last;
|
|
|
|
list->prev = item;
|
|
list->last = NULL;
|
|
|
|
return item;
|
|
}
|
|
|
|
EAPI Eina_Inlist *
|
|
eina_inlist_demote(Eina_Inlist *list, Eina_Inlist *item)
|
|
{
|
|
Eina_Inlist *l;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(list, NULL);
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(item, list);
|
|
|
|
if (list->last == item)
|
|
return list;
|
|
|
|
if (!list->last)
|
|
{
|
|
for (l = list; l->next; l = l->next)
|
|
;
|
|
list->last = l;
|
|
}
|
|
|
|
l = list;
|
|
if (item->prev)
|
|
item->prev->next = item->next;
|
|
else
|
|
l = item->next;
|
|
|
|
item->next->prev = item->prev;
|
|
|
|
list->last->next = item;
|
|
item->prev = list->last;
|
|
item->next = NULL;
|
|
|
|
l->last = item;
|
|
return l;
|
|
}
|
|
|
|
EAPI Eina_Inlist *
|
|
eina_inlist_find(Eina_Inlist *list, Eina_Inlist *item)
|
|
{
|
|
Eina_Inlist *l;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
|
|
|
|
for (l = list; l; l = l->next)
|
|
{
|
|
if (l == item)
|
|
return item;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
EAPI unsigned int
|
|
eina_inlist_count(const Eina_Inlist *list)
|
|
{
|
|
const Eina_Inlist *l;
|
|
unsigned int i = 0;
|
|
|
|
for (l = list; l; l = l->next)
|
|
i++;
|
|
|
|
return i;
|
|
}
|
|
|
|
EAPI int
|
|
eina_inlist_sorted_state_init(Eina_Inlist_Sorted_State *state, Eina_Inlist *list)
|
|
{
|
|
Eina_Inlist *ct = NULL;
|
|
int count = 0;
|
|
int jump_count = 1;
|
|
|
|
/*
|
|
* prepare a jump table to avoid doing unnecessary rewalk
|
|
* of the inlist as much as possible.
|
|
*/
|
|
for (ct = list; ct; ct = ct->next, jump_count++, count++)
|
|
{
|
|
if (jump_count == state->jump_div)
|
|
{
|
|
if (state->jump_limit == EINA_INLIST_JUMP_SIZE)
|
|
{
|
|
_eina_inlist_sorted_state_compact(state);
|
|
}
|
|
|
|
state->jump_table[state->jump_limit] = ct;
|
|
state->jump_limit++;
|
|
jump_count = 0;
|
|
}
|
|
}
|
|
|
|
state->inserted = count;
|
|
return count;
|
|
}
|
|
|
|
EAPI Eina_Inlist_Sorted_State *
|
|
eina_inlist_sorted_state_new(void)
|
|
{
|
|
Eina_Inlist_Sorted_State *r;
|
|
|
|
r = calloc(1, sizeof (Eina_Inlist_Sorted_State));
|
|
if (!r) return NULL;
|
|
|
|
r->jump_div = 1;
|
|
|
|
return r;
|
|
}
|
|
|
|
EAPI void
|
|
eina_inlist_sorted_state_free(Eina_Inlist_Sorted_State *state)
|
|
{
|
|
free(state);
|
|
}
|
|
|
|
static void
|
|
_eina_inlist_sorted_state_insert(Eina_Inlist_Sorted_State *state,
|
|
unsigned short idx,
|
|
int offset)
|
|
{
|
|
Eina_Inlist *last;
|
|
int jump_count;
|
|
int start;
|
|
|
|
state->inserted++;
|
|
|
|
if (offset != 0) idx++;
|
|
for (; idx < state->jump_limit; idx++)
|
|
{
|
|
state->jump_table[idx] = state->jump_table[idx]->prev;
|
|
}
|
|
|
|
start = state->jump_limit - 3;
|
|
if (start < 0)
|
|
start = 0;
|
|
|
|
last = state->jump_table[start];
|
|
start++;
|
|
|
|
/* Correctly rebuild end of list */
|
|
for (jump_count = 0; last->next != NULL; last = last->next, jump_count++)
|
|
{
|
|
if (jump_count == state->jump_div)
|
|
{
|
|
if (state->jump_limit == start)
|
|
{
|
|
if (state->jump_limit == EINA_INLIST_JUMP_SIZE)
|
|
{
|
|
_eina_inlist_sorted_state_compact(state);
|
|
start = state->jump_limit - 1;
|
|
continue ;
|
|
}
|
|
else
|
|
{
|
|
state->jump_limit++;
|
|
}
|
|
}
|
|
|
|
state->jump_table[start++] = last;
|
|
jump_count = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
EAPI Eina_Inlist *
|
|
eina_inlist_sorted_insert(Eina_Inlist *list,
|
|
Eina_Inlist *item,
|
|
Eina_Compare_Cb func)
|
|
{
|
|
Eina_Inlist *ct = NULL;
|
|
Eina_Inlist_Sorted_State state;
|
|
int cmp = 0;
|
|
int inf, sup;
|
|
int cur = 0;
|
|
int count;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(item, list);
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(func, list);
|
|
|
|
if (!list) return eina_inlist_append(NULL, item);
|
|
|
|
if (!list->next)
|
|
{
|
|
cmp = func(list, item);
|
|
|
|
if (cmp < 0)
|
|
return eina_inlist_append(list, item);
|
|
return eina_inlist_prepend(list, item);
|
|
}
|
|
|
|
state.jump_div = 1;
|
|
state.jump_limit = 0;
|
|
count = eina_inlist_sorted_state_init(&state, list);
|
|
|
|
/*
|
|
* now do a dychotomic search directly inside the jump_table.
|
|
*/
|
|
inf = 0;
|
|
sup = state.jump_limit - 1;
|
|
cur = 0;
|
|
ct = state.jump_table[cur];
|
|
cmp = func(ct, item);
|
|
|
|
while (inf <= sup)
|
|
{
|
|
cur = inf + ((sup - inf) >> 1);
|
|
ct = state.jump_table[cur];
|
|
|
|
cmp = func(ct, item);
|
|
if (cmp == 0)
|
|
break ;
|
|
else if (cmp < 0)
|
|
inf = cur + 1;
|
|
else
|
|
{
|
|
if (cur > 0)
|
|
sup = cur - 1;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If at the beginning of the table and cmp < 0,
|
|
* insert just after the head */
|
|
if (cur == 0 && cmp > 0)
|
|
return eina_inlist_prepend_relative(list, item, ct);
|
|
|
|
/* If at the end of the table and cmp >= 0,
|
|
* just append the item to the list */
|
|
if (cmp < 0 && ct == list->last)
|
|
return eina_inlist_append(list, item);
|
|
|
|
/*
|
|
* Now do a dychotomic search between two entries inside the jump_table
|
|
*/
|
|
cur *= state.jump_div;
|
|
inf = cur - state.jump_div - 1;
|
|
sup = cur + state.jump_div + 1;
|
|
|
|
if (sup > count - 1) sup = count - 1;
|
|
if (inf < 0) inf = 0;
|
|
|
|
while (inf <= sup)
|
|
{
|
|
int tmp = cur;
|
|
|
|
cur = inf + ((sup - inf) >> 1);
|
|
if (tmp < cur)
|
|
for (; tmp != cur; tmp++, ct = ct->next);
|
|
else if (tmp > cur)
|
|
for (; tmp != cur; tmp--, ct = ct->prev);
|
|
|
|
cmp = func(ct, item);
|
|
if (cmp == 0)
|
|
break ;
|
|
else if (cmp < 0)
|
|
inf = cur + 1;
|
|
else
|
|
{
|
|
if (cur > 0)
|
|
sup = cur - 1;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cmp <= 0)
|
|
return eina_inlist_append_relative(list, item, ct);
|
|
return eina_inlist_prepend_relative(list, item, ct);
|
|
}
|
|
|
|
EAPI Eina_Inlist *
|
|
eina_inlist_sorted_state_insert(Eina_Inlist *list,
|
|
Eina_Inlist *item,
|
|
Eina_Compare_Cb func,
|
|
Eina_Inlist_Sorted_State *state)
|
|
{
|
|
Eina_Inlist *ct = NULL;
|
|
int cmp = 0;
|
|
int inf, sup;
|
|
int cur = 0;
|
|
int count;
|
|
unsigned short head;
|
|
unsigned int offset;
|
|
|
|
if (!list)
|
|
{
|
|
state->inserted = 1;
|
|
state->jump_limit = 1;
|
|
state->jump_table[0] = item;
|
|
return eina_inlist_append(NULL, item);
|
|
}
|
|
|
|
if (!list->next)
|
|
{
|
|
cmp = func(list, item);
|
|
|
|
state->jump_limit = 2;
|
|
state->inserted = 2;
|
|
|
|
if (cmp < 0)
|
|
{
|
|
state->jump_table[1] = item;
|
|
return eina_inlist_append(list, item);
|
|
}
|
|
state->jump_table[1] = state->jump_table[0];
|
|
state->jump_table[0] = item;
|
|
return eina_inlist_prepend(list, item);
|
|
}
|
|
|
|
count = state->inserted;
|
|
|
|
/*
|
|
* now do a dychotomic search directly inside the jump_table.
|
|
*/
|
|
inf = 0;
|
|
sup = state->jump_limit - 1;
|
|
cur = 0;
|
|
ct = state->jump_table[cur];
|
|
cmp = func(ct, item);
|
|
|
|
while (inf <= sup)
|
|
{
|
|
cur = inf + ((sup - inf) >> 1);
|
|
ct = state->jump_table[cur];
|
|
|
|
cmp = func(ct, item);
|
|
if (cmp == 0)
|
|
break ;
|
|
else if (cmp < 0)
|
|
inf = cur + 1;
|
|
else
|
|
{
|
|
if (cur > 0)
|
|
sup = cur - 1;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If at the beginning of the table and cmp < 0,
|
|
* insert just after the head */
|
|
if (cur == 0 && cmp > 0)
|
|
{
|
|
ct = eina_inlist_prepend_relative(list, item, ct);
|
|
_eina_inlist_sorted_state_insert(state, 0, 0);
|
|
return ct;
|
|
}
|
|
|
|
/* If at the end of the table and cmp >= 0,
|
|
* just append the item to the list */
|
|
if (cmp < 0 && ct == list->last)
|
|
{
|
|
ct = eina_inlist_append(list, item);
|
|
_eina_inlist_sorted_state_insert(state, state->jump_limit - 1, 1);
|
|
return ct;
|
|
}
|
|
|
|
/*
|
|
* Now do a dychotomic search between two entries inside the jump_table
|
|
*/
|
|
cur *= state->jump_div;
|
|
inf = cur - state->jump_div - 1;
|
|
sup = cur + state->jump_div + 1;
|
|
|
|
if (sup > count - 1) sup = count - 1;
|
|
if (inf < 0) inf = 0;
|
|
|
|
while (inf <= sup)
|
|
{
|
|
int tmp = cur;
|
|
|
|
cur = inf + ((sup - inf) >> 1);
|
|
if (tmp < cur)
|
|
for (; tmp != cur; tmp++, ct = ct->next);
|
|
else if (tmp > cur)
|
|
for (; tmp != cur; tmp--, ct = ct->prev);
|
|
|
|
cmp = func(ct, item);
|
|
if (cmp == 0)
|
|
break ;
|
|
else if (cmp < 0)
|
|
inf = cur + 1;
|
|
else if (cmp > 0)
|
|
{
|
|
if (cur > 0)
|
|
sup = cur - 1;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cmp <= 0)
|
|
{
|
|
cur++;
|
|
|
|
ct = eina_inlist_append_relative(list, item, ct);
|
|
}
|
|
else
|
|
{
|
|
ct = eina_inlist_prepend_relative(list, item, ct);
|
|
}
|
|
|
|
head = cur / state->jump_div;
|
|
offset = cur % state->jump_div;
|
|
|
|
_eina_inlist_sorted_state_insert(state, head, offset);
|
|
return ct;
|
|
}
|
|
|
|
EAPI Eina_Inlist *
|
|
eina_inlist_sort(Eina_Inlist *head, Eina_Compare_Cb func)
|
|
{
|
|
unsigned int i = 0;
|
|
unsigned int n = 0;
|
|
Eina_Inlist *tail = head;
|
|
Eina_Inlist *stack[EINA_INLIST_SORT_STACK_SIZE];
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(head, NULL);
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(func, head);
|
|
|
|
while (tail)
|
|
{
|
|
unsigned int idx, tmp;
|
|
|
|
Eina_Inlist *a = tail;
|
|
Eina_Inlist *b = tail->next;
|
|
|
|
if (!b)
|
|
{
|
|
stack[i++] = a;
|
|
break;
|
|
}
|
|
|
|
tail = b->next;
|
|
|
|
if (func(a, b) < 0)
|
|
((stack[i++] = a)->next = b)->next = 0;
|
|
else
|
|
((stack[i++] = b)->next = a)->next = 0;
|
|
|
|
tmp = n++;
|
|
for (idx = n ^ tmp; idx &= idx - 1; i--)
|
|
stack[i - 2] = eina_inlist_sort_merge(stack[i - 2], stack[i - 1], func);
|
|
}
|
|
|
|
while (i-- > 1)
|
|
stack[i - 1] = eina_inlist_sort_merge(stack[i - 1], stack[i], func);
|
|
|
|
head = stack[0];
|
|
tail = eina_inlist_sort_rebuild_prev(head);
|
|
|
|
head->last = tail;
|
|
|
|
return head;
|
|
|
|
}
|
|
|
|
EAPI Eina_Iterator *
|
|
eina_inlist_iterator_new(const Eina_Inlist *list)
|
|
{
|
|
Eina_Iterator_Inlist *it;
|
|
|
|
it = calloc(1, sizeof (Eina_Iterator_Inlist));
|
|
if (!it) return NULL;
|
|
|
|
it->head = list;
|
|
it->current = list;
|
|
|
|
it->iterator.version = EINA_ITERATOR_VERSION;
|
|
it->iterator.next = FUNC_ITERATOR_NEXT(eina_inlist_iterator_next);
|
|
it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
|
|
eina_inlist_iterator_get_container);
|
|
it->iterator.free = FUNC_ITERATOR_FREE(eina_inlist_iterator_free);
|
|
|
|
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
|
|
|
|
return &it->iterator;
|
|
}
|
|
|
|
EAPI Eina_Accessor *
|
|
eina_inlist_accessor_new(const Eina_Inlist *list)
|
|
{
|
|
Eina_Accessor_Inlist *ac;
|
|
|
|
ac = calloc(1, sizeof (Eina_Accessor_Inlist));
|
|
if (!ac) return NULL;
|
|
|
|
ac->head = list;
|
|
ac->current = list;
|
|
ac->index = 0;
|
|
|
|
ac->accessor.version = EINA_ACCESSOR_VERSION;
|
|
ac->accessor.get_at = FUNC_ACCESSOR_GET_AT(eina_inlist_accessor_get_at);
|
|
ac->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(
|
|
eina_inlist_accessor_get_container);
|
|
ac->accessor.free = FUNC_ACCESSOR_FREE(eina_inlist_accessor_free);
|
|
|
|
EINA_MAGIC_SET(&ac->accessor, EINA_MAGIC_ACCESSOR);
|
|
|
|
return &ac->accessor;
|
|
}
|