Platon Technologies
not logged in Login Registration
EnglishSlovak
open source software development celebrating 10 years of open source development! Saturday, April 20, 2024

File: [Platon] / libco / libco / co_o_default.c (download)

Revision 1.1, Sun Mar 30 10:27:02 2003 UTC (21 years ago) by yenar

add implementation of 'default' object flavour: event handling
stacked on top of 'small' flavour [co_o_default.c, co_o_default.h]

/***{{{*******************************************************************
 * This file is part of libco - object library for C                     *
 * Copyright (c) 2002                                                    *
 *     Peter Rockai (yenar) <yenar@host.sk>                              *
 *                                                                       *
 * 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 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, write to the Free Software   *
 * Foundation, Inc., 59 Temple Place, Suite 330,                         *
 * Boston, MA 02111-1307  USA                                            *
 *******************************************************************}}}***/
/* {{{ file description */
/**
 * @file co_o_default.c
 * @brief Implementation of "default" object flavour.
 **/
/* }}} */

/* {{{ includes */
#include "co_o_default.h"
#include "co_exception.h"
#include "co_conv.h"
#include "co_util.h"
/* }}} */

#include "co_o_default.cometa"

/* {{{ */
static void co_listen_cleanup (co _o)
    /// Clean up listener list (internal).
    /**
     * This function is called automatically and shouldn't be used directly.
     * It cleans up the list of event listeners, so we regain memory and speed
     * up lookup in co_ev function.
     **/
{
    co_o_default o = _o;
    co_ev_listen i, in;

    CO_DEBUG (3, "removing from head...");
    while (o -> listen && o -> listen -> deleted) {
        i = o -> listen;
        o -> listen = i -> n;
        free (i);
    }

    CO_DEBUG (4, "removing from tail...");
    for (i = o -> listen; i && i -> n; i = i -> n) {
        if (i -> n -> deleted) {
            in = i -> n;
            i -> n = in -> n;
            free (in);
        }
    }
}
/* }}} */
/* {{{ */
static void co_o_default_disconnect (co _emit, co listen)
    /// Disconnect two objects.
    /**
     * This removes all references to @a listen from @a _emit. When @a listen
     * is being destroyed, this is called automatically.
     **/
{
    co_o_default emit;
    co_ev_listen i;

    emit = _emit;

    CO_DEBUG (4, "marking items for deletion (_o = %p, dis = %p)...",
            emit, listen);
    for (i = emit -> listen; i; i = i -> n) {
        CO_DEBUG (8, "testing: i = %p, i -> o = %p", i, i -> o);
        if (i -> o == listen) {
            CO_DEBUG (6, "marked: %p", i);
            i -> deleted = 1;
            emit -> check_listen = 1;
        }
    }
}
/* }}} */

/* {{{ */
co_v co_o_default_destroy (co _o, co self, co_id_t message, va_list ap)
    /// Destroy object (internal: no checking is done).
    /**
     * This destroys object without checking the state prior to taking
     * actions and without calling object's own destruction handler. Do not
     * use or, if absolutely needed, only with extreme caution. Use co_del_f
     * for standard but forced destruction or co_del for standard checked
     * destruction.
     *
     * @see co_del, co_del_f
     **/
{
    co_o_default o = _o;
    co_ev_listen i, in;
    CO_DEBUG (4, "cleaning o (= %p) -> listen", o);
    for (i = o -> listen; i; i = i -> n) {
        CO_DEBUG (6, "disconnecting (i = %p, deleted = %d)", i, i -> deleted);
        if (i -> ev == COE (disconnect_object) && ! i -> deleted)
            co_o_default_disconnect (i -> o, o);
    }
    for (i = o -> listen; i; i = in) {
        in = i -> n;
        free (i);
    }
    return co_o_small_destroy (_o, self, message, ap);
}
/* }}} */
/* {{{ */
co_v co_o_default_delete (co _o, co self, co_id_t message, va_list ap)
{
    return co_o_small_delete (_o, self, message, ap);
}
/* }}} */

/* {{{ */
void co_o_default_bless (co _o)
{
    co_o_default o = _o;
    co_o_small_bless (_o);

    o -> listen = 0;
    o -> ev_running = 0;
    o -> check_listen = 0;
}
/* }}} */
/* {{{ */
co co_o_default_new (void)
{
    co_o_default this;
    this = new (co_o_default_s);
    co_o_default_bless (this);
    cox_pop (this);
    CO_PUSH (this);
    return this;
}
/* }}} */

/* {{{ */
co_v co_o_default_event (co this, co self, co_id_t message, va_list ap)
{
    volatile co_ev_listen i;
    co_id_t ot;
    int erb;
    co_o_default o = this;
    va_list ap2;
#if DEBUGLVL > 0
    int __dbglvl = __co_debug_msg_level;
    //char __ev_id [128];
#endif

    co_id_t ev = va_arg (ap, co_id_t);

    erb = o -> ev_running;
    o -> ev_running = 1;

    ot = o -> type;
/* {{{ debug *//*
#if DEBUGLVL > 0
    __co_debug_msg_level ++;
    snprintf (__ev_id, 128, "%s/%s",
            __co_type_array [_o -> type] . name, __co_event_array [ev]);
    CO_DEBUG2 (2, "---------------------------------------------------"
            "-----------------------------\n");
    CO_DEBUG2 (2, "            BEGIN EVENT | %23s | %p\n", __ev_id, o);
#endif
*//* }}} */
    for (i = o -> listen; i; i = i -> n) {
        if (ev == i -> ev && ! i -> deleted) {
            //CO_DEBUG (2, "match: o = %p, msg = %s", i -> o, __co_action_array [i -> msg]);
            CO_DEBUG (2, "match: o = %p, msg = %d", i -> o, i -> msg);
            __va_copy (ap2, ap);
            // FIXME?
            /* if (i -> msg == COM (destroy)) {
                i -> deleted = 1;
                co_del (i -> o);
            } else */ {
                if (! erb) {
                    COX_TRY {
                        co_m_v (i -> o, i -> o, i -> msg, ap2);
                    }
                    COX_CATCH (err) {
                        o -> ev_running = 0;
#if DEBUGLVL > 0
                        __co_debug_msg_level = __dbglvl;
#endif
                        COX_RETHROW (err);
                    } COX_CATCH_END;
                } else {
                    co_m_v (i -> o, i -> o, i -> msg, ap);
                }
            }
            if (i -> ad) i -> deleted = 1;
        }
    }
/* {{{ debug *//*
#if DEBUGLVL > 0
    CO_DEBUG2 (2, "              END EVENT | %23s | %p\n", __ev_id, o);
    CO_DEBUG2 (2, "---------------------------------------------------"
            "-----------------------------\n");
    __co_debug_msg_level --;
#endif
*//* }}} */
    o -> ev_running = erb;
    if (! erb & o -> check_listen)
        co_listen_cleanup (o);
    CO_RETURN (int, 0);
} /* }}} */
/* {{{ */
void co_cnt (co emit, co_id_t ev, co listen, co_id_t msg, bool ad)
{
    co_ev_listen i, nw;
    co_o_default _e = emit;

    /* CO_DEBUG (2, "%p (%s) listens to %p (%s))",
            listen, __co_type_array [((co_o) listen) -> type] . name,
            emit, __co_type_array [_e -> type] . name);
    CO_DEBUG (2, "msg = %s, ev = %s",
        __co_action_array [msg],
        __co_event_array [ev]); */

    // do not create two identical connections
    for (i = _e -> listen; i; i = i -> n) {
        if (i -> ev == ev && listen == i -> o && i -> msg == msg) {
            CO_DEBUG (2, "already exists, aborting");
            return;
        }
    }

    CO_DEBUG (3, "creating connection data...");
    nw = new_p (co_ev_listen_s);
    nw -> o = listen;
    nw -> ev = ev;
    nw -> msg = msg;
    nw -> n = 0;
    nw -> deleted = 0;
    nw -> ad = ad;

    CO_DEBUG (3, "embedding data into linked list...");
    if (_e -> listen) {
        nw -> n = _e -> listen;
    }
    _e -> listen = nw;

    if (emit != listen) {
        CO_DEBUG (3, "creating auto-disconnect connection...");
        CO_CNT (listen, disconnect_object, emit, disconnect_object);
    }
} /* }}} */

/* {{{ */
void co_o_default_copy (co dest, co src)
{
    co_o_small_copy (dest, src);
    // XXX do our own stuff here
}
/* }}} */
/* {{{ */
co_v co_o_default_clone_min (co this, co self, co_id_t message, va_list ap)
{
    co_o_default dest, o = this;
    (void) message; (void) self; (void) ap;

    CO_DEBUG (2, "called");

    dest = co_o_default_new ();
    co_o_default_copy (dest, this);

    CO_RETURN (co, dest);
}
/* }}} */
/* {{{ */
co_v co_o_default_clone (co this, co self, co_id_t message, va_list ap)
{
    co_o_default dest, o = this;

    CO_DEBUG (2, "called");

    dest = co_o_default_clone_min (this, self, message, ap) . _co;
    M (dest, data_copy_from, this);

    CO_RETURN (co, dest);
}
/* }}} */
/* {{{ */
co_v co_o_default_clone_deep (co this, co self, co_id_t message, va_list ap)
{
    co_o_default dest, o = this;

    CO_DEBUG (2, "called");

    dest = co_o_default_clone_min (this, self, message, ap) . _co;
    M (dest, data_copy_deep_from, this);

    CO_RETURN (co, dest);
}
/* }}} */

#if 0
/* {{{ */
void co_ev (co _o, co_id_t ev, ...)
{
    volatile co_ev_listen i;
    co_id_t ot;
    int erb;
    co_o_default o = _o;
    va_list ap;
#if DEBUGLVL > 0
    int __dbglvl = __co_debug_msg_level;
    //char __ev_id [128];
#endif

    erb = o -> ev_running;
    o -> ev_running = 1;

    ot = o -> type;
/* {{{ debug *//*
#if DEBUGLVL > 0
    __co_debug_msg_level ++;
    snprintf (__ev_id, 128, "%s/%s",
            __co_type_array [_o -> type] . name, __co_event_array [ev]);
    CO_DEBUG2 (2, "---------------------------------------------------"
            "-----------------------------\n");
    CO_DEBUG2 (2, "            BEGIN EVENT | %23s | %p\n", __ev_id, o);
#endif
*//* }}} */
    for (i = o -> __co_listen; i; i = i -> n) {
        if (ev == i -> ev && ! i -> deleted) {
            //CO_DEBUG (2, "match: o = %p, msg = %s", i -> o, __co_action_array [i -> msg]);
            va_start (ap, ev);
            if (i -> msg == COM (destroy)) {
                i -> deleted = 1;
                co_del (i -> o);
            } else {
                if (! erb) {
                    COX_TRY {
                        co_m_v (i -> o, i -> o, i -> msg, ap);
                    }
                    COX_CATCH (err) {
                        o -> ev_running = 0;
#if DEBUGLVL > 0
                        __co_debug_msg_level = __dbglvl;
#endif
                        COX_RETHROW (err);
                    } COX_CATCH_END;
                } else {
                    co_m_v (i -> o, i -> o, i -> msg, ap);
                }
            }
            va_end (ap);
            if (i -> ad) i -> deleted = 1;
        }
    }
/* {{{ debug *//*
#if DEBUGLVL > 0
    CO_DEBUG2 (2, "              END EVENT | %23s | %p\n", __ev_id, o);
    CO_DEBUG2 (2, "---------------------------------------------------"
            "-----------------------------\n");
    __co_debug_msg_level --;
#endif
*//* }}} */
    o -> ev_running = erb;
    if (! erb & o -> check_listen)
        co_listen_cleanup (o);
} /* }}} */
#endif /* 0 */

Platon Group <platon@platon.org> http://platon.org/
Copyright © 2002-2006 Platon Group
Site powered by Metafox CMS
Go to Top