source: NonGTP/Boost/boost/spirit/iterator/impl/file_iterator.ipp @ 857

Revision 857, 11.9 KB checked in by igarcia, 18 years ago (diff)
Line 
1/*=============================================================================
2    Copyright (c) 2003 Giovanni Bajo
3    Copyright (c) 2003 Martin Wille
4    Copyright (c) 2003 Hartmut Kaiser
5    http://spirit.sourceforge.net/
6
7    Use, modification and distribution is subject to the Boost Software
8    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9    http://www.boost.org/LICENSE_1_0.txt)
10=============================================================================*/
11
12#ifndef BOOST_SPIRIT_FILE_ITERATOR_IPP
13#define BOOST_SPIRIT_FILE_ITERATOR_IPP
14
15#ifdef BOOST_SPIRIT_FILEITERATOR_WINDOWS
16#  define WIN32_LEAN_AND_MEAN
17#  include <windows.h>
18#endif
19
20#include <cstdio>
21#include <boost/shared_ptr.hpp>
22
23#ifdef BOOST_SPIRIT_FILEITERATOR_WINDOWS
24#  include <boost/type_traits/remove_pointer.hpp>
25#endif
26
27#ifdef BOOST_SPIRIT_FILEITERATOR_POSIX
28#  include <sys/types.h> // open, stat, mmap, munmap
29#  include <sys/stat.h>  // stat
30#  include <fcntl.h>     // open
31#  include <unistd.h>    // stat, mmap, munmap
32#  include <sys/mman.h>  // mmap, mmunmap
33#endif
34
35///////////////////////////////////////////////////////////////////////////////
36namespace boost { namespace spirit {
37
38///////////////////////////////////////////////////////////////////////////////
39namespace fileiter_impl {
40
41using namespace std;
42
43///////////////////////////////////////////////////////////////////////////////
44//
45//  std_file_iterator
46//
47//  Base class that implements iteration through a file using standard C
48//  stream library (fopen and friends). This class and the following are
49//  the base components on which the iterator is built (through the
50//  iterator adaptor library).
51//
52//  The opened file stream (FILE) is held with a shared_ptr<>, whose
53//  custom deleter invokes fcose(). This makes the syntax of the class
54//  very easy, especially everything related to copying.
55//
56///////////////////////////////////////////////////////////////////////////////
57
58template <typename CharT>
59class std_file_iterator
60{
61public:
62    typedef CharT value_type;
63
64    std_file_iterator()
65    {}
66
67    explicit std_file_iterator(std::string fileName)
68    {
69        FILE* f = fopen(fileName.c_str(), "rb");
70
71        // If the file was opened, store it into
72        //  the smart pointer.
73        if (f)
74        {
75            m_file.reset(f, fclose);
76            m_pos = 0;
77            m_eof = false;
78            update_char();
79        }
80    }
81
82    std_file_iterator(const std_file_iterator& iter)
83    { *this = iter; }
84
85    std_file_iterator& operator=(const std_file_iterator& iter)
86    {
87        m_file = iter.m_file;
88        m_curChar = iter.m_curChar;
89        m_eof = iter.m_eof;
90        m_pos = iter.m_pos;
91
92        return *this;
93    }
94
95    // Nasty bug in Comeau up to 4.3.0.1, we need explicit boolean context
96    //  for shared_ptr to evaluate correctly
97    operator bool() const
98    { return m_file ? true : false; }
99
100    bool operator==(const std_file_iterator& iter) const
101    {
102        return (m_file == iter.m_file) && (m_eof == iter.m_eof) &&
103            (m_pos == iter.m_pos);
104    }
105
106    const CharT& get_cur_char(void) const
107    {
108        return m_curChar;
109    }
110
111    void prev_char(void)
112    {
113        m_pos -= sizeof(CharT);
114        update_char();
115    }
116
117    void next_char(void)
118    {
119        m_pos += sizeof(CharT);
120        update_char();
121    }
122
123    void seek_end(void)
124    {
125        fseek(m_file.get(), 0, SEEK_END);
126        m_pos = ftell(m_file.get()) / sizeof(CharT);
127        m_eof = true;
128    }
129
130    void advance(signed long n)
131    {
132        m_pos += n * sizeof(CharT);
133        update_char();
134    }
135
136    long distance(const std_file_iterator& iter) const
137    {
138        return (long)(m_pos - iter.m_pos) / sizeof(CharT);
139    }
140
141private:
142    boost::shared_ptr<FILE> m_file;
143    std::size_t m_pos;
144    CharT m_curChar;
145    bool m_eof;
146
147    void update_char(void)
148    {
149        if ((std::size_t)ftell(m_file.get()) != m_pos)
150            fseek(m_file.get(), m_pos, SEEK_SET);
151
152        m_eof = (fread(&m_curChar, sizeof(CharT), 1, m_file.get()) < 1);
153    }
154};
155
156
157///////////////////////////////////////////////////////////////////////////////
158//
159//  mmap_file_iterator
160//
161//  File iterator for memory mapped files, for now implemented on Windows and
162//  POSIX  platforms. This class has the same interface of std_file_iterator,
163//  and can be used in its place (in fact, it's the default for Windows and
164//  POSIX).
165//
166///////////////////////////////////////////////////////////////////////////////
167
168///////////////////////////////////////////////////////////////////////////////
169// mmap_file_iterator, Windows version
170#ifdef BOOST_SPIRIT_FILEITERATOR_WINDOWS
171template <typename CharT>
172class mmap_file_iterator
173{
174public:
175    typedef CharT value_type;
176
177    mmap_file_iterator()
178    {}
179
180    explicit mmap_file_iterator(std::string fileName)
181    {
182        HANDLE hFile = ::CreateFileA(
183            fileName.c_str(),
184            GENERIC_READ,
185            FILE_SHARE_READ,
186            NULL,
187            OPEN_EXISTING,
188            FILE_FLAG_SEQUENTIAL_SCAN,
189            NULL
190        );
191
192        if (hFile == INVALID_HANDLE_VALUE)
193            return;
194
195        // Store the size of the file, it's used to construct
196        //  the end iterator
197        m_filesize = ::GetFileSize(hFile, NULL);
198
199        HANDLE hMap = ::CreateFileMapping(
200            hFile,
201            NULL,
202            PAGE_READONLY,
203            0, 0,
204            NULL
205        );
206
207        if (hMap == NULL)
208        {
209            ::CloseHandle(hFile);
210            return;
211        }
212
213        LPVOID pMem = ::MapViewOfFile(
214            hMap,
215            FILE_MAP_READ,
216            0, 0, 0
217        );
218
219        if (pMem == NULL)
220        {
221            ::CloseHandle(hMap);
222            ::CloseHandle(hFile);
223            return;
224        }
225
226        // We hold both the file handle and the memory pointer.
227        // We can close the hMap handle now because Windows holds internally
228        //  a reference to it since there is a view mapped.
229        ::CloseHandle(hMap);
230
231        // It seems like we can close the file handle as well (because
232        //  a reference is hold by the filemap object).
233        ::CloseHandle(hFile);
234
235        // Store the handles inside the shared_ptr (with the custom destructors)
236        m_mem.reset(static_cast<CharT*>(pMem), ::UnmapViewOfFile);
237
238        // Start of the file
239        m_curChar = m_mem.get();
240    }
241
242    mmap_file_iterator(const mmap_file_iterator& iter)
243    { *this = iter; }
244
245    mmap_file_iterator& operator=(const mmap_file_iterator& iter)
246    {
247        m_curChar = iter.m_curChar;
248        m_mem = iter.m_mem;
249        m_filesize = iter.m_filesize;
250
251        return *this;
252    }
253
254    // Nasty bug in Comeau up to 4.3.0.1, we need explicit boolean context
255    //  for shared_ptr to evaluate correctly
256    operator bool() const
257    { return m_mem ? true : false; }
258
259    bool operator==(const mmap_file_iterator& iter) const
260    { return m_curChar == iter.m_curChar; }
261
262    const CharT& get_cur_char(void) const
263    { return *m_curChar; }
264
265    void next_char(void)
266    { m_curChar++; }
267
268    void prev_char(void)
269    { m_curChar--; }
270
271    void advance(signed long n)
272    { m_curChar += n; }
273
274    long distance(const mmap_file_iterator& iter) const
275    { return m_curChar - iter.m_curChar; }
276
277    void seek_end(void)
278    {
279        m_curChar = m_mem.get() +
280            (m_filesize / sizeof(CharT));
281    }
282
283private:
284#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
285    typedef boost::remove_pointer<HANDLE>::type handle_t;
286#else
287    typedef void handle_t;
288#endif
289
290    boost::shared_ptr<CharT> m_mem;
291    std::size_t m_filesize;
292    CharT* m_curChar;
293};
294
295#endif // BOOST_SPIRIT_FILEITERATOR_WINDOWS
296
297///////////////////////////////////////////////////////////////////////////////
298// mmap_file_iterator, POSIX version
299#ifdef BOOST_SPIRIT_FILEITERATOR_POSIX
300template <typename CharT>
301class mmap_file_iterator
302{
303private:
304    struct mapping
305    {
306        mapping(void *p, off_t len)
307            : data(p)
308            , size(len)
309        { }
310
311        CharT const *begin() const
312        {
313            return static_cast<CharT *>(data);
314        }
315
316        CharT const *end() const
317        {
318            return static_cast<CharT *>(data) + size/sizeof(CharT);
319        }
320
321        ~mapping()
322        {
323            munmap(data, size);
324        }
325
326    private:
327        void *data;
328        off_t size;
329    };
330
331public:
332    typedef CharT value_type;
333
334    mmap_file_iterator()
335    {}
336
337    explicit mmap_file_iterator(std::string file_name)
338    {
339        // open the file
340       int fd = open(file_name.c_str(),
341#ifdef O_NOCTTY
342            O_NOCTTY | // if stdin was closed then opening a file
343                       // would cause the file to become the controlling
344                       // terminal if the filename refers to a tty. Setting
345                       // O_NOCTTY inhibits this.
346#endif
347            O_RDONLY);
348
349        if (fd == -1)
350            return;
351
352        // call fstat to find get information about the file just
353        // opened (size and file type)
354        struct stat stat_buf;
355        if ((fstat(fd, &stat_buf) != 0) || !S_ISREG(stat_buf.st_mode))
356        {   // if fstat returns an error or if the file isn't a
357            // regular file we give up.
358            close(fd);
359            return;
360        }
361
362        // perform the actual mapping
363        void *p = mmap(0, stat_buf.st_size, PROT_READ, MAP_SHARED, fd, 0);
364        // it is safe to close() here. POSIX requires that the OS keeps a
365        // second handle to the file while the file is mmapped.
366        close(fd);
367
368        if (p == MAP_FAILED)
369            return;
370
371        mapping *m = 0;
372        try
373        {
374            m = new mapping(p, stat_buf.st_size);
375        }
376        catch(...)
377        {
378            munmap(p, stat_buf.st_size);
379            throw;
380        }
381
382        m_mem.reset(m);
383
384        // Start of the file
385        m_curChar = m_mem->begin();
386    }
387
388    mmap_file_iterator(const mmap_file_iterator& iter)
389    { *this = iter; }
390
391    mmap_file_iterator& operator=(const mmap_file_iterator& iter)
392    {
393        m_curChar = iter.m_curChar;
394        m_mem = iter.m_mem;
395
396        return *this;
397    }
398
399    // Nasty bug in Comeau up to 4.3.0.1, we need explicit boolean context
400    //  for shared_ptr to evaluate correctly
401    operator bool() const
402    { return m_mem ? true : false; }
403
404    bool operator==(const mmap_file_iterator& iter) const
405    { return m_curChar == iter.m_curChar; }
406
407    const CharT& get_cur_char(void) const
408    { return *m_curChar; }
409
410    void next_char(void)
411    { m_curChar++; }
412
413    void prev_char(void)
414    { m_curChar--; }
415
416    void advance(signed long n)
417    { m_curChar += n; }
418
419    long distance(const mmap_file_iterator& iter) const
420    { return m_curChar - iter.m_curChar; }
421
422    void seek_end(void)
423    {
424        m_curChar = m_mem->end();
425    }
426
427private:
428
429    boost::shared_ptr<mapping> m_mem;
430    CharT const* m_curChar;
431};
432
433#endif // BOOST_SPIRIT_FILEITERATOR_POSIX
434
435///////////////////////////////////////////////////////////////////////////////
436} /* namespace boost::spirit::fileiter_impl */
437
438template <typename CharT, typename BaseIteratorT>
439file_iterator<CharT,BaseIteratorT>
440file_iterator<CharT,BaseIteratorT>::make_end(void)
441{
442    file_iterator iter(*this);
443    iter.base_reference().seek_end();
444    return iter;
445}
446
447template <typename CharT, typename BaseIteratorT>
448file_iterator<CharT,BaseIteratorT>&
449file_iterator<CharT,BaseIteratorT>::operator=(const base_t& iter)
450{
451    base_t::operator=(iter);
452    return *this;
453}
454
455///////////////////////////////////////////////////////////////////////////////
456}} /* namespace boost::spirit */
457
458
459#endif /* BOOST_SPIRIT_FILE_ITERATOR_IPP */
Note: See TracBrowser for help on using the repository browser.