#include "LCRangeQuery.h" #include "LCBooleanQuery.h" #include "LCTermQuery.h" #include "LCTerm.h" #include "LCTermEnum.h" #include "LCIndexReader.h" #include "NSString+Additions.h" #include "LCSmallFloat.h" #include "GNUstep.h" @implementation LCRangeQuery - (id) initWithLowerTerm: (LCTerm *) lower upperTerm: (LCTerm *) upper inclusive: (BOOL) incl { if (lower == nil && upper == nil) { NSLog(@"At least one term must be non-null"); return nil; } if (lower && upper && [[lower field] isEqualToString: [upper field]] == NO) { NSLog(@"Both terms must be for the same field"); return nil; } self = [self init]; lowerTerm = [[LCTerm alloc] initWithField: [upper field] text: @""]; if (lower) { [lowerTerm setTerm: lower]; } if (upper) { upperTerm = [[LCTerm alloc] initWithField: [upper field] text: [upper text]]; } else { upperTerm = nil; } inclusive = incl; return self; } - (void) dealloc { DESTROY(lowerTerm); DESTROY(upperTerm); [super dealloc]; } - (LCQuery *) rewrite: (LCIndexReader *) reader { LCBooleanQuery *query = [[LCBooleanQuery alloc] initWithCoordination: YES]; LCTermEnumerator *enumerator = [reader termEnumeratorWithTerm: lowerTerm]; BOOL checkLower = NO; if (inclusive == NO) // make adjustments to set to exclusive checkLower = YES; NSString *testField = [self field]; do { LCTerm *term = [enumerator term]; if (term && [[term field] isEqualToString: testField]) { if ((checkLower == NO) || ([[term text] compare: [lowerTerm text]] == NSOrderedDescending)) { checkLower = NO; if (upperTerm) { int compare = [[upperTerm text] compare: [term text]]; /* if beyond the upper term, or is exclusive and * this is equal to the upper term, break out */ if ((compare == NSOrderedAscending) || ((inclusive == NO) && (compare == NSOrderedSame))) break; } LCTermQuery *tq = [[LCTermQuery alloc] initWithTerm: term]; // found a match [tq setBoost: [self boost]]; // set the boost [query addQuery: tq occur: LCOccur_SHOULD]; // add to query DESTROY(tq); } } else { break; } } while ([enumerator hasNextTerm]); [enumerator close]; return AUTORELEASE(query); } - (NSString *) field { return (lowerTerm) ? [lowerTerm field] : [upperTerm field]; } - (LCTerm *) lowerTerm { return lowerTerm; } - (LCTerm *) upperTerm { return upperTerm; } - (BOOL) isInclusive { return inclusive; } - (NSString *) descriptionWithField: (NSString *) field { NSMutableString *ms = [[NSMutableString alloc] init]; if ([[self field] isEqualToString: field] == NO) { [ms appendFormat: @"%@:", [self field]]; } [ms appendString: (inclusive ? @"[" : @"{")]; [ms appendString: (lowerTerm) ? [lowerTerm text] : @"null"]; [ms appendString: @" TO "]; [ms appendString: (upperTerm) ? [upperTerm text] : @"null"]; [ms appendString: (inclusive ? @"]" : @"}")]; [ms appendString: LCStringFromBoost([self boost])]; return AUTORELEASE(ms); } - (BOOL) isEqual: (id) o { if (self == o) return YES; if ([o isKindOfClass: [LCRangeQuery class]] == NO) return NO; LCRangeQuery *other = (LCRangeQuery *) o; if ([self boost] != [other boost]) return NO; if ([self isInclusive] != [other isInclusive]) return NO; if (lowerTerm) { if ([[self lowerTerm] isEqual: [other lowerTerm]] == NO) return NO; } else { if ([other lowerTerm] != nil) return NO; } if (upperTerm) { if ([[self upperTerm] isEqual: [other upperTerm]] == NO) return NO; } else { if ([other upperTerm] != nil) return NO; } return YES; } - (unsigned) hash { int h = FloatToIntBits([self boost]); h ^= (lowerTerm ? [lowerTerm hash] : 0); // reversible mix to make lower and upper position dependent and // to prevent them from cancelling out. h ^= (h << 25) | (h >> 8); // FIXME: should be (h >>> 8) h ^= (upperTerm ? [upperTerm hash] : 0); h ^= (inclusive ? 0x2742E74A : 0); return h; } @end