Tweaks to NSDate changes

This commit is contained in:
rfm 2024-11-01 08:47:02 +00:00
parent 7a59450341
commit d0bff27c77
2 changed files with 113 additions and 78 deletions

View file

@ -1,3 +1,8 @@
2024-11-01 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSDate.m: Fix returing receiver when earlier/later argument
is equal to the receiver. Various formatting fixes.
2024-10-29 Richard Frith-Macdonald <rfm@gnu.org> 2024-10-29 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSUndoManager.m: set zero/nil return value when forwarding * Source/NSUndoManager.m: set zero/nil return value when forwarding

View file

@ -140,70 +140,74 @@ static id _distantFuture = nil;
#define CREATE_SMALL_DATE(interval) (id)(compressTimeInterval(interval) | SMALL_DATE_MASK) #define CREATE_SMALL_DATE(interval) (id)(compressTimeInterval(interval) | SMALL_DATE_MASK)
union CompressedDouble { union CompressedDouble {
uintptr_t data; uintptr_t data;
struct { struct {
uintptr_t tag : 3; // placeholder for tag bits uintptr_t tag : 3; // placeholder for tag bits
uintptr_t fraction : 52; uintptr_t fraction : 52;
intptr_t exponent : 8; // signed! intptr_t exponent : 8; // signed!
uintptr_t sign : 1; uintptr_t sign : 1;
}; };
}; };
union DoubleBits { union DoubleBits {
double val; double val;
struct { struct {
uintptr_t fraction : 52; uintptr_t fraction : 52;
uintptr_t exponent : 11; uintptr_t exponent : 11;
uintptr_t sign : 1; uintptr_t sign : 1;
}; };
}; };
static __attribute__((always_inline)) uintptr_t compressTimeInterval(NSTimeInterval interval) { static __attribute__((always_inline)) uintptr_t
union CompressedDouble c; compressTimeInterval(NSTimeInterval interval)
union DoubleBits db; {
intptr_t exponent; union CompressedDouble c;
union DoubleBits db;
intptr_t exponent;
db.val = interval; db.val = interval;
c.fraction = db.fraction; c.fraction = db.fraction;
c.sign = db.sign; c.sign = db.sign;
// 1. Cast 11-bit unsigned exponent to 64-bit signed // 1. Cast 11-bit unsigned exponent to 64-bit signed
exponent = db.exponent; exponent = db.exponent;
// 2. Subtract secondary Bias first // 2. Subtract secondary Bias first
exponent -= EXPONENT_BIAS; exponent -= EXPONENT_BIAS;
// 3. Truncate to 8-bit signed // 3. Truncate to 8-bit signed
c.exponent = exponent; c.exponent = exponent;
c.tag = 0; c.tag = 0;
return c.data; return c.data;
} }
static __attribute__((always_inline)) NSTimeInterval decompressTimeInterval(uintptr_t compressed) { static __attribute__((always_inline)) NSTimeInterval
union CompressedDouble c; decompressTimeInterval(uintptr_t compressed)
union DoubleBits d; {
intptr_t biased_exponent; union CompressedDouble c;
union DoubleBits d;
intptr_t biased_exponent;
c.data = compressed; c.data = compressed;
d.fraction = c.fraction; d.fraction = c.fraction;
d.sign = c.sign; d.sign = c.sign;
// 1. Sign Extend 8-bit to 64-bit // 1. Sign Extend 8-bit to 64-bit
biased_exponent = c.exponent; biased_exponent = c.exponent;
// 2. Add secondary Bias // 2. Add secondary Bias
biased_exponent += 0x3EF; biased_exponent += 0x3EF;
// Cast to 11-bit unsigned exponent // Cast to 11-bit unsigned exponent
d.exponent = biased_exponent; d.exponent = biased_exponent;
return d.val; return d.val;
} }
static __attribute__((always_inline)) BOOL isSmallDate(id obj) { static __attribute__((always_inline)) BOOL isSmallDate(id obj) {
// Do a fast check if the object is also a small date. // Do a fast check if the object is also a small date.
// libobjc2 guarantees that the classes are 16-byte (word) aligned. // libobjc2 guarantees that the classes are 16-byte (word) aligned.
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-objc-pointer-introspection" #pragma clang diagnostic ignored "-Wdeprecated-objc-pointer-introspection"
return !!((uintptr_t)obj & SMALL_DATE_MASK); return !!((uintptr_t)obj & SMALL_DATE_MASK);
#pragma clang diagnostic pop #pragma clang diagnostic pop
} }
// Populated in +[GSSmallDate load] // Populated in +[GSSmallDate load]
@ -234,10 +238,13 @@ static BOOL useSmallDate;
+ (void) load + (void) load
{ {
useSmallDate = objc_registerSmallObjectClass_np(self, SMALL_DATE_MASK); useSmallDate = objc_registerSmallObjectClass_np(self, SMALL_DATE_MASK);
// If this fails, someone else has already registered a small object class for this slot. /* If this fails, someone else has already registered
* a small object class for this slot.
*/
if (unlikely(useSmallDate == NO)) if (unlikely(useSmallDate == NO))
{ {
[NSException raise: NSInternalInconsistencyException format: @"Failed to register GSSmallDate small object class"]; [NSException raise: NSInternalInconsistencyException
format: @"Failed to register GSSmallDate small object class"];
} }
} }
@ -349,6 +356,7 @@ static BOOL useSmallDate;
- (id) initWithCoder: (NSCoder*)coder - (id) initWithCoder: (NSCoder*)coder
{ {
double secondsSinceRef; double secondsSinceRef;
if ([coder allowsKeyedCoding]) if ([coder allowsKeyedCoding])
{ {
secondsSinceRef = [coder decodeDoubleForKey: @"NS.time"]; secondsSinceRef = [coder decodeDoubleForKey: @"NS.time"];
@ -394,11 +402,13 @@ static BOOL useSmallDate;
} }
if (IS_CONCRETE_CLASS(otherDate)) if (IS_CONCRETE_CLASS(otherDate))
{ {
otherTime = GET_INTERVAL(otherDate); otherTime = GET_INTERVAL(otherDate);
} else { }
else
{
otherTime = [otherDate timeIntervalSinceReferenceDate]; otherTime = [otherDate timeIntervalSinceReferenceDate];
} }
if (selfTime > otherTime) if (selfTime > otherTime)
{ {
@ -422,14 +432,17 @@ static BOOL useSmallDate;
} }
if (IS_CONCRETE_CLASS(other)) if (IS_CONCRETE_CLASS(other))
{ {
otherTime = GET_INTERVAL(other); otherTime = GET_INTERVAL(other);
} else if ([other isKindOfClass: abstractClass]) }
{ else if ([other isKindOfClass: abstractClass])
{
otherTime = [other timeIntervalSinceReferenceDate]; otherTime = [other timeIntervalSinceReferenceDate];
} else { }
return NO; else
} {
return NO;
}
return selfTime == otherTime; return selfTime == otherTime;
} }
@ -452,14 +465,18 @@ static BOOL useSmallDate;
selfTime = GET_INTERVAL(self); selfTime = GET_INTERVAL(self);
if (IS_CONCRETE_CLASS(otherDate)) if (IS_CONCRETE_CLASS(otherDate))
{ {
otherTime = GET_INTERVAL(otherDate); otherTime = GET_INTERVAL(otherDate);
} else { }
else
{
otherTime = [otherDate timeIntervalSinceReferenceDate]; otherTime = [otherDate timeIntervalSinceReferenceDate];
} }
// If the receiver and anotherDate represent the same date, returns the receiver. /* If the receiver and anotherDate represent the same date,
if (selfTime <= otherTime) * returns the receiver.
*/
if (selfTime < otherTime)
{ {
return otherDate; return otherDate;
} }
@ -480,14 +497,18 @@ static BOOL useSmallDate;
selfTime = GET_INTERVAL(self); selfTime = GET_INTERVAL(self);
if (IS_CONCRETE_CLASS(otherDate)) if (IS_CONCRETE_CLASS(otherDate))
{ {
otherTime = GET_INTERVAL(otherDate); otherTime = GET_INTERVAL(otherDate);
} else { }
else
{
otherTime = [otherDate timeIntervalSinceReferenceDate]; otherTime = [otherDate timeIntervalSinceReferenceDate];
} }
// If the receiver and anotherDate represent the same date, returns the receiver. /* If the receiver and anotherDate represent the same date,
if (selfTime >= otherTime) * returns the receiver.
*/
if (selfTime > otherTime)
{ {
return otherDate; return otherDate;
} }
@ -498,9 +519,10 @@ static BOOL useSmallDate;
- (void) encodeWithCoder: (NSCoder*)coder - (void) encodeWithCoder: (NSCoder*)coder
{ {
double time = GET_INTERVAL(self); double time = GET_INTERVAL(self);
if ([coder allowsKeyedCoding]) if ([coder allowsKeyedCoding])
{ {
[coder encodeDouble:time forKey:@"NS.time"]; [coder encodeDouble: time forKey:@"NS.time"];
} }
else else
{ {
@ -519,6 +541,7 @@ static BOOL useSmallDate;
- (NSTimeInterval) timeIntervalSinceDate: (NSDate*)otherDate - (NSTimeInterval) timeIntervalSinceDate: (NSDate*)otherDate
{ {
double otherTime; double otherTime;
if (unlikely(otherDate == nil)) if (unlikely(otherDate == nil))
{ {
[NSException raise: NSInvalidArgumentException [NSException raise: NSInvalidArgumentException
@ -526,11 +549,13 @@ static BOOL useSmallDate;
} }
if (IS_CONCRETE_CLASS(otherDate)) if (IS_CONCRETE_CLASS(otherDate))
{ {
otherTime = GET_INTERVAL(otherDate); otherTime = GET_INTERVAL(otherDate);
} else { }
else
{
otherTime = [otherDate timeIntervalSinceReferenceDate]; otherTime = [otherDate timeIntervalSinceReferenceDate];
} }
return GET_INTERVAL(self) - otherTime; return GET_INTERVAL(self) - otherTime;
} }
@ -700,7 +725,9 @@ otherTime(NSDate* other)
if (self == abstractClass) if (self == abstractClass)
{ {
#if USE_SMALL_DATE #if USE_SMALL_DATE
return [DATE_CONCRETE_CLASS_NAME alloc]; // alloc is overridden to return a small object /* alloc is overridden to return a small object
*/
return [DATE_CONCRETE_CLASS_NAME alloc];
#else #else
return NSAllocateObject(concreteClass, 0, NSDefaultMallocZone()); return NSAllocateObject(concreteClass, 0, NSDefaultMallocZone());
#endif #endif
@ -713,7 +740,9 @@ otherTime(NSDate* other)
if (self == abstractClass) if (self == abstractClass)
{ {
#if USE_SMALL_DATE #if USE_SMALL_DATE
return [DATE_CONCRETE_CLASS_NAME alloc]; // alloc is overridden to return a small object /* alloc is overridden to return a small object
*/
return [DATE_CONCRETE_CLASS_NAME alloc];
#else #else
return NSAllocateObject(concreteClass, 0, z); return NSAllocateObject(concreteClass, 0, z);
#endif #endif
@ -1784,10 +1813,11 @@ otherTime(NSDate* other)
- (NSDate*) laterDate: (NSDate*)otherDate - (NSDate*) laterDate: (NSDate*)otherDate
{ {
double selfTime; double selfTime;
if (otherDate == nil) if (otherDate == nil)
{ {
return nil; return nil;
} }
selfTime = [self timeIntervalSinceReferenceDate]; selfTime = [self timeIntervalSinceReferenceDate];
if (selfTime < otherTime(otherDate)) if (selfTime < otherTime(otherDate))