Annotation of gpl/axl/src/axl_stack.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *  LibAxl:  Another XML library
                      3:  *  Copyright (C) 2006 Advanced Software Production Line, S.L.
                      4:  *
                      5:  *  This program is free software; you can redistribute it and/or
                      6:  *  modify it under the terms of the GNU Lesser General Public License
                      7:  *  as published by the Free Software Foundation; either version 2.1 of
                      8:  *  the License, or (at your option) any later version.
                      9:  *
                     10:  *  This program is distributed in the hope that it will be useful,
                     11:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
                     12:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
                     13:  *  GNU Lesser General Public License for more details.
                     14:  *
                     15:  *  You should have received a copy of the GNU Lesser General Public
                     16:  *  License along with this program; if not, write to the Free
                     17:  *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
                     18:  *  02111-1307 USA
                     19:  *  
                     20:  *  You may find a copy of the license under this software is released
                     21:  *  at COPYING file. This is LGPL software: you are welcome to
                     22:  *  develop proprietary applications using this library without any
                     23:  *  royalty or fee but returning back any change, improvement or
                     24:  *  addition in the form of source code, project image, documentation
                     25:  *  patches, etc. 
                     26:  *
                     27:  *  For commercial support on build XML enabled solutions contact us:
                     28:  *          
                     29:  *      Postal address:
                     30:  *         Advanced Software Production Line, S.L.
                     31:  *         Edificio Alius A, Oficina 102,
                     32:  *         C/ Antonio Suarez Nº 10,
                     33:  *         Alcalá de Henares 28802 Madrid
                     34:  *         Spain
                     35:  *
                     36:  *      Email address:
                     37:  *         info@aspl.es - http://www.aspl.es/xml
                     38:  */
                     39: 
                     40: #include <axl_decl.h>
                     41: #include <axl_stack.h>
                     42: #include <axl_list.h>
                     43: #include <axl_log.h>
                     44: #define LOG_DOMAIN "axl-stack"
                     45: 
                     46: struct _axlStack {
                     47:        axlPointer     * stack;
                     48:        int              size;
                     49:        int              items;
                     50:        axlDestroyFunc   destroy;
                     51: };
                     52: 
                     53: /**
                     54:  * \defgroup axl_stack_module Axl Stack: A stack built used across AXL library
                     55:  */
                     56: 
                     57: /** 
                     58:  * \addtogroup axl_stack_module
                     59:  * @{
                     60:  */
                     61: 
                     62: /** 
                     63:  * @brief Creates a new stack.
                     64:  *
                     65:  * Creates a new \ref axlStack object, which will accept to store a
                     66:  * retrieve objects in a FIFO manner.
                     67:  * 
                     68:  * @param destroy_data A function to be used to destroy data stored on
                     69:  * the stack is the stack is deallocated containing data. This
                     70:  * parameter is optional. If not provided, no automatic memory
                     71:  * deallocation will peformed.
                     72:  * 
                     73:  * @return A newly allocated stack that must be deallocated by using
                     74:  * axl_stack_destroy.
                     75:  */
                     76: axlStack * axl_stack_new (axlDestroyFunc destroy_data)
                     77: {
                     78:        axlStack * stack;
                     79: 
                     80:        /* create an empty stack */
                     81:        stack          = axl_new (axlStack, 1);
                     82:        stack->destroy = destroy_data;
                     83: 
                     84:        return stack;
                     85: }
                     86: 
                     87: /** 
                     88:  * @brief Push data on top of the stack.
                     89:  *
                     90:  * The stack doesn't support storing NULL references. If a null
                     91:  * reference is provided the function won't perform any operation on
                     92:  * the stack.
                     93:  * 
                     94:  * @param stack The stack where the data will be pushed.
                     95:  * @param data The data to push.
                     96:  */
                     97: void       axl_stack_push (axlStack * stack, axlPointer data)
                     98: {
                     99:        axl_return_if_fail (stack);
                    100:        axl_return_if_fail (data);
                    101: 
                    102:        /* check if we have enough space to store the pointer */
                    103:        if (stack->size == stack->items) {
                    104:                if (stack->size == 0) {
                    105:                        /* ask for a single pointer */
                    106:                        stack->stack = axl_new (axlPointer, 1);
                    107:                }else {
                    108:                        /* ask to grow the memory already allocated */
                    109:                        stack->stack = realloc (stack->stack, sizeof (axlPointer) * (stack->size + 1));
                    110:                }
                    111:                /* update the size available */
                    112:                stack->size++;
                    113:        }
                    114: 
                    115:        /* store the item */
                    116:        stack->stack[stack->items] = data;
                    117:        
                    118:        /* update items stored */
                    119:        stack->items++;
                    120:        
                    121:        return;
                    122: }
                    123: 
                    124: /** 
                    125:  * @brief Pop data from the stack.
                    126:  * 
                    127:  * @param stack The stack where the pop operation will be performed.
                    128:  * 
                    129:  * @return A \ref axlPointer containing previously pushed data or NULL
                    130:  * if fails.
                    131:  */
                    132: axlPointer axl_stack_pop  (axlStack * stack)
                    133: {
                    134:        axlPointer pointer;
                    135: 
                    136:        axl_return_val_if_fail (stack, NULL);
                    137: 
                    138:        /* do not perform any operation if the stack is empty */
                    139:        if (axl_stack_is_empty (stack))
                    140:                return NULL;
                    141: 
                    142:        /* reduce the items stored */
                    143:        stack->items--;
                    144: 
                    145:        /* return the pointer */
                    146:        pointer = stack->stack[stack->items];
                    147: 
                    148:        return pointer;
                    149: }
                    150: 
                    151: /** 
                    152:  * @brief Allows to get current current element at the top of the
                    153:  * stack without removing it.
                    154:  *
                    155:  * This function allows to perform the same operation like pop (\ref
                    156:  * axl_stack_pop) function, but without removing the element from the
                    157:  * top.
                    158:  * 
                    159:  * @param stack The stack where the element from the top will be returned.
                    160:  * 
                    161:  * @return An \ref axlPointer reference or NULL if fails.
                    162:  */
                    163: axlPointer axl_stack_peek (axlStack * stack)
                    164: {
                    165:        axl_return_val_if_fail (stack, NULL);
                    166: 
                    167:        /* do not perform any operation if the stack is empty */
                    168:        if (axl_stack_is_empty (stack)) {
                    169:                return NULL;
                    170:        }
                    171: 
                    172:        /* return the very first element without poping */
                    173:        return stack->stack[stack->items - 1];
                    174: }
                    175: 
                    176: /** 
                    177:  * @internal Common support function for foreach over an stack for all
                    178:  * foreach functions defined.
                    179:  */
                    180: axl_bool       __axl_stack_foreach_common (axlStack         * stack, 
                    181:                                           axlStackForeach2   func,
                    182:                                           axlStackForeach3   func3,
                    183:                                           axlPointer         user_data, 
                    184:                                           axlPointer         user_data2,
                    185:                                           axlPointer         user_data3)
                    186: {
                    187:        int iterator;
                    188: 
                    189:        axl_return_val_if_fail (stack, axl_false);
                    190: 
                    191:        /* for each item inside the stack */
                    192:        iterator = 0;
                    193:        while (iterator < stack->items) {
                    194:                /* call fo the function and check returning value  */
                    195:                if (func != NULL && func (stack->stack [stack->items - iterator - 1],  user_data,  user_data2))
                    196:                        return axl_false;
                    197: 
                    198:                /* call fo the function and check returning value  */
                    199:                if (func3 != NULL && func3 (stack->stack [stack->items - iterator - 1],  user_data,  user_data2, user_data3))
                    200:                        return axl_false;
                    201: 
                    202:                /* update the iterator */
                    203:                iterator ++;
                    204:        }
                    205: 
                    206:        /* iteration performed completely */
                    207:        return axl_true;
                    208: }
                    209: 
                    210: /** 
                    211:  * @brief Allows to perform a foreach operation from the head of the
                    212:  * stack (the next item to be poped) to the tail of the stack (the
                    213:  * very first item pushed).
                    214:  *
                    215:  * The foreach process is non intrusive: it doesn't perform any change
                    216:  * of the stack, but allows to traverse all items in the natural order
                    217:  * in which items are stored (push) and removed (pop).
                    218:  *
                    219:  * The function provided to perform the foreach operation will be
                    220:  * called providing the stack data found, and the two user defined
                    221:  * pointers provided. 
                    222:  * 
                    223:  * @param stack The stack where the foreach operation will be
                    224:  * performed.
                    225:  *
                    226:  * @param func The foreach function to be called for each item found
                    227:  * in the stack.
                    228:  *
                    229:  * @param user_data User defined pointer to be passed to the function
                    230:  * provided.
                    231:  *
                    232:  * @param user_data2 User defined pointer to be passed to the function
                    233:  * provided.
                    234:  * 
                    235:  * @return \ref axl_true if the foreach process was performed completely
                    236:  * through all items inside the stack or \ref axl_false if not. The
                    237:  * function will also return \ref axl_false to indicate a failure the
                    238:  * stack and func parameters are null.
                    239:  */
                    240: axl_bool       axl_stack_foreach (axlStack         * stack, 
                    241:                                  axlStackForeach2   func,
                    242:                                  axlPointer         user_data, 
                    243:                                  axlPointer         user_data2)
                    244: {
                    245:        /* call to common function */
                    246:        return __axl_stack_foreach_common (stack, func, NULL, user_data, user_data2, NULL);
                    247: }
                    248: 
                    249: 
                    250: /** 
                    251:  * @brief Allows to perform a foreach operation from the head of the
                    252:  * stack (the next item to be poped) to the tail of the stack (the
                    253:  * very first item pushed).
                    254:  *
                    255:  * The foreach process is non intrusive: it doesn't perform any change
                    256:  * of the stack, but allows to traverse all items in the natural order
                    257:  * in which items are stored (push) and removed (pop).
                    258:  *
                    259:  * The function provided to perform the foreach operation will be
                    260:  * called providing the stack data found, and the three user defined
                    261:  * pointers provided.
                    262:  * 
                    263:  * @param stack The stack where the foreach operation will be
                    264:  * performed.
                    265:  *
                    266:  * @param func The foreach function to be called for each item found
                    267:  * in the stack.
                    268:  *
                    269:  * @param user_data User defined pointer to be passed to the function
                    270:  * provided.
                    271:  *
                    272:  * @param user_data2 User defined pointer to be passed to the function
                    273:  * provided.
                    274:  *
                    275:  * @param user_data3 User defined pointer to be passed to the function
                    276:  * provided.
                    277:  * 
                    278:  * @return \ref axl_true if the foreach process was performed completely
                    279:  * through all items inside the stack or \ref axl_false if not. The
                    280:  * function will also return \ref axl_false to indicate a failure the
                    281:  * stack and func parameters are null.
                    282:  */
                    283: axl_bool       axl_stack_foreach3 (axlStack         * stack, 
                    284:                                   axlStackForeach3   func,
                    285:                                   axlPointer         user_data,
                    286:                                   axlPointer         user_data2,
                    287:                                   axlPointer         user_data3)
                    288: {
                    289:        /* call to common function */
                    290:        return __axl_stack_foreach_common (stack, NULL, func, user_data, user_data2, user_data3);
                    291: }
                    292: 
                    293: /** 
                    294:  * @brief Returns current stack size, that is, elements stored on the
                    295:  * stack.
                    296:  * 
                    297:  * @param stack The stack where the operation will performed.
                    298:  * 
                    299:  * @return The number of items stored.
                    300:  */
                    301: int        axl_stack_size (axlStack * stack)
                    302: {
                    303:        axl_return_val_if_fail (stack, -1);
                    304: 
                    305:        /* current items stored */
                    306:        return stack->items;
                    307: }
                    308: 
                    309: 
                    310: /** 
                    311:  * @brief Allows to check if the given stack is empty.
                    312:  * 
                    313:  * @param stack The stack to check.
                    314:  * 
                    315:  * @return \ref axl_true if the stack is empty or axl_false if not.
                    316:  */
                    317: axl_bool       axl_stack_is_empty (axlStack * stack)
                    318: {
                    319:        axl_return_val_if_fail (stack, axl_false);
                    320:        
                    321:        /* return if there are stored items in the stack */
                    322:        return (stack->items == 0);
                    323: }
                    324: 
                    325: /** 
                    326:  * @brief Destroy the given stack.
                    327:  * 
                    328:  * @param stack The stack to destroy.
                    329:  */
                    330: void       axl_stack_free (axlStack * stack)
                    331: {
                    332:        axl_return_if_fail (stack);
                    333: 
                    334:        /* destroy the list inside (if the destroy function is
                    335:         * defined) */
                    336:        if (stack->destroy) {
                    337:                while (! axl_stack_is_empty (stack)) {
                    338:                        
                    339:                        /* destroy */
                    340:                        stack->destroy (axl_stack_pop (stack));
                    341:                        
                    342:                } /* end while */
                    343:        } /* end if */
                    344: 
                    345:        /* free stack array */
                    346:        axl_free (stack->stack);
                    347:        
                    348:        /* destroy the stack */
                    349:        axl_free (stack);
                    350: 
                    351:        return;
                    352: }
                    353: 
                    354: /* @} */
                    355: 
                    356: typedef struct _axlBinaryStackNode {
                    357:        int      count;
                    358:        axl_bool state;
                    359: } axlBinaryStackNode;
                    360: 
                    361: 
                    362: struct _axlBinaryStack {
                    363:        axlBinaryStackNode * last;
                    364:        axlStack           * stack;
                    365:        axlFactory         * factory;
                    366:        int                  count;
                    367: };
                    368: 
                    369: /**
                    370:  * \defgroup axl_binary_stack_module Axl Binary Stack: A compact binary state stack
                    371:  */
                    372: 
                    373: /** 
                    374:  * \addtogroup axl_binary_stack_module
                    375:  * @{
                    376:  */
                    377: 
                    378: /** 
                    379:  * @brief Allows to create a compact binary state stack.
                    380:  * 
                    381:  * To stack is designed to store boolean values in an efficient
                    382:  * way. In idea behind this structure is that storing 10 boolean axl_true
                    383:  * values only holds a node, with the axl_true value and the count of
                    384:  * items that previously was signaled with the same value. 
                    385:  *
                    386:  * The intention is to compact a binary succession of data into a list
                    387:  * of touples signaling the state and the number of times it was
                    388:  * signaled.
                    389:  *
                    390:  * This structure is meant to be more efficient than a plain \ref
                    391:  * axlStack but there is a case where is not more efficient, that is,
                    392:  * when all stored boolean values alternates.
                    393:  * 
                    394:  * @return A newly allocated binary stack. Push boolean values with
                    395:  * \ref axl_binary_stack_push. Pop previous stored value with \ref
                    396:  * axl_binary_stack_pop. Once finished, use \ref axl_binary_stack_free
                    397:  * to free the binary stack.
                    398:  */
                    399: axlBinaryStack * axl_binary_stack_new (void)
                    400: {
                    401:        axlBinaryStack * result;
                    402: 
                    403:        result           = axl_new (axlBinaryStack, 1);
                    404:        result->stack    = axl_stack_new (axl_free);
                    405: 
                    406:        /* return stack created */
                    407:        return result;
                    408: } 
                    409: 
                    410: /** 
                    411:  * @brief Push a new boolean item into the binary stack.
                    412:  * 
                    413:  * @param bstack The binary stack
                    414:  *
                    415:  * @param state The state to push into the queue.
                    416:  */
                    417: void             axl_binary_stack_push (axlBinaryStack * bstack, axl_bool state)
                    418: {
                    419:        axlBinaryStackNode * node;
                    420: 
                    421:        /* check references */
                    422:        axl_return_if_fail (bstack);
                    423:        
                    424:        /* check basic case */
                    425:        if (bstack->last == NULL) {
                    426: 
                    427:        axl_binary_stack_push_create_and_return:
                    428: 
                    429:                /* configure last */
                    430:                node         = axl_new (axlBinaryStackNode, 1);
                    431:                node->count  = 1;
                    432:                node->state  = state;
                    433: 
                    434:                /* configure */
                    435:                bstack->last = node;
                    436: 
                    437:                /* store in the stack */
                    438: /*             __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Storing first item: 0x%x", node); */
                    439:                axl_stack_push (bstack->stack, node);
                    440:                
                    441:                /* update count */
                    442:                bstack->count++;
                    443: 
                    444: /*             __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Storing item state=%d, count=%d, bcount=%d",
                    445:                node->state, node->count, bstack->count); */
                    446: 
                    447:                return;
                    448:        } /* end if */
                    449: 
                    450:        /* default case, check current state */
                    451:        if (bstack->last->state == state) {
                    452: 
                    453:                /* found same state, increase count and return */
                    454:                bstack->last->count++;
                    455: 
                    456:                /* update count */
                    457:                bstack->count++;
                    458: 
                    459: /*             __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Found same state, reusing..state=%d, count=%d, bcount=%d",
                    460:                bstack->last->state, bstack->last->count, bstack->count); */
                    461: 
                    462:                return;
                    463:        } /* end if */
                    464: 
                    465: /*     __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Found state changed, creating..state=%d (previuos state: %d), count=%d, bcount=%d",
                    466:        state, bstack->last->state, bstack->last->count, bstack->count); */
                    467: 
                    468:        /* if reached this place, create a new node */
                    469:        goto axl_binary_stack_push_create_and_return;
                    470: }
                    471: 
                    472: /** 
                    473:  * @brief Convenience function that allows to push a new value using
                    474:  * the last one pushed in the stack. This function allows to implement
                    475:  * the same feature provided by peeking (\ref axl_binary_stack_peek)
                    476:  * the next visible value on the stack head and then pushing it again.
                    477:  * 
                    478:  * @param bstack The binary stack where to perform the operation. 
                    479:  *
                    480:  * NOTE: The stack must not be empty before calling to this
                    481:  * function. It has to have at least one value already pushed.
                    482:  */
                    483: void             axl_binary_stack_push_the_same (axlBinaryStack * bstack)
                    484: {
                    485:        axl_return_if_fail (bstack);
                    486:        axl_return_if_fail (bstack->last);
                    487:        
                    488:        /* update stack */
                    489:        bstack->last->count++;
                    490:        bstack->count++;
                    491: 
                    492:        return;
                    493: }
                    494: 
                    495: /** 
                    496:  * @brief Allows to pop the next value from the stack.
                    497:  * 
                    498:  * @param bstack The binary stack where the next value will be
                    499:  * restored.
                    500:  * 
                    501:  * @return The next value stored in the stack. You must check if the
                    502:  * stack is empty before calling to this function since you won't be
                    503:  * able to differenciate a axl_false value stored from a axl_false value
                    504:  * returned by an error.
                    505:  */
                    506: axl_bool             axl_binary_stack_pop  (axlBinaryStack * bstack)
                    507: {
                    508:        axlBinaryStackNode     * node;
                    509:        axl_bool                 state;
                    510:        axl_return_val_if_fail (bstack, axl_false);
                    511: 
                    512:        /* get last value */
                    513:        node = bstack->last; 
                    514:        if (node == NULL) {
                    515:                /* return axl_false because the stack is empty */
                    516:                return axl_false;
                    517:        } /* end if */
                    518: 
                    519:        /* check if there are more than 1 item, that is, at least
                    520:         * 2. */
                    521:        if (node->count > 1) {
                    522: 
                    523:                /* update count */
                    524:                bstack->count--;
                    525: 
                    526:                /* decrease the counter and return */
                    527:                node->count--;
                    528: 
                    529: /*             __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "POP: found state with more than 1 item, poping: state=%d, count=%d, bcount=%d",
                    530:                node->state, node->count, bstack->count); */
                    531: 
                    532:                return node->state;
                    533: 
                    534:        } else if (node->count == 1) {
                    535: 
                    536: /*             __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "POP: found state with only 1 item, poping: state=%d, count=%d, bcount=%d",
                    537:                node->state, node->count, bstack->count); */
                    538: 
                    539:                /* get the value */
                    540:                state = node->state;
                    541:                
                    542:                /* update the next last (remove the current last) and
                    543:                 * use the next */
                    544:                axl_stack_pop (bstack->stack);
                    545:                bstack->last = axl_stack_peek (bstack->stack);
                    546: 
                    547:                /* release to the factory */
                    548: /*             __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "POP: new node to use: 0x%x, about to release 0x%x", 
                    549:                bstack->last, node); */
                    550:                axl_free (node);
                    551: 
                    552:                /* update count */
                    553:                bstack->count--;
                    554: 
                    555:                node = bstack->last;
                    556: /*             if (node != NULL) {
                    557:                        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "POP: after poping: state=%d, count=%d, bcount=%d",
                    558:                                   node->state, node->count, bstack->count);
                    559:                } */
                    560: 
                    561:                return state;
                    562:        } /* end if */
                    563: 
                    564:        /* this shouldn't be reached */
                    565:        return axl_false;
                    566: }
                    567: 
                    568: /** 
                    569:  * @brief Allows to get the current stack head value stored without
                    570:  * removing it from the stack.
                    571:  * 
                    572:  * @param bstack The binary stack where to perform the operation.
                    573:  * 
                    574:  * @return The value stored in the stack head. The stack must contain
                    575:  * at least one value, otherwise the returned value is not
                    576:  * reliable. See \ref axl_binary_stack_is_empty to avoid calling to this function.
                    577:  */
                    578: axl_bool             axl_binary_stack_peek (axlBinaryStack * bstack)
                    579: {
                    580:        axl_return_val_if_fail (bstack, axl_false);
                    581: 
                    582:        /* return current state */
                    583:        return (bstack->last && bstack->last->state);
                    584: }
                    585: 
                    586: /** 
                    587:  * @brief Check current emptyness status for the provided binary
                    588:  * stack.
                    589:  * 
                    590:  * @param bstack The binary stack to check.
                    591:  * 
                    592:  * @return axl_true if the binary stack is empty, otherwise axl_false is
                    593:  * returned.
                    594:  */
                    595: axl_bool             axl_binary_stack_is_empty (axlBinaryStack * bstack)
                    596: {
                    597:        axl_return_val_if_fail (bstack, axl_false);
                    598: 
                    599:        /* return current emptyness status */
                    600:        return (bstack->last == NULL && axl_stack_is_empty (bstack->stack));
                    601: }
                    602: 
                    603: /** 
                    604:  * @brief Allows to get current number of items stored.
                    605:  * 
                    606:  * @param bstack The binary stack to check current number of items
                    607:  * stored.
                    608:  * 
                    609:  * @return The number of items stored or -1 if it fails.
                    610:  */
                    611: int              axl_binary_stack_size     (axlBinaryStack * bstack)
                    612: {
                    613:        axl_return_val_if_fail (bstack, -1);
                    614: 
                    615:        /* return item count */
                    616:        return bstack->count;
                    617: }
                    618: 
                    619: /** 
                    620:  * @brief Release the provided binary stack.
                    621:  * 
                    622:  * @param bstack The binary stack to release.
                    623:  */
                    624: void             axl_binary_stack_free (axlBinaryStack * bstack)
                    625: {
                    626:        if (bstack == NULL)
                    627:                return;
                    628: 
                    629:        /* free resources */
                    630:        axl_stack_free (bstack->stack);
                    631:        axl_free (bstack);
                    632: 
                    633:        return;
                    634: }
                    635: 
                    636: /**
                    637:  * @}
                    638:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>