ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/io/basic_ifstrstream.hpp
Revision: 1930
Committed: Wed Jan 12 22:41:40 2005 UTC (19 years, 5 months ago) by gezelter
File size: 14220 byte(s)
Log Message:
merging new_design branch into OOPSE-2.0

File Contents

# User Rev Content
1 gezelter 1930 /*
2     * Copyright (c) 2005 The University of Notre Dame. All Rights Reserved.
3 tim 1570 *
4 gezelter 1930 * The University of Notre Dame grants you ("Licensee") a
5     * non-exclusive, royalty free, license to use, modify and
6     * redistribute this software in source and binary code form, provided
7     * that the following conditions are met:
8     *
9     * 1. Acknowledgement of the program authors must be made in any
10     * publication of scientific results based in part on use of the
11     * program. An acceptable form of acknowledgement is citation of
12     * the article in which the program was described (Matthew
13     * A. Meineke, Charles F. Vardeman II, Teng Lin, Christopher
14     * J. Fennell and J. Daniel Gezelter, "OOPSE: An Object-Oriented
15     * Parallel Simulation Engine for Molecular Dynamics,"
16     * J. Comput. Chem. 26, pp. 252-271 (2005))
17     *
18     * 2. Redistributions of source code must retain the above copyright
19     * notice, this list of conditions and the following disclaimer.
20     *
21     * 3. Redistributions in binary form must reproduce the above copyright
22     * notice, this list of conditions and the following disclaimer in the
23     * documentation and/or other materials provided with the
24     * distribution.
25     *
26     * This software is provided "AS IS," without a warranty of any
27     * kind. All express or implied conditions, representations and
28     * warranties, including any implied warranty of merchantability,
29     * fitness for a particular purpose or non-infringement, are hereby
30     * excluded. The University of Notre Dame and its licensors shall not
31     * be liable for any damages suffered by licensee as a result of
32     * using, modifying or distributing the software or its
33     * derivatives. In no event will the University of Notre Dame or its
34     * licensors be liable for any lost revenue, profit or data, or for
35     * direct, indirect, special, consequential, incidental or punitive
36     * damages, however caused and regardless of the theory of liability,
37     * arising out of the use of or inability to use software, even if the
38     * University of Notre Dame has been advised of the possibility of
39     * such damages.
40 tim 1570 */
41 gezelter 1930
42 tim 1570 /**
43     * @file basic_ifstrstream.hpp
44     * @author Teng Lin
45     * @date 10/14/2004
46     * @version 1.0
47     */
48    
49     #ifndef IO_IFSTRSTREAM_HPP
50     #define IO_IFSTRSTREAM_HPP
51    
52 tim 1583 #include <cassert>
53 tim 1572 #include <cstring>
54 tim 1570 #include <fstream>
55     #include <sstream>
56    
57 tim 1572 #ifdef IS_MPI
58 tim 1577 #include <mpi.h>
59 tim 1572 #endif
60    
61 tim 1570 namespace oopse {
62 gezelter 1930
63 tim 1570 /**
64     * @class basic_ifstrstream basic_ifstrstream.hpp "io/basic_ifstrstream.hpp"
65 gezelter 1930 * @brief basic_ifstrstream class provides a stream interface to read data from files.
66 tim 1570 * <p>In single mode, it falls back to ifstream. Don't need to read the whole file into memory.
67     * In parallel mode, the master node will read the whole file and brocast it to other slave nodes.
68     * After brocasting, every node will fall back to stringstream.</p>
69     *
70     * @code
71     * const int MAXLEN = 1024;
72     * char buffer[MAXLEN];
73     * ifstrstream in;
74     * in.open("Shapes.frc");
75 tim 1572 * if (in.is_open()) {
76 tim 1570 * in.getline(buffer, MAXLEN);
77     * }
78     * in.close();
79     * @endcode
80     */
81     template <class _CharT, class _Traits, class _Alloc>
82 gezelter 1930 class basic_ifstrstream : public std::basic_istream<_CharT, _Traits> {
83 tim 1570 public:
84     //traits
85     typedef _CharT char_type;
86     typedef typename _Traits::int_type int_type;
87     typedef typename _Traits::pos_type pos_type;
88     typedef typename _Traits::off_type off_type;
89     typedef _Traits traits_type;
90    
91 gezelter 1930 typedef std::basic_ios<_CharT, _Traits> _Basic_ios;
92     typedef std::basic_istream<_CharT, _Traits> _Base;
93 tim 1570
94     #ifdef IS_MPI
95 gezelter 1930 typedef std::basic_stringbuf<_CharT, _Traits, _Alloc> _Buf;
96 tim 1570 #else
97 gezelter 1930 typedef std::basic_filebuf<_CharT, _Traits> _Buf;
98 tim 1570 #endif
99    
100 gezelter 1930 static const int FileNotExists = -1;
101 tim 1570 static const int FileIOError = -2;
102    
103     public:
104    
105     /** Constructs an object of class ifstream. */
106     basic_ifstrstream()
107 gezelter 1930 : std::basic_ios<_CharT, _Traits>(), std::basic_istream<_CharT, _Traits>(0),
108 tim 1570 internalBuf_(NULL), isRead(false) {
109    
110     #ifdef IS_MPI
111     //in parallel mode, fall back to istringstream
112 gezelter 1930 std::basic_stringbuf<_CharT, _Traits, _Alloc>* stringBuffer = new std::basic_stringbuf<_CharT, _Traits, _Alloc>();
113 tim 1570 internalBuf_ = stringBuffer;
114     #else
115     //in single version, fall back to ifstream
116 gezelter 1930 std::basic_filebuf<_CharT, _Traits>* fileBuffer = new std::basic_filebuf<_CharT, _Traits>();
117 tim 1570 internalBuf_ = fileBuffer;
118     #endif
119    
120     this->init(internalBuf_);
121     isRead = false;
122     }
123    
124     /**
125     * Explicit constructor
126     * @filename String containing the name of the file to be opened
127 tim 1572 * @mode Flags describing the requested i/o mode for the file, default value is ios_base::in
128     * @checkFilename Flags indicating checking the file name in parallel
129 tim 1570 */
130 gezelter 1930 explicit basic_ifstrstream(const char* filename, std::ios_base::openmode mode = std::ios_base::in, bool checkFilename = false)
131     : std::basic_ios<_CharT, _Traits>(), std::basic_istream<_CharT, _Traits>(0),
132 tim 1570 internalBuf_(NULL), isRead(false) {
133    
134 gezelter 1930 isRead = internalOpen(filename, mode | std::ios_base::in, checkFilename);
135 tim 1570 }
136    
137     /**
138 tim 1577 * virtual destructor will close the file(in single mode) and clear the stream buffer
139 tim 1570 */
140     ~basic_ifstrstream(){
141     close();
142     delete internalBuf_;
143     internalBuf_ = NULL;
144     }
145    
146     /**
147     * Opens a file and associats a buffer with the specified file to perform the i/o operations
148     * (single mode). Master reads a file and brocasts its content to the other slave nodes. After
149     * brocasting, every nodes fall back to stringstream (parallel mode).
150     * @filename String containing the name of the file to be opened
151     * @mode Flags describing the requested i/o mode for the file
152 tim 1572 * @checkFilename Flags indicating checking the file name in parallel
153 tim 1570 */
154 gezelter 1930 void open(const char* filename, std::ios_base::openmode mode = std::ios_base::in, bool checkFilename = false){
155 tim 1570
156     if (!isRead ) {
157 tim 1572 isRead = internalOpen(filename, mode, checkFilename);
158 tim 1570 }
159     }
160    
161     /**
162     * Tests if the stream is currently associated with a valid buffer.
163     * @return true if a file has successfully been opened (single mode) or the whole file is read
164     * and spreaded among all of the processors (parallel mode), otherwise false is returned
165     */
166     bool is_open ( ) {
167     #ifdef IS_MPI
168     return isRead;
169     #else
170     //single version fall back to ifstream
171     return this->rdbuf()->is_open();
172     #endif
173     }
174    
175     /**
176     * In single mode, closes a file. The stream's file buffer is released from its association with
177     * the currently open file. In parallel mode, clean the
178     */
179     void close() {
180     #ifndef IS_MPI
181     //single version fall back to ifstream
182     if (!this->rdbuf()->close())
183 gezelter 1930 this->setstate(std::ios_base::failbit);
184 tim 1570 #endif
185    
186     isRead = false;
187     }
188    
189     /**
190     * Gets the stream buffer object associated with the stream
191     * @return A pointer to the stream buffe object(filebuf in single mode, stringbuf in
192     * parallel mode) associated with the stream.
193     */
194     _Buf* rdbuf() const{
195 tim 1582 return static_cast<_Buf*>(internalBuf_);
196 tim 1570 }
197    
198     private:
199    
200     /**
201     * Internal function used to open the file
202     * @return true if succesfully opens a file (single mode) or gets the file content (parallel mode)
203     * otherwise return false
204     * @filename String containing the name of the file to be opened
205     * @mode Flags describing the requested i/o mode for the file
206     * @todo use try - catch syntax to make the program more readable
207     */
208 gezelter 1930 bool internalOpen(const char* filename, std::ios_base::openmode mode, bool checkFilename){
209 tim 1570
210     #ifdef IS_MPI
211     int commStatus;
212     long fileSize;
213     char* fbuf;
214     int filenameLen;
215     int diffFilename;
216     int error;
217 tim 1572 int myRank;
218     int masterNode;
219 tim 1570
220 tim 1572 commStatus = MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
221     masterNode = 0;
222    
223     if (myRank == masterNode) {
224 tim 1570
225 tim 1572 if (checkFilename) {
226 tim 1570
227 tim 1572 //check the filename is the same
228     filenameLen = strlen(filename);
229 tim 1583 commStatus = MPI_Bcast(&filenameLen, 1, MPI_INT, masterNode, MPI_COMM_WORLD);
230     commStatus = MPI_Bcast((void*)filename, filenameLen, MPI_CHAR, masterNode, MPI_COMM_WORLD);
231 tim 1570
232 tim 1572 diffFilename = 0;
233 tim 1583 commStatus = MPI_Allreduce(&diffFilename, &error, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
234 tim 1572
235     //if file names are different just return false
236     if (error > 0)
237 tim 1570 return false;
238 tim 1572 }
239 tim 1570
240 gezelter 1930 std::ifstream fin(filename, mode);
241     std::basic_stringbuf<_CharT, _Traits, _Alloc>* sbuf;
242 tim 1570
243     if (fin.is_open()) {
244    
245 gezelter 1930 fin.seekg(0, std::ios::end);
246 tim 1570 fileSize = fin.tellg();
247 gezelter 1930 fin.seekg(0, std::ios::beg);
248 tim 1583
249 tim 1570 // '\0' need one more char
250     fbuf = new char[fileSize+1];
251    
252     assert(fbuf != 0);
253    
254     fin.read(fbuf, fileSize);
255    
256     if (fin.fail())
257     fileSize = FileIOError;
258    
259     //brocasting the file size
260     commStatus = MPI_Bcast(&fileSize, 1, MPI_LONG, masterNode, MPI_COMM_WORLD);
261    
262     if (fileSize < 0) {
263     fin.close();
264     delete fbuf;
265    
266     return false;
267     }
268    
269 gezelter 1930 // make a c-style std::string and brocasting it
270 tim 1570 fbuf[fileSize] = '\0';
271     commStatus = MPI_Bcast(fbuf, fileSize + 1, MPI_CHAR, masterNode, MPI_COMM_WORLD);
272    
273     //it is safe to delete null pointer
274     delete internalBuf_;
275    
276     //initilaize istream
277 gezelter 1930 internalBuf_ = new std::basic_stringbuf<_CharT, _Traits, _Alloc>(fbuf, mode);
278 tim 1570 assert(internalBuf_);
279     this->init(internalBuf_);
280    
281     //close the file and delete the buffer
282     fin.close();
283     delete fbuf;
284     }else{
285 gezelter 1930 fileSize = FileNotExists;
286 tim 1570 commStatus = MPI_Bcast(&fileSize, 1, MPI_LONG, masterNode, MPI_COMM_WORLD);
287     return false;
288     }
289    
290 gezelter 1930 } else{ //slave nodes
291    
292 tim 1570 //check file name
293 tim 1572 if (checkFilename) {
294 tim 1583 commStatus = MPI_Bcast(&filenameLen, 1, MPI_INT, masterNode, MPI_COMM_WORLD);
295 tim 1570
296 tim 1572 char * masterFilename = new char[filenameLen];
297     commStatus = MPI_Bcast(masterFilename, filenameLen, MPI_CHAR, masterNode, MPI_COMM_WORLD);
298    
299     if( strcmp(masterFilename, filename) == 0)
300     diffFilename = 0;
301     else
302     diffFilename = 1;
303 tim 1570
304 tim 1572 delete masterFilename;
305    
306 tim 1583 commStatus = MPI_Allreduce(&diffFilename, &error, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
307 tim 1570
308 tim 1572 if (error > 0)
309     return false;
310     }
311 tim 1570 //get file size
312     commStatus = MPI_Bcast(&fileSize, 1, MPI_LONG, masterNode, MPI_COMM_WORLD);
313    
314     if (fileSize >= 0 ) {
315     fbuf = new char[fileSize+1];
316     assert(fbuf);
317    
318     //receive file content
319     commStatus = MPI_Bcast(fbuf, fileSize + 1, MPI_CHAR, masterNode, MPI_COMM_WORLD);
320    
321     //it is safe to delete null pointer
322     delete internalBuf_;
323    
324     //initilaize istream
325 gezelter 1930 internalBuf_ = new std::basic_stringbuf<_CharT, _Traits, _Alloc>(fbuf, mode);
326 tim 1570 assert(internalBuf_);
327     this->init(internalBuf_);
328    
329     delete fbuf;
330    
331 gezelter 1930 } else if (fileSize == FileNotExists ) {
332 tim 1570 return false;
333    
334     } else if (fileSize == FileIOError ) {
335     return false;
336     }
337     }
338    
339     #else
340     //in single version, fall back to ifstream
341 gezelter 1930 std::basic_filebuf<_CharT, _Traits>* fileBuffer = new std::basic_filebuf<_CharT, _Traits>();
342 tim 1570
343 gezelter 1930 //it is safe to delete null pointer
344     delete internalBuf_;
345     internalBuf_ = fileBuffer;
346 tim 1570
347 gezelter 1930 this->init(internalBuf_);
348     if (!fileBuffer->open(filename, mode)) {
349     this->setstate(std::ios_base::failbit);
350     return false;
351     }
352    
353 tim 1570 #endif
354    
355     return true;
356     }
357    
358 gezelter 1930 std::basic_streambuf<_CharT, _Traits>* internalBuf_; /** internal stream buffer */
359 tim 1570 bool isRead; /** file opened flag */
360     };
361    
362 gezelter 1930 typedef basic_ifstrstream<char, std::char_traits<char>, std::allocator<char> > ifstrstream;
363 tim 1570 }//namespace oopse
364     #endif //IO_IFSTRSTREAM_HPP