pike.git / src / builtin.cmod

version» Context lines:

pike.git/src/builtin.cmod:1:   /* -*- c -*-   || This file is part of Pike. For copyright information see COPYRIGHT.   || Pike is distributed under GPL, LGPL and MPL. See the file COPYING   || for more information. - || $Id: builtin.cmod,v 1.162 2004/09/10 15:24:42 grubba Exp $ + || $Id: builtin.cmod,v 1.163 2004/09/11 09:44:17 grubba Exp $   */      #include "global.h"   #include "interpret.h"   #include "svalue.h"   #include "pike_macros.h"   #include "object.h"   #include "program.h"   #include "array.h"   #include "pike_error.h"
pike.git/src/builtin.cmod:2920:   #define INIT_BLOCK(NODE) do { \    (NODE)->next = (NODE)->prev = NULL; \    (NODE)->refs = 1; \    (NODE)->val.type = T_INT; \    (NODE)->val.subtype = NUMBER_UNDEFINED; \    (NODE)->val.u.integer = 0; \    } while(0)      #undef EXIT_BLOCK   #define EXIT_BLOCK(NODE) do { \ +  if ((NODE)->prev) { \ +  free_list_node((NODE)->prev); \ +  } \ +  if ((NODE)->next) { \ +  free_list_node((NODE)->next); \ +  } \    free_svalue(&(NODE)->val); \    } while(0)      BLOCK_ALLOC_FILL_PAGES(list_node, 4);      PMOD_EXPORT void free_list_node(struct list_node *node)   {    if (!sub_ref(node)) {    really_free_list_node(node);    }
pike.git/src/builtin.cmod:2942:   PMOD_EXPORT void unlink_list_node(struct list_node *n)   {   #ifdef PIKE_DEBUG    if (!n) {    Pike_fatal("Unlinking NULL node.\n");    }    if (!n->next || !n->prev) {    Pike_fatal("Unlinking unlinked node.\n");    }   #endif /* PIKE_DEBUG */ +  if (n->prev->next == n) { + #ifdef PIKE_DEBUG +  if (n->next->prev != n) { +  Pike_fatal("Partially detached node.\n"); +  } + #endif /* PIKE_DEBUG */    n->prev->next = n->next;    n->next->prev = n->prev;    n->next = n->prev = NULL;       /* We've lost two references. */    free_list_node(n);    free_list_node(n); -  +  } else { + #ifdef PIKE_DEBUG +  if (n->next->prev == n) { +  Pike_fatal("Partially detached node.\n");    } -  + #endif /* PIKE_DEBUG */ +  /* The node is already detached. */ +  n->next = n->prev = NULL; +  } + }    -  + PMOD_EXPORT void detach_list_node(struct list_node *n) + { + #ifdef PIKE_DEBUG +  if (!n) { +  Pike_fatal("Detaching NULL node.\n"); +  } +  if (!n->next || !n->prev) { +  Pike_fatal("Detaching unlinked node.\n"); +  } + #endif /* PIKE_DEBUG */ +  if (n->prev->next == n) { + #ifdef PIKE_DEBUG +  if (n->next->prev != n) { +  Pike_fatal("Partially detached node.\n"); +  } + #endif /* PIKE_DEBUG */ +  n->prev->next = n->next; +  n->next->prev = n->prev; +  add_ref(n->next); +  add_ref(n->prev); +  +  /* We've lost two references. */ +  free_list_node(n); +  free_list_node(n); + #ifdef PIKE_DEBUG +  } else if (n->next->prev == n) { +  Pike_fatal("Partially detached node.\n"); + #endif /* PIKE_DEBUG */ +  } + } +    PMOD_EXPORT void prepend_list_node(struct list_node *node,    struct list_node *new)   {   #ifdef PIKE_DEBUG    if (!node) {    Pike_fatal("No node to prepend.\n");    }    if (!node->prev) {    Pike_fatal("Prepending unhooked node.\n");    }
pike.git/src/builtin.cmod:3005:    add_ref(new);    add_ref(new);   }      /*! @class List    *!    *! Linked list of values.    */   PIKECLASS List   { -  CVAR struct list_node *head; /* Doubles as head sentinel->next. */ +  CVAR struct list_node *head;    CVAR INT32 head_sentinel_refs; -  CVAR struct list_node *tail; /* NULL. head s->prev & tail s->next */ +  CVAR struct list_node *tail; /* Always NULL. */    CVAR INT32 tail_sentinel_refs; -  CVAR struct list_node *tail_pred; /* Doubles as tail sentinel->prev. */ +  CVAR struct list_node *tail_pred;      #define HEAD_SENTINEL(this) ((struct list_node *)(&this->head))   #define TAIL_SENTINEL(this) ((struct list_node *)(&this->tail))    -  +  /* Sentinel overlap description: +  * +  * List Head sentinel Tail sentinel +  * head next +  * head_sentinel_refs refs +  * tail prev next +  * tail_sentinel_refs refs +  * tail_pred prev +  */ +     INIT    {    THIS->tail = NULL;    THIS->head = TAIL_SENTINEL(THIS);    THIS->tail_pred = HEAD_SENTINEL(THIS);    THIS->head_sentinel_refs = THIS->tail_sentinel_refs = 1;    }       EXIT    {    struct list_node *node = THIS->head;    struct list_node *next;    while ((next = node->next)) { -  + #ifdef PIKE_DEBUG +  if (node->refs != 2) { +  Pike_fatal("Unexpected number of references for node: %d\n", +  node->refs); +  } + #endif /* PIKE_DEBUG */    unlink_list_node(node);    node = next;    }    }    -  +  /* Called at gc_check time. */ +  GC_CHECK +  { +  struct list_node *node = THIS->head; +  struct list_node *next; +  while ((next = node->next)) { +  debug_gc_check_svalues(&node->val, 1, " as member of a list"); +  node = next; +  } +  } +  +  /* Called at gc_mark time */ +  GC_RECURSE +  { +  struct list_node *node = THIS->head; +  struct list_node *next; +  while ((next = node->next)) { +  gc_recurse_svalues(&node->val, 1); +  node = next; +  } +  } +     /*! @decl void append(mixed ... values)    *!    *! Append @[values] to the end of the list.    *!    *! @seealso    *! @[insert()]    */    PIKEFUN void append(mixed ... values)    {    struct list_node *node = TAIL_SENTINEL(THIS);
pike.git/src/builtin.cmod:3093:       /*! @class _get_iterator    *!    *! @[Iterator] that loops over the @[List].    */    PIKECLASS _get_iterator    program_flags PROGRAM_USES_PARENT;    flags ID_STATIC;    {    CVAR struct list_node *cur; -  CVAR INT32 ind; +  CVAR INT32 ind; /* Not meaningful, but requred by the API. */    -  +  /* NOTE: cur may never refer to an unlinked node. +  * cur may however refer to a detached node, or to sentinels. +  */ +     INIT    {    struct external_variable_context loc;    struct List_struct *parent;       /* Find our parent. */    loc.o = Pike_fp->current_object;    loc.parent_identifier = Pike_fp->fun;    loc.inherit = INHERIT_FROM_INT(loc.o->prog, loc.parent_identifier);    find_external_context(&loc, 1);
pike.git/src/builtin.cmod:3119:    }       EXIT    {    if (THIS->cur) {    free_list_node(THIS->cur);    THIS->cur = NULL;    }    }    +  /* Called at gc_check time. */ +  GC_CHECK +  { +  if (!THIS->cur->next || !THIS->cur->prev) return; +  if (THIS->cur->next->prev == THIS->cur) { + #ifdef PIKE_DEBUG +  if (THIS->cur->prev->next != THIS->cur) { +  Pike_fatal("Partially detached node.\n"); +  } + #endif /* PIKE_DEBUG */ +  return; +  } + #ifdef PIKE_DEBUG +  if (THIS->cur->prev->next == THIS->cur) { +  Pike_fatal("Partially detached node.\n"); +  } + #endif /* PIKE_DEBUG */ +  /* Detached node. */ +  debug_gc_check_svalues(&THIS->cur->val, 1, +  " as current position for a list iterator"); +  /* FIXME: The node can hold other detached nodes alive! */ +  } +  +  /* Called at gc_mark time */ +  GC_RECURSE +  { +  if (!THIS->cur->next || !THIS->cur->prev) return; +  if (THIS->cur->next->prev == THIS->cur) { + #ifdef PIKE_DEBUG +  if (THIS->cur->prev->next != THIS->cur) { +  Pike_fatal("Partially detached node.\n"); +  } + #endif /* PIKE_DEBUG */ +  return; +  } + #ifdef PIKE_DEBUG +  if (THIS->cur->prev->next == THIS->cur) { +  Pike_fatal("Partially detached node.\n"); +  } + #endif /* PIKE_DEBUG */ +  /* Detached node. */ +  gc_recurse_svalues(&THIS->cur->val, 1); +  /* FIXME: The node can hold other detached nodes alive! */ +  } +     PIKEFUN int(0..1) `!()    flags ID_STATIC;    {    pop_n_elems(args);    push_int(!THIS->cur->next || !THIS->cur->prev);    }       PIKEFUN int(0..) index()    {    pop_n_elems(args);
pike.git/src/builtin.cmod:3324:    *!    *! @seealso    *! @[insert()], @[append()], @[set()]    */    PIKEFUN void delete()    {    struct list_node *next;    if (!(next = THIS->cur->next) || !THIS->cur->prev) {    Pike_error("Attempt to delete a sentinel.\n");    } +  add_ref(next); +  if (THIS->cur->refs == 3) {    unlink_list_node(THIS->cur); -  +  } else { +  /* There's some other iterator holding references to this node. */ +  detach_list_node(THIS->cur); +  }    free_list_node(THIS->cur); -  add_ref(THIS->cur = next); +  THIS->cur = next;    pop_n_elems(args);    push_int(0);    }       /*! @decl void set(mixed val)    *!    *! Set the value of the current position to @[val].    *!    *! @seealso    *! @[insert()], @[append()], @[delete()]