Annotation of gpl/axl/src/axl_stack.c, revision 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>