Johan Wikman / SQUIRREL3

Dependents:   Squirrel

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sqstate.cpp Source File

sqstate.cpp

00001 /*
00002     see copyright notice in squirrel.h
00003 */
00004 #include "sqpcheader.h"
00005 #include "sqopcodes.h"
00006 #include "sqvm.h"
00007 #include "sqfuncproto.h"
00008 #include "sqclosure.h"
00009 #include "sqstring.h"
00010 #include "sqtable.h"
00011 #include "sqarray.h"
00012 #include "squserdata.h"
00013 #include "sqclass.h"
00014 
00015 //SQObjectPtr _null_;
00016 //SQObjectPtr _true_(true);
00017 //SQObjectPtr _false_(false);
00018 //SQObjectPtr _one_((SQInteger)1);
00019 //SQObjectPtr _minusone_((SQInteger)-1);
00020 
00021 SQSharedState::SQSharedState()
00022 {
00023     _compilererrorhandler = NULL;
00024     _printfunc = NULL;
00025     _errorfunc = NULL;
00026     _debuginfo = false;
00027     _notifyallexceptions = false;
00028 }
00029 
00030 #define newsysstring(s) {   \
00031     _systemstrings->push_back(SQString::Create(this,s));    \
00032     }
00033 
00034 #define newmetamethod(s) {  \
00035     _metamethods->push_back(SQString::Create(this,s));  \
00036     _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \
00037     }
00038 
00039 bool CompileTypemask(SQIntVec &res,const SQChar *typemask)
00040 {
00041     SQInteger i = 0;
00042     
00043     SQInteger mask = 0;
00044     while(typemask[i] != 0) {
00045         
00046         switch(typemask[i]){
00047                 case 'o': mask |= _RT_NULL; break;
00048                 case 'i': mask |= _RT_INTEGER; break;
00049                 case 'f': mask |= _RT_FLOAT; break;
00050                 case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break;
00051                 case 's': mask |= _RT_STRING; break;
00052                 case 't': mask |= _RT_TABLE; break;
00053                 case 'a': mask |= _RT_ARRAY; break;
00054                 case 'u': mask |= _RT_USERDATA; break;
00055                 case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break;
00056                 case 'b': mask |= _RT_BOOL; break;
00057                 case 'g': mask |= _RT_GENERATOR; break;
00058                 case 'p': mask |= _RT_USERPOINTER; break;
00059                 case 'v': mask |= _RT_THREAD; break;
00060                 case 'x': mask |= _RT_INSTANCE; break;
00061                 case 'y': mask |= _RT_CLASS; break;
00062                 case 'r': mask |= _RT_WEAKREF; break;
00063                 case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue;
00064                 case ' ': i++; continue; //ignores spaces
00065                 default:
00066                     return false;
00067         }
00068         i++;
00069         if(typemask[i] == '|') { 
00070             i++; 
00071             if(typemask[i] == 0)
00072                 return false;
00073             continue; 
00074         }
00075         res.push_back(mask);
00076         mask = 0;
00077         
00078     }
00079     return true;
00080 }
00081 
00082 SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz)
00083 {
00084     SQInteger i=0;
00085     SQTable *t=SQTable::Create(ss,0);
00086     while(funcz[i].name!=0){
00087         SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f,0);
00088         nc->_nparamscheck = funcz[i].nparamscheck;
00089         nc->_name = SQString::Create(ss,funcz[i].name);
00090         if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask))
00091             return NULL;
00092         t->NewSlot(SQString::Create(ss,funcz[i].name),nc);
00093         i++;
00094     }
00095     return t;
00096 }
00097 
00098 void SQSharedState::Init()
00099 {   
00100     _scratchpad=NULL;
00101     _scratchpadsize=0;
00102 #ifndef NO_GARBAGE_COLLECTOR
00103     _gc_chain=NULL;
00104 #endif
00105     _stringtable = (SQStringTable*)SQ_MALLOC(sizeof(SQStringTable));
00106     new (_stringtable) SQStringTable(this);
00107     sq_new(_metamethods,SQObjectPtrVec);
00108     sq_new(_systemstrings,SQObjectPtrVec);
00109     sq_new(_types,SQObjectPtrVec);
00110     _metamethodsmap = SQTable::Create(this,MT_LAST-1);
00111     //adding type strings to avoid memory trashing
00112     //types names
00113     newsysstring(_SC("null"));
00114     newsysstring(_SC("table"));
00115     newsysstring(_SC("array"));
00116     newsysstring(_SC("closure"));
00117     newsysstring(_SC("string"));
00118     newsysstring(_SC("userdata"));
00119     newsysstring(_SC("integer"));
00120     newsysstring(_SC("float"));
00121     newsysstring(_SC("userpointer"));
00122     newsysstring(_SC("function"));
00123     newsysstring(_SC("generator"));
00124     newsysstring(_SC("thread"));
00125     newsysstring(_SC("class"));
00126     newsysstring(_SC("instance"));
00127     newsysstring(_SC("bool"));
00128     //meta methods
00129     newmetamethod(MM_ADD);
00130     newmetamethod(MM_SUB);
00131     newmetamethod(MM_MUL);
00132     newmetamethod(MM_DIV);
00133     newmetamethod(MM_UNM);
00134     newmetamethod(MM_MODULO);
00135     newmetamethod(MM_SET);
00136     newmetamethod(MM_GET);
00137     newmetamethod(MM_TYPEOF);
00138     newmetamethod(MM_NEXTI);
00139     newmetamethod(MM_CMP);
00140     newmetamethod(MM_CALL);
00141     newmetamethod(MM_CLONED);
00142     newmetamethod(MM_NEWSLOT);
00143     newmetamethod(MM_DELSLOT);
00144     newmetamethod(MM_TOSTRING);
00145     newmetamethod(MM_NEWMEMBER);
00146     newmetamethod(MM_INHERITED);
00147 
00148     _constructoridx = SQString::Create(this,_SC("constructor"));
00149     _registry = SQTable::Create(this,0);
00150     _consts = SQTable::Create(this,0);
00151     _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz);
00152     _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz);
00153     _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz);
00154     _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz);
00155     _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz);
00156     _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz);
00157     _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz);
00158     _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz);
00159     _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz);
00160     _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz);
00161 
00162 }
00163 
00164 SQSharedState::~SQSharedState()
00165 {
00166     _constructoridx.Null();
00167     _table(_registry)->Finalize();
00168     _table(_consts)->Finalize();
00169     _table(_metamethodsmap)->Finalize();
00170     _registry.Null();
00171     _consts.Null();
00172     _metamethodsmap.Null();
00173     while(!_systemstrings->empty()) {
00174         _systemstrings->back().Null();
00175         _systemstrings->pop_back();
00176     }
00177     _thread(_root_vm)->Finalize();
00178     _root_vm.Null();
00179     _table_default_delegate.Null();
00180     _array_default_delegate.Null();
00181     _string_default_delegate.Null();
00182     _number_default_delegate.Null();
00183     _closure_default_delegate.Null();
00184     _generator_default_delegate.Null();
00185     _thread_default_delegate.Null();
00186     _class_default_delegate.Null();
00187     _instance_default_delegate.Null();
00188     _weakref_default_delegate.Null();
00189     _refs_table.Finalize();
00190 #ifndef NO_GARBAGE_COLLECTOR
00191     SQCollectable *t = _gc_chain;
00192     SQCollectable *nx = NULL;
00193     if(t) {
00194         t->_uiRef++;
00195         while(t) {
00196             t->Finalize();
00197             nx = t->_next;
00198             if(nx) nx->_uiRef++;
00199             if(--t->_uiRef == 0)
00200                 t->Release();
00201             t = nx;
00202         }
00203     }
00204     assert(_gc_chain==NULL); //just to proove a theory
00205     while(_gc_chain){
00206         _gc_chain->_uiRef++;
00207         _gc_chain->Release();
00208     }
00209 #endif
00210 
00211     sq_delete(_types,SQObjectPtrVec);
00212     sq_delete(_systemstrings,SQObjectPtrVec);
00213     sq_delete(_metamethods,SQObjectPtrVec);
00214     sq_delete(_stringtable,SQStringTable);
00215     if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize);
00216 }
00217 
00218 
00219 SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name)
00220 {
00221     if(type(name) != OT_STRING)
00222         return -1;
00223     SQObjectPtr ret;
00224     if(_table(_metamethodsmap)->Get(name,ret)) {
00225         return _integer(ret);
00226     }
00227     return -1;
00228 }
00229 
00230 #ifndef NO_GARBAGE_COLLECTOR
00231 
00232 void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain)
00233 {
00234     switch(type(o)){
00235     case OT_TABLE:_table(o)->Mark(chain);break;
00236     case OT_ARRAY:_array(o)->Mark(chain);break;
00237     case OT_USERDATA:_userdata(o)->Mark(chain);break;
00238     case OT_CLOSURE:_closure(o)->Mark(chain);break;
00239     case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;
00240     case OT_GENERATOR:_generator(o)->Mark(chain);break;
00241     case OT_THREAD:_thread(o)->Mark(chain);break;
00242     case OT_CLASS:_class(o)->Mark(chain);break;
00243     case OT_INSTANCE:_instance(o)->Mark(chain);break;
00244     case OT_OUTER:_outer(o)->Mark(chain);break;
00245     case OT_FUNCPROTO:_funcproto(o)->Mark(chain);break;
00246     default: break; //shutup compiler
00247     }
00248 }
00249 
00250 
00251 void SQSharedState::RunMark(SQVM *vm,SQCollectable **tchain)
00252 {
00253     SQVM *vms = _thread(_root_vm);
00254     
00255     vms->Mark(tchain);
00256     
00257     _refs_table.Mark(tchain);
00258     MarkObject(_registry,tchain);
00259     MarkObject(_consts,tchain);
00260     MarkObject(_metamethodsmap,tchain);
00261     MarkObject(_table_default_delegate,tchain);
00262     MarkObject(_array_default_delegate,tchain);
00263     MarkObject(_string_default_delegate,tchain);
00264     MarkObject(_number_default_delegate,tchain);
00265     MarkObject(_generator_default_delegate,tchain);
00266     MarkObject(_thread_default_delegate,tchain);
00267     MarkObject(_closure_default_delegate,tchain);
00268     MarkObject(_class_default_delegate,tchain);
00269     MarkObject(_instance_default_delegate,tchain);
00270     MarkObject(_weakref_default_delegate,tchain);
00271 
00272 }
00273 
00274 SQInteger SQSharedState::ResurrectUnreachable(SQVM *vm)
00275 {
00276     SQInteger n=0;
00277     SQCollectable *tchain=NULL;
00278 
00279     RunMark(vm,&tchain);
00280 
00281     SQCollectable *resurrected = _gc_chain;
00282     SQCollectable *t = resurrected;
00283     //SQCollectable *nx = NULL;
00284 
00285     _gc_chain = tchain;
00286 
00287     SQArray *ret = NULL;
00288     if(resurrected) {
00289         ret = SQArray::Create(this,0);
00290         SQCollectable *rlast = NULL;
00291         while(t) {
00292             rlast = t;
00293             SQObjectType type = t->GetType();
00294             if(type != OT_FUNCPROTO && type != OT_OUTER) {
00295                 SQObject sqo;
00296                 sqo._type = type;
00297                 sqo._unVal.pRefCounted = t;
00298                 ret->Append(sqo);
00299             }
00300             t = t->_next;
00301             n++;
00302         }
00303 
00304         assert(rlast->_next == NULL);
00305         rlast->_next = _gc_chain;
00306         if(_gc_chain)
00307         {
00308             _gc_chain->_prev = rlast;
00309         }
00310         _gc_chain = resurrected;
00311     }
00312 
00313     t = _gc_chain;
00314     while(t) {
00315         t->UnMark();
00316         t = t->_next;
00317     }
00318 
00319     if(ret) {
00320         SQObjectPtr temp = ret;
00321         vm->Push(temp);
00322     }
00323     else {
00324         vm->PushNull();
00325     }
00326     return n;
00327 }
00328 
00329 SQInteger SQSharedState::CollectGarbage(SQVM *vm)
00330 {
00331     SQInteger n = 0;
00332     SQCollectable *tchain = NULL;
00333 
00334     RunMark(vm,&tchain);
00335 
00336     SQCollectable *t = _gc_chain;
00337     SQCollectable *nx = NULL;
00338     if(t) {
00339         t->_uiRef++;
00340         while(t) {
00341             t->Finalize();
00342             nx = t->_next;
00343             if(nx) nx->_uiRef++;
00344             if(--t->_uiRef == 0)
00345                 t->Release();
00346             t = nx;
00347             n++;
00348         }
00349     }
00350 
00351     t = tchain;
00352     while(t) {
00353         t->UnMark();
00354         t = t->_next;
00355     }
00356     _gc_chain = tchain;
00357     
00358     return n;
00359 }
00360 #endif
00361 
00362 #ifndef NO_GARBAGE_COLLECTOR
00363 void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c)
00364 {
00365     c->_prev = NULL;
00366     c->_next = *chain;
00367     if(*chain) (*chain)->_prev = c;
00368     *chain = c;
00369 }
00370 
00371 void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c)
00372 {
00373     if(c->_prev) c->_prev->_next = c->_next;
00374     else *chain = c->_next;
00375     if(c->_next)
00376         c->_next->_prev = c->_prev;
00377     c->_next = NULL;
00378     c->_prev = NULL;
00379 }
00380 #endif
00381 
00382 SQChar* SQSharedState::GetScratchPad(SQInteger size)
00383 {
00384     SQInteger newsize;
00385     if(size>0) {
00386         if(_scratchpadsize < size) {
00387             newsize = size + (size>>1);
00388             _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
00389             _scratchpadsize = newsize;
00390 
00391         }else if(_scratchpadsize >= (size<<5)) {
00392             newsize = _scratchpadsize >> 1;
00393             _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
00394             _scratchpadsize = newsize;
00395         }
00396     }
00397     return _scratchpad;
00398 }
00399 
00400 RefTable::RefTable()
00401 {
00402     AllocNodes(4);
00403 }
00404 
00405 void RefTable::Finalize()
00406 {
00407     RefNode *nodes = _nodes;
00408     for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
00409         nodes->obj.Null();
00410         nodes++;
00411     }
00412 }
00413 
00414 RefTable::~RefTable()
00415 {
00416     SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode)));
00417 }
00418 
00419 #ifndef NO_GARBAGE_COLLECTOR
00420 void RefTable::Mark(SQCollectable **chain)
00421 {
00422     RefNode *nodes = (RefNode *)_nodes;
00423     for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
00424         if(type(nodes->obj) != OT_NULL) {
00425             SQSharedState::MarkObject(nodes->obj,chain);
00426         }
00427         nodes++;
00428     }
00429 }
00430 #endif
00431 
00432 void RefTable::AddRef(SQObject &obj)
00433 {
00434     SQHash mainpos;
00435     RefNode *prev;
00436     RefNode *ref = Get(obj,mainpos,&prev,true);
00437     ref->refs++;
00438 }
00439 
00440 SQUnsignedInteger RefTable::GetRefCount(SQObject &obj)
00441 {
00442      SQHash mainpos;
00443      RefNode *prev;
00444      RefNode *ref = Get(obj,mainpos,&prev,true);
00445      return ref->refs;
00446 }
00447 
00448 
00449 SQBool RefTable::Release(SQObject &obj)
00450 {
00451     SQHash mainpos;
00452     RefNode *prev;
00453     RefNode *ref = Get(obj,mainpos,&prev,false);
00454     if(ref) {
00455         if(--ref->refs == 0) {
00456             SQObjectPtr o = ref->obj;
00457             if(prev) {
00458                 prev->next = ref->next;
00459             }
00460             else {
00461                 _buckets[mainpos] = ref->next;
00462             }
00463             ref->next = _freelist;
00464             _freelist = ref;
00465             _slotused--;
00466             ref->obj.Null();
00467             //<<FIXME>>test for shrink?
00468             return SQTrue;
00469         }
00470     }
00471     else {
00472         assert(0);
00473     }
00474     return SQFalse;
00475 }
00476 
00477 void RefTable::Resize(SQUnsignedInteger size)
00478 {
00479     RefNode **oldbucks = _buckets;
00480     RefNode *t = _nodes;
00481     SQUnsignedInteger oldnumofslots = _numofslots;
00482     AllocNodes(size);
00483     //rehash
00484     SQUnsignedInteger nfound = 0;
00485     for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {
00486         if(type(t->obj) != OT_NULL) {
00487             //add back;
00488             assert(t->refs != 0);
00489             RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);
00490             nn->refs = t->refs; 
00491             t->obj.Null();
00492             nfound++;
00493         }
00494         t++;
00495     }
00496     assert(nfound == oldnumofslots);
00497     SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode)));
00498 }
00499 
00500 RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj)
00501 {
00502     RefNode *t = _buckets[mainpos];
00503     RefNode *newnode = _freelist;
00504     newnode->obj = obj;
00505     _buckets[mainpos] = newnode;
00506     _freelist = _freelist->next;
00507     newnode->next = t;
00508     assert(newnode->refs == 0);
00509     _slotused++;
00510     return newnode;
00511 }
00512 
00513 RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add)
00514 {
00515     RefNode *ref;
00516     mainpos = ::HashObj(obj)&(_numofslots-1);
00517     *prev = NULL;
00518     for (ref = _buckets[mainpos]; ref; ) {
00519         if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj))
00520             break;
00521         *prev = ref;
00522         ref = ref->next;
00523     }
00524     if(ref == NULL && add) {
00525         if(_numofslots == _slotused) {
00526             assert(_freelist == 0);
00527             Resize(_numofslots*2);
00528             mainpos = ::HashObj(obj)&(_numofslots-1);
00529         }
00530         ref = Add(mainpos,obj);
00531     }
00532     return ref;
00533 }
00534 
00535 void RefTable::AllocNodes(SQUnsignedInteger size)
00536 {
00537     RefNode **bucks;
00538     RefNode *nodes;
00539     bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode)));
00540     nodes = (RefNode *)&bucks[size];
00541     RefNode *temp = nodes;
00542     SQUnsignedInteger n;
00543     for(n = 0; n < size - 1; n++) {
00544         bucks[n] = NULL;
00545         temp->refs = 0;
00546         new (&temp->obj) SQObjectPtr;
00547         temp->next = temp+1;
00548         temp++;
00549     }
00550     bucks[n] = NULL;
00551     temp->refs = 0;
00552     new (&temp->obj) SQObjectPtr;
00553     temp->next = NULL;
00554     _freelist = nodes;
00555     _nodes = nodes;
00556     _buckets = bucks;
00557     _slotused = 0;
00558     _numofslots = size;
00559 }
00560 //////////////////////////////////////////////////////////////////////////
00561 //SQStringTable
00562 /*
00563 * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)
00564 * http://www.lua.org/copyright.html#4
00565 * http://www.lua.org/source/4.0.1/src_lstring.c.html
00566 */
00567 
00568 SQStringTable::SQStringTable(SQSharedState *ss)
00569 {
00570     _sharedstate = ss;
00571     AllocNodes(4);
00572     _slotused = 0;
00573 }
00574 
00575 SQStringTable::~SQStringTable()
00576 {
00577     SQ_FREE(_strings,sizeof(SQString*)*_numofslots);
00578     _strings = NULL;
00579 }
00580 
00581 void SQStringTable::AllocNodes(SQInteger size)
00582 {
00583     _numofslots = size;
00584     _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots);
00585     memset(_strings,0,sizeof(SQString*)*_numofslots);
00586 }
00587 
00588 SQString *SQStringTable::Add(const SQChar *news,SQInteger len)
00589 {
00590     if(len<0)
00591         len = (SQInteger)scstrlen(news);
00592     SQHash newhash = ::_hashstr(news,len);
00593     SQHash h = newhash&(_numofslots-1);
00594     SQString *s;
00595     for (s = _strings[h]; s; s = s->_next){
00596         if(s->_len == len && (!memcmp(news,s->_val,rsl(len))))
00597             return s; //found
00598     }
00599 
00600     SQString *t = (SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString));
00601     new (t) SQString;
00602     t->_sharedstate = _sharedstate;
00603     memcpy(t->_val,news,rsl(len));
00604     t->_val[len] = _SC('\0');
00605     t->_len = len;
00606     t->_hash = newhash;
00607     t->_next = _strings[h];
00608     _strings[h] = t;
00609     _slotused++;
00610     if (_slotused > _numofslots)  /* too crowded? */
00611         Resize(_numofslots*2);
00612     return t;
00613 }
00614 
00615 void SQStringTable::Resize(SQInteger size)
00616 {
00617     SQInteger oldsize=_numofslots;
00618     SQString **oldtable=_strings;
00619     AllocNodes(size);
00620     for (SQInteger i=0; i<oldsize; i++){
00621         SQString *p = oldtable[i];
00622         while(p){
00623             SQString *next = p->_next;
00624             SQHash h = p->_hash&(_numofslots-1);
00625             p->_next = _strings[h];
00626             _strings[h] = p;
00627             p = next;
00628         }
00629     }
00630     SQ_FREE(oldtable,oldsize*sizeof(SQString*));
00631 }
00632 
00633 void SQStringTable::Remove(SQString *bs)
00634 {
00635     SQString *s;
00636     SQString *prev=NULL;
00637     SQHash h = bs->_hash&(_numofslots - 1);
00638     
00639     for (s = _strings[h]; s; ){
00640         if(s == bs){
00641             if(prev)
00642                 prev->_next = s->_next;
00643             else
00644                 _strings[h] = s->_next;
00645             _slotused--;
00646             SQInteger slen = s->_len;
00647             s->~SQString();
00648             SQ_FREE(s,sizeof(SQString) + rsl(slen));
00649             return;
00650         }
00651         prev = s;
00652         s = s->_next;
00653     }
00654     assert(0);//if this fail something is wrong
00655 }