ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/io/basic_ifstrstream.hpp
Revision: 1583
Committed: Fri Oct 15 21:10:50 2004 UTC (19 years, 8 months ago) by tim
File size: 13055 byte(s)
Log Message:
fix a bunch of bugs

File Contents

# Content
1 /*
2 * Copyright (C) 2000-2004 Object Oriented Parallel Simulation Engine (OOPSE) project
3 *
4 * Contact: oopse@oopse.org
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
10 * All we ask is that proper credit is given for our work, which includes
11 * - but is not limited to - adding the above copyright notice to the beginning
12 * of your source code files, and to any copyright notice that you may distribute
13 * with programs based on this work.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 *
24 */
25
26 /**
27 * @file basic_ifstrstream.hpp
28 * @author Teng Lin
29 * @date 10/14/2004
30 * @version 1.0
31 */
32
33 #ifndef IO_IFSTRSTREAM_HPP
34 #define IO_IFSTRSTREAM_HPP
35
36 #include <cassert>
37 #include <cstring>
38 #include <fstream>
39 #include <sstream>
40
41 #ifdef IS_MPI
42 #include <mpi.h>
43 #endif
44
45 namespace oopse {
46 using namespace std;
47 /**
48 * @class basic_ifstrstream basic_ifstrstream.hpp "io/basic_ifstrstream.hpp"
49 * @brief class provides a stream interface to read data from files.
50 * <p>In single mode, it falls back to ifstream. Don't need to read the whole file into memory.
51 * In parallel mode, the master node will read the whole file and brocast it to other slave nodes.
52 * After brocasting, every node will fall back to stringstream.</p>
53 *
54 * @code
55 * const int MAXLEN = 1024;
56 * char buffer[MAXLEN];
57 * ifstrstream in;
58 * in.open("Shapes.frc");
59 * if (in.is_open()) {
60 * in.getline(buffer, MAXLEN);
61 * }
62 * in.close();
63 * @endcode
64 */
65 template <class _CharT, class _Traits, class _Alloc>
66 class basic_ifstrstream : public basic_istream<_CharT, _Traits> {
67 public:
68 //traits
69 typedef _CharT char_type;
70 typedef typename _Traits::int_type int_type;
71 typedef typename _Traits::pos_type pos_type;
72 typedef typename _Traits::off_type off_type;
73 typedef _Traits traits_type;
74
75 typedef basic_ios<_CharT, _Traits> _Basic_ios;
76 typedef basic_istream<_CharT, _Traits> _Base;
77
78 #ifdef IS_MPI
79 typedef basic_stringbuf<_CharT, _Traits, _Alloc> _Buf;
80 #else
81 typedef basic_filebuf<_CharT, _Traits> _Buf;
82 #endif
83
84 static const int FileNoExists = -1;
85 static const int FileIOError = -2;
86
87 public:
88
89 /** Constructs an object of class ifstream. */
90 basic_ifstrstream()
91 : basic_ios<_CharT, _Traits>(), basic_istream<_CharT, _Traits>(0),
92 internalBuf_(NULL), isRead(false) {
93
94 #ifdef IS_MPI
95 //in parallel mode, fall back to istringstream
96 basic_stringbuf<_CharT, _Traits, _Alloc>* stringBuffer = new basic_stringbuf<_CharT, _Traits, _Alloc>();
97 internalBuf_ = stringBuffer;
98 #else
99 //in single version, fall back to ifstream
100 basic_filebuf<_CharT, _Traits>* fileBuffer = new basic_filebuf<_CharT, _Traits>();
101 internalBuf_ = fileBuffer;
102 #endif
103
104 this->init(internalBuf_);
105 isRead = false;
106 }
107
108 /**
109 * Explicit constructor
110 * @filename String containing the name of the file to be opened
111 * @mode Flags describing the requested i/o mode for the file, default value is ios_base::in
112 * @checkFilename Flags indicating checking the file name in parallel
113 */
114 explicit basic_ifstrstream(const char* filename, ios_base::openmode mode = ios_base::in, bool checkFilename = false)
115 : basic_ios<_CharT, _Traits>(), basic_istream<_CharT, _Traits>(0),
116 internalBuf_(NULL), isRead(false) {
117
118 isRead = internalOpen(filename, mode | ios_base::in, checkFilename);
119 }
120
121 /**
122 * virtual destructor will close the file(in single mode) and clear the stream buffer
123 */
124 ~basic_ifstrstream(){
125 close();
126 delete internalBuf_;
127 internalBuf_ = NULL;
128 }
129
130 /**
131 * Opens a file and associats a buffer with the specified file to perform the i/o operations
132 * (single mode). Master reads a file and brocasts its content to the other slave nodes. After
133 * brocasting, every nodes fall back to stringstream (parallel mode).
134 * @filename String containing the name of the file to be opened
135 * @mode Flags describing the requested i/o mode for the file
136 * @checkFilename Flags indicating checking the file name in parallel
137 */
138 void open(const char* filename, ios_base::openmode mode = ios_base::in, bool checkFilename = false){
139
140 if (!isRead ) {
141 isRead = internalOpen(filename, mode, checkFilename);
142 }
143 }
144
145 /**
146 * Tests if the stream is currently associated with a valid buffer.
147 * @return true if a file has successfully been opened (single mode) or the whole file is read
148 * and spreaded among all of the processors (parallel mode), otherwise false is returned
149 */
150 bool is_open ( ) {
151 #ifdef IS_MPI
152 return isRead;
153 #else
154 //single version fall back to ifstream
155 return this->rdbuf()->is_open();
156 #endif
157 }
158
159 /**
160 * In single mode, closes a file. The stream's file buffer is released from its association with
161 * the currently open file. In parallel mode, clean the
162 */
163 void close() {
164 #ifndef IS_MPI
165 //single version fall back to ifstream
166 if (!this->rdbuf()->close())
167 this->setstate(ios_base::failbit);
168 #endif
169
170 isRead = false;
171 }
172
173 /**
174 * Gets the stream buffer object associated with the stream
175 * @return A pointer to the stream buffe object(filebuf in single mode, stringbuf in
176 * parallel mode) associated with the stream.
177 */
178 _Buf* rdbuf() const{
179 return static_cast<_Buf*>(internalBuf_);
180 }
181
182 private:
183
184 /**
185 * Internal function used to open the file
186 * @return true if succesfully opens a file (single mode) or gets the file content (parallel mode)
187 * otherwise return false
188 * @filename String containing the name of the file to be opened
189 * @mode Flags describing the requested i/o mode for the file
190 * @todo use try - catch syntax to make the program more readable
191 */
192 bool internalOpen(const char* filename, ios_base::openmode mode, bool checkFilename){
193
194 #ifdef IS_MPI
195 int commStatus;
196 long fileSize;
197 char* fbuf;
198 int filenameLen;
199 int diffFilename;
200 int error;
201 int myRank;
202 int masterNode;
203
204 commStatus = MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
205 masterNode = 0;
206
207 if (myRank == masterNode) {
208
209 if (checkFilename) {
210
211 //check the filename is the same
212 filenameLen = strlen(filename);
213 commStatus = MPI_Bcast(&filenameLen, 1, MPI_INT, masterNode, MPI_COMM_WORLD);
214 commStatus = MPI_Bcast((void*)filename, filenameLen, MPI_CHAR, masterNode, MPI_COMM_WORLD);
215
216 diffFilename = 0;
217 commStatus = MPI_Allreduce(&diffFilename, &error, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
218
219 //if file names are different just return false
220 if (error > 0)
221 return false;
222 }
223
224 ifstream fin(filename, mode);
225 basic_stringbuf<_CharT, _Traits, _Alloc>* sbuf;
226
227 if (fin.is_open()) {
228
229 fin.seekg(0, ios::end);
230 fileSize = fin.tellg();
231 fin.seekg(0, ios::beg);
232
233 // '\0' need one more char
234 fbuf = new char[fileSize+1];
235
236 assert(fbuf != 0);
237
238 fin.read(fbuf, fileSize);
239
240 if (fin.fail())
241 fileSize = FileIOError;
242
243 //brocasting the file size
244 commStatus = MPI_Bcast(&fileSize, 1, MPI_LONG, masterNode, MPI_COMM_WORLD);
245
246 if (fileSize < 0) {
247 fin.close();
248 delete fbuf;
249
250 return false;
251 }
252
253 // make a c-style string and brocasting it
254 fbuf[fileSize] = '\0';
255 commStatus = MPI_Bcast(fbuf, fileSize + 1, MPI_CHAR, masterNode, MPI_COMM_WORLD);
256
257 //it is safe to delete null pointer
258 delete internalBuf_;
259
260 //initilaize istream
261 internalBuf_ = new basic_stringbuf<_CharT, _Traits, _Alloc>(fbuf, mode);
262 assert(internalBuf_);
263 this->init(internalBuf_);
264
265 //close the file and delete the buffer
266 fin.close();
267 delete fbuf;
268 }else{
269 fileSize = FileNoExists;
270 commStatus = MPI_Bcast(&fileSize, 1, MPI_LONG, masterNode, MPI_COMM_WORLD);
271 return false;
272 }
273
274 } else{
275 //check file name
276 if (checkFilename) {
277 commStatus = MPI_Bcast(&filenameLen, 1, MPI_INT, masterNode, MPI_COMM_WORLD);
278
279 char * masterFilename = new char[filenameLen];
280 commStatus = MPI_Bcast(masterFilename, filenameLen, MPI_CHAR, masterNode, MPI_COMM_WORLD);
281
282 if( strcmp(masterFilename, filename) == 0)
283 diffFilename = 0;
284 else
285 diffFilename = 1;
286
287 delete masterFilename;
288
289 commStatus = MPI_Allreduce(&diffFilename, &error, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
290
291 if (error > 0)
292 return false;
293 }
294 //get file size
295 commStatus = MPI_Bcast(&fileSize, 1, MPI_LONG, masterNode, MPI_COMM_WORLD);
296
297 if (fileSize >= 0 ) {
298 fbuf = new char[fileSize+1];
299 assert(fbuf);
300
301 //receive file content
302 commStatus = MPI_Bcast(fbuf, fileSize + 1, MPI_CHAR, masterNode, MPI_COMM_WORLD);
303
304 //it is safe to delete null pointer
305 delete internalBuf_;
306
307 //initilaize istream
308 internalBuf_ = new basic_stringbuf<_CharT, _Traits, _Alloc>(fbuf, mode);
309 assert(internalBuf_);
310 this->init(internalBuf_);
311
312 delete fbuf;
313
314 } else if (fileSize == FileNoExists ) {
315 return false;
316
317 } else if (fileSize == FileIOError ) {
318 return false;
319 }
320 }
321
322 #else
323 //in single version, fall back to ifstream
324 basic_filebuf<_CharT, _Traits>* fileBuffer = new basic_filebuf<_CharT, _Traits>();
325
326 this->init(fileBuffer);
327 if (!fileBuffer->open(filename, mode))
328 this->setstate(ios_base::failbit);
329
330 //it is safe to delete null pointer
331 delete internalBuf_;
332
333 internalBuf_ = fileBuffer;
334 #endif
335
336 return true;
337 }
338
339 basic_streambuf<_CharT, _Traits>* internalBuf_; /** internal stream buffer */
340 bool isRead; /** file opened flag */
341 };
342
343 typedef basic_ifstrstream<char, char_traits<char>, allocator<char> > ifstrstream;
344 }//namespace oopse
345 #endif //IO_IFSTRSTREAM_HPP