-
Notifications
You must be signed in to change notification settings - Fork 0
/
CMCodeIndex.m
152 lines (123 loc) · 4.56 KB
/
CMCodeIndex.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
* CMCodeIndex.m Colin MacCreery
*
* Implementation for the Code Index. Stores a single node
* from the binary file at a time. Is able to search for a
* particular country code's DRP and list all codes
* alphabetically.
*
************************************************************/
#import "CMCodeIndex.h"
@implementation CMCodeIndex
// ----- PUBLIC ---------------------------------------------/
// initWithFile
//
// constructor for the object, opens the file passed
// to it and reads the header into a struct. Calculates
// the record size and the header size
-(id)initWithFile:(NSString*)f {
self = [super init];
binHandle = [NSFileHandle fileHandleForReadingAtPath:f];
header *head=(header*)malloc(sizeof(header));
head->m = CFSwapInt16BigToHost( *(short*)[[binHandle readDataOfLength:2] bytes] );
head->r = CFSwapInt16BigToHost( *(short*)[[binHandle readDataOfLength:2] bytes] );
head->e = CFSwapInt16BigToHost( *(short*)[[binHandle readDataOfLength:2] bytes] );
head->f = CFSwapInt16BigToHost( *(short*)[[binHandle readDataOfLength:2] bytes] );
head->k = CFSwapInt16BigToHost( *(short*)[[binHandle readDataOfLength:2] bytes] );
h = head;
recSize = 1 + 2 + (h->m * 3) + (h->m * 2);
headSize = sizeof(header);
return self;
}
// query
//
// public query function. Begins the search
// for a particular country code at the root.
// Uses recursion
-(NSDictionary*)query:(NSString*)c {
nodesRead = 0;
comparisons = 0;
NSNumber* ans = [self query:c AtNode:h->r];
NSNumber* nR = [NSNumber numberWithInt:nodesRead];
NSNumber* comp = [NSNumber numberWithInt:comparisons];
NSDictionary* result;
if([ans isNotEqualTo:nil]) {
result = [NSDictionary dictionaryWithObjects:@[ans, nR, comp] forKeys:@[@"pointer", @"nodes", @"comparisons"]];
} else {
result = [NSDictionary dictionaryWithObjects:@[nR, comp] forKeys:@[@"nodes", @"comparisons"]];
}
return result;
}
// list
//
// aggregates a string containing the country
// codes listed alphabetically
-(NSString*)list {
NSMutableString* listing = [NSMutableString stringWithString:@""];
[self readNode:h->f];
while(_next != 0) {
for(int i = 0; i < [_codes count]; i++) {
if([[_codes objectAtIndex:i] isEqualToString:@"^^^"]) break;
[listing appendFormat:@"%@ %3d\n", [_codes objectAtIndex:i], [[_pointers objectAtIndex:i] intValue]];
}
[self readNode:_next];
}
[listing appendFormat:@"+++++ END OF DATA +++++ (%d countries)\n\n", h->k];
return listing;
}
// close
//
// closes the binary file
-(void)close {
[binHandle closeFile];
}
// ----- PRIVATE --------------------------------------------/
// queryAtNode
//
// recursive method for searching for a country code. Fails
// fast if it ever runs into an "^^^" entry and counts
// the number of nodes read as well as number of comparisons
// made
-(NSNumber*)query:(NSString*)c AtNode:(int)n {
nodesRead++;
[self readNode:n];
if(_type != 'L') {
for(int i = 0; i < [_codes count]; i++) {
comparisons++;
if([[_codes objectAtIndex:i] isEqualToString:@"^^^"]) return nil;
if([c isLessThanOrEqualTo:[_codes objectAtIndex:i]]) return [self query:c AtNode:[[_pointers objectAtIndex:i] intValue]];
}
} else {
for(int i = 0; i < [_codes count]; i++) {
comparisons++;
if([[_codes objectAtIndex:i] isEqualToString:@"^^^"]) return nil;
if([c isEqualTo:[_codes objectAtIndex:i]]) return [_pointers objectAtIndex:i];
}
}
return nil;
}
// readNode
//
// reads in a single node from the file specified
// by the record number
-(void)readNode:(int)record {
[binHandle seekToFileOffset:(headSize + (record - 1) * recSize)];
_type = *(char*)[[binHandle readDataOfLength:1] bytes];
_next = CFSwapInt16BigToHost( *(short*)[[binHandle readDataOfLength:2] bytes] );
_codes = [[NSMutableArray alloc] initWithCapacity:h->m];
for (int i = 0; i < h->m; i++) {
[_codes addObject: [
[NSString alloc]
initWithBytes:[[binHandle readDataOfLength:3] bytes]
length:3 encoding:NSASCIIStringEncoding]
];
}
_pointers = [[NSMutableArray alloc] initWithCapacity:h->m];
for (int i = 0; i < h->m; i++) {
[_pointers addObject: [
NSNumber numberWithShort:
CFSwapInt16BigToHost( *(short*)[[binHandle readDataOfLength:2] bytes] )]
];
}
}
@end