e576bb2002-10-11Martin Nilsson /* || 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. */
1b10db2002-10-08Martin Nilsson 
24ddc71998-03-28Henrik Grubbström (Grubba) #include "global.h"
fc33451997-10-02Fredrik Hübinette (Hubbe) #include "cyclic.h"
16b4af2014-08-27Henrik Grubbström (Grubba) #define CYCLIC_HASH_SIZE 0x1000
fc33451997-10-02Fredrik Hübinette (Hubbe) 
c7719a2003-11-09Martin Nilsson static CYCLIC *cyclic_hash[CYCLIC_HASH_SIZE];
fc33451997-10-02Fredrik Hübinette (Hubbe) 
d4b7202014-08-25Henrik Grubbström (Grubba) static size_t cyclic_hash_func(CYCLIC *c) { size_t h; h = PTR_TO_INT(c->id); h *= 33; h ^= PTR_TO_INT(c->a); h *= 33; h ^= PTR_TO_INT(c->b); h *= 33; h ^= PTR_TO_INT(c->th);
16b4af2014-08-27Henrik Grubbström (Grubba) #if SIZEOF_CHAR_P > 4 h ^= h>>8; #endif /* Fold h. This is to retain as many bits of h as possible. * * NB: The "magic" constant below has a 1 bit every 10 bits * starting at the least significant, and is == 1 when * shifted right 20 bits. Note also that 32 - 20 == 12 * and 1<<12 == 0x1000 == CYCLIC_HASH_SIZE. * * The multiplication has the effect of accumulating * the segments of 10 bits of h in the most significant * segment, which is then shifted down. */ h *= 0x100401; h >>= 20; return h & (CYCLIC_HASH_SIZE-1);
d4b7202014-08-25Henrik Grubbström (Grubba) }
9dbc722021-09-28Henrik Grubbström (Grubba) void low_unlink_cyclic(CYCLIC *c)
fc33451997-10-02Fredrik Hübinette (Hubbe) {
c7241b2000-08-10Henrik Grubbström (Grubba)  size_t h;
fc33451997-10-02Fredrik Hübinette (Hubbe)  CYCLIC **p;
d4b7202014-08-25Henrik Grubbström (Grubba)  h = cyclic_hash_func(c);
fc33451997-10-02Fredrik Hübinette (Hubbe)  for(p=cyclic_hash+h;*p;p=&(p[0]->next)) { if(c == *p) { *p=c->next;
3b6bff2002-12-01Martin Stjernholm #ifdef CYCLIC_DEBUG fprintf (stderr, "%s: END_CYCLIC a=%p b=%p: no cycle\n", c->id, c->a, c->b); #endif
fc33451997-10-02Fredrik Hübinette (Hubbe)  return; } }
d4b7202014-08-25Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG Pike_fatal("Unlink cyclic on lost cyclic struct (%s).\n", c->id); #else
5aad932002-08-15Marcus Comstedt  Pike_fatal("Unlink cyclic on lost cyclic struct.\n");
d4b7202014-08-25Henrik Grubbström (Grubba) #endif
fc33451997-10-02Fredrik Hübinette (Hubbe) }
8822552010-06-01Henrik Grubbström (Grubba) PMOD_EXPORT void unlink_cyclic(CYCLIC *c)
545ca81997-10-07Fredrik Hübinette (Hubbe) { UNSET_ONERROR(c->onerr); low_unlink_cyclic(c); }
9dbc722021-09-28Henrik Grubbström (Grubba) void *low_begin_cyclic(CYCLIC *c, char *id, void *th, void *a, void *b)
fc33451997-10-02Fredrik Hübinette (Hubbe) {
c7241b2000-08-10Henrik Grubbström (Grubba)  size_t h;
d4b7202014-08-25Henrik Grubbström (Grubba)  void *ret = 0;
fc33451997-10-02Fredrik Hübinette (Hubbe)  CYCLIC *p;
d4b7202014-08-25Henrik Grubbström (Grubba)  c->ret = (void *)(ptrdiff_t)1; c->a = a; c->b = b; c->id = id; c->th = th; h = cyclic_hash_func(c);
fc33451997-10-02Fredrik Hübinette (Hubbe)  for(p=cyclic_hash[h];p;p=p->next)
14bb592000-05-06Fredrik Hübinette (Hubbe)  {
8d6f5c2014-08-26Henrik Grubbström (Grubba)  if(a == p->a && b==p->b && id==p->id && th==p->th)
14bb592000-05-06Fredrik Hübinette (Hubbe)  {
3b6bff2002-12-01Martin Stjernholm #ifdef CYCLIC_DEBUG fprintf (stderr, "%s: BEGIN_CYCLIC a=%p b=%p: found cycle\n", id, a, b); #endif
8d6f5c2014-08-26Henrik Grubbström (Grubba)  c->ret = ret = p->ret;
14bb592000-05-06Fredrik Hübinette (Hubbe)  break; } }
fc33451997-10-02Fredrik Hübinette (Hubbe) 
d4b7202014-08-25Henrik Grubbström (Grubba)  c->next = cyclic_hash[h]; cyclic_hash[h] = c;
3b6bff2002-12-01Martin Stjernholm #ifdef CYCLIC_DEBUG if (!ret) fprintf (stderr, "%s: BEGIN_CYCLIC a=%p b=%p: no cycle\n", id, a, b); #endif
14bb592000-05-06Fredrik Hübinette (Hubbe)  return ret;
fc33451997-10-02Fredrik Hübinette (Hubbe) }
9dbc722021-09-28Henrik Grubbström (Grubba)  PMOD_EXPORT void *begin_cyclic(CYCLIC *c, char *id, void *th, void *a, void *b) { void *ret = low_begin_cyclic(c, id, th, a, b); SET_ONERROR(c->onerr, low_unlink_cyclic, c); return ret; }