static int ReplaceWithIterator(Iterator *it, void *data,int direction) { struct strCollectionIterator *ali = (struct strCollectionIterator *)it; int result; size_t pos; if (it == NULL) { return NullPtrError("Replace"); } if (ali->SC->count == 0) return 0; if (ali->timestamp != ali->SC->timestamp) { ali->SC->RaiseError("Replace",CONTAINER_ERROR_OBJECT_CHANGED); return CONTAINER_ERROR_OBJECT_CHANGED; } if (ali->SC->Flags & CONTAINER_READONLY) { ali->SC->RaiseError("Replace",CONTAINER_ERROR_READONLY); return CONTAINER_ERROR_READONLY; } pos = ali->index; if (direction) GetNext(it); else GetPrevious(it); if (data == NULL) result = RemoveAt(ali->SC,pos); else { result = ReplaceAt(ali->SC,pos,data); } if (result >= 0) { ali->timestamp = ali->SC->timestamp; } return result; }
/*------------------------------------------------------------------------ Procedure: Add ID:1 Purpose: Adds a string to the string collection. Input: The collection and the string to be added to it Output: Number of items in the collection or <= 0 if error Errors: ------------------------------------------------------------------------*/ static int Add(ElementType *SC,const CHAR_TYPE *newval) { if (SC == NULL) { return NullPtrError("Add"); } if (SC->Flags & CONTAINER_READONLY) return ReadOnlyError(SC,"Add"); if ((SC->count+1) >= SC->capacity) { int r = Resize(SC); if (r <= 0) return r; } if (newval) { SC->contents[SC->count] = DuplicateString(SC,newval,"Add"); if (SC->contents[SC->count] == NULL) { return 0; } } else SC->contents[SC->count] = NULL; SC->timestamp++; ++SC->count; return 1; }
static int ReplaceWithIterator(Iterator *it, void *data,int direction) { struct HashTableIterator *li = (struct HashTableIterator *)it; int result; HashIndex current; if (it == NULL) { return NullPtrError("Replace"); } if (li->timestamp != li->ht->timestamp) { li->ht->RaiseError("Replace",CONTAINER_ERROR_OBJECT_CHANGED); return CONTAINER_ERROR_OBJECT_CHANGED; } if (li->ht->Flags & CONTAINER_READONLY) { li->ht->RaiseError("Replace",CONTAINER_ERROR_READONLY,li->ht); return CONTAINER_ERROR_READONLY; } if (li->ht->count == 0) return 0; current = *li->Current; GetNext(it); if (data == NULL) result = Remove(li->ht, current.This->key,current.This->klen); else { memcpy(current.This->val,data,li->ht->ElementSize); result = 1; } if (result >= 0) { li->timestamp = li->ht->timestamp; } return result; }
static int SetCapacity(ElementType *SC,size_t newCapacity) { CHAR_TYPE **newContents; if (SC == NULL) { return NullPtrError("SetCapacity"); } if (SC->Flags & CONTAINER_READONLY) { return ReadOnlyError(SC,"SetCapacity"); } newContents = SC->Allocator->malloc(newCapacity*sizeof(void *)); if (newContents == NULL) { return NoMemoryError(SC,"SetCapacity"); } memset(SC->contents,0,sizeof(void *)*newCapacity); SC->capacity = newCapacity; if (newCapacity > SC->count) newCapacity = SC->count; else if (newCapacity < SC->count) SC->count = newCapacity; if (newCapacity > 0) { memcpy(newContents,SC->contents,newCapacity*sizeof(void *)); } SC->Allocator->free(SC->contents); SC->contents = newContents; SC->timestamp++; return 1; }
static Mask *CompareEqualScalar(const ElementType *left,const CHAR_TYPE *right,Mask *bytearray) { size_t left_len; size_t i; if (left == NULL || right == NULL) { NullPtrError("CompareEqual"); return NULL; } left_len = left->count; if (bytearray == NULL || iMask.Size(bytearray) < left_len) { if (bytearray) iMask.Finalize(bytearray); bytearray = iMask.Create(left_len); if (bytearray == NULL) { iError.RaiseError("CompareEqual",CONTAINER_ERROR_NOMEMORY); return NULL; } } else iMask.Clear(bytearray); if (bytearray == NULL) { iError.RaiseError("CompareEqual",CONTAINER_ERROR_NOMEMORY); return NULL; } for (i=0; i<left_len;i++) { bytearray->data[i] = !STRCMP(left->contents[i],right); } return bytearray; }
static int Select(ElementType *src,const Mask *m) { size_t i,offset=0; if (src == NULL || m == NULL) return NullPtrError("Select"); if (m->length != src->count) { iError.RaiseError("iVector.Select",CONTAINER_ERROR_BADMASK,src,m); return CONTAINER_ERROR_BADMASK; } for (i=0; i<m->length;i++) { if (m->data[i]) { if (i != offset) { if (src->DestructorFn) src->DestructorFn(src->contents[offset]); src->Allocator->free(src->contents[offset]); src->contents[offset] = src->contents[i]; } offset++; } } src->count = offset; if (offset < i) { while (offset < i) { if (src->DestructorFn) src->DestructorFn(src->contents[offset]); src->Allocator->free(src->contents[offset]); src->contents[offset] = NULL; offset++; } } return 1; }
static int Reverse(ElementType *SC) { CHAR_TYPE **p, **q, *t; if (SC == NULL) { return NullPtrError("Reverse"); } if (SC->Flags & CONTAINER_READONLY) { return ReadOnlyError(SC,"Reverse"); } if (SC->count < 2) return 1; p = SC->contents; q = &p[SC->count-1]; while ( p < q ) { t = *p; *p = *q; *q = t; p++; q--; } SC->timestamp++; return 1; }
static int RemoveRange(ElementType *SC,size_t start, size_t end) { size_t i; if (SC == NULL) return NullPtrError("RemoveRange"); if (SC->count == 0) return 0; if (end > SC->count) end = SC->count; if (start == end) return 0; if (start >= SC->count) return IndexError(SC,start,"RemoveRange"); if (SC->DestructorFn) { for (i=start; i<end; i++) { SC->DestructorFn(SC->contents[i]); SC->Allocator->free(SC->contents[i]); } } else { for (i=start; i<end; i++) { SC->Allocator->free(SC->contents[i]); } } if (end < SC->count) memmove(SC->contents+start, SC->contents+end, (SC->count-end)*sizeof(char *)); SC->count -= end - start; return 1; }
static int WriteToFile(const ElementType *SC,const char *fileName) { FILE *f; size_t i; int result = 0; CHAR_TYPE nl[2]; if (SC == NULL || fileName == NULL) { return NullPtrError("WriteToFile"); } f = fopen(fileName,"w"); if (f == NULL) { SC->RaiseError("istrCollection.WriteToFile",CONTAINER_ERROR_FILEOPEN); return CONTAINER_ERROR_FILEOPEN; } nl[0] = NEWLINE; for (i=0; i<SC->count;i++) { if (SC->contents[i][0] && fwrite(SC->contents[i],1,strlen((char *)SC->contents[i]),f) == 0) { writeerror: iError.RaiseError("istrCollection.WriteToFile",CONTAINER_ERROR_FILE_WRITE); result = CONTAINER_ERROR_FILE_WRITE; break; } if (fwrite(nl,1,sizeof(CHAR_TYPE),f) == 0) goto writeerror; } if (i == SC->count && i > 0) result = 1; fclose(f); return result; }
static int EraseInternal(ElementType *SC,const CHAR_TYPE *str,int all) { size_t i; int result = CONTAINER_ERROR_NOTFOUND; if (SC == NULL) { return NullPtrError("Erase"); } if (str == NULL) { return BadArgError(SC,"Erase"); } if (SC->Flags & CONTAINER_READONLY) return ReadOnlyError(SC,"Erase"); for (i=0; i<SC->count;i++) { if (!SC->strcompare((const void **)&SC->contents[i], (const void **)&str,SC->StringCompareContext)) { if (SC->DestructorFn) SC->DestructorFn(SC->contents[i]); SC->Allocator->free(SC->contents[i]); if (i < (SC->count-1)) memmove(SC->contents+i,SC->contents+i+1,(SC->count-i)*sizeof(char *)); --SC->count; SC->contents[SC->count]=NULL; SC->timestamp++; result = 1; if (all == 0) break; i--; } } return result; }
static ElementType *GetRange(ElementType *SC, size_t start,size_t end) { ElementType *result; size_t idx=0; if (SC == NULL) { NullPtrError("GetRange"); return NULL; } result = SC->VTable->Create(SC->count); result->VTable = SC->VTable; if (SC->count == 0) return result; if (end >= SC->count) end = SC->count; if (start > end) return result; while (start < end) { result->contents[idx] = DuplicateString(SC,SC->contents[start],"GetRange"); if (result->contents[idx] == NULL) { while (idx > 0) { if (idx > 0) idx--; SC->Allocator->free(result->contents[idx]); } SC->Allocator->free(SC->contents); SC->Allocator->free(result); NoMemoryError(SC,"GetRange"); return NULL; } start++; } result->Flags = SC->Flags; return result; }
static size_t PopBack(ElementType *SC,CHAR_TYPE *buffer,size_t buflen) { CHAR_TYPE *result; size_t len,tocopy; if (SC == NULL) { NullPtrError("PopBack"); return 0; } if (SC->Flags&CONTAINER_READONLY) return 0; if (SC->count == 0) return 0; len = 1+strlen((char *)SC->contents[SC->count-1]); SC->count--; result = SC->contents[SC->count]; SC->contents[SC->count] = NULL; SC->timestamp++; tocopy = len; if (buffer) { if (buflen < tocopy) tocopy = buflen-1; memcpy(buffer,result,tocopy); buffer[tocopy-1] = 0; } SC->Allocator->free(result); return len; }
static ElementType *IndexIn(const ElementType *SC,const Vector *AL) { ElementType *result = NULL; size_t i,top,idx; const CHAR_TYPE *p; int r; if (SC == NULL || AL == NULL) { NullPtrError("IndexIn"); return NULL; } if (iVector.GetElementSize(AL) != sizeof(size_t)) { SC->RaiseError("istrCollection.IndexIn",CONTAINER_ERROR_INCOMPATIBLE); return NULL; } top = iVector.Size(AL); result = iElementType.Create(top); for (i=0; i<top;i++) { idx = *(size_t *)iVector.GetElement(AL,i); p = GetElement(SC,idx); if (p == NULL) goto err; r = Add(result,p); if (r < 0) { err: Finalize(result); return NULL; } } return result; }
static size_t GetCapacity(const ElementType *SC) { if (SC == NULL) { NullPtrError("SetCapacity"); return 0; } return SC->capacity; }
/*------------------------------------------------------------------------ Procedure: IsReadOnly ID:1 Purpose: Reads the read-only flag Input: The collection Output: the state of the flag Errors: None ------------------------------------------------------------------------*/ static unsigned GetFlags(const ElementType *SC) { if (SC == NULL) { NullPtrError("GetFlags"); return 0; } return SC->Flags; }
static size_t GetCount(const ElementType *SC) { if (SC == NULL) { NullPtrError("GetCount"); return 0; } return SC->count; }
static void *GetCurrent(Iterator *it) { struct strCollectionIterator *ali = (struct strCollectionIterator *)it; if (ali == NULL) { NullPtrError("GetCurrent"); return NULL; } return ali->current; }
static int Append(ElementType *SC1, ElementType *SC2) { if (SC1 == NULL || SC2 == NULL) { return NullPtrError("Append"); } if (SC1->Flags & CONTAINER_READONLY) { return ReadOnlyError(SC1,"Append"); } return AddRange(SC1,SC2->count,(const CHAR_TYPE **)SC2->contents); }
static int Contains(const HashTable *ht,const void *Key,size_t klen) { if (ht == NULL) { return NullPtrError("Contains"); } if (Key == NULL) { iError.RaiseError("Contains",CONTAINER_ERROR_BADARG); return CONTAINER_ERROR_BADARG; } return GetElement(ht,Key,klen) ? 1 : 0; }
static StringCompareFn SetCompareFunction(ElementType *SC,StringCompareFn fn) { StringCompareFn oldFn; if (SC == NULL) { NullPtrError("SetCompareFunction"); return 0; } oldFn = SC->strcompare; if (fn) SC->strcompare = fn; return oldFn; }
static int DeleteIterator(Iterator *it) { struct strCollectionIterator *sci = (struct strCollectionIterator *)it; ElementType *SC; if (sci == NULL) { return NullPtrError("DeleteIterator"); } SC = sci->SC; SC->Allocator->free(it); return 1; }
/*------------------------------------------------------------------------ Procedure: SetReadOnly ID:1 Purpose: Sets the value of the read only flag Input: The collection to be changed Output: The old value of the flag Errors: None ------------------------------------------------------------------------*/ static unsigned SetFlags(ElementType *SC,unsigned newval) { unsigned oldval; if (SC == NULL) { NullPtrError("SetFlags"); return 0; } oldval = SC->Flags; SC->Flags = newval; SC->timestamp++; return oldval; }
static ElementType *Load(FILE *stream, ReadFunction readFn,void *arg) { size_t i,len=0; ElementType *result,SC; guid Guid; if (stream == NULL) { NullPtrError("Load"); return NULL; } if (readFn == NULL) { readFn = DefaultLoadFunction; arg = &len; } if (fread(&Guid,sizeof(guid),1,stream) == 0) { iError.RaiseError("istrCollection.Load",CONTAINER_ERROR_FILE_READ); return NULL; } if (memcmp(&Guid,&strCollectionGuid,sizeof(guid))) { iError.RaiseError("istrCollection.Load",CONTAINER_ERROR_WRONGFILE); return NULL; } if (fread(&SC,1,sizeof(ElementType),stream) == 0) { iError.RaiseError("istrCollection.Load",CONTAINER_ERROR_FILE_READ); return NULL; } result = iElementType.Create(SC.count); if (result == 0) { return NULL; } result->Flags = SC.Flags; for (i=0; i< SC.count; i++) { if (decode_ule128(stream, &len) <= 0) { goto err; } len++; result->contents[i] = result->Allocator->malloc(len); if (result->contents[i] == NULL) { NoMemoryError(result,"Load"); Finalize(result); return NULL; } if (readFn(result->contents[i],arg,stream) <= 0) { err: iError.RaiseError("ElementType.Load",CONTAINER_ERROR_FILE_READ); break; } result->count++; } return result; }
static void *GetFirst(Iterator *it) { struct strCollectionIterator *ali = (struct strCollectionIterator *)it; if (ali == NULL) { NullPtrError("GetFirst"); return NULL; } if (ali->SC->count == 0) return NULL; ali->index = 0; ali->current = ali->SC->contents[0]; return ali->current; }
static CHAR_TYPE *Front(const ElementType *cb) { if (cb == NULL) { NullPtrError("Front"); return NULL; } if (cb->Flags&CONTAINER_READONLY) { cb->RaiseError("Front",CONTAINER_ERROR_READONLY); return NULL; } if (cb->count == 0) return NULL; return cb->contents[0]; }
static int InsertIn(ElementType *source, size_t idx, ElementType *newData) { size_t newCount,i,j,siz; CHAR_TYPE **p,**oldcontents; if (source == NULL || newData == NULL) { return NullPtrError("InsertIn"); } if (source->Flags & CONTAINER_READONLY) return ReadOnlyError(source,"InsertIn"); if (idx > source->count) { return IndexError(source,idx,"InsertIn"); } newCount = source->count + newData->count; if (newData->count == 0) return 1; if (newCount == 0) return 1; if (newCount >= (source->capacity-1)) { int r = ResizeTo(source,1+newCount+newCount/4); if (r <= 0) return r; } p = source->contents; siz = source->capacity*sizeof(CHAR_TYPE *); oldcontents = source->Allocator->malloc(siz); if (oldcontents == NULL) { return NoMemoryError(source,"InsertIn"); } memset(oldcontents,0,siz); memcpy(oldcontents,p,sizeof(char *)*source->count); if (idx < source->count) { memmove(p+(idx+newData->count), p+idx, (source->count-idx)*sizeof(char *)); } for (i=idx,j=0; i<idx+newData->count;i++,j++) { source->contents[i] = DuplicateString(newData,newData->contents[j],"InsertIn"); if (source->contents[i] == NULL) { source->Allocator->free(source->contents); source->contents = oldcontents; return NoMemoryError(source,"InsertIn"); } } source->Allocator->free(oldcontents); source->timestamp++; source->count = newCount; return 1; }
static int Apply(ElementType *SC,int (*Applyfn)(CHAR_TYPE *,void *),void *arg) { size_t i; if (SC == NULL) { return NullPtrError("Apply"); } if (Applyfn == NULL) { return BadArgError(SC,"Apply"); } for (i=0; i<SC->count;i++) { Applyfn(SC->contents[i],arg); } return 1; }
static CHAR_TYPE *GetElement(const ElementType *SC,size_t idx) { if (SC == NULL) { NullPtrError("GetElement"); return NULL; } if (SC->Flags & CONTAINER_READONLY) { ReadOnlyError(SC,"GetElement"); return NULL; } if (idx >=SC->count) { IndexError(SC,idx,"GetElement"); return NULL; } return SC->contents[idx]; }
static int Sort(ElementType *SC) { CompareInfo ci; ci.ExtraArgs = NULL; ci.ContainerLeft = SC; ci.ContainerRight = NULL; if (SC == NULL) { return NullPtrError("Sort"); } if (SC->Flags & CONTAINER_READONLY) { return ReadOnlyError(SC,"Sort"); } qsortEx(SC->contents,SC->count,sizeof(char *),(CompareFunction)SC->strcompare,&ci); SC->timestamp++; return 1; }
static int Contains(const ElementType *SC,const CHAR_TYPE *str) { int c; size_t i; if (SC == NULL) { return NullPtrError("Contains"); } if (str == NULL) return 0; c = *str; for (i=0; i<SC->count;i++) { if (c == SC->contents[i][0] && !SC->strcompare((const void **)&SC->contents[i], (const void **)&str,NULL)) return 1; } return 0; }