MOOS 0.2375
/home/toby/moos-ivp/MOOS-2375-Oct0611/Essentials/MOOSUtilityLib/MOOSMemoryMapped.h
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines