Skip to content

Commit

Permalink
Revert display regressions.
Browse files Browse the repository at this point in the history
1. Revert "Merge pull request #148 from JanX2/two-gigaseconds-mini"

This reverts commit 7365174, reversing
changes made to c5ac867.

2. Revert "Two gigaseconds (#147)"

This reverts commit c5ac867.
  • Loading branch information
nevack committed May 8, 2021
1 parent 17fd41f commit b69cb98
Show file tree
Hide file tree
Showing 16 changed files with 238 additions and 997 deletions.
332 changes: 165 additions & 167 deletions Base.lproj/MainMenu.xib

Large diffs are not rendered by default.

298 changes: 1 addition & 297 deletions Cog.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

10 changes: 0 additions & 10 deletions Cog.xcodeproj/xcshareddata/xcschemes/Cog.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,6 @@
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "3D42D1B42642BB62002A170C"
BuildableName = "CogTests.xctest"
BlueprintName = "CogTests"
ReferencedContainer = "container:Cog.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
Expand Down

This file was deleted.

36 changes: 0 additions & 36 deletions CogTests/CogTests.m

This file was deleted.

22 changes: 0 additions & 22 deletions CogTests/Info.plist

This file was deleted.

2 changes: 0 additions & 2 deletions Formatters/SecondsFormatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,4 @@
{
}

- (NSString * _Nullable)stringForTimeInterval:(NSTimeInterval)timeInterval;

@end
208 changes: 41 additions & 167 deletions Formatters/SecondsFormatter.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,202 +20,78 @@

#import "SecondsFormatter.h"

#define TWO_GIGASECONDS_IS_ENOUGH 1 // 2 Gs is about 68 years.
#if TWO_GIGASECONDS_IS_ENOUGH
typedef int32_t sec_t; // Type used internally for time values (mostly in seconds).
#define PRIsec PRIi32
#define SEC_MAX INT32_MAX
#define scanSec scanInt
#else
typedef NSInteger sec_t;
#define PRIsec "zd"
#define SEC_MAX NSIntegerMax
#define scanSec scanInteger
#endif

@implementation SecondsFormatter

- (NSString *) stringForObjectValue:(id)object
{
if (nil == object || NO == [object isKindOfClass:[NSNumber class]]) {
// Docs state: “Returns nil if object is not of the correct class.”
return nil;
NSString *result = nil;
unsigned value;
unsigned days = 0;
unsigned hours = 0;
unsigned minutes = 0;
unsigned seconds = 0;

if(nil == object || NO == [object isKindOfClass:[NSNumber class]] || isnan([object doubleValue])) {
return @"";
}

NSTimeInterval timeInterval = [object doubleValue];

return [self stringForTimeInterval:timeInterval];
}
value = (unsigned)([object doubleValue]);

- (NSString * _Nullable)stringForTimeInterval:(NSTimeInterval)timeInterval;
{
if (isnan(timeInterval)) { return @"NaN"; }
if (isinf(timeInterval)) { return @"Inf"; }
seconds = value % 60;
minutes = value / 60;

BOOL isNegative = signbit(timeInterval);

sec_t totalSeconds = (sec_t)(isNegative ? -timeInterval : timeInterval);

sec_t seconds = totalSeconds % 60;
sec_t minutes = totalSeconds / 60;
sec_t hours = 0;
sec_t days = 0;

while (60 <= minutes) {
while(60 <= minutes) {
minutes -= 60;
++hours;
}

while (24 <= hours) {
while(24 <= hours) {
hours -= 24;
++days;
}

NSString *result = nil;

const char *signPrefix = isNegative ? "-" : "";

if (0 < days) {
result = [NSString stringWithFormat:@"%s" "%" PRIsec ":" "%02" PRIsec ":" "%02" PRIsec ":" "%02" PRIsec "", signPrefix, days, hours, minutes, seconds];

if(0 < days) {
result = [NSString stringWithFormat:@"%u:%.2u:%.2u:%.2u", days, hours, minutes, seconds];
}
else if (0 < hours) {
result = [NSString stringWithFormat:@"%s" "%" PRIsec ":" "%02" PRIsec ":" "%02" PRIsec "", signPrefix, hours, minutes, seconds];
else if(0 < hours) {
result = [NSString stringWithFormat:@"%u:%.2u:%.2u", hours, minutes, seconds];
}
else if (0 < minutes) {
result = [NSString stringWithFormat:@"%s" "%" PRIsec ":" "%02" PRIsec "", signPrefix, minutes, seconds];
else if(0 < minutes) {
result = [NSString stringWithFormat:@"%u:%.2u", minutes, seconds];
}
else {
result = [NSString stringWithFormat:@"%s" "0:" "%02" PRIsec "", signPrefix, seconds];
result = [NSString stringWithFormat:@"0:%.2u", seconds];
}

return result;
}

- (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)object
forString:(NSString *)string
errorDescription:(out NSString * _Nullable __autoreleasing *)error
- (BOOL) getObjectValue:(id *)object forString:(NSString *)string errorDescription:(NSString **)error
{
// In the previous implementation,
// all types were incorrectly treated indentically.
// This made the code much simpler,
// but the added complexity is needed to support both negative and large values.

NSScanner *scanner = [NSScanner scannerWithString:string];

BOOL malformed = NO;

const int segmentCount = 4;
const int lastSegment = segmentCount - 1;
sec_t segments[segmentCount] = {-1, -1, -1, -1};
int lastScannedSegment = -1;
NSScanner *scanner = nil;
BOOL result = NO;
int value = 0;
unsigned seconds = 0;

BOOL isNegative = NO;

if ([scanner isAtEnd] == NO) {
isNegative = [scanner scanString:@"-" intoString:NULL];

int segmentIndex = 0;

while ([scanner isAtEnd] == NO) {
// Grab a value
if ([scanner scanSec:&(segments[segmentIndex])] == NO) {
segments[segmentIndex] = -1;
malformed = YES;
break;
}

if (segmentIndex == lastSegment) {
break;
}

// Grab the separator, if present
if ([scanner scanString:@":" intoString:NULL] == NO) {
break;
}

segmentIndex += 1;
}

lastScannedSegment = segmentIndex;
}

if ([scanner isAtEnd] == NO) {
malformed = YES;
}

sec_t seconds = 0;
scanner = [NSScanner scannerWithString:string];

if (malformed == NO) {
// `segments` entries need to be mapped to the correct unit type.
// The position of each type depends on the number of scanned segments.
while(NO == [scanner isAtEnd]) {

const int typeCount = segmentCount;

typedef enum : int {
DAYS = 0, HOURS = 1, MINUTES = 2, SECONDS = 3,
} SegmentType;

const int segmentIndexes[segmentCount][typeCount] = {
{ -1, -1, -1, 0 },
{ -1, -1, 0, 1 },
{ -1, 0, 1, 2 },
{ 0, 1, 2, 3 },
};

#define HAS_SEGMENT(segmentType) \
(segmentIndexes[lastScannedSegment][(segmentType)] >= 0)

typedef struct {
sec_t max;
sec_t scaleFactor;
} SegmentMetadata;

const SegmentMetadata segmentMetadata[segmentCount] = {
{.max = SEC_MAX, .scaleFactor = 24},
{.max = 24, .scaleFactor = 60},
{.max = 60, .scaleFactor = 60},
{.max = 60, .scaleFactor = 1},
};

for (SegmentType segmentType = DAYS; segmentType < segmentCount; segmentType += 1) {
if (!HAS_SEGMENT(segmentType)) {
if (segmentType == SECONDS) {
// Must have SECONDS.
malformed = YES;
break;
}
else {
continue;
}
}

const int index = segmentIndexes[lastScannedSegment][segmentType];

const SegmentMetadata metadata = segmentMetadata[segmentType];

if ((segments[index] >= 0) && (segments[index] < metadata.max)) {
seconds += segments[index];
seconds *= metadata.scaleFactor;
}
else {
malformed = YES;
break;
}
// Grab a value
if([scanner scanInt:&value]) {
seconds *= 60;
seconds += value;
result = YES;
}

seconds *= (isNegative ? -1 : 1);
// Grab the separator, if present
[scanner scanString:@":" intoString:NULL];
}

const BOOL result = (malformed == NO);

if (result && NULL != object) {
NSTimeInterval timeInterval = (NSTimeInterval)seconds;
// NOTE: The floating point standard has support for negative zero.
// We use that to represent the parsing result without information loss.
if (isNegative && (timeInterval == 0.0)) { timeInterval = -0.0; }
*object = @(timeInterval);
if(result && NULL != object) {
*object = [NSNumber numberWithUnsignedInt:seconds];
}
else if (NULL != error) {
else if(NULL != error) {
*error = @"Couldn't convert value to seconds";
}

Expand All @@ -224,11 +100,9 @@ - (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)object

- (NSAttributedString *) attributedStringForObjectValue:(id)object withDefaultAttributes:(NSDictionary *)attributes
{
NSString *stringValue = [self stringForObjectValue:object];
if(nil == stringValue)
return nil;
NSAttributedString *result = nil;

NSAttributedString *result = [[NSAttributedString alloc] initWithString:stringValue attributes:attributes];
result = [[NSAttributedString alloc] initWithString:[self stringForObjectValue:object] attributes:attributes];
return result;
}

Expand Down
Loading

0 comments on commit b69cb98

Please sign in to comment.