/* Implementation of Objective C NeXT-compatible Storage object Copyright (C) 1993,1994, 1996 Free Software Foundation, Inc. Written by: Kresten Krab Thorup Dept. of Mathematics and Computer Science, Aalborg U., Denmark This file is part of the GNUstep Base Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* #include */ #include "Storage.h" #include #include #define GNU_STORAGE_NTH(x,N) \ ({ GNUStorageId* __s=(GNUStorageId*)(x); \ (void*)(((char*)__s->dataPtr)+(__s->elementSize*(N))); }) #define STORAGE_NTH(N) GNU_STORAGE_NTH (self, N) typedef struct { @defs (Storage) } GNUStorageId; @implementation Storage +initialize { if (self ==[Storage class]) [self setVersion:0]; /* beta release */ return self; } // INITIALIZING, FREEING; -initCount: (NSUInteger) numSlots elementSize: (NSUInteger) sizeInBytes description:(const char *) elemDesc; { [super init]; numElements = numSlots; maxElements = (numSlots > 0) ? numSlots : 1; elementSize = sizeInBytes; description = elemDesc; dataPtr = (void *) objc_malloc (maxElements * elementSize); bzero (dataPtr, numElements * elementSize); return self; } -init { return[self initCount: 1 elementSize:sizeof (id) description:@encode (id)]; } -(void) dealloc { if (dataPtr) free (dataPtr); [super dealloc]; } -(const char *) description { return description; } // COPYING; -copy { Storage *c =[super copy]; c->dataPtr = (void *) objc_malloc (maxElements * elementSize); memcpy (c->dataPtr, dataPtr, numElements * elementSize); return c; } // COMPARING TWO STORAGES; -(BOOL) isEqual:anObject { if ([anObject isKindOfClass:[Storage class]] &&[anObject count] ==[self count] && !memcmp (((GNUStorageId *) anObject)->dataPtr, dataPtr, numElements * elementSize)) return YES; else return NO; } // MANAGING THE STORAGE CAPACITY; static inline void _makeRoomForAnotherIfNecessary (Storage * self) { if (self->numElements == self->maxElements) { self->maxElements *= 2; self->dataPtr = (void *) objc_realloc (self->dataPtr, self->maxElements * self->elementSize); } } static inline void _shrinkIfDesired (Storage * self) { if (self->numElements < (self->maxElements / 2)) { self->maxElements /= 2; self->dataPtr = (void *) objc_realloc (self->dataPtr, self->maxElements * self->elementSize); } } -setAvailableCapacity:(NSUInteger) numSlots { if (numSlots > numElements) { maxElements = numSlots; dataPtr = (void *) objc_realloc (dataPtr, maxElements * elementSize); } return self; } -setNumSlots:(NSUInteger) numSlots { if (numSlots > numElements) { maxElements = numSlots; dataPtr = (void *) objc_realloc (dataPtr, maxElements * elementSize); bzero (STORAGE_NTH (numElements), (maxElements - numElements) * elementSize); } else if (numSlots < numElements) { numElements = numSlots; _shrinkIfDesired (self); } return self; } /* Manipulating objects by index */ #define CHECK_INDEX(IND) if (IND >= numElements) return 0 -(NSUInteger) count { return numElements; } -(void *) elementAt:(NSUInteger) index { CHECK_INDEX (index); return STORAGE_NTH (index); } -addElement:(void *) anElement { _makeRoomForAnotherIfNecessary (self); memcpy (STORAGE_NTH (numElements), anElement, elementSize); numElements++; return self; } -insertElement:(void *) anElement at:(NSUInteger) index { NSUInteger i; CHECK_INDEX (index); _makeRoomForAnotherIfNecessary (self); #ifndef STABLE_MEMCPY for (i = numElements; i >= index; i--) memcpy (STORAGE_NTH (i + 1), STORAGE_NTH (i), elementSize); #else memcpy (STORAGE_NTH (index + 1), STORAGE_NTH (index), elementSize * (numElements - index)); #endif memcpy (STORAGE_NTH (i), anElement, elementSize); numElements++; return self; } -removeElementAt:(NSUInteger) index { NSUInteger i; CHECK_INDEX (index); numElements--; #ifndef STABLE_MEMCPY for (i = index; i < numElements; i++) memcpy (STORAGE_NTH (i), STORAGE_NTH (i + 1), elementSize); #else memcpy (STORAGE_NTH (index), STORAGE_NTH (index + 1), elementSize * (numElements - index - 1)); #endif _shrinkIfDesired (self); return self; } -removeLastElement { if (numElements) { numElements--; _shrinkIfDesired (self); } return self; } -replaceElementAt:(NSUInteger) index with:(void *) newElement { CHECK_INDEX (index); memcpy (STORAGE_NTH (index), newElement, elementSize); return self; } /* Emptying the Storage */ -empty { numElements = 0; maxElements = 1; dataPtr = (void *) objc_realloc (dataPtr, maxElements * elementSize); return self; } /* Archiving */ -write:(TypedStream *) aStream { NSUInteger i; [super write:aStream]; objc_write_types (aStream, "III*", &numElements, &maxElements, &elementSize, &description); for (i = 0; i < numElements; i++) objc_write_type (aStream, description, STORAGE_NTH (i)); return self; } -read:(TypedStream *) aStream { NSUInteger i; [super read:aStream]; objc_read_types (aStream, "III*", &numElements, &maxElements, &elementSize, &description); dataPtr = (void *) objc_malloc (maxElements * elementSize); for (i = 0; i < numElements; i++) objc_read_type (aStream, description, STORAGE_NTH (i)); return self; } +new { return[[self alloc] init]; } +newCount:(NSUInteger) count elementSize:(NSUInteger) sizeInBytes description:(const char *) descriptor { return[[self alloc] initCount: count elementSize: sizeInBytes description:descriptor]; } @end