ITstream.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2015 OpenFOAM Foundation
9  Copyright (C) 2017-2025 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "error.H"
30 #include "ITstream.H"
31 #include "SpanStream.H"
32 #include <algorithm>
33 #include <memory>
34 
35 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
39 
40 // Convert input sequence into a list of tokens.
41 // Return the number of tokens in the resulting list.
42 static label parseStream(ISstream& is, tokenList& tokens)
43 {
44  tokens.clear();
45 
46  label count = 0;
47  token tok;
48  while (!is.read(tok).bad() && tok.good())
49  {
50  if (count >= tokens.size())
51  {
52  // Increase capacity (doubling) with min-size [64]
53  tokens.resize(Foam::max(label(64), label(2*tokens.size())));
54  }
55 
56  tokens[count] = std::move(tok);
57  ++count;
58  }
59 
60  tokens.resize(count);
61 
62  return count;
63 }
64 
65 } // End namespace Foam
66 
67 
68 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
69 
71 {
72  static std::unique_ptr<ITstream> singleton;
73 
74  if (!singleton)
75  {
76  singleton = std::make_unique<ITstream>(Foam::zero{}, "empty-stream");
77  }
78  else
79  {
80  singleton->ITstream::clear(); // Ensure it really is empty
81  singleton->ITstream::seek(0); // rewind() bypassing virtual
82  }
83 
84  // Set stream as bad - indicates it is not a valid stream
85  singleton->setBad();
86 
87  return *singleton;
88 }
89 
90 
91 Foam::tokenList Foam::ITstream::parse_chars
92 (
93  const char* s,
94  size_t nbytes,
95  IOstreamOption streamOpt
96 )
97 {
98  ISpanStream is(s, nbytes, streamOpt);
99 
100  tokenList tokens;
101  parseStream(is, tokens);
102  return tokens;
103 }
104 
105 
106 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
107 
108 void Foam::ITstream::reset(const char* input, size_t nbytes)
109 {
110  ISpanStream is(input, nbytes, static_cast<IOstreamOption>(*this));
111 
112  parseStream(is, static_cast<tokenList&>(*this));
113  ITstream::seek(0); // rewind() bypassing virtual
114 }
115 
116 
117 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
118 
119 void Foam::ITstream::reserveCapacity(const label newCapacity)
120 {
121  // Reserve - leave excess capacity for further appends
122 
123  label len = tokenList::size();
124 
125  if (len < newCapacity)
126  {
127  // Min-size (16) when starting from zero
128  if (!len) len = 8;
129 
130  // Increase capacity. Strict doubling
131  do
132  {
133  len *= 2;
134  }
135  while (len < newCapacity);
136 
138  }
139 }
140 
141 
142 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
143 
144 Foam::ITstream::ITstream(const ITstream& is)
145 :
146  Istream(static_cast<IOstreamOption>(is)),
147  tokenList(is),
148  name_(is.name_),
149  tokenIndex_(0)
150 {
151  setOpened();
152  setGood();
153 }
154 
155 
157 :
158  Istream(static_cast<IOstreamOption>(is)),
159  tokenList(std::move(static_cast<tokenList&>(is))),
160  name_(std::move(is.name_)),
161  tokenIndex_(0)
162 {
163  setOpened();
164  setGood();
165 }
166 
167 
169 (
170  IOstreamOption streamOpt,
171  const string& name
172 )
173 :
174  Istream(IOstreamOption(streamOpt.format(), streamOpt.version())),
175  tokenList(),
176  name_(name),
177  tokenIndex_(0)
178 {
179  setOpened();
180  setGood();
181 }
182 
183 
185 (
186  Foam::zero,
187  const string& name,
188  IOstreamOption streamOpt
189 )
190 :
191  ITstream(streamOpt, name)
192 {}
193 
194 
196 (
197  const UList<token>& tokens,
198  IOstreamOption streamOpt,
199  const string& name
200 )
201 :
202  Istream(IOstreamOption(streamOpt.format(), streamOpt.version())),
203  tokenList(tokens),
204  name_(name),
205  tokenIndex_(0)
206 {
207  setOpened();
208  setGood();
209 }
210 
211 
213 (
214  List<token>&& tokens,
215  IOstreamOption streamOpt,
216  const string& name
217 )
218 :
219  Istream(IOstreamOption(streamOpt.format(), streamOpt.version())),
220  tokenList(std::move(tokens)),
221  name_(name),
222  tokenIndex_(0)
223 {
224  setOpened();
225  setGood();
226 }
227 
228 
230 (
231  const UList<char>& input,
232  IOstreamOption streamOpt,
233  const string& name
234 )
235 :
236  ITstream(streamOpt, name)
237 {
238  reset(input.cdata(), input.size_bytes());
239 }
240 
241 
243 (
244  const char* input,
245  IOstreamOption streamOpt,
246  const string& name
247 )
248 :
249  ITstream(streamOpt, name)
250 {
251  reset(input, strlen(input));
252 }
253 
254 
255 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
256 
257 void Foam::ITstream::print(Ostream& os) const
258 {
259  os << "ITstream : " << name_.c_str() << ", line ";
260 
261  if (tokenList::empty())
262  {
263  os << lineNumber();
264  }
265  else
266  {
267  const tokenList& toks = *this;
268 
269  os << toks.front().lineNumber();
270 
271  if (toks.front().lineNumber() < toks.back().lineNumber())
272  {
273  os << '-' << toks.back().lineNumber();
274  }
275  }
276  os << ", ";
277 
279 }
280 
281 
282 std::string Foam::ITstream::toString() const
283 {
284  if (tokenList::empty())
285  {
286  return std::string();
287  }
288  else if (tokenList::size() == 1 && tokenList::front().isStringType())
289  {
290  // Already a string-type (WORD, STRING, ...). Just copy.
291  return tokenList::front().stringToken();
292  }
293 
294  // Stringify
295  OCharStream buf;
296  buf.precision(16); // Some reasonably high precision
297 
298  auto iter = tokenList::cbegin();
299  const auto last = tokenList::cend();
300 
301  // Note: could also just use the buffer token-wise
302 
303  // Contents - space separated
304  if (iter != last)
305  {
306  buf << *iter;
307 
308  for (++iter; (iter != last); (void)++iter)
309  {
310  buf << token::SPACE << *iter;
311  }
312  }
314  const auto view = buf.view();
315 
316  return std::string(view.data(), view.size());
317 }
318 
319 
321 {
322  // Use putback token if it exists
323  if (Istream::hasPutback())
324  {
326  }
327 
328  return peekNoFail(tokenIndex_);
329 }
330 
331 
333 {
334  if (tokenIndex_ < 0 || tokenIndex_ >= tokenList::size())
335  {
337  << "Token index " << tokenIndex_ << " out of range [0,"
338  << tokenList::size() << "]\n"
340  }
341 
342  return tokenList::operator[](tokenIndex_);
343 }
344 
345 
347 {
348  lineNumber_ = 0;
349 
350  if (pos < 0 || pos >= tokenList::size())
351  {
352  // Seek end (-1) or seek is out of range
353  tokenIndex_ = tokenList::size();
354 
355  if (!tokenList::empty())
356  {
357  // The closest reference lineNumber
358  lineNumber_ = tokenList::cdata()[tokenIndex_-1].lineNumber();
359  }
360 
361  setEof();
362  }
363  else
364  {
365  tokenIndex_ = pos;
366 
367  if (tokenIndex_ < tokenList::size())
368  {
369  lineNumber_ = tokenList::cdata()[tokenIndex_].lineNumber();
370  }
372  setOpened();
373  setGood();
374  }
375 }
376 
377 
378 bool Foam::ITstream::skip(label n) noexcept
379 {
380  if (!n)
381  {
382  // No movement - just check the current range
383  return (tokenIndex_ >= 0 && tokenIndex_ < tokenList::size());
384  }
385 
386  tokenIndex_ += n; // Move forward (+ve) or backwards (-ve)
387 
388  bool noError = true;
389 
390  if (tokenIndex_ < 0)
391  {
392  // Underflow range
393  noError = false;
394  tokenIndex_ = 0;
395  }
396  else if (tokenIndex_ >= tokenList::size())
397  {
398  // Overflow range
399  noError = false;
400  tokenIndex_ = tokenList::size();
401 
402  if (!tokenList::empty())
403  {
404  // The closest reference lineNumber
405  lineNumber_ = tokenList::cdata()[tokenIndex_-1].lineNumber();
406  }
407  }
408 
409  // Update stream information
410  if (tokenIndex_ < tokenList::size())
411  {
412  lineNumber_ = tokenList::cdata()[tokenIndex_].lineNumber();
413  setOpened();
414  setGood();
415  }
416  else
417  {
418  setEof();
419  }
420 
421  return noError;
422 }
423 
424 
426 {
427  // Use putback token if it exists
428  if (Istream::getBack(tok))
429  {
430  lineNumber_ = tok.lineNumber();
431  return *this;
432  }
433 
434  tokenList& toks = *this;
435  const label nToks = toks.size();
436 
437  if (tokenIndex_ < nToks)
438  {
439  tok = toks[tokenIndex_++];
440  lineNumber_ = tok.lineNumber();
441 
442  if (tokenIndex_ == nToks)
443  {
444  setEof();
445  }
446  }
447  else
448  {
449  if (eof())
450  {
452  << "attempt to read beyond EOF"
453  << exit(FatalIOError);
454  setBad();
455  }
456  else
457  {
458  setEof();
459  }
460 
461  tok.reset();
462 
463  if (nToks)
464  {
465  tok.lineNumber(toks.back().lineNumber());
466  }
467  else
468  {
469  tok.lineNumber(this->lineNumber());
470  }
471  }
472 
473  return *this;
474 }
475 
476 
478 (
479  const token::punctuationToken delimOpen,
480  const token::punctuationToken delimClose,
481  label pos
482 ) const
483 {
484  if (pos < 0)
485  {
486  pos = tokenIndex_;
487  }
488 
489  labelRange slice;
490 
491  for (label depth = 0; pos < tokenList::size(); ++pos)
492  {
493  const token& tok = tokenList::operator[](pos);
494 
495  if (tok.isPunctuation())
496  {
497  if (tok.isPunctuation(delimOpen))
498  {
499  if (!depth)
500  {
501  // Initial open delimiter
502  slice.start() = pos;
503  }
504 
505  ++depth;
506  }
507  else if (tok.isPunctuation(delimClose))
508  {
509  --depth;
510 
511  if (depth < 0)
512  {
513  // A closing delimiter without an open!
514  // Raise error?
515  break;
516  }
517  if (!depth)
518  {
519  // The end - include delimiter into the count
520  slice.size() = (pos - slice.start()) + 1;
521  break;
522  }
523  }
524  }
525  }
526 
527  return slice;
528 }
529 
530 
532 {
533  ITstream result
534  (
535  static_cast<IOstreamOption>(*this),
536  this->name()
537  );
538  result.setLabelByteSize(this->labelByteSize());
539  result.setScalarByteSize(this->scalarByteSize());
540 
541  // Validate the slice range of list
542  const labelRange slice(range.subset0(tokenList::size()));
543 
544  if (!slice.good())
545  {
546  // No-op
547  return result;
548  }
549 
550  auto first = tokenList::begin(slice.begin_value());
551  auto last = tokenList::begin(slice.end_value());
552 
553  result.resize(label(last - first));
554 
555  // Move tokens into result list
556  std::move(first, last, result.begin());
557  result.seek(0); // rewind() bypassing virtual
558 
560  (void) remove(slice); // Adjust the original list
561 
562  return result;
563 }
564 
565 
566 Foam::label Foam::ITstream::remove(const labelRange& range)
567 {
568  // Validate the slice range of list
569  const labelRange slice(range.subset0(tokenList::size()));
570 
571  if (!slice.good())
572  {
573  // No-op
574  return 0;
575  }
576 
577  if (slice.end_value() >= tokenList::size())
578  {
579  // Remove entire tail
580  tokenList::resize(slice.begin_value());
581  }
582  else
583  {
584  // Attempt to adjust the current token index to something sensible...
585  if (slice.contains(tokenIndex_))
586  {
587  // Within the removed slice - reposition tokenIndex before it
588  seek(slice.begin_value());
589  skip(-1);
590  }
591  else if (tokenIndex_ >= slice.end_value())
592  {
593  // After the removed slice - reposition tokenIndex relatively
594  skip(-slice.size());
595  }
596 
597  // Move tokens down in the list
598  std::move
599  (
600  tokenList::begin(slice.end_value()),
601  tokenList::end(),
602  tokenList::begin(slice.begin_value())
603  );
604 
605  // Truncate
606  tokenList::resize(tokenList::size() - slice.size());
607  }
608 
609  if (tokenIndex_ >= tokenList::size())
610  {
611  tokenIndex_ = tokenList::size();
612  setEof();
613  }
614  else if (tokenIndex_ >= 0 && tokenIndex_ < tokenList::size())
615  {
616  lineNumber_ = tokenList::operator[](tokenIndex_).lineNumber();
617  }
619  return slice.size();
620 }
621 
622 
623 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
624 
626 {
628  return *this;
629 }
630 
631 
633 {
635  return *this;
636 }
637 
638 
640 {
642  return *this;
643 }
644 
645 
647 {
649  return *this;
650 }
651 
652 
654 {
656  return *this;
657 }
658 
659 
661 {
663  return *this;
664 }
665 
666 
667 Foam::Istream& Foam::ITstream::readRaw(char*, std::streamsize)
668 {
670  return *this;
671 }
672 
673 
674 Foam::Istream& Foam::ITstream::read(char*, std::streamsize)
675 {
677  return *this;
678 }
679 
680 
681 void Foam::ITstream::add_tokens(const token& tok)
682 {
683  reserveCapacity(tokenIndex_ + 1);
684 
685  tokenList::operator[](tokenIndex_) = tok;
686  ++tokenIndex_;
687 }
688 
689 
691 {
692  reserveCapacity(tokenIndex_ + 1);
693 
694  tokenList::operator[](tokenIndex_) = std::move(tok);
695  ++tokenIndex_;
696 }
697 
698 
700 {
701  const label len = toks.size();
702  reserveCapacity(tokenIndex_ + len);
703 
704  std::copy_n(toks.begin(), len, tokenList::begin(tokenIndex_));
705  tokenIndex_ += len;
706 }
707 
708 
710 {
711  const label len = toks.size();
712  reserveCapacity(tokenIndex_ + len);
713 
714  std::move(toks.begin(), toks.end(), tokenList::begin(tokenIndex_));
715  tokenIndex_ += len;
716  toks.clear();
717 }
718 
719 
720 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
721 
722 void Foam::ITstream::operator=(const ITstream& is)
723 {
724  // Self-assignment is a no-op
725  if (this != &is)
726  {
727  Istream::operator=(is);
729  name_ = is.name_;
730  ITstream::seek(0); // rewind() bypassing virtual
731  }
732 }
733 
734 
736 {
737  tokenList::operator=(toks);
738  ITstream::seek(0); // rewind() bypassing virtual
739 }
740 
741 
743 {
744  tokenList::operator=(std::move(toks));
745  ITstream::seek(0); // rewind() bypassing virtual
746 }
747 
748 
749 // ************************************************************************* //
void add_tokens(const token &tok)
Copy append a token at the current tokenIndex, incrementing the index.
Definition: ITstream.C:674
bool good() const noexcept
True if token is not UNDEFINED or ERROR.
Definition: tokenI.H:507
const_iterator cend() const noexcept
Return const_iterator to end traversing the constant UList.
Definition: UListI.H:443
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
const token & peekBack() const noexcept
Examine putback token without removing it.
Definition: Istream.C:42
bool getBack(token &tok)
Retrieve the put-back token if there is one.
Definition: Istream.C:115
Input/output streams with (internal or external) character storage.
bool bad() const noexcept
True if stream is corrupted.
Definition: IOstream.H:305
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:150
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:56
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
A range or interval of labels defined by a start and a size.
Definition: labelRange.H:52
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:697
A token holds an item read from Istream.
Definition: token.H:65
T & front()
Access first element of the list, position [0].
Definition: UListI.H:230
label remove(const labelRange &range)
Remove a (start,size) subset from the list and move remaining elements down.
Definition: ITstream.C:559
A simple container for options an IOstream can normally have.
std::string toString() const
Concatenate tokens into a space-separated std::string. The resulting string may contain quote charact...
Definition: ITstream.C:275
List< token > tokenList
List of token, used for dictionary primitive entry (for example)
Definition: tokenList.H:32
scalar range
T & operator[](const label i)
Return element of UList.
Definition: UListI.H:362
dimensionedScalar pos(const dimensionedScalar &ds)
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
virtual Istream & read(token &tok) override
Return next token from stream.
Definition: ITstream.C:418
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
void operator=(const UList< T > &list)
Assignment to UList operator. Takes linear time.
Definition: List.C:371
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:130
virtual Istream & readRaw(char *data, std::streamsize count) override
Low-level raw binary read : triggers not implemented error.
Definition: ITstream.C:660
A class for handling words, derived from Foam::string.
Definition: word.H:63
static Istream & input(Istream &is, IntRange< T > &range)
Definition: IntRanges.C:33
Space [isspace].
Definition: token.H:131
punctuationToken
Standard punctuation tokens (a character)
Definition: token.H:126
const token & currentToken() const noexcept
Read access to the token at the current tokenIndex.
Definition: ITstream.H:451
errorManip< error > abort(error &err)
Definition: errorManip.H:139
iterator begin() noexcept
Return an iterator to begin traversing the UList.
Definition: UListI.H:385
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:105
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
const direction noexcept
Definition: scalarImpl.H:255
label size() const noexcept
The number of elements in the container.
Definition: UList.H:702
OBJstream os(runTime.globalPath()/outputName)
virtual void print(Ostream &os) const
Print stream description to Ostream.
Definition: IOstream.C:67
virtual Istream & read(token &t) override
Return next token from stream.
Definition: ISstream.C:535
unsigned scalarByteSize(const std::string &str)
Extract scalar size (in bytes) from "scalar=" tag in string.
label lineNumber() const noexcept
Const access to the current stream line number.
Definition: IOstream.H:390
word format(conversionProperties.get< word >("format"))
const std::string version
OpenFOAM version (name or stringified number) as a std::string.
Generic input stream using a standard (STL) stream.
Definition: ISstream.H:51
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:629
limits reset(1/(limits.max()+VSMALL), 1/(limits.min()+VSMALL))
const token & peek() const noexcept
Failsafe peek at what the next read would return, including handling of any putback.
Definition: ITstream.C:313
bool hasPutback() const noexcept
True if putback token is in use.
Definition: Istream.H:81
labelRange find(const token::punctuationToken delimOpen, const token::punctuationToken delimClose, label pos=0) const
Find range containing matching delimiter pair, starting at the specified position. The position -1 indicates to continue from the present tokenIndex() position.
Definition: ITstream.C:471
unsigned labelByteSize(const std::string &str)
Extract label size (in bytes) from "label=" tag in string.
static ITstream & empty_stream()
Return reference to an empty ITstream, for functions needing to return an ITstream reference but whic...
Definition: ITstream.C:63
static label parseStream(ISstream &is, tokenList &tokens)
Definition: ITstream.C:35
A class representing the concept of 0 (zero) that can be used to avoid manipulating objects known to ...
Definition: zero.H:57
const_iterator cbegin() const noexcept
Return const_iterator to begin traversing the constant UList.
Definition: UListI.H:399
label n
const T * cdata() const noexcept
Return pointer to the underlying array serving as data storage.
Definition: UListI.H:258
void print(Ostream &os) const override
Print stream description to Ostream.
Definition: ITstream.C:250
bool skip(label n=1) noexcept
Move tokenIndex relative to the current position.
Definition: ITstream.C:371
iterator end() noexcept
Return an iterator to end traversing the UList.
Definition: UListI.H:429
ITstream(const ITstream &is)
Copy construct.
Definition: ITstream.C:137
void operator=(const ITstream &is)
Copy assignment, with rewind()
Definition: ITstream.C:715
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
#define NotImplemented
Issue a FatalErrorIn for a function not currently implemented.
Definition: error.H:688
void seek(label pos) noexcept
Move tokenIndex to the specified position and adjust the stream status (open/good/eof ...
Definition: ITstream.C:339
An input stream of tokens.
Definition: ITstream.H:52
void setBad() noexcept
Set stream state to be &#39;bad&#39;.
Definition: IOstream.H:469
Namespace for OpenFOAM.
ITstream extract(const labelRange &range)
Remove a (start,size) subset from the list and move remaining elements down.
Definition: ITstream.C:524
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...