On Mon, Aug 4, 2008 at 6:28 AM, Cedric BAIL <[EMAIL PROTECTED]> wrote:
> On Sat, Aug 2, 2008 at 4:49 PM, Gustavo Sverzut Barbieri
> <[EMAIL PROTECTED]> wrote:
>> On Sat, Aug 2, 2008 at 11:34 AM, Jorge Luis Zapata Muga
>> <[EMAIL PROTECTED]> wrote:
>>> On Sat, Aug 2, 2008 at 9:27 AM, Gustavo Sverzut Barbieri
>>> <[EMAIL PROTECTED]> wrote:
>>>> Hi guys,
>>>>
>>>> I still don't have time to play/help with Eina, but from what I saw so
>>>> far, I'd like to propose some ideas and request some features:
>>>>
>>>>  - make data types thread safe. I know evas and other libraries are
>>>> not thread safe, but not being able to create lists, arrays and hashes
>>>> on different threads is too much limited! I'm not talking about append
>>>> to the same list from different threads, but creating nodes for
>>>> different lists on different threads. Today this will fail because of
>>>> mempool and other cache.
>
>>> I agree with you, making eina thread safe is one of the goals we have.
>>> An making the data types thread safe is a must.
>>> As a side note, there are already comments on such a thing for
>>> eina_error, I'd like to make the error subsystem thread safe, and add
>>> a callback to actually do something when an error wants to be printed
>>> instead of sending the data to stdout, a callback so a an application
>>> might want to write the errors into a file (logging), etc.
>
>> great!
>
> Making eina thread safe is one of the goal. As I care about
> performance, I just don't know how, but definitively on the road map.

see, I'm talking about mempool here, not really about types being
thread safe. You can do that by either adding locks to current
implementation or choosing another algorithm (?), maybe look at how
others do (glib/gslice, pymalloc, malloc itself).


>>>>  - provide iterator pattern as a different, complementary system. I'm
>>>> using this with Guarana and have iterator for my own list and also
>>>> Evas_List. What I have is something as simple as:
>>>>             eina_iterator_t *eina_XXXX_iterator_get(XXXX_t *object);
>>>>             int eina_iterator_next(eina_iterator_t *itr, void **data);
>>>>             void eina_iterator_del(eina_iterator_t *itr);
>>>>             typedef struct { int (*next)(eina_iterator_t *itr, void
>>>> **data); void (*free)(eina_iterator_t *itr) } eina_iterator_t;
>>>>     users can "extend" from eina_iterator_t and append required
>>>> fields, like current list node. This simplifies iteration and
>>>> abstracts if you want to use array, lists and even Python/Perl/JS list
>>>> objects.
>>>
>>> Yes, this is good too, im not sure if cedric might want it, as he is
>>> some kind of performance addict :) and adding another pointer
>>> reference might slow it down, but i prefer this normalization on the
>>> API, is a trade-off i prefer.
>>
>> I don't want everyone to always use it, it can be kept as a helper and
>> people who wish to have an abstract data model (usually void *) and
>> access it as a list can provide the iterator. I use it in my mvc
>> lists, something like: model_set(void *model, eina_iterator_t
>> *(*accessor_constructor)(void *model)) and whenever I want to iterate
>> the whole list, I delete the old, create a new and start the loop.
>
>>>>  - provide accessor (? don't know the real name) pattern, similar to
>>>> iterator, this one will access based on index. This one make code
>>>> really simple and if you implement it right, for Evas_List you can
>>>> have very quick access if you remember last accessed node and search
>>>> from head, tail or current position. I also have this code and can
>>>> contribute with Evas_List example.
>>>>
>>>
>>> Im not sure if i understood this correctly, but i think what you are
>>> proposing is similar to what Ecore_List do, you keep track of the last
>>> accessed node on one side and the last added/deleted node in the
>>> other, even so IMHO the ecore_list API is not clear enough on what
>>> functions update one or the other, and yes, this is possible, i did an
>>> ecore_list wrapper using evas_list (i gave the reference for it on
>>> another ml thread), and i think is good to have to speed up node
>>> retrieve.
>>
>> It's a bit different as it's an external structure, you can create as
>> much iterators or accessors as you want and use them in different
>> ways. What you CAN'T is modify the iterated/accessed object while it's
>> in use.
>>
>> Similar to eina_iterator:
>>
>> typedef struct eina_accessor {
>>   int (*get)(eina_acessor_t *accessor, int index, void **data);
>>   void (*free)(eina_accessor_t *accessor);
>> } eina_acessor_t;
>>
>> When you want to create an accessor for Evas_List, you extend this
>> with some members:
>>
>> struct eina_accessor_evas_list {
>>    eina_accessor_t base;
>>    const Evas_List *head;
>>    struct {
>>        const Evas_List *node;
>>        int index;
>>    } last_used;
>> }
>>
>> when you access some index you calculate: am I near to 'index' going
>> from head (0), tail (evas_list_count()) or last_used index? Than you
>> calculate the direction and how many items you have to go.
>
> This accessor and iterator stuff sounds interresting feature to me
> too. I am going to add them to eina during the week. Do people want
> this also for inlist too ?

I'd add them for ALL iterable types, including vectors. These way we
can make our systems accept iterators and accessors where we'd get
lists/arrays and make it independent.

attached are three files we're using in guarana, feel free to use them in eina.

-- 
Gustavo Sverzut Barbieri
http://profusion.mobi embedded systems
--------------------------------------
MSN: [EMAIL PROTECTED]
Skype: gsbarbieri
Mobile: +55 (19) 9225-2202
/**
 * @file
 *
 * Copyright (C) 2008 by ProFUSION embedded systems
 *
 * This program 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 3 of the License, or (at your
 * option) any later version.
 *
 * This program 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 General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
 * USA.
 *
 * @author Gustavo Sverzut Barbieri <[EMAIL PROTECTED]>
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <guarana.h>
#include <guarana_private.h>
#include <stdlib.h>
#include <stdio.h>

/**
 * Return the element data at given index.
 *
 * Do not modify the accessed object (the one that returned the accessor)
 * while you are using it or the accessor behavior will be undefined.
 *
 * @return 0 on failure, 1 on success.
 */
int
grn_accessor_get(grn_accessor_t *accessor, int index, void **data)
{
    CHECK_NULL_RET_VAL(accessor, 0);
    CHECK_NULL_RET_VAL(data, 0);
    return accessor->get(accessor, index, data);
}

/**
 * Free the accessor, after this point, any reference to data
 * returned in grn_accessor_get() might be invalid.
 */
void
grn_accessor_free(grn_accessor_t *accessor)
{
    CHECK_NULL_RET(accessor);
    accessor->free(accessor);
}
/**
 * @file
 *
 * Copyright (C) 2008 by ProFUSION embedded systems
 *
 * This program 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 3 of the License, or (at your
 * option) any later version.
 *
 * This program 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 General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
 * USA.
 *
 * @author Gustavo Sverzut Barbieri <[EMAIL PROTECTED]>
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <guarana.h>
#include <guarana_private.h>
#include <stdlib.h>
#include <stdio.h>

/**
 * Return the current element and go to the next.
 *
 * Do not modify the iterated object (the one that returned the iterator)
 * while you are iterating over it or the iterator behavior will
 * be undefined.
 */
int
grn_iterator_next(grn_iterator_t *itr, void **data)
{
    CHECK_NULL_RET_VAL(itr, 0);
    CHECK_NULL_RET_VAL(data, 0);
    return itr->next(itr, data);
}

/**
 * Free the iterator, after this point, any reference to data
 * returned in grn_iterator_next() might be invalid.
 */
void
grn_iterator_free(grn_iterator_t *itr)
{
    CHECK_NULL_RET(itr);
    itr->free(itr);
}
/**
 * @file
 *
 * Copyright (C) 2008 by ProFUSION embedded systems
 *
 * This program 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 3 of the License, or (at your
 * option) any later version.
 *
 * This program 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 General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
 * USA.
 *
 * @author Gustavo Sverzut Barbieri <[EMAIL PROTECTED]>
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <guarana.h>
#include <guarana_private.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

struct grn_list_accounting {
    struct grn_list *last;
    unsigned int count;
};

static int _grn_list_alloc_error = 0;

int
grn_list_alloc_error(void)
{
    return _grn_list_alloc_error;
}

static void
_grn_list_add_node_setup(grn_list_t *list, grn_list_t *node, struct grn_list_accounting **p_accounting)
{
    if (list)
        *p_accounting = list->accounting;
    else {
        *p_accounting = calloc(1, sizeof(**p_accounting));
        if (!*p_accounting) {
            _grn_list_alloc_error = 1;
            return;
        }
    }

    node->accounting = *p_accounting;
    (*p_accounting)->count++;

    _grn_list_alloc_error = 0;
}

static void
_grn_list_add_setup(grn_list_t *list, grn_list_t **p_node, struct grn_list_accounting **p_accounting, const void *data)
{
    *p_node = malloc(sizeof(**p_node));
    if (!*p_node) {
        grn_critical("malloc: %s", strerror(errno));
        _grn_list_alloc_error = 1;
        return;
    }

    _grn_list_add_node_setup(list, *p_node, p_accounting);
    if (!_grn_list_alloc_error)
        (*p_node)->data = (void *)data;
    else
        free(*p_node);
}

static grn_list_t *
_grn_list_append_node(grn_list_t *list, grn_list_t *node, struct grn_list_accounting *accounting)
{
    if (list)
        accounting->last->next = node;
    else
        list = node;

    node->next = NULL;
    accounting->last = node;

    return list;
}

static grn_list_t *
_grn_list_prepend_node(grn_list_t *list, grn_list_t *node, struct grn_list_accounting *accounting)
{
    node->next = list;
    if (!list)
        accounting->last = node;

    return node;
}

static grn_list_t *
_grn_list_insert_ordered_node(grn_list_t *list, grn_list_t *node, struct grn_list_accounting *accounting, int (*cmp)(const void *a, const void *b))
{
    grn_list_t *p, *c;

    if (!list)
        return _grn_list_prepend_node(list, node, accounting);

    if (cmp(node->data, list->data) <= 0)
        return _grn_list_prepend_node(list, node, accounting);

    p = list;
    c = list->next;
    for (; c != NULL; p = c, c = c->next) {
        if (cmp(node->data, c->data) <= 0) {
            p->next = node;
            node->next = c;
            return list;
        }
    }

    return _grn_list_append_node(list, node, accounting);
}

grn_list_t *
grn_list_append_node(grn_list_t *list, grn_list_t *node)
{
    struct grn_list_accounting *accounting;

    if (!node)
        return list;

    _grn_list_add_node_setup(list, node, &accounting);
    if (_grn_list_alloc_error)
        return list;

    return _grn_list_append_node(list, node, accounting);
}

grn_list_t *
grn_list_append(grn_list_t *list, const void *data)
{
    grn_list_t *node;
    struct grn_list_accounting *accounting;

    _grn_list_add_setup(list, &node, &accounting, data);
    if (_grn_list_alloc_error)
        return list;

    return _grn_list_append_node(list, node, accounting);
}

grn_list_t *
grn_list_prepend_node(grn_list_t *list, grn_list_t *node)
{
    struct grn_list_accounting *accounting;

    if (!node)
        return list;

    _grn_list_add_node_setup(list, node, &accounting);
    if (_grn_list_alloc_error)
        return list;

    return _grn_list_prepend_node(list, node, accounting);
}

grn_list_t *
grn_list_prepend(grn_list_t *list, const void *data)
{
    grn_list_t *node;
    struct grn_list_accounting *accounting;

    _grn_list_add_setup(list, &node, &accounting, data);
    if (_grn_list_alloc_error)
        return list;

    return _grn_list_prepend_node(list, node, accounting);
}

grn_list_t *
grn_list_insert_ordered_node(grn_list_t *list, grn_list_t *node, int (*cmp)(const void *a, const void *b))
{
    struct grn_list_accounting *accounting;

    if (!node)
        return list;

    _grn_list_add_node_setup(list, node, &accounting);
    if (_grn_list_alloc_error)
        return list;

    return _grn_list_insert_ordered_node(list, node, accounting, cmp);
}

grn_list_t *
grn_list_insert_ordered(grn_list_t *list, const void *data, int (*cmp)(const void *a, const void *b))
{
    grn_list_t *node;
    struct grn_list_accounting *accounting;

    if (!cmp)
        return list;

    _grn_list_add_setup(list, &node, &accounting, data);
    if (_grn_list_alloc_error)
        return list;

    return _grn_list_insert_ordered_node(list, node, accounting, cmp);
}

static grn_list_t *
_grn_list_unlink_node(grn_list_t *list, grn_list_t *node, struct grn_list_accounting *accounting)
{
    node->next = NULL;
    node->accounting = NULL;
    accounting->count--;
    if (accounting->count == 0) {
        free(accounting);
        return NULL;
    }

    return list;
}

grn_list_t *
grn_list_unlink_node(grn_list_t *list, grn_list_t *node)
{
    struct grn_list_accounting *accounting;
    grn_list_t *p, *c;

    if (!list || !node)
        return list;

    if (list->accounting != node->accounting)
        return list;

    accounting = list->accounting;
    if (list == node) {
        node = node->next;
        list = _grn_list_unlink_node(list, list, accounting);
        return node;
    }

    p = list;
    c = list->next;
    for (; c != NULL; p = c, c = c->next)
        if (c == node) {
            p->next = c->next;
            return _grn_list_unlink_node(list, node, accounting);
        }

    return list;
}

grn_list_t *
grn_list_remove_node(grn_list_t *list, grn_list_t *node)
{
    if (!node)
        return list;

    list = grn_list_unlink_node(list, node);
    free(node);

    return list;
}

grn_list_t *
grn_list_remove(grn_list_t *list, const void *data)
{
    struct grn_list_accounting *accounting;
    grn_list_t *p, *c;

    if (!list)
        return list;

    accounting = list->accounting;
    if (list->data == data) {
        p = list->next;
        _grn_list_unlink_node(list, list, accounting);
        free(list);
        return p;
    }

    p = list;
    c = list->next;
    for (; c != NULL; p = c, c = c->next)
        if (c->data == data) {
            p->next = c->next;
            list = _grn_list_unlink_node(list, c, accounting);
            free(c);
            break;
        }

    return list;
}

void *
grn_list_find(const grn_list_t *list, const void *data)
{
    for (; list != NULL; list = list->next)
        if (list->data == data)
            return list->data;

    return NULL;
}

grn_list_t *
grn_list_find_node(const grn_list_t *list, const void *data)
{
    for (; list != NULL; list = list->next)
        if (list->data == data)
            return (grn_list_t *)list;

    return NULL;
}

grn_list_t *
grn_list_free(grn_list_t *list)
{
    if (!list)
        return NULL;

    free(list->accounting);

    while (list) {
        grn_list_t *tmp;

        tmp = list;
        list = list->next;

        free(tmp);
    }

    return NULL;
}

void *
grn_list_data(const grn_list_t *node)
{
    if (!node)
        return NULL;
    return node->data;
}

grn_list_t *
grn_list_next(const grn_list_t *node)
{
    if (!node)
        return NULL;
    return node->next;
}

grn_list_t *
grn_list_last(const grn_list_t *list)
{
    if (!list)
        return NULL;

    if (!list->accounting)
        return NULL;

    return list->accounting->last;
}

unsigned int
grn_list_count(const grn_list_t *list)
{
    if (!list)
        return 0;

    if (!list->accounting)
        return 0;

    return list->accounting->count;
}

struct grn_list_iterator {
    grn_iterator_t base;
    const grn_list_t *node;
};

static void
_grn_list_iterator_free(grn_iterator_t *itr)
{
    free(itr);
}

static int
_grn_list_iterator_next(grn_iterator_t *p, void **data)
{
    struct grn_list_iterator *itr = (struct grn_list_iterator *)p;

    if (itr->node) {
        *data = itr->node->data;
        itr->node = itr->node->next;
        return 1;
    } else
        return 0;
}

grn_iterator_t *
grn_list_iterator(const grn_list_t *list)
{
    struct grn_list_iterator *itr;

    itr = malloc(sizeof(*itr));
    if (!itr) {
        grn_critical("malloc: %s", strerror(errno));
        return NULL;
    }

    itr->base.free = _grn_list_iterator_free;
    itr->base.next = _grn_list_iterator_next;
    itr->node = list;
    return (grn_iterator_t *)itr;
}

struct grn_list_accessor {
    grn_accessor_t base;
    const grn_list_t *head;
    struct {
        const grn_list_t *node;
        int index;
    } last;
};

static void
_grn_list_accessor_free(grn_accessor_t *accessor)
{
    free(accessor);
}

static int
_grn_list_accessor_get(grn_accessor_t *p, int index, void **data)
{
    struct grn_list_accessor *accessor = (struct grn_list_accessor *)p;
    const grn_list_t *n;
    int todo, count;

    if (index < 0)
        return 0;

    count = grn_list_count(accessor->head);
    if (index >= count)
        return 0;

    if (index == count - 1) {
        *data = grn_list_last(accessor->head)->data;
        return 1;
    }

    todo = index - accessor->last.index;
    if (todo == 0) {
        *data = accessor->last.node->data;
        return 1;
    } else if (todo > 0)
        n = accessor->last.node;
    else {
        n = accessor->head;
        todo = index;
    }

    for (; todo > 0; todo--)
        n = n->next;

    accessor->last.index = index;
    accessor->last.node = n;
    *data = n->data;

    return 1;
}

grn_accessor_t *
grn_list_accessor(const grn_list_t *list)
{
    struct grn_list_accessor *accessor;

    accessor = malloc(sizeof(*accessor));
    if (!accessor) {
        grn_critical("malloc: %s", strerror(errno));
        return NULL;
    }

    accessor->base.free = _grn_list_accessor_free;
    accessor->base.get = _grn_list_accessor_get;
    accessor->head = list;
    accessor->last.index = 0;
    accessor->last.node = list;
    return (grn_accessor_t *)accessor;
}
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
enlightenment-devel mailing list
enlightenment-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to