MOOS 0.2375
|
00001 #ifdef _WIN32 00002 #pragma warning(disable : 4786) 00003 #pragma warning(disable : 4996) 00004 #endif 00005 00006 #ifndef MOOSMemoryMappedH 00007 #define MOOSMemoryMappedH 00008 00009 00010 #include <stdlib.h> 00011 #include <iostream> 00012 #include <vector> 00013 #include <iterator> 00014 #include <algorithm> 00015 #include <sstream> 00016 #include <set> 00017 #include <iterator> 00018 #include <algorithm> 00019 #include <iomanip> 00020 #include <functional> 00021 00022 00023 00024 #ifdef WIN32 00025 #include <windows.h> 00026 #else 00027 #include <unistd.h> 00028 #include <sys/types.h> 00029 #include <sys/mman.h> 00030 #include <sys/fcntl.h> 00031 #include <sys/stat.h> 00032 #include <ctype.h> 00033 #endif 00034 00035 class CMOOSMemMappedFile 00036 { 00037 public: 00039 CMOOSMemMappedFile() 00040 { 00041 m_hMapHandle = 0; 00042 m_pBuffer = NULL; 00043 m_nSize = -1; 00044 } 00045 00046 std::string GetFileName() 00047 { 00048 return m_sName; 00049 } 00050 00051 bool Open(const std::string & sfName) 00052 { 00053 m_hMapHandle = 0; 00054 m_sName = sfName; 00055 m_pBuffer = NULL; 00056 m_nSize = -1; 00057 00058 #ifdef WIN32 00059 //Windows land 00060 m_hFileHandle = CreateFile(m_sName.c_str(), 00061 GENERIC_READ, 00062 FILE_SHARE_READ, 00063 NULL, 00064 OPEN_EXISTING, 00065 FILE_ATTRIBUTE_NORMAL, 00066 NULL); 00067 00068 if (m_hFileHandle!=INVALID_HANDLE_VALUE) 00069 { 00070 m_hMapHandle = CreateFileMapping(m_hFileHandle, NULL, PAGE_READONLY, 0,0, NULL); 00071 if (m_hMapHandle != NULL) 00072 { 00073 m_pBuffer = (char*)MapViewOfFile(m_hMapHandle, FILE_MAP_READ, 0, 0, 0); 00074 } 00075 } 00076 else 00077 { 00078 00079 PrintLastWin32Error(); 00080 00081 m_hFileHandle = NULL; 00082 m_hMapHandle = NULL; 00083 } 00084 #else 00085 //linux side.. 00086 m_hMapHandle = open(m_sName.c_str(), O_RDWR, 0); 00087 if (m_hMapHandle != -1) 00088 { 00089 //get file stats 00090 struct stat StatusBuffer; 00091 fstat(m_hMapHandle, &StatusBuffer); 00092 m_pBuffer = (char*)mmap(NULL, 00093 StatusBuffer.st_size, 00094 PROT_READ, 00095 MAP_SHARED, 00096 m_hMapHandle , 0); 00097 } 00098 else 00099 { 00100 m_hMapHandle = 0; 00101 } 00102 #endif 00103 00104 m_nSize = GetSize(); 00105 00106 //report out success 00107 if(IsOpen()) 00108 { 00109 std::cout<<"Successfully Memory Mapped "<<double(m_nSize)/(1048576)<<"MB file \n"; 00110 return true; 00111 } 00112 else 00113 { 00114 return MOOSFail("CATASTROPHE : Failed to open file %s",sfName.c_str()); 00115 } 00116 00117 } 00118 00119 ~CMOOSMemMappedFile() 00120 { 00121 Close(); 00122 } 00123 00124 00125 //helper function to print WIN32 00126 void PrintLastWin32Error() 00127 { 00128 #ifdef _WIN32 00129 LPVOID lpMsgBuf; 00130 FormatMessage( 00131 FORMAT_MESSAGE_ALLOCATE_BUFFER | 00132 FORMAT_MESSAGE_FROM_SYSTEM | 00133 FORMAT_MESSAGE_IGNORE_INSERTS, 00134 NULL, 00135 GetLastError(), 00136 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language 00137 (LPTSTR) &lpMsgBuf, 00138 0, 00139 NULL 00140 ); 00141 00142 std::string s((LPCTSTR)lpMsgBuf); 00143 MOOSTrace("Problem : %s\n",s.c_str()); 00144 LocalFree( lpMsgBuf ); 00145 #endif 00146 } 00147 00148 void Close() 00149 { 00150 if (m_hMapHandle) 00151 { 00152 #ifdef WIN32 00153 UnmapViewOfFile(m_pBuffer); 00154 CloseHandle(m_hMapHandle); 00155 CloseHandle(m_hFileHandle); 00156 m_hFileHandle = 0; 00157 00158 #else 00159 munmap(m_pBuffer, 0); 00160 close(m_hMapHandle); 00161 #endif 00162 m_hMapHandle = 0; 00163 m_pBuffer = 0; 00164 } 00165 } 00166 00168 int GetSize() 00169 { 00170 if(!IsOpen()) 00171 return 0; 00172 00173 if(m_nSize<0) 00174 { 00175 #ifdef WIN32 00176 m_nSize = (int)GetFileSize(m_hFileHandle,NULL); 00177 #else 00178 struct stat sbuf; 00179 fstat(m_hMapHandle, &sbuf); 00180 m_nSize = sbuf.st_size; 00181 #endif 00182 } 00183 return m_nSize; 00184 } 00185 00187 char * operator[](int i) 00188 { 00189 if(i<GetSize()) 00190 return (GetContents()+i); 00191 else 00192 return NULL; 00193 } 00194 00195 00197 bool IsOpen() 00198 { 00199 return m_hMapHandle!=0 && GetContents()!=NULL; 00200 } 00201 00203 char* GetContents() 00204 { 00205 return m_pBuffer; 00206 } 00207 00208 private: 00209 00210 00211 #ifdef WIN32 00212 HANDLE m_hMapHandle; 00213 HANDLE m_hFileHandle; 00214 #else 00215 int m_hMapHandle; 00216 #endif 00217 00218 std::string m_sName; 00219 char* m_pBuffer; 00220 int m_nSize; 00221 00222 }; 00223 00224 00225 00227 struct TextLineInfo 00228 { 00229 TextLineInfo(){pLineStart=NULL;pLineEnd = NULL;}; 00230 TextLineInfo(char * pStart,char * pEnd) 00231 { 00232 pLineStart = pStart; 00233 pLineEnd = pEnd; 00234 } 00235 char * Start(){return pLineStart;}; 00236 char * End(){return pLineEnd;}; 00237 bool IsWanted(){return true;}; 00238 00239 char * pLineStart; 00240 char * pLineEnd; 00241 }; 00242 00243 00244 00258 template <class T = TextLineInfo > 00259 class CMOOSMemMappedTextFile : public CMOOSMemMappedFile 00260 { 00261 private: 00262 typedef CMOOSMemMappedFile BASE; 00263 public: 00264 00266 typedef T LINE; 00267 00269 CMOOSMemMappedTextFile(){m_nLineCount = -1;}; 00270 00271 bool Open(const std::string & sName,int nMaxLines=-1) 00272 { 00273 if(!BASE::Open(sName)) 00274 return false; 00275 00276 if(nMaxLines<0) 00277 m_nLineCount = GetLineCount(); 00278 else 00279 m_nLineCount = nMaxLines; 00280 00281 BuildLineIndex(nMaxLines); 00282 00283 return true; 00284 } 00285 00287 int GetLineCount() 00288 { 00289 if(IsOpen()) 00290 { 00291 if(m_nLineCount<0) 00292 { 00293 //counting lines - 00294 std::cout<<"Counting Lines...."; 00295 int nc = std::count(GetContents(),GetContents()+GetSize(),'\n'); 00296 /* 00297 char * pLook = GetContents(); 00298 char * pStop = pLook+GetSize(); 00299 int nc = 0; 00300 while(pLook<pStop) 00301 { 00302 if(*pLook++=='\n') 00303 nc++; 00304 }*/ 00305 00306 std::cout<<"done ("<<nc<<")\n"; 00307 return nc; 00308 } 00309 else 00310 { 00311 return m_nLineCount; 00312 } 00313 } 00314 return 0; 00315 } 00316 00318 bool BuildLineIndex(int nNumLines = -1) 00319 { 00320 std::cout<<"Indexing lines...."; 00321 00322 if(nNumLines==-1) 00323 nNumLines = m_nLineCount; 00324 00325 m_LineIndex.resize(nNumLines); 00326 00327 char * pNewLine = GetContents(); 00328 char *pFileEnd = pNewLine+GetSize(); 00329 int n = 0; 00330 while(pNewLine<pFileEnd && n<nNumLines) 00331 { 00332 char * pLineEnd = std::find(pNewLine,pFileEnd,'\n'); 00333 if(pLineEnd<pFileEnd) 00334 { 00335 //this is where specialised constructors for the non default 00336 //line type template may get called... 00337 m_LineIndex[n] = LINE(pNewLine,pLineEnd); 00338 00339 if(m_LineIndex[n].IsWanted()) 00340 n++; 00341 } 00342 pNewLine = pLineEnd+1; 00343 } 00344 00345 std::cout<<"done\n"; 00346 00347 //we may have discounted some lines... 00348 std::cout<<"Pruning "<<std::distance(m_LineIndex.begin()+n,m_LineIndex.end())<<" elements from LineIndex (comments)\n"; 00349 m_LineIndex.erase(m_LineIndex.begin()+n,m_LineIndex.end()); 00350 00351 //re measure the number of lines 00352 m_nLineCount = m_LineIndex.size(); 00353 00354 return true; 00355 } 00356 00358 std::string GetLine(int nLine) 00359 { 00360 //note templated type nmust support Start() and End() 00361 if(nLine<static_cast<int>(m_LineIndex.size())) 00362 return std::string(m_LineIndex[nLine].Start(),m_LineIndex[nLine].End()); 00363 else 00364 { 00365 std::cerr<<"OUCH - indexing past end of file index!\n"; 00366 return ""; 00367 } 00368 } 00369 00371 std::vector< LINE > m_LineIndex; 00372 00374 int m_nLineCount; 00375 }; 00376 00377 00378 00379 00380 00381 00382 struct ALogLineInfo : public TextLineInfo 00383 { 00384 ALogLineInfo(){}; 00385 ALogLineInfo(char * pStart,char * pEnd):TextLineInfo(pStart,pEnd) 00386 { 00387 dfTimeField = FastATOF(pStart); 00388 //std::cout<<dfTimeField<<std::endl; 00389 } 00390 00391 //returns true if comment 00392 bool IsComment() const 00393 { 00394 // alog are well formatted - first char in a line being a % 00395 //indicates a comment 00396 return *pLineStart=='%'; 00397 } 00398 00399 static bool Printable(char c) 00400 { 00401 return (isalnum(c) != 0); 00402 } 00403 00404 static bool isnumeric(char c) 00405 { 00406 return (isdigit(c)!=0) || c=='-' || c=='.'; 00407 } 00408 00409 00410 bool IsEmpty() 00411 { 00412 // return std::find_if(pLineStart,pLineEnd,isalnum)==pLineEnd; 00413 return std::find_if(pLineStart,pLineEnd,Printable)==pLineEnd; 00414 } 00415 00416 bool IsNumFirst() 00417 { 00418 // This does not detect lines with negative time stamps (as we seem to get when 00419 // we use wildcard logging). I'm not sure if this is a problem or not. ARH 00420 return (isdigit(*pLineStart) != 0); 00421 } 00422 00423 bool IsNumFollowedByWhiteSpace() 00424 { 00425 char *pFirstNonNumeric = std::find_if(pLineStart,pLineEnd, std::not1(std::ptr_fun(isnumeric)) ); 00426 00427 if (pFirstNonNumeric == pLineEnd) 00428 { 00429 return true; 00430 } 00431 00432 return (iswspace(*pFirstNonNumeric) != 0); 00433 } 00434 00435 bool IsWanted() 00436 { 00437 if(IsComment()) 00438 return false; 00439 00440 if(IsEmpty()) 00441 return false; 00442 00443 if(!IsNumFirst()) 00444 return false; 00445 00446 if(!IsNumFollowedByWhiteSpace()) 00447 return false; 00448 00449 return true; 00450 } 00451 00452 double GetTimeField(double dfOffset=0) const 00453 { 00454 return dfTimeField+dfOffset; 00455 } 00456 00457 double FastATOF(const char * pStart) 00458 { 00459 //quick and dirty - looks for double in first 20 digits 00460 //beginnin at pStart. 00461 //prevents long call of strlen embedded in atof .. 00462 #define MAX_DOUBLE_STRING_LENGTH 20 00463 char Tmp[MAX_DOUBLE_STRING_LENGTH]; 00464 std::copy(pStart,pStart+sizeof(Tmp),Tmp); 00465 Tmp[sizeof(Tmp)-1] = 0; 00466 00467 return atof(Tmp); 00468 00469 } 00470 00471 00472 00473 double dfTimeField; 00474 }; 00475 00476 00477 inline bool ALogLineInfoLessThan(const ALogLineInfo & L1,const ALogLineInfo & L2) 00478 { 00479 /*static int nCalls = 0; 00480 if(nCalls++%10000==0) 00481 cout<<"nC:"<<nCalls<<std::endl;*/ 00482 00483 if(L1.IsComment() && L2.IsComment()) 00484 return false; 00485 if(L1.IsComment()) 00486 return true; 00487 if(L2.IsComment()) 00488 return false; 00489 00490 //look at first column of times... 00491 return L1.dfTimeField < L2.dfTimeField; 00492 } 00493 00497 class CMOOSMemMappedAlogFile : public CMOOSMemMappedTextFile< ALogLineInfo > 00498 { 00499 00500 private: 00501 typedef CMOOSMemMappedTextFile <ALogLineInfo> BASE; 00502 public: 00503 CMOOSMemMappedAlogFile(){m_dfLogStart = -1;} 00504 00505 bool Open(const std::string & sName,bool bSummary = true, int nMaxLines=-1) 00506 { 00507 if(!BASE::Open(sName,nMaxLines)) 00508 return false; 00509 00510 if(!SortLineIndex()) 00511 return false; 00512 00513 if(bSummary && !ReadSourceAndTypeSets()) 00514 return false; 00515 00516 if(!ReadStartTime()) 00517 return false; 00518 00519 return true; 00520 } 00521 00522 bool SortLineIndex() 00523 { 00524 std::cout<<"Sorting Lines...."; 00525 std::sort(m_LineIndex.begin(),m_LineIndex.end(),ALogLineInfoLessThan); 00526 std::cout<<"done"<<std::endl; 00527 return true; 00528 } 00529 00530 static bool TimePredicate(const LINE & L, double dfT) 00531 { 00532 return L.GetTimeField()<dfT; 00533 } 00534 00535 static bool TimePredicate2(const LINE & L, const LINE & L2) 00536 { 00537 return L.GetTimeField()<L2.GetTimeField(); 00538 } 00539 00540 int SeekToFindTime(double dfT) 00541 { 00542 std::vector<LINE>::iterator p; 00543 LINE Q; 00544 Q.dfTimeField = dfT - m_dfLogStart; 00545 //GCC and VC<8 are OK with this but VC8 is less sure.. 00546 //p = std::lower_bound(m_LineIndex.begin(),m_LineIndex.end(),dfT - m_dfLogStart,TimePredicate); 00547 p = std::lower_bound(m_LineIndex.begin(),m_LineIndex.end(),Q,TimePredicate2); 00548 if(p==m_LineIndex.end()) 00549 return -1; 00550 else 00551 return std::distance(m_LineIndex.begin(),p); 00552 } 00553 00554 //simply extract a space delimeted token from a string startign at position nPos 00555 static bool GetNextToken(const std::string & s,int & nPos,std::string & sTk) 00556 { 00557 std::string::size_type Start = s.find_first_not_of(" \t", nPos); 00558 nPos = s.find_first_of(" \t", Start); 00559 if( Start!=std::string::npos) 00560 { 00561 sTk =s.substr(Start,nPos-Start); 00562 return true; 00563 } 00564 return false; 00565 } 00566 00569 bool ReadSourceAndTypeSets() 00570 { 00571 00572 std::cout<<"extracting message names and sources....."; 00573 for(int i = 0; i<m_nLineCount;i++) 00574 { 00575 if(!m_LineIndex[i].IsComment()) 00576 { 00577 std::string sLine = GetLine(i); 00578 std::string sT,sWhat,sWho; 00579 int n= 0; 00580 00581 //time 00582 GetNextToken(sLine,n,sT); 00583 00584 //what 00585 GetNextToken(sLine,n,sWhat); 00586 m_MessageNames.insert(sWhat); 00587 00588 //who 00589 GetNextToken(sLine,n,sWho); 00590 m_SourceNames.insert(sWho); 00591 00592 } 00593 } 00594 std::cout<<"done\n"; 00595 00596 //print out some warm fuzzies 00597 std::cout<<"\nThere are "<<m_MessageNames.size()<<" different message types:\n\t"; 00598 std::copy(m_MessageNames.begin(), 00599 m_MessageNames.end(), 00600 std::ostream_iterator<std::string>(std::cout ,"\n\t")); 00601 00602 std::cout<<"\nThere are "<<m_SourceNames.size()<<" different sources:\n\t"; 00603 std::copy(m_SourceNames.begin(), 00604 m_SourceNames.end(), 00605 std::ostream_iterator<std::string>(std::cout ,"\n\t")); 00606 00607 00608 return true; 00609 } 00610 00611 //simply fills in the log fills start time 00612 bool ReadStartTime() 00613 { 00614 int nHeaderBlock = 1000; 00615 std::string sHeader(GetContents(),GetContents()+nHeaderBlock); 00616 MOOSChomp(sHeader,"LOGSTART"); 00617 m_dfLogStart = atof(sHeader.c_str()); 00618 00619 //this is unix time so it must be geqz 00620 return m_dfLogStart>=0; 00621 } 00622 00623 double GetLogStart(){return m_dfLogStart;}; 00624 00625 double GetEntryTime(int i) 00626 { 00627 if(i>=static_cast<int> (m_LineIndex.size())) 00628 return -1; 00629 00630 //return the time of the ith index offset by the 00631 //start time of the whoel log 00632 return m_LineIndex[i].GetTimeField(GetLogStart()); 00633 } 00634 00635 std::set<std::string> GetSourceNames(){return m_SourceNames;}; 00636 std::set<std::string> GetMessageNames(){return m_MessageNames;}; 00637 00638 std::set<std::string> m_MessageNames; 00639 std::set<std::string> m_SourceNames; 00640 double m_dfLogStart; 00641 00642 }; 00643 00644 00645 00646 #endif 00647