Branch: Tag:

2018-07-01

2018-07-01 12:21:13 by Henrik Grubbström (Grubba) <grubba@grubba.org>

ADT.LowLevelStack: Moved implementation to builtin.cmod.

5412:   /*! @endmodule    */    + /*! @module __builtin +  */ +  + /*! @class Stack +  *! This class implements a simple stack. Instead of adding and removing +  *! elements to an array, and thus making it vary in size for every push +  *! and pop operation, this stack tries to keep the stack size constant. +  *! If however the stack risks to overflow, it will allocate double its +  *! current size, i.e. pushing an element on an full 32 slot stack will +  *! result in a 64 slot stack with 33 elements. +  *! +  *! @note +  *! This class is usually accessed as @[ADT.LowLevelStack]. +  */ + PIKECLASS Stack + { +  PIKEVAR array arr; +  +  /*! @decl void push(mixed val) +  *! Push an element on the top of the stack. +  */ +  PIKEFUN void push(mixed val) +  { +  if (!THIS->arr) { +  THIS->arr = real_allocate_array(1, 31); +  array_set_index_no_free(THIS->arr, 0, val); +  } else { +  THIS->arr = array_insert(THIS->arr, val, THIS->arr->size); +  } +  push_int(0); +  } +  +  /*! @decl mixed top() +  *! Returns the top element from the stack, without +  *! popping it. +  *! @throws +  *! Throws an error if called on an empty stack. +  */ +  PIKEFUN mixed top() +  { +  if (THIS->arr && THIS->arr->size) { +  push_svalue(ITEM(THIS->arr) + THIS->arr->size - 1); +  return; +  } +  Pike_error("Stack underflow\n"); +  } +  +  /*! @decl mixed pop(void|int val) +  *! Pops and returns entry @[val] from the stack, counting +  *! from the top. If no value is given the top element is +  *! popped and returned. All popped entries are freed from +  *! the stack. +  */ +  PIKEFUN mixed pop(void|int val) +  { +  if (!THIS->arr || !THIS->arr->size) { +  Pike_error("Stack underflow\n"); +  } +  +  if (val && (val->u.integer > 0)) { +  ptrdiff_t new_size; +  ptrdiff_t old_size; +  +  new_size = THIS->arr->size - val->u.integer; +  if (new_size < 0) new_size = 0; +  +  /* NB: Steal reference from the array element. */ +  *Pike_sp = ITEM(THIS->arr)[new_size]; +  old_size = THIS->arr->size; +  THIS->arr->size = new_size; +  Pike_sp++; +  +  free_svalues(ITEM(THIS->arr) + new_size + 1, old_size - (new_size + 1), +  THIS->arr->type_field); +  } else { +  /* NB: Steal reference from the array element. */ +  THIS->arr->size--; +  *Pike_sp = ITEM(THIS->arr)[THIS->arr->size]; +  Pike_sp++; +  } +  } +  +  /*! @decl void quick_pop(void|int val) +  *! Pops @[val] entries from the stack, or one entry +  *! if no value is given. The popped entries are not +  *! returned. +  */ +  PIKEFUN void quick_pop(void|int val) +  { +  apply_current(f_Stack_pop_fun_num, args); +  push_int(0); +  } +  +  /*! @decl void reset(int|void initial_size) +  *! Empties the stack, resets the stack pointer +  *! and shrinks the stack size to the given value +  *! or 32 if none is given. +  *! @seealso +  *! @[create] +  */ +  PIKEFUN void reset(int|void initial_size) +  { +  ptrdiff_t size = 32; +  if (initial_size && (initial_size->u.integer > 0)) { +  size = initial_size->u.integer; +  } +  +  if (THIS->arr) { +  free_array(THIS->arr); +  THIS->arr = NULL; +  } +  +  /* NB: The initial size MUST != 0 else the empty array will be returned. */ +  THIS->arr = real_allocate_array(1, size-1); +  THIS->arr->size = 0; +  } +  +  /*! @decl void create(int|void initial_size) +  *! An initial stack size can be given when +  *! a stack is cloned. The default value is +  *! 32. +  */ +  PIKEFUN void create(int|void initial_size) +  { +  apply_current(f_Stack_reset_fun_num, args); +  } +  +  /*! @decl void set_stack(array stack) +  *! Sets the stacks content to the provided array. +  */ +  PIKEFUN void set_stack(array stack) +  { +  if (THIS->arr) { +  free_array(THIS->arr); +  } +  add_ref(THIS->arr = stack); +  } +  +  /*! @decl int _sizeof() +  *! @[sizeof] on a stack returns the number of entries +  *! in the stack. +  */ +  PIKEFUN int _sizeof() +  flags ID_PROTECTED; +  { +  push_int(THIS->arr ? THIS->arr->size : 0); +  } +  +  /*! @decl array _values() +  *! @[values] on a stack returns all the entries in +  *! the stack, in order. +  */ +  PIKEFUN array _values() +  flags ID_PROTECTED; +  { +  if (THIS->arr) { +  push_array(copy_array(THIS->arr)); +  } else { +  ref_push_array(&empty_array); +  } +  } +  +  /*! @decl int _search(mixed item) +  *! Return the stack-depth to @[item]. +  *! +  *! This function makes it possible to use +  *! eg @[search()] and @[has_value()] on the stack. +  */ +  PIKEFUN int _search(mixed item) +  flags ID_PROTECTED; +  { +  if (!THIS->arr || !THIS->arr->size) { +  push_int(-1); +  } else { +  push_int(array_search(THIS->arr, item, 0)); +  } +  } +  +  /*! @decl this_program `+(this_program s) +  *! A stack added with another stack yields a new +  *! stack with all the elements from both stacks, +  *! and the elements from the second stack at the +  *! top of the new stack. +  */ +  PIKEFUN Stack `+(Stack s) +  flags ID_PROTECTED; +  { +  struct Stack_struct *other_st = get_storage(s, Stack_program); +  int cnt = 0; +  if (!other_st) { +  SIMPLE_BAD_ARG_ERROR("`+", 1, "Stack"); +  } +  if (THIS->arr) { +  ref_push_array(THIS->arr); +  cnt++; +  } +  if (other_st->arr) { +  ref_push_array(other_st->arr); +  cnt++; +  } +  if (cnt == 1) { +  ref_push_array(&empty_array); +  } +  if (cnt) { +  f_add(2); + #ifdef PIKE_DEBUG +  if (TYPEOF(Pike_sp[-1]) != PIKE_T_ARRAY) { +  Pike_fatal("Stack addition failure.\n"); +  } + #endif +  push_object(s = fast_clone_object(Stack_program)); +  other_st = get_storage(s, Stack_program); + #ifdef PIKE_DEBUG +  if (!other_st) { +  Pike_fatal("Stack lost storage.\n"); +  } + #endif +  add_ref(other_st->arr = Pike_sp[-2].u.array); +  return; +  } +  push_object(clone_object(Stack_program, 0)); +  } +  +  PIKEFUN mixed cast(string to) +  flags ID_PROTECTED; +  { +  if( to == MK_STRING("array") ) { +  apply_current(f_Stack_cq__values_fun_num, 0); +  } else { +  push_undefined(); +  } +  } +  +  PIKEFUN string _sprintf(int t) +  flags ID_PROTECTED; +  { +  if (t != '0') { +  push_undefined(); +  } +  +  push_constant_text("%O%O"); +  ref_push_program(Pike_fp->current_program); +  apply_current(f_Stack_cq__values_fun_num, 0); +  f_sprintf(3); +  } + } + /*! @endclass +  */ +  + /*! @endmodule +  */ +    /*! @module Pike    */