1 /***************************************
2 $Header: /home/amb/routino/src/RCS/waysx.c,v 1.51 2010/09/19 16:17:45 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 ***************************************/
36 #include "functions.h"
41 /*+ The command line '--tmpdir' option or its default value. +*/
42 extern char *option_tmpdirname;
44 /*+ A temporary file-local variable for use by the sort functions. +*/
45 static WaysX *sortwaysx;
49 static int sort_by_id(WayX *a,WayX *b);
50 static int sort_by_name_and_id(WayX *a,WayX *b);
51 static int sort_by_name_and_prop_and_id(WayX *a,WayX *b);
53 static int deduplicate_and_index_by_id(WayX *wayx,index_t index);
56 /*++++++++++++++++++++++++++++++++++++++
57 Allocate a new way list (create a new file or open an existing one).
59 WaysX *NewWayList Returns the way list.
61 int append Set to 1 if the file is to be opened for appending (now or later).
62 ++++++++++++++++++++++++++++++++++++++*/
64 WaysX *NewWayList(int append)
68 waysx=(WaysX*)calloc(1,sizeof(WaysX));
70 assert(waysx); /* Check calloc() worked */
72 waysx->filename=(char*)malloc(strlen(option_tmpdirname)+32);
75 sprintf(waysx->filename,"%s/waysx.input.tmp",option_tmpdirname);
77 sprintf(waysx->filename,"%s/waysx.%p.tmp",option_tmpdirname,waysx);
81 off_t size,position=0;
83 waysx->fd=OpenFileAppend(waysx->filename);
85 size=SizeFile(waysx->filename);
89 FILESORT_VARINT waysize;
91 SeekFile(waysx->fd,position);
92 ReadFile(waysx->fd,&waysize,FILESORT_VARSIZE);
95 position+=waysize+FILESORT_VARSIZE;
98 SeekFile(waysx->fd,size);
101 waysx->fd=OpenFileNew(waysx->filename);
103 waysx->nfilename=(char*)malloc(strlen(option_tmpdirname)+32);
104 sprintf(waysx->nfilename,"%s/waynames.%p.tmp",option_tmpdirname,waysx);
110 /*++++++++++++++++++++++++++++++++++++++
113 WaysX *waysx The list to be freed.
115 int keep Set to 1 if the file is to be kept.
116 ++++++++++++++++++++++++++++++++++++++*/
118 void FreeWayList(WaysX *waysx,int keep)
121 DeleteFile(waysx->filename);
123 free(waysx->filename);
128 DeleteFile(waysx->nfilename);
130 free(waysx->nfilename);
136 /*++++++++++++++++++++++++++++++++++++++
137 Append a single way to an unsorted way list.
139 WaysX* waysx The set of ways to process.
141 way_t id The ID of the way.
143 Way *way The way data itself.
145 const char *name The name or reference of the way.
146 ++++++++++++++++++++++++++++++++++++++*/
148 void AppendWay(WaysX* waysx,way_t id,Way *way,const char *name)
151 FILESORT_VARINT size;
157 size=sizeof(WayX)+strlen(name)+1;
159 WriteFile(waysx->fd,&size,FILESORT_VARSIZE);
160 WriteFile(waysx->fd,&wayx,sizeof(WayX));
161 WriteFile(waysx->fd,name,strlen(name)+1);
165 assert(!(waysx->xnumber==0)); /* Zero marks the high-water mark for ways. */
169 /*++++++++++++++++++++++++++++++++++++++
170 Sort the list of ways.
172 WaysX* waysx The set of ways to process.
173 ++++++++++++++++++++++++++++++++++++++*/
175 void SortWayList(WaysX* waysx)
179 char *names[2]={NULL,NULL};
180 int namelen[2]={0,0};
182 uint32_t lastlength=0;
184 /* Print the start message */
186 printf("Sorting Ways by Name");
189 /* Close the file and re-open it (finished appending) */
191 CloseFile(waysx->fd);
192 waysx->fd=ReOpenFile(waysx->filename);
194 DeleteFile(waysx->filename);
196 fd=OpenFileNew(waysx->filename);
198 /* Sort the ways to allow separating the names */
200 filesort_vary(waysx->fd,fd,(int (*)(const void*,const void*))sort_by_name_and_id,NULL);
202 /* Close the files */
204 CloseFile(waysx->fd);
207 /* Print the final message */
209 printf("\rSorted Ways by Name: Ways=%d\n",waysx->xnumber);
213 /* Print the start message */
215 printf("Separating Way Names: Ways=0 Names=0");
220 waysx->fd=ReOpenFile(waysx->filename);
222 DeleteFile(waysx->filename);
224 fd=OpenFileNew(waysx->filename);
225 nfd=OpenFileNew(waysx->nfilename);
227 /* Copy from the single file into two files */
229 for(i=0;i<waysx->xnumber;i++)
232 FILESORT_VARINT size;
234 ReadFile(waysx->fd,&size,FILESORT_VARSIZE);
236 if(namelen[nnames%2]<size)
237 names[nnames%2]=(char*)realloc((void*)names[nnames%2],namelen[nnames%2]=size);
239 ReadFile(waysx->fd,&wayx,sizeof(WayX));
240 ReadFile(waysx->fd,names[nnames%2],size-sizeof(WayX));
242 if(nnames==0 || strcmp(names[0],names[1]))
244 WriteFile(nfd,names[nnames%2],size-sizeof(WayX));
246 lastlength=waysx->nlength;
247 waysx->nlength+=size-sizeof(WayX);
252 wayx.way.name=lastlength;
254 WriteFile(fd,&wayx,sizeof(WayX));
258 printf("\rSeparating Way Names: Ways=%d Names=%d",i+1,nnames);
263 if(names[0]) free(names[0]);
264 if(names[1]) free(names[1]);
266 /* Close the files */
268 CloseFile(waysx->fd);
271 waysx->fd=ReOpenFile(waysx->filename);
275 /* Print the final message */
277 printf("\rSeparated Way Names: Ways=%d Names=%d \n",waysx->xnumber,nnames);
281 /* Print the start message */
283 printf("Sorting Ways");
288 waysx->fd=ReOpenFile(waysx->filename);
290 DeleteFile(waysx->filename);
292 fd=OpenFileNew(waysx->filename);
294 /* Allocate the array of indexes */
296 waysx->idata=(way_t*)malloc(waysx->xnumber*sizeof(way_t));
298 assert(waysx->idata); /* Check malloc() worked */
300 /* Sort the ways by index and index them */
306 filesort_fixed(waysx->fd,fd,sizeof(WayX),(int (*)(const void*,const void*))sort_by_id,(int (*)(void*,index_t))deduplicate_and_index_by_id);
308 /* Close the files and re-open them */
310 CloseFile(waysx->fd);
313 waysx->fd=ReOpenFile(waysx->filename);
315 /* Print the final message */
317 printf("\rSorted Ways: Ways=%d Duplicates=%d\n",waysx->number,waysx->xnumber-waysx->number);
322 /*++++++++++++++++++++++++++++++++++++++
323 Compact the list of ways.
325 WaysX* waysx The set of ways to process.
326 ++++++++++++++++++++++++++++++++++++++*/
328 void CompactWayList(WaysX* waysx)
334 /* Print the start message */
336 printf("Sorting Ways by Properties");
339 /* Close the file and re-open it */
341 CloseFile(waysx->fd);
342 waysx->fd=ReOpenFile(waysx->filename);
344 DeleteFile(waysx->filename);
346 fd=OpenFileNew(waysx->filename);
348 /* Sort the ways to allow compacting according to he properties */
350 filesort_fixed(waysx->fd,fd,sizeof(WayX),(int (*)(const void*,const void*))sort_by_name_and_prop_and_id,NULL);
352 /* Close the files */
354 CloseFile(waysx->fd);
357 /* Print the final message */
359 printf("\rSorted Ways by Properties: Ways=%d\n",waysx->number);
363 /* Print the start message */
365 printf("Compacting Ways: Ways=0 Properties=0");
370 waysx->fd=ReOpenFile(waysx->filename);
372 DeleteFile(waysx->filename);
374 fd=OpenFileNew(waysx->filename);
376 /* Update the way as we go using the sorted index */
380 for(i=0;i<waysx->number;i++)
384 ReadFile(waysx->fd,&wayx,sizeof(WayX));
386 if(waysx->cnumber==0 || wayx.way.name!=lastway.name || WaysCompare(&lastway,&wayx.way))
393 wayx.prop=waysx->cnumber-1;
395 WriteFile(fd,&wayx,sizeof(WayX));
399 printf("\rCompacting Ways: Ways=%d Properties=%d",i+1,waysx->cnumber);
404 /* Close the files */
406 CloseFile(waysx->fd);
409 /* Print the final message */
411 printf("\rCompacted Ways: Ways=%d Properties=%d \n",waysx->number,waysx->cnumber);
415 /* Print the start message */
417 printf("Sorting Ways");
422 waysx->fd=ReOpenFile(waysx->filename);
424 DeleteFile(waysx->filename);
426 fd=OpenFileNew(waysx->filename);
428 /* Sort the ways by index */
430 filesort_fixed(waysx->fd,fd,sizeof(WayX),(int (*)(const void*,const void*))sort_by_id,NULL);
432 /* Close the files and re-open them */
434 CloseFile(waysx->fd);
437 waysx->fd=ReOpenFile(waysx->filename);
439 /* Print the final message */
441 printf("\rSorted Ways: Ways=%d\n",waysx->number);
446 /*++++++++++++++++++++++++++++++++++++++
447 Sort the ways into id order.
449 int sort_by_id Returns the comparison of the id fields.
451 WayX *a The first extended way.
453 WayX *b The second extended way.
454 ++++++++++++++++++++++++++++++++++++++*/
456 static int sort_by_id(WayX *a,WayX *b)
470 /*++++++++++++++++++++++++++++++++++++++
471 Sort the ways into name and id order.
473 int sort_by_name_and_id Returns the comparison of the name and id fields.
475 WayX *a The first extended Way.
477 WayX *b The second extended Way.
478 ++++++++++++++++++++++++++++++++++++++*/
480 static int sort_by_name_and_id(WayX *a,WayX *b)
483 char *a_name=(char*)a+sizeof(WayX);
484 char *b_name=(char*)b+sizeof(WayX);
486 compare=strcmp(a_name,b_name);
491 return(sort_by_id(a,b));
495 /*++++++++++++++++++++++++++++++++++++++
496 Sort the ways into name, properties and id order.
498 int sort_by_name_and_prop_and_id Returns the comparison of the name, properties and id fields.
500 WayX *a The first extended Way.
502 WayX *b The second extended Way.
503 ++++++++++++++++++++++++++++++++++++++*/
505 static int sort_by_name_and_prop_and_id(WayX *a,WayX *b)
508 index_t a_name=a->way.name;
509 index_t b_name=b->way.name;
513 else if(a_name>b_name)
516 compare=WaysCompare(&a->way,&b->way);
521 return(sort_by_id(a,b));
525 /*++++++++++++++++++++++++++++++++++++++
526 Deduplicate the extended ways using the id after sorting and create the index.
528 int deduplicate_and_index_by_id Return 1 if the value is to be kept, otherwise zero.
530 WayX *wayx The extended way.
532 index_t index The index of this way in the total.
533 ++++++++++++++++++++++++++++++++++++++*/
535 static int deduplicate_and_index_by_id(WayX *wayx,index_t index)
539 if(index==0 || wayx->id!=previd)
545 sortwaysx->idata[index]=wayx->id;
554 /*++++++++++++++++++++++++++++++++++++++
555 Find a particular way index.
557 index_t IndexWayX Returns the index of the extended way with the specified id.
559 WaysX* waysx The set of ways to process.
561 way_t id The way id to look for.
562 ++++++++++++++++++++++++++++++++++++++*/
564 index_t IndexWayX(WaysX* waysx,way_t id)
567 int end=waysx->number-1;
570 /* Binary search - search key exact match only is required.
572 * # <- start | Check mid and move start or end if it doesn't match
574 * # | Since an exact match is wanted we can set end=mid-1
575 * # <- mid | or start=mid+1 because we know that mid doesn't match.
577 * # | Eventually either end=start or end=start+1 and one of
578 * # <- end | start or end is the wanted one.
581 if(end<start) /* There are no ways */
583 else if(id<waysx->idata[start]) /* Check key is not before start */
585 else if(id>waysx->idata[end]) /* Check key is not after end */
591 mid=(start+end)/2; /* Choose mid point */
593 if(waysx->idata[mid]<id) /* Mid point is too low */
595 else if(waysx->idata[mid]>id) /* Mid point is too high */
597 else /* Mid point is correct */
600 while((end-start)>1);
602 if(waysx->idata[start]==id) /* Start is correct */
605 if(waysx->idata[end]==id) /* End is correct */
613 /*++++++++++++++++++++++++++++++++++++++
614 Save the way list to a file.
616 WaysX* waysx The set of ways to save.
618 const char *filename The name of the file to save.
619 ++++++++++++++++++++++++++++++++++++++*/
621 void SaveWayList(WaysX* waysx,const char *filename)
626 WaysFile waysfile={0};
630 /* Print the start message */
632 printf("Writing Ways: Ways=0");
635 /* Map into memory */
638 waysx->xdata=MapFile(waysx->filename);
641 /* Write out the ways data */
643 fd=OpenFileNew(filename);
645 SeekFile(fd,sizeof(WaysFile));
647 for(i=0;i<waysx->number;i++)
649 WayX *wayx=LookupWayX(waysx,i,1);
651 allow|=wayx->way.allow;
652 props|=wayx->way.props;
654 SeekFile(fd,sizeof(WaysFile)+(off_t)wayx->prop*sizeof(Way));
655 WriteFile(fd,&wayx->way,sizeof(Way));
659 printf("\rWriting Ways: Ways=%d",i+1);
664 /* Unmap from memory */
667 waysx->xdata=UnmapFile(waysx->filename);
670 /* Write out the ways names */
672 SeekFile(fd,sizeof(WaysFile)+(off_t)waysx->cnumber*sizeof(Way));
674 nfd=ReOpenFile(waysx->nfilename);
676 while(position<waysx->nlength)
681 if((waysx->nlength-position)<1024)
682 len=waysx->nlength-position;
684 ReadFile(nfd,temp,len);
685 WriteFile(fd,temp,len);
692 /* Write out the header structure */
694 waysfile.number=waysx->cnumber;
695 waysfile.onumber=waysx->number;
697 waysfile.allow=allow;
698 waysfile.props=props;
701 WriteFile(fd,&waysfile,sizeof(WaysFile));
705 /* Print the final message */
707 printf("\rWrote Ways: Ways=%d \n",waysx->number);