/* -*- mode: objc; coding: utf-8 -*- */ /* Toilet Lisp, a Common Lisp subset for the Étoilé runtime. * Copyright (C) 2008 Matthias Andreas Benkard. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * * This program 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #import "MLKArray.h" #import "functions.h" #import "util.h" #import #import #include #include @implementation MLKArray -(id) initWithDimensions:(NSArray *)dimensions { NSEnumerator *e; id el; _size = 1; e = [dimensions objectEnumerator]; while ((el = [e nextObject])) { el = denullify (el); _size *= MLKIntWithInteger (el); } LASSIGN (_dimensions, [dimensions mutableCopy]); _data = calloc (_size, sizeof (id)); _fillPointer = -1; _displacement = nil; return self; } -(id) idAtIndex:(NSUInteger)index { if (index > _size || (_fillPointer != -1 && index > _fillPointer)) [NSException raise:@"NSRangeException" format:@"Array index out of bounds"]; return _data[index]; } -(void) insertId:(id)anObject atIndex:(NSUInteger)index { _size++; if (_fillPointer != -1) _fillPointer++; _data = realloc (_data, _size * sizeof (id)); memmove (_data+index+1, _data+index, _size-index); _data[index] = anObject; } -(void) removeObjectAtIndex:(NSUInteger)index { _size--; if (_fillPointer != -1) _fillPointer--; memmove (_data+index, _data+index+1, _size-index-1); _data = realloc (_data, _size * sizeof (id)); } -(void) replaceIdAtIndex:(NSUInteger)index withId:(id)anObject { _data[index] = anObject; } -(NSUInteger) indexOfObjectIdenticalTo:(id)anObject { return [self indexOfObjectIdenticalTo:anObject inRange:NSMakeRange(0, _size)]; } static int eq (const void *x, const void *y) { return (x == y ? 0 : 1); } -(NSUInteger) indexOfObjectIdenticalTo:(id)anObject inRange:(NSRange)range { // FIXME: How to treat [NSNull null]? return ((id*)lfind (anObject, _data + range.location, &range.length, sizeof(id), eq) - _data); } -(NSUInteger) indexOfObject:(id)anObject { return [self indexOfObject:anObject inRange:NSMakeRange(0, _size)]; } static int equalp (const void *x, const void *y) { // FIXME: Hmm... What about fixnums? What about nil? return ([(id)x isEqual:(id)y] ? 0 : 1); } -(NSUInteger) indexOfObject:(id)anObject inRange:(NSRange)range { // FIXME: How to treat [NSNull null]? return ((id*)lfind (anObject, _data + range.location, &range.length, sizeof(id), equalp) - _data); } -(void) addId:(id)anObject { [self insertId:anObject atIndex:(_fillPointer == -1 ? _size-1 : _fillPointer-1)]; } -(void) setSize:(int)size ofDimension:(int)dimension { // I'd love to comment the following code, but I can't find the right // words to do so. There's this picture of jumping pointers in // parallel in my head. How to describe it? I pass. int i; int old_size; id *sourcePointer, *destPointer; int subblock_length, old_block_length, new_block_length; NSEnumerator *e; id el; id *old_data; old_size = _size; subblock_length = 1; for (i = dimension + 1; i < [_dimensions count]; i++) subblock_length *= [[_dimensions objectAtIndex:i] intValue]; old_block_length = subblock_length * [[_dimensions objectAtIndex:dimension] intValue]; new_block_length = subblock_length * size; [_dimensions replaceObjectAtIndex:dimension withObject:[MLKInteger integerWithInt:size]]; _size = 1; e = [_dimensions objectEnumerator]; while ((el = [e nextObject])) { el = denullify (el); _size *= MLKIntWithInteger (el); } old_data = _data; _data = calloc (_size, sizeof (id)); sourcePointer = old_data; destPointer = _data; while (destPointer < _data + size - 1) { memmove (destPointer, sourcePointer, (old_block_length < new_block_length ? old_block_length : new_block_length) * sizeof(id)); sourcePointer += old_block_length; destPointer += new_block_length; } free (old_data); } -(void) setFillPointer:(int)fillPointer { _fillPointer = fillPointer; } -(int) fillPointer { return _fillPointer; } -(void) setDisplacement:(NSArray *)array { LASSIGN (_displacement, array); } -(NSArray *) displacement { return _displacement; } -(NSUInteger) count { return (_fillPointer == -1 ? _size : _fillPointer); } -(id) objectAtIndex:(NSUInteger)index { NS_DURING { NS_VALUERETURN (nullify([self idAtIndex:index]), id); } NS_HANDLER { if ([[localException name] isEqualToString:@"NSRangeException"]) return nil; else [localException raise]; return nil; } NS_ENDHANDLER; } -(void) insertObject:(id)anObject atIndex:(NSUInteger)index { [self insertId:denullify(anObject) atIndex:index]; } -(void) addObject:(id)anObject { [self addId:denullify(anObject)]; } -(void) removeLastObject { if (_fillPointer == -1) [self removeObjectAtIndex:(_size-1)]; else if (_fillPointer == 0) [NSException raise:@"NSRangeException" format:@"Tried to remove an object from an empty array"]; else _fillPointer--; } -(void) replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject { [self replaceIdAtIndex:index withId:anObject]; } -(void) dealloc { free (_data); LDESTROY (_dimensions); LDESTROY (_displacement); [super dealloc]; } @end