ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-2.0/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

# Content
1 /*
2 * Copyright (c) 2005 The University of Notre Dame. All Rights Reserved.
3 *
4 * 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 */
41
42 /**
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 #include <cassert>
53 #include <cstring>
54 #include <fstream>
55 #include <sstream>
56
57 #ifdef IS_MPI
58 #include <mpi.h>
59 #endif
60
61 namespace oopse {
62
63 /**
64 * @class basic_ifstrstream basic_ifstrstream.hpp "io/basic_ifstrstream.hpp"
65 * @brief basic_ifstrstream class provides a stream interface to read data from files.
66 * <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 * if (in.is_open()) {
76 * in.getline(buffer, MAXLEN);
77 * }
78 * in.close();
79 * @endcode
80 */
81 template <class _CharT, class _Traits, class _Alloc>
82 class basic_ifstrstream : public std::basic_istream<_CharT, _Traits> {
83 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 typedef std::basic_ios<_CharT, _Traits> _Basic_ios;
92 typedef std::basic_istream<_CharT, _Traits> _Base;
93
94 #ifdef IS_MPI
95 typedef std::basic_stringbuf<_CharT, _Traits, _Alloc> _Buf;
96 #else
97 typedef std::basic_filebuf<_CharT, _Traits> _Buf;
98 #endif
99
100 static const int FileNotExists = -1;
101 static const int FileIOError = -2;
102
103 public:
104
105 /** Constructs an object of class ifstream. */
106 basic_ifstrstream()
107 : std::basic_ios<_CharT, _Traits>(), std::basic_istream<_CharT, _Traits>(0),
108 internalBuf_(NULL), isRead(false) {
109
110 #ifdef IS_MPI
111 //in parallel mode, fall back to istringstream
112 std::basic_stringbuf<_CharT, _Traits, _Alloc>* stringBuffer = new std::basic_stringbuf<_CharT, _Traits, _Alloc>();
113 internalBuf_ = stringBuffer;
114 #else
115 //in single version, fall back to ifstream
116 std::basic_filebuf<_CharT, _Traits>* fileBuffer = new std::basic_filebuf<_CharT, _Traits>();
117 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 * @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 */
130 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 internalBuf_(NULL), isRead(false) {
133
134 isRead = internalOpen(filename, mode | std::ios_base::in, checkFilename);
135 }
136
137 /**
138 * virtual destructor will close the file(in single mode) and clear the stream buffer
139 */
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 * @checkFilename Flags indicating checking the file name in parallel
153 */
154 void open(const char* filename, std::ios_base::openmode mode = std::ios_base::in, bool checkFilename = false){
155
156 if (!isRead ) {
157 isRead = internalOpen(filename, mode, checkFilename);
158 }
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 this->setstate(std::ios_base::failbit);
184 #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 return static_cast<_Buf*>(internalBuf_);
196 }
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 bool internalOpen(const char* filename, std::ios_base::openmode mode, bool checkFilename){
209
210 #ifdef IS_MPI
211 int commStatus;
212 long fileSize;
213 char* fbuf;
214 int filenameLen;
215 int diffFilename;
216 int error;
217 int myRank;
218 int masterNode;
219
220 commStatus = MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
221 masterNode = 0;
222
223 if (myRank == masterNode) {
224
225 if (checkFilename) {
226
227 //check the filename is the same
228 filenameLen = strlen(filename);
229 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
232 diffFilename = 0;
233 commStatus = MPI_Allreduce(&diffFilename, &error, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
234
235 //if file names are different just return false
236 if (error > 0)
237 return false;
238 }
239
240 std::ifstream fin(filename, mode);
241 std::basic_stringbuf<_CharT, _Traits, _Alloc>* sbuf;
242
243 if (fin.is_open()) {
244
245 fin.seekg(0, std::ios::end);
246 fileSize = fin.tellg();
247 fin.seekg(0, std::ios::beg);
248
249 // '\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 // make a c-style std::string and brocasting it
270 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 internalBuf_ = new std::basic_stringbuf<_CharT, _Traits, _Alloc>(fbuf, mode);
278 assert(internalBuf_);
279 this->init(internalBuf_);
280
281 //close the file and delete the buffer
282 fin.close();
283 delete fbuf;
284 }else{
285 fileSize = FileNotExists;
286 commStatus = MPI_Bcast(&fileSize, 1, MPI_LONG, masterNode, MPI_COMM_WORLD);
287 return false;
288 }
289
290 } else{ //slave nodes
291
292 //check file name
293 if (checkFilename) {
294 commStatus = MPI_Bcast(&filenameLen, 1, MPI_INT, masterNode, MPI_COMM_WORLD);
295
296 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
304 delete masterFilename;
305
306 commStatus = MPI_Allreduce(&diffFilename, &error, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
307
308 if (error > 0)
309 return false;
310 }
311 //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 internalBuf_ = new std::basic_stringbuf<_CharT, _Traits, _Alloc>(fbuf, mode);
326 assert(internalBuf_);
327 this->init(internalBuf_);
328
329 delete fbuf;
330
331 } else if (fileSize == FileNotExists ) {
332 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 std::basic_filebuf<_CharT, _Traits>* fileBuffer = new std::basic_filebuf<_CharT, _Traits>();
342
343 //it is safe to delete null pointer
344 delete internalBuf_;
345 internalBuf_ = fileBuffer;
346
347 this->init(internalBuf_);
348 if (!fileBuffer->open(filename, mode)) {
349 this->setstate(std::ios_base::failbit);
350 return false;
351 }
352
353 #endif
354
355 return true;
356 }
357
358 std::basic_streambuf<_CharT, _Traits>* internalBuf_; /** internal stream buffer */
359 bool isRead; /** file opened flag */
360 };
361
362 typedef basic_ifstrstream<char, std::char_traits<char>, std::allocator<char> > ifstrstream;
363 }//namespace oopse
364 #endif //IO_IFSTRSTREAM_HPP