2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include "WETableCalcMatrix.h"
27 NSMutableArray *items;
39 typedef enum { WERow, WEColumn } WEOrientation;
41 static NSNull *null = nil;
43 @implementation WETableCalcMatrixSpan
45 + (id)spanWithObject:(id)_obj range:(NSRange *)_range {
47 span = [[WETableCalcMatrixSpan alloc] initWithObject:_obj range:_range];
48 return [span autorelease];
50 - (id)initWithObject:(id)_obj range:(NSRange *)_range {
51 self->object = [_obj retain];
52 self->range = *_range;
56 [self->object release];
71 - (BOOL)startsAtIndex:(unsigned)_idx {
72 return (_idx == self->range.location) ? YES : NO;
74 - (BOOL)occupiesIndex:(unsigned)_idx {
75 if (_idx < self->range.location)
77 if (_idx >= (self->range.location + self->range.length))
82 return self->range.length;
87 - (NSString *)description {
88 return [NSString stringWithFormat:
89 @"<0x%08X[%@]: object=0x%08X start=%d len=%d>",
90 self, NSStringFromClass([self class]),
96 @end /* WETableCalcMatrixSpan */
98 @interface WETableCalcMatrixStripe : NSObject
102 MatrixThread *threads;
104 WETableCalcMatrix *matrix; /* non-retained */
105 id delegate; /* non-retained */
108 - (unsigned)threadCount;
109 - (NSArray *)threads;
110 - (NSArray *)threadSpans;
114 - (void)addObject:(id)_obj atPositions:(unsigned *)_pos count:(unsigned)_c;
118 @implementation WETableCalcMatrixStripe
121 if (null == nil) null = [[NSNull null] retain];
124 - (id)initWithSize:(unsigned)_h
125 matrix:(WETableCalcMatrix *)_matrix
126 delegate:(id)_delegate
129 self->matrix = _matrix;
131 if ([_delegate respondsToSelector:
132 @selector(tableCalcMatrix:spanForObject:range:)])
133 self->delegate = _delegate;
141 for (i = 0; i < (unsigned)self->threadCount; i++) {
142 if (self->threads[i].objects) {
145 for (j = 0; j < self->size; j++)
146 [self->threads[i].objects[j] release];
147 free(self->threads[i].objects);
157 - (unsigned)threadCount {
158 return self->threadCount;
161 - (NSArray *)threadAtIndex:(unsigned)_idx {
166 objs = calloc(self->size, sizeof(id));
167 NSAssert(objs, @"could not allocate memory ..");
168 NSAssert(self->size > 0, @"invalid size ..");
170 for (i = 0; i < self->size; i++) {
171 objs[i] = self->threads[_idx].objects[i];
176 result = [NSArray arrayWithObjects:objs count:self->size];
180 - (NSArray *)spansAtIndex:(unsigned)_idx {
182 unsigned i, spanCount;
185 spans = calloc(self->size, sizeof(id));
187 for (i = 0, spanCount = 0; i < self->size; ) {
188 WETableCalcMatrixSpan *span;
193 obj = self->threads[_idx].objects[i];
195 if ((i + 1) == self->size) {
202 /* look ahead for similiar entries */
208 for (j = i + 1; j < self->size; j++) {
211 nextObj = self->threads[_idx].objects[j];
217 /* continue at end of this object */
222 if (self->delegate) {
223 span = [self->delegate tableCalcMatrix:self->matrix
228 span = [[WETableCalcMatrixSpan alloc] initWithObject:obj range:&r];
232 spans[spanCount] = span;
235 result = [NSArray arrayWithObjects:spans count:spanCount];
240 - (NSArray *)threads {
241 if (self->threadCount == 0)
243 if (self->threadCount == 1)
244 return [NSArray arrayWithObject:[self threadAtIndex:0]];
247 id threadArrays[self->threadCount];
250 for (i = 0; i < (unsigned)self->threadCount; i++)
251 threadArrays[i] = [self threadAtIndex:i];
253 return [NSArray arrayWithObjects:threadArrays count:self->threadCount];
256 - (NSArray *)threadSpans {
257 if (self->threadCount == 0)
259 else if (self->threadCount == 1)
260 return [NSArray arrayWithObject:[self spansAtIndex:0]];
262 NSArray *threadArrays[self->threadCount];
265 for (i = 0; i < (unsigned)self->threadCount; i++) {
266 threadArrays[i] = [self spansAtIndex:i];
269 return [NSArray arrayWithObjects:threadArrays count:self->threadCount];
275 - (unsigned)threadForPositions:(unsigned *)_pos count:(unsigned)_c {
279 if (self->threadCount == 0) {
280 self->threads = calloc(1, sizeof(MatrixThread));
281 self->threads[0].objects = calloc(self->size, sizeof(id));
282 self->threadCount = 1;
286 /* check each column */
287 for (i = 0; i < (unsigned)self->threadCount; i++) {
289 MatrixThread *column;
292 column = &(self->threads[i]);
294 /* check each required position in column */
295 for (j = 0, ok = YES; j < _c; j++) {
296 unsigned requiredPos;
298 requiredPos = _pos[j];
299 NSAssert(requiredPos < self->size, @"index to high ..");
301 if (column->objects[requiredPos] != nil) {
302 /* position already assigned */
308 /* all required position available, return column */
311 /* check next column */
314 /* all available threads are full, make new one .. */
316 self->threads = calloc(self->threadCount + 1, sizeof(MatrixThread));
317 memcpy(self->threads, tmp, self->threadCount * sizeof(MatrixThread));
318 self->threads[self->threadCount].objects = calloc(self->size, sizeof(id));
320 return (self->threadCount - 1);
323 - (void)addObject:(id)_obj atPositions:(unsigned *)_pos count:(unsigned)_c {
330 thread = [self threadForPositions:_pos count:_c];
331 NSAssert(thread < (unsigned)self->threadCount, @"invalid idx");
334 for (i = 0; i < _c; i++) {
335 unsigned requiredIdx;
337 requiredIdx = _pos[i];
340 NSAssert(requiredIdx < self->size, @"index to high ..");
341 NSAssert3(self->threads[thread].objects[requiredIdx] == nil,
342 @"index %i is already marked (by=0x%08X, my=0x%08X) !",
343 requiredIdx, self->threads[thread].objects[requiredIdx], _obj);
346 self->threads[thread].objects[requiredIdx] = RETAIN(_obj);
352 @interface WETableCalcMatrixPositionArray : NSObject
353 { /* mutable array of matrix coordinates */
356 MatrixCoord *positions;
359 - (void)addPosition:(unsigned)_x:(unsigned)_y;
360 - (void)checkForDuplicates;
362 /* narrow set to row or column */
363 - (unsigned *)indicesInColumn:(unsigned)_x count:(unsigned *)_count;
364 - (unsigned *)indicesInRow:(unsigned)_y count:(unsigned *)_count;
368 @implementation WETableCalcMatrixPositionArray
371 if (self->positions) free(self->positions);
375 - (void)checkForDuplicates {
378 for (j = 0; j < self->count; j++) {
381 for (i = 0; i < j; i++) {
382 NSAssert4(!((self->positions[j].x) == self->positions[i].x &&
383 (self->positions[j].y) == self->positions[i].y),
384 @"duplicate coordinate at %d and %d: %d/%d !",
385 j, i, self->positions[j].x, self->positions[j].y);
390 - (void)addPosition:(unsigned)_x:(unsigned)_y {
391 if (self->positions == NULL) {
392 self->positions = calloc(1, sizeof(MatrixCoord));
393 self->positions[0].x = _x;
394 self->positions[0].y = _y;
398 unsigned oldCount = self->count;
401 tmp = self->positions;
402 self->positions = calloc(oldCount + 1, sizeof(MatrixCoord));
403 memcpy(self->positions, tmp, (oldCount * sizeof(MatrixCoord)));
405 self->positions[oldCount].x = _x;
406 self->positions[oldCount].y = _y;
411 - (unsigned *)indicesIn:(WEOrientation)o index:(unsigned)_idx
412 count:(unsigned *)_count
414 unsigned i, rowCount;
418 for (i = 0, rowCount = 0; i < self->count; i++) {
421 j = (o == WEColumn) ? self->positions[i].x : self->positions[i].y;
429 pos = calloc(rowCount, sizeof(unsigned));
432 for (i = 0, p = pos; i < self->count; i++) {
435 j = (o == WEColumn) ? self->positions[i].x : self->positions[i].y;
439 ? self->positions[i].y
440 : self->positions[i].x;
447 - (unsigned *)indicesInRow:(unsigned)_y count:(unsigned *)_count {
448 return [self indicesIn:WERow index:_y count:_count];
450 - (unsigned *)indicesInColumn:(unsigned)_x count:(unsigned *)_count {
451 return [self indicesIn:WEColumn index:_x count:_count];
454 - (NSString *)description {
455 return [NSString stringWithFormat:@"<%08X[%@]: count=%d>",
456 self, NSStringFromClass([self class]),
460 @end /* WETableCalcMatrixPositionArray */
462 @implementation WETableCalcMatrix
468 static inline MatrixEntry *entryAt(WETableCalcMatrix *self, unsigned x,
470 return self->matrix +
471 (x * self->height * sizeof(MatrixEntry)) +
472 (y * sizeof(MatrixEntry));
475 - (id)initWithSize:(unsigned)_width:(unsigned)_height {
476 if (_width == 0 || _height == 0) {
477 [self logWithFormat:@"ERROR: specified invalid matrix dimensions: %ix%i",
483 NSAssert(_width > 0 && _height > 0, @"invalid args ..");
484 self->width = _width;
485 self->height = _height;
486 self->matrix = (void *)calloc(_width * _height, sizeof(MatrixEntry));
487 memset(self->matrix, 0, _width * _height * sizeof(MatrixEntry));
489 self->objToPos = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
490 NSObjectMapValueCallBacks,
496 [self removeAllObjects];
499 NSFreeMapTable(self->objToPos);
516 - (void)setDelegate:(id)_delegate {
517 self->delegate = _delegate;
520 [_delegate respondsToSelector:
521 @selector(tableCalcMatrix:shouldProcessColumn:forObject:)];
523 [_delegate respondsToSelector:
524 @selector(tableCalcMatrix:shouldProcessRow:forObject:)];
527 return self->delegate;
530 /* clearing the structure */
532 - (void)removeAllObjects {
535 if (self->objToPos) {
536 NSResetMapTable(self->objToPos);
537 self->objToPos = NULL;
540 if (self->matrix == NULL)
543 for (y = 0; y < self->height; y++) {
544 for (x = 0; x < self->width; x++) {
547 e = entryAt(self, x, y);
552 [e->items release]; e->items = nil;
559 - (BOOL)object:(id)_obj possibleInRow:(unsigned)_y {
560 /* optimization method, can always return 'YES' */
561 if (self->rowCheck) {
562 return [self->delegate tableCalcMatrix:self
569 - (BOOL)object:(id)_obj possibleInColumn:(unsigned)_x {
570 /* optimization method, can always return 'YES' */
571 if (self->columnCheck) {
572 return [self->delegate tableCalcMatrix:self
573 shouldProcessColumn:_x
579 - (BOOL)object:(id)_obj matchesCellAt:(unsigned)_x:(unsigned)_y {
580 return [self->delegate tableCalcMatrix:self
581 shouldPlaceObject:_obj
585 /* adding object to structure */
587 - (void)addObject:(id)_obj toCellAt:(unsigned)_x:(unsigned)_y {
588 WETableCalcMatrixPositionArray *positions;
591 if ((positions = NSMapGet(self->objToPos, _obj)) == nil) {
592 positions = [[WETableCalcMatrixPositionArray alloc] init];
593 NSMapInsert(self->objToPos, _obj, positions);
597 [positions checkForDuplicates];
599 e = entryAt(self, _x, _y);
602 e->items = [[NSMutableArray alloc] init];
604 [e->items addObject:_obj];
606 [positions checkForDuplicates];
607 [positions addPosition:_x:_y];
608 [positions checkForDuplicates];
611 /* placing objects */
613 - (void)placeObject:(id)_object {
616 if (NSMapGet(self->objToPos, _object)) {
617 //NSLog(@"already placed object %@ !", _object);
621 if (self->rowCheck) {
622 for (y = 0; y < self->height; y++) {
623 if (![self object:_object possibleInRow:y])
626 for (x = 0; x < self->width; x++) {
627 if ([self object:_object matchesCellAt:x:y]) {
628 /* add to cell x:y */
629 [self addObject:_object toCellAt:x:y];
635 for (x = 0; x < self->width; x++) {
636 if (![self object:_object possibleInColumn:x])
639 for (y = 0; y < self->height; y++) {
640 if ([self object:_object matchesCellAt:x:y]) {
641 /* add to cell x:y */
642 [self addObject:_object toCellAt:x:y];
649 - (void)placeObjects:(NSArray *)_objects {
652 if ((oc = [_objects count]) == 0)
655 for (i = 0; i < oc; i++)
656 [self placeObject:[_objects objectAtIndex:i]];
661 - (NSArray *)objectsInColumn:(unsigned)_x {
666 set = [[NSMutableSet alloc] init];
668 for (y = 0; y < self->height; y++) {
671 e = entryAt(self, _x, y);
673 [set addObjectsFromArray:e->items];
675 result = [set allObjects];
679 - (NSArray *)objectsInRow:(unsigned)_y {
684 set = [[NSMutableSet alloc] init];
686 for (x = 0; x < self->width; x++) {
689 e = entryAt(self, x, _y);
691 [set addObjectsFromArray:e->items];
693 result = [set allObjects];
698 - (NSArray *)spansOfColumn:(unsigned)_x {
699 WETableCalcMatrixStripe *stripe;
700 NSEnumerator *objects;
703 stripe = [[WETableCalcMatrixStripe alloc]
704 initWithSize:self->height
706 delegate:self->delegate];
708 objects = [[self objectsInColumn:_x] objectEnumerator];
709 while ((object = [objects nextObject])) {
710 WETableCalcMatrixPositionArray *pos;
714 pos = NSMapGet(self->objToPos, object);
715 [pos checkForDuplicates];
717 indices = [pos indicesInColumn:_x count:&idxCount];
718 NSAssert(indices, @"available in column, but no indices ?");
720 [stripe addObject:object atPositions:indices count:idxCount];
724 return [stripe threadSpans];
726 - (id)spansOfRow:(unsigned)_y {
727 WETableCalcMatrixStripe *stripe;
728 NSEnumerator *objects;
731 stripe = [[WETableCalcMatrixStripe alloc]
732 initWithSize:self->width
734 delegate:self->delegate];
736 objects = [[self objectsInRow:_y] objectEnumerator];
737 while ((object = [objects nextObject])) {
738 WETableCalcMatrixPositionArray *pos;
742 pos = NSMapGet(self->objToPos, object);
743 [pos checkForDuplicates];
745 indices = [pos indicesInRow:_y count:&idxCount];
746 NSAssert(indices, @"available in column, but no indices ?");
748 [stripe addObject:object atPositions:indices count:idxCount];
752 return [stripe threadSpans];
755 - (NSArray *)columnSpans {
756 id objs[self->width];
759 for (i = 0; i < self->width; i++) {
760 objs[i] = [self spansOfColumn:i];
761 if (objs[i] == nil) objs[i] = [NSArray array];
763 return [NSArray arrayWithObjects:objs count:self->width];
765 - (NSArray *)rowSpans {
766 id objs[self->height];
769 for (i = 0; i < self->height; i++) {
770 objs[i] = [self spansOfRow:i];
771 if (objs[i] == nil) objs[i] = [NSArray array];
773 return [NSArray arrayWithObjects:objs count:self->height];
778 - (unsigned)widthOfColumn:(unsigned)_x {
782 for (y = 0, count = 0; y < self->height; y++) {
785 e = entryAt(self, _x, y);
786 if ([e->items count] > count)
787 count = [e->items count];
792 - (unsigned)countOfColumn:(unsigned)_x {
793 return [[self objectsInColumn:_x] count];
796 @end /* WETableCalcMatrix */