1 /***************************************
2 $Header: /home/amb/routino/src/RCS/waysx.c,v 1.38 2010/05/22 18:40:47 amb Exp $
4 Extended Way data type functions.
6 Part of the Routino routing software.
7 ******************/ /******************
8 This file Copyright 2008-2010 Andrew M. Bishop
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU Affero General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Affero General Public License for more details.
20 You should have received a copy of the GNU Affero General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 ***************************************/
30 #include "functions.h"
37 /*+ The command line '--slim' option. +*/
38 extern int option_slim;
40 /*+ The command line '--tmpdir' option or its default value. +*/
41 extern char *option_tmpdirname;
43 /*+ A temporary file-local variable for use by the sort functions. +*/
44 static WaysX *sortwaysx;
48 static int sort_by_name_and_prop_and_id(WayX *a,WayX *b);
49 static int deduplicate_by_id(WayX *wayx,index_t index);
51 static int sort_by_id(WayX *a,WayX *b);
52 static int index_by_id(WayX *wayx,index_t index);
55 /*++++++++++++++++++++++++++++++++++++++
56 Allocate a new way list (create a new file or open an existing one).
58 WaysX *NewWayList Returns the way list.
60 int append Set to 1 if the file is to be opened for appending (now or later).
61 ++++++++++++++++++++++++++++++++++++++*/
63 WaysX *NewWayList(int append)
67 waysx=(WaysX*)calloc(1,sizeof(WaysX));
69 assert(waysx); /* Check calloc() worked */
71 waysx->filename=(char*)malloc(strlen(option_tmpdirname)+32);
74 sprintf(waysx->filename,"%s/ways.input.tmp",option_tmpdirname);
76 sprintf(waysx->filename,"%s/ways.%p.tmp",option_tmpdirname,waysx);
80 off_t size,position=0;
82 waysx->fd=AppendFile(waysx->filename);
84 size=SizeFile(waysx->filename);
88 FILESORT_VARINT waysize;
90 SeekFile(waysx->fd,position);
91 ReadFile(waysx->fd,&waysize,FILESORT_VARSIZE);
94 position+=waysize+FILESORT_VARSIZE;
97 SeekFile(waysx->fd,size);
100 waysx->fd=OpenFile(waysx->filename);
102 waysx->nfilename=(char*)malloc(strlen(option_tmpdirname)+32);
103 sprintf(waysx->nfilename,"%s/waynames.%p.tmp",option_tmpdirname,waysx);
109 /*++++++++++++++++++++++++++++++++++++++
112 WaysX *waysx The list to be freed.
114 int keep Set to 1 if the file is to be kept.
115 ++++++++++++++++++++++++++++++++++++++*/
117 void FreeWayList(WaysX *waysx,int keep)
120 DeleteFile(waysx->filename);
122 free(waysx->filename);
127 DeleteFile(waysx->nfilename);
129 free(waysx->nfilename);
135 /*++++++++++++++++++++++++++++++++++++++
136 Append a way to a way list.
138 void AppendWay Returns the newly appended way.
140 WaysX* waysx The set of ways to process.
142 way_t id The ID of the way.
144 Way *way The way data itself.
146 const char *name The name or reference of the way.
147 ++++++++++++++++++++++++++++++++++++++*/
149 void AppendWay(WaysX* waysx,way_t id,Way *way,const char *name)
152 FILESORT_VARINT size;
154 assert(!waysx->idata); /* Must not have idata filled in => unsorted */
160 size=sizeof(WayX)+strlen(name)+1;
162 WriteFile(waysx->fd,&size,FILESORT_VARSIZE);
163 WriteFile(waysx->fd,&wayx,sizeof(WayX));
164 WriteFile(waysx->fd,name,strlen(name)+1);
170 /*++++++++++++++++++++++++++++++++++++++
171 Sort the list of ways.
173 WaysX* waysx The set of ways to process.
174 ++++++++++++++++++++++++++++++++++++++*/
176 void SortWayList(WaysX* waysx)
180 char *names[2]={NULL,NULL};
181 int namelen[2]={0,0};
182 int nnames=0,nprops=0;
183 uint32_t lastlength=0;
186 /* Check the start conditions */
188 assert(!waysx->idata); /* Must not have idata filled in => unsorted */
190 /* Print the start message */
192 printf("Sorting Ways");
195 /* Close the file and re-open it (finished appending) */
197 CloseFile(waysx->fd);
198 waysx->fd=ReOpenFile(waysx->filename);
200 DeleteFile(waysx->filename);
202 fd=OpenFile(waysx->filename);
204 /* Sort the ways to allow compacting them and remove duplicates */
208 filesort_vary(waysx->fd,fd,(int (*)(const void*,const void*))sort_by_name_and_prop_and_id,(int (*)(void*,index_t))deduplicate_by_id);
210 /* Close the files */
212 CloseFile(waysx->fd);
215 /* Print the final message */
217 printf("\rSorted Ways: Ways=%d Duplicates=%d\n",waysx->xnumber,waysx->xnumber-waysx->number);
221 /* Print the start message */
223 printf("Compacting Ways: Ways=0 Names=0 Properties=0");
228 waysx->fd=ReOpenFile(waysx->filename);
230 DeleteFile(waysx->filename);
232 fd=OpenFile(waysx->filename);
233 nfd=OpenFile(waysx->nfilename);
235 /* Copy from the single file into two files and index as we go. */
237 for(i=0;i<waysx->number;i++)
240 FILESORT_VARINT size;
242 ReadFile(waysx->fd,&size,FILESORT_VARSIZE);
244 if(namelen[nnames%2]<size)
245 names[nnames%2]=(char*)realloc((void*)names[nnames%2],namelen[nnames%2]=size);
247 ReadFile(waysx->fd,&wayx,sizeof(WayX));
248 ReadFile(waysx->fd,names[nnames%2],size-sizeof(WayX));
250 if(nnames==0 || strcmp(names[0],names[1]))
252 WriteFile(nfd,names[nnames%2],size-sizeof(WayX));
254 lastlength=waysx->nlength;
255 waysx->nlength+=size-sizeof(WayX);
260 wayx.way.name=lastlength;
262 if(nprops==0 || wayx.way.name!=lastway.name || WaysCompare(&lastway,&wayx.way))
273 WriteFile(fd,&wayx,sizeof(WayX));
277 printf("\rCompacting Ways: Ways=%d Names=%d Properties=%d",i+1,nnames,nprops);
282 if(names[0]) free(names[0]);
283 if(names[1]) free(names[1]);
285 /* Close the files */
287 CloseFile(waysx->fd);
290 waysx->fd=ReOpenFile(waysx->filename);
294 /* Print the final message */
296 printf("\rCompacted Ways: Ways=%d Names=%d Properties=%d \n",waysx->number,nnames,nprops);
300 /* Print the start message */
302 printf("Sorting Ways");
307 waysx->fd=ReOpenFile(waysx->filename);
309 DeleteFile(waysx->filename);
311 fd=OpenFile(waysx->filename);
313 /* Allocate the array of indexes */
315 waysx->idata=(way_t*)malloc(waysx->number*sizeof(way_t));
317 assert(waysx->idata); /* Check malloc() worked */
319 /* Sort the ways by index and index them */
323 filesort_fixed(waysx->fd,fd,sizeof(WayX),(int (*)(const void*,const void*))sort_by_id,(int (*)(void*,index_t))index_by_id);
325 /* Close the files and re-open them */
327 CloseFile(waysx->fd);
330 waysx->fd=ReOpenFile(waysx->filename);
332 /* Print the final message */
334 printf("\rSorted Ways: Ways=%d\n",waysx->number);
339 /*++++++++++++++++++++++++++++++++++++++
340 Sort the ways into id order.
342 int sort_by_id Returns the comparison of the id fields.
344 WayX *a The first extended way.
346 WayX *b The second extended way.
347 ++++++++++++++++++++++++++++++++++++++*/
349 static int sort_by_id(WayX *a,WayX *b)
363 /*++++++++++++++++++++++++++++++++++++++
364 Sort the ways into name, properties and id order.
366 int sort_by_name_and_prop_and_id Returns the comparison of the name, properties and id fields.
368 WayX *a The first extended Way.
370 WayX *b The second extended Way.
371 ++++++++++++++++++++++++++++++++++++++*/
373 static int sort_by_name_and_prop_and_id(WayX *a,WayX *b)
376 char *a_name=(char*)a+sizeof(WayX);
377 char *b_name=(char*)b+sizeof(WayX);
379 compare=strcmp(a_name,b_name);
384 compare=WaysCompare(&a->way,&b->way);
389 return(sort_by_id(a,b));
393 /*++++++++++++++++++++++++++++++++++++++
394 Deduplicate the extended ways using the id after sorting.
396 int deduplicate_by_id Return 1 if the value is to be kept, otherwise zero.
398 WayX *wayx The extended way.
400 index_t index The index of this way in the total.
401 ++++++++++++++++++++++++++++++++++++++*/
403 static int deduplicate_by_id(WayX *wayx,index_t index)
407 if(index==0 || wayx->id!=previd)
420 /*++++++++++++++++++++++++++++++++++++++
421 Index the ways after sorting.
423 int index_by_id Return 1 if the value is to be kept, otherwise zero.
425 WayX *wayx The extended way.
427 index_t index The index of this way in the total.
428 ++++++++++++++++++++++++++++++++++++++*/
430 static int index_by_id(WayX *wayx,index_t index)
432 sortwaysx->idata[index]=wayx->id;
438 /*++++++++++++++++++++++++++++++++++++++
439 Find a particular way index.
441 index_t IndexWayX Returns the index of the extended way with the specified id.
443 WaysX* waysx The set of ways to process.
445 way_t id The way id to look for.
446 ++++++++++++++++++++++++++++++++++++++*/
448 index_t IndexWayX(WaysX* waysx,way_t id)
451 int end=waysx->number-1;
454 assert(waysx->idata); /* Must have idata filled in => sorted */
456 /* Binary search - search key exact match only is required.
458 * # <- start | Check mid and move start or end if it doesn't match
460 * # | Since an exact match is wanted we can set end=mid-1
461 * # <- mid | or start=mid+1 because we know that mid doesn't match.
463 * # | Eventually either end=start or end=start+1 and one of
464 * # <- end | start or end is the wanted one.
467 if(end<start) /* There are no ways */
469 else if(id<waysx->idata[start]) /* Check key is not before start */
471 else if(id>waysx->idata[end]) /* Check key is not after end */
477 mid=(start+end)/2; /* Choose mid point */
479 if(waysx->idata[mid]<id) /* Mid point is too low */
481 else if(waysx->idata[mid]>id) /* Mid point is too high */
483 else /* Mid point is correct */
486 while((end-start)>1);
488 if(waysx->idata[start]==id) /* Start is correct */
491 if(waysx->idata[end]==id) /* End is correct */
499 /*++++++++++++++++++++++++++++++++++++++
500 Lookup a particular way.
502 WayX *LookupWayX Returns a pointer to the extended way with the specified id.
504 WaysX* waysx The set of ways to process.
506 index_t index The way index to look for.
508 int position The position in the cache to use.
509 ++++++++++++++++++++++++++++++++++++++*/
511 WayX *LookupWayX(WaysX* waysx,index_t index,int position)
513 assert(index!=NO_WAY); /* Must be a valid way */
517 SeekFile(waysx->fd,index*sizeof(WayX));
519 ReadFile(waysx->fd,&waysx->cached[position-1],sizeof(WayX));
521 return(&waysx->cached[position-1]);
525 return(&waysx->xdata[index]);
530 /*++++++++++++++++++++++++++++++++++++++
531 Save the way list to a file.
533 WaysX* waysx The set of ways to save.
535 const char *filename The name of the file to save.
536 ++++++++++++++++++++++++++++++++++++++*/
538 void SaveWayList(WaysX* waysx,const char *filename)
545 printf("Writing Ways: Ways=0");
549 waysx->xdata=MapFile(waysx->filename);
551 /* Fill in a Ways structure with the offset of the real data in the file after
552 the Way structure itself. */
554 ways=calloc(1,sizeof(Ways));
556 assert(ways); /* Check calloc() worked */
558 ways->number=waysx->cnumber;
559 ways->onumber=waysx->number;
568 /* Write out the Ways structure and then the real data. */
570 fd=OpenFile(filename);
572 for(i=0;i<waysx->number;i++)
574 WayX *wayx=LookupWayX(waysx,i,1);
576 ways->allow|=wayx->way.allow;
577 ways->props|=wayx->way.props;
579 SeekFile(fd,sizeof(Ways)+wayx->prop*sizeof(Way));
580 WriteFile(fd,&wayx->way,sizeof(Way));
584 printf("\rWriting Ways: Ways=%d",i+1);
590 WriteFile(fd,ways,sizeof(Ways));
593 waysx->xdata=UnmapFile(waysx->filename);
595 SeekFile(fd,sizeof(Ways)+ways->number*sizeof(Way));
597 nfd=ReOpenFile(waysx->nfilename);
599 while(position<waysx->nlength)
604 if((waysx->nlength-position)<1024)
605 len=waysx->nlength-position;
607 ReadFile(nfd,temp,len);
608 WriteFile(fd,temp,len);
617 printf("\rWrote Ways: Ways=%d \n",waysx->number);
620 /* Free the fake Ways */