Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of LibParserUtils.
  3.  * Licensed under the MIT License,
  4.  *                http://www.opensource.org/licenses/mit-license.php
  5.  * Copyright 2008 John-Mark Bell <jmb@netsurf-browser.org>
  6.  */
  7.  
  8. #include <inttypes.h>
  9. #include <string.h>
  10.  
  11. #include <parserutils/utils/stack.h>
  12.  
  13. /**
  14.  * Stack object
  15.  */
  16. struct parserutils_stack
  17. {
  18.         size_t item_size;               /**< Size of an item in the stack */
  19.         size_t chunk_size;              /**< Size of a stack chunk */
  20.         size_t items_allocated;         /**< Number of slots allocated */
  21.         int32_t current_item;           /**< Index of current item */
  22.         void *items;                    /**< Items in stack */
  23.  
  24.         parserutils_alloc alloc;        /**< Memory (de)allocation function */
  25.         void *pw;                       /**< Client-specific data */
  26. };
  27.  
  28. /**
  29.  * Create a stack
  30.  *
  31.  * \param item_size   Length, in bytes, of an item in the stack
  32.  * \param chunk_size  Number of stack slots in a chunk
  33.  * \param alloc       Memory (de)allocation function
  34.  * \param pw          Pointer to client-specific private data
  35.  * \param stack       Pointer to location to receive stack instance
  36.  * \return PARSERUTILS_OK on success,
  37.  *         PARSERUTILS_BADPARM on bad parameters
  38.  *         PARSERUTILS_NOMEM on memory exhaustion
  39.  */
  40. parserutils_error parserutils_stack_create(size_t item_size, size_t chunk_size,
  41.                 parserutils_alloc alloc, void *pw, parserutils_stack **stack)
  42. {
  43.         parserutils_stack *s;
  44.  
  45.         if (item_size == 0 || chunk_size == 0 || alloc == NULL || stack == NULL)
  46.                 return PARSERUTILS_BADPARM;
  47.  
  48.         s = alloc(NULL, sizeof(parserutils_stack), pw);
  49.         if (s == NULL)
  50.                 return PARSERUTILS_NOMEM;
  51.  
  52.         s->items = alloc(NULL, item_size * chunk_size, pw);
  53.         if (s->items == NULL) {
  54.                 alloc(s, 0, pw);
  55.                 return PARSERUTILS_NOMEM;
  56.         }
  57.  
  58.         s->item_size = item_size;
  59.         s->chunk_size = chunk_size;
  60.         s->items_allocated = chunk_size;
  61.         s->current_item = -1;
  62.  
  63.         s->alloc = alloc;
  64.         s->pw = pw;
  65.  
  66.         *stack = s;
  67.  
  68.         return PARSERUTILS_OK;
  69. }
  70.  
  71. /**
  72.  * Destroy a stack instance
  73.  *
  74.  * \param stack  The stack to destroy
  75.  * \return PARSERUTILS_OK on success, appropriate error otherwise.
  76.  */
  77. parserutils_error parserutils_stack_destroy(parserutils_stack *stack)
  78. {
  79.         if (stack == NULL)
  80.                 return PARSERUTILS_BADPARM;
  81.  
  82.         stack->alloc(stack->items, 0, stack->pw);
  83.         stack->alloc(stack, 0, stack->pw);
  84.  
  85.         return PARSERUTILS_OK;
  86. }
  87.  
  88. /**
  89.  * Push an item onto the stack
  90.  *
  91.  * \param stack  The stack to push onto
  92.  * \param item   The item to push
  93.  * \return PARSERUTILS_OK on success, appropriate error otherwise
  94.  */
  95. parserutils_error parserutils_stack_push(parserutils_stack *stack,
  96.                 const void *item)
  97. {
  98.         int32_t slot;
  99.  
  100.         if (stack == NULL || item == NULL)
  101.                 return PARSERUTILS_BADPARM;
  102.  
  103.         /* Ensure we'll get a valid slot */
  104.         if (stack->current_item < -1 || stack->current_item == INT32_MAX)
  105.                 return PARSERUTILS_INVALID;
  106.  
  107.         slot = stack->current_item + 1;
  108.  
  109.         if ((size_t) slot >= stack->items_allocated) {
  110.                 void *temp = stack->alloc(stack->items,
  111.                                 (stack->items_allocated + stack->chunk_size) *
  112.                                 stack->item_size, stack->pw);
  113.                 if (temp == NULL)
  114.                         return PARSERUTILS_NOMEM;
  115.  
  116.                 stack->items = temp;
  117.                 stack->items_allocated += stack->chunk_size;
  118.         }
  119.  
  120.         memcpy((uint8_t *) stack->items + (slot * stack->item_size),
  121.                         item, stack->item_size);
  122.         stack->current_item = slot;
  123.  
  124.         return PARSERUTILS_OK;
  125. }
  126.  
  127. /**
  128.  * Pop an item off a stack
  129.  *
  130.  * \param stack  The stack to pop from
  131.  * \param item   Pointer to location to receive popped item, or NULL
  132.  * \return PARSERUTILS_OK on success, appropriate error otherwise.
  133.  */
  134. parserutils_error parserutils_stack_pop(parserutils_stack *stack, void *item)
  135. {
  136.         if (stack == NULL)
  137.                 return PARSERUTILS_BADPARM;
  138.  
  139.         if (stack->current_item < 0)
  140.                 return PARSERUTILS_INVALID;
  141.  
  142.         if (item != NULL) {
  143.                 memcpy(item, (uint8_t *) stack->items +
  144.                                 (stack->current_item * stack->item_size),
  145.                                 stack->item_size);
  146.         }
  147.  
  148.         stack->current_item -= 1;
  149.  
  150.         return PARSERUTILS_OK;
  151. }
  152.  
  153. /**
  154.  * Retrieve a pointer to the current item on the stack
  155.  *
  156.  * \param stack  The stack to inspect
  157.  * \return Pointer to item on stack, or NULL if none
  158.  */
  159. void *parserutils_stack_get_current(parserutils_stack *stack)
  160. {
  161.         if (stack == NULL || stack->current_item < 0)
  162.                 return NULL;
  163.  
  164.         return (uint8_t *) stack->items +
  165.                         (stack->current_item * stack->item_size);
  166. }
  167.  
  168. #ifndef NDEBUG
  169. #include <stdio.h>
  170.  
  171. extern void parserutils_stack_dump(parserutils_stack *stack, const char *prefix,
  172.                 void (*printer)(void *item));
  173.  
  174. void parserutils_stack_dump(parserutils_stack *stack, const char *prefix,
  175.                 void (*printer)(void *item))
  176. {
  177.         int32_t i;
  178.  
  179.         if (stack == NULL || printer == NULL)
  180.                 return;
  181.  
  182.         for (i = 0; i <= stack->current_item; i++) {
  183.                 printf("%s %d: ", prefix != NULL ? prefix : "", i);
  184.                 printer((uint8_t *) stack->items + (i * stack->item_size));
  185.                 printf("\n");
  186.         }
  187. }
  188.  
  189. #endif
  190.  
  191.