memoryStreamBuffer.H
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) 2016-2023 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 Class
27  Foam::memorybuf
28 
29 Description
30  A std::streambuf used for memory buffer streams such as
31  ispanstream, ocharstream, etc.
32 
33 \*---------------------------------------------------------------------------*/
34 
35 #ifndef Foam_memoryStreamBuffer_H
36 #define Foam_memoryStreamBuffer_H
37 
38 #include "stdFoam.H" // For span
39 #include "DynamicList.H"
40 
41 #include <memory>
42 #include <type_traits>
43 
44 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
45 
46 namespace Foam
47 {
48 
49 /*---------------------------------------------------------------------------*\
50  Class memorybuf Declaration
51 \*---------------------------------------------------------------------------*/
52 
53 //- A streambuf for memory similar to std::spanbuf (C++23)
54 class memorybuf
55 :
56  public std::streambuf
57 {
58 protected:
59 
60  //- Set position pointer to relative position
61  virtual std::streampos seekoff
62  (
63  std::streamoff off,
64  std::ios_base::seekdir way,
65  std::ios_base::openmode which = std::ios_base::in|std::ios_base::out
66  )
67  {
68  const bool testin = which & std::ios_base::in;
69  const bool testout = which & std::ios_base::out;
70 
71  if (way == std::ios_base::beg)
72  {
73  if (testin)
74  {
75  setg(eback(), eback(), egptr());
76  gbump(off);
77  }
78  if (testout)
79  {
80  setp(pbase(), epptr());
81  pbump(off);
82  }
83  }
84  else if (way == std::ios_base::cur)
85  {
86  if (testin)
87  {
88  gbump(off);
89  }
90  if (testout)
91  {
92  pbump(off);
93  }
94  }
95  else if (way == std::ios_base::end)
96  {
97  if (testin)
98  {
99  setg(eback(), eback(), egptr());
100  gbump(egptr() - eback() - off);
101  }
102  if (testout)
103  {
104  setp(pbase(), epptr());
105  pbump(epptr() - pbase() - off);
106  }
107  }
108 
109  if (testin)
110  {
111  return (gptr() - eback()); // span_tellg()
112  }
113  if (testout)
114  {
115  return (pptr() - pbase()); // span_tellp()
116  }
117 
118  return -1;
119  }
120 
121 
122  //- Set position pointer to absolute position
123  virtual std::streampos seekpos
124  (
125  std::streampos pos,
126  std::ios_base::openmode which = std::ios_base::in|std::ios_base::out
127  )
128  {
129  return seekoff(pos, std::ios_base::beg, which);
130  }
131 
132 public:
133 
134  // Forward Declarations
135  class in_base;
136  class in_dynamic;
137  class out_base;
138  class out_dynamic;
139 };
140 
141 
142 /*---------------------------------------------------------------------------*\
143  Class memorybuf::in_base Declaration
144 \*---------------------------------------------------------------------------*/
145 
146 //- The base input streambuf with memory access
147 class memorybuf::in_base
148 :
149  public memorybuf
150 {
151 protected:
152 
153  //- Get sequence of characters from a fixed region
154  virtual std::streamsize xsgetn(char* s, std::streamsize n)
155  {
156  std::streamsize count = 0;
157  while (count < n && gptr() < egptr())
158  {
159  *(s + count++) = *(gptr());
160  gbump(1);
161  }
162  return count;
163  }
164 
165 public:
166 
167  // Constructors
168 
169  //- Default construct
170  in_base() = default;
171 
172  //- Construct for character array (can be nullptr) and number of bytes
173  in_base(char* s, std::streamsize n)
174  {
175  resetg(s, n);
176  }
177 
178 
179  // Member Functions
181  // //- Reset get buffer pointer to the beginning of existing span
182  // void rewind() { setg(eback(), eback(), egptr()); }
183 
184  //- Reset get buffer with character data (can be nullptr) and count
185  // Sets get pointer to the begin.
186  void resetg(char* s, std::streamsize n)
187  {
188  if (s)
189  {
190  setg(s, s, s + n);
191  }
192  else
193  {
194  setg(nullptr, nullptr, nullptr);
195  }
196  }
197 
198  //- The current buffer get position
199  std::streamsize span_tellg() const { return (gptr() - eback()); }
200 
201  //- The get buffer capacity
202  std::streamsize span_capacity() const { return (egptr() - eback()); }
203 
204  //- The number of characters remaining in the get area
205  std::streamsize span_remaining() const
206  {
207  return (gptr() < egptr()) ? (egptr() - gptr()) : 0;
208  }
209 
210  //- The span data (start of input characters)
211  char* data_bytes() const { return eback(); }
212 
213  //- The span size (number of input characters)
214  std::streamsize size_bytes() const { return (egptr() - eback()); }
215 
216  #if __cplusplus >= 201703L
217  std::string_view view() const
218  {
219  return std::string_view(data_bytes(), size_bytes());
220  }
221  #else
223  {
225  }
226  #endif
227 
228  //- Some information about the input buffer position/capacity
229  void info(Ostream& os) const
230  {
231  os << "get=" << span_tellg() << '/' << span_capacity();
232  }
233 };
235 
236 /*---------------------------------------------------------------------------*\
237  Class memorybuf::in_dynamic Declaration
238 \*---------------------------------------------------------------------------*/
239 
240 //- An output streambuf for memory access
242 :
243  public memorybuf::in_base
244 {
245 private:
246 
247  //- Character storage
248  List<char> storage_;
249 
250 
251 public:
252 
253  // Constructors
254 
255  //- Default construct - empty
256  in_dynamic() = default;
257 
258  //- Copy construct from content
259  in_dynamic(const char* s, std::streamsize n)
260  {
261  if (s && n)
262  {
263  storage_.resize_nocopy(n);
264  std::copy(s, (s + n), storage_.data());
265  }
266  sync_gbuffer();
267  }
268 
269  //- Move construct from List
270  in_dynamic(::Foam::List<char>&& buffer)
271  :
272  storage_(std::move(buffer))
273  {
274  sync_gbuffer();
275  }
276 
277  //- Move construct from DynamicList (added length only)
278  template<int SizeMin>
280  {
281  storage_.transfer(buffer); // Implies shrink_to_fit
282  sync_gbuffer();
283  }
284 
285 
286  // Member Functions
287 
288  //- Sync get buffer pointers to agree with list dimensions
289  // Sets get pointer to the begin (rewind).
290  void sync_gbuffer()
291  {
292  resetg(storage_.data(), storage_.size());
293  }
294 
295  //- Reset content (copy)
296  void reset(const char* s, std::streamsize n)
297  {
298  if (s && n)
299  {
300  storage_.resize_nocopy(n);
301  std::copy(s, (s + n), storage_.data());
302  }
303  else
304  {
305  storage_.clear();
306  }
307  sync_gbuffer();
308  }
309 
310  //- Exchange buffer content and parameter contents, reset positions
311  void swap(List<char>& other)
312  {
313  other.swap(storage_); // Swap contents
314  sync_gbuffer();
315  }
316 
317  //- Exchange buffer content and parameter contents, reset positions
318  template<int SizeMin>
319  void swap(DynamicList<char,SizeMin>& other)
320  {
321  // NB: not storage_.swap(other)! - incorrect slicing
322  other.swap(storage_); // Swap contents: implies shrink_to_fit
323  sync_gbuffer();
324  }
325 
326  //- Reset buffer and return contents
328  {
329  DynamicList<char> chars(std::move(storage_));
330  sync_gbuffer();
331  return chars;
332  }
333 };
334 
336 /*---------------------------------------------------------------------------*\
337  Class memorybuf::out_base Declaration
338 \*---------------------------------------------------------------------------*/
339 
340 //- An output streambuf for memory access
342 :
343  public memorybuf
344 {
345 protected:
346 
347  //- Put sequence of characters to a fixed region
348  virtual std::streamsize xsputn(const char* s, std::streamsize n)
349  {
350  std::streamsize count = 0;
351  while (count < n && pptr() < epptr())
352  {
353  *(pptr()) = *(s + count++);
354  pbump(1);
355  }
356  return count;
357  }
358 
359 public:
360 
361  // Constructors
363  //- Default construct
364  out_base() = default;
365 
366  //- Construct for character array (can be nullptr) and number of bytes
367  out_base(char* s, std::streamsize n)
368  {
369  resetp(s, n);
370  }
371 
373  // Member Functions
374 
375  // //- Reset put buffer pointer to the beginning of existing span
376  // void rewind() { setp(pbase(), epptr()); }
377 
378  //- Reset put buffer with character data (can be nullptr) and count
379  // Sets put pointer to the begin.
380  inline void resetp(char* s, std::streamsize n)
381  {
382  if (s)
383  {
384  // As per (std::ios_base::out && !std::ios_base::ate)
385  setp(s, s + n);
386  // No treatment for (std::ios_base::out && std::ios_base::ate)
387  }
388  else
389  {
390  setp(nullptr, nullptr);
391  }
392  }
393 
394  //- The current buffer put position
395  std::streamsize span_tellp() const { return (pptr() - pbase()); }
396 
397  //- The put buffer capacity
398  std::streamsize span_capacity() const { return (epptr() - pbase()); }
399 
400  //- The span data (start of output characters)
401  char* data_bytes() const { return pbase(); }
402 
403  //- The span size (size of output buffer)
404  std::streamsize size_bytes() const { return (pptr() - pbase()); }
405 
406  #if __cplusplus >= 201703L
407  std::string_view view() const
408  {
409  return std::string_view(data_bytes(), size_bytes());
410  }
411  #else
413  {
415  }
416  #endif
417 
418  //- Some information about the output buffer position/capacity
419  void info(Ostream& os) const
420  {
421  os << "put=" << span_tellp() << '/' << span_capacity();
422  }
423 };
424 
425 
426 /*---------------------------------------------------------------------------*\
427  Class memorybuf::out_dynamic Declaration
428 \*---------------------------------------------------------------------------*/
429 
430 //- An output streambuf for memory access
432 :
433  public memorybuf::out_base
434 {
435 private:
437  //- Character storage.
438  // Internally manage like a DynamicList, with its capacity known
439  // from the list size and the addressable size known through the
440  // stream pointers.
441  List<char> storage_;
442 
443 protected:
444 
445  //- Handle overflow
446  virtual int overflow(int_type c = traits_type::eof())
447  {
448  if (c != traits_type::eof())
449  {
450  // Need more space?
451  reserve(1 + span_tellp());
452 
453  *(pptr()) = c;
454  pbump(1);
455  }
456  return c;
457  }
459  //- Put sequence of characters
460  virtual std::streamsize xsputn(const char* s, std::streamsize n)
461  {
462  // Enough space so that appends work without problem
464 
465  std::streamsize count = 0;
466  while (count < n && pptr() < epptr())
467  {
468  *(pptr()) = *(s + count++);
469  pbump(1);
470  }
471 
472  return count;
473  }
474 
475 
476 public:
477 
478  // Constructors
479 
480  //- Default construct with initial reserved number of bytes.
481  // The value of 512 is a bit arbitrary, but consistent with
482  // std::stringstream
483  out_dynamic(size_t nbytes = 512)
484  :
485  storage_(label(nbytes))
486  {
487  sync_pbuffer();
488  }
489 
490  //- Move construct from List
491  out_dynamic(::Foam::List<char>&& buffer)
492  :
493  storage_(std::move(buffer))
494  {
495  sync_pbuffer();
496  }
497 
498  //- Move construct from DynamicList (uses entire capacity)
499  template<int SizeMin>
501  {
502  buffer.resize(buffer.capacity()); // Use entire space
503  storage_.transfer(buffer);
504  sync_pbuffer();
505  }
506 
507 
508  // Member Functions
509 
510  //- Increment capacity (if needed) and adjust buffer pointers
511  void reserve(const std::streamsize len)
512  {
513  if (storage_.size() < len)
514  {
515  const auto cur = span_tellp(); // Current location
516 
517  label newCapacity = 512;
518 
519  if (newCapacity < len)
520  {
521  // Increase capacity (doubling)
522  newCapacity = max(len, label(2*storage_.size()));
523  }
524 
525  // Info<<"request:" << len
526  // << " cur cap:" << storage_.size()
527  // << " new cap:" << newCapacity
528  // << " pos:" << cur << endl;
529 
530  storage_.resize(newCapacity);
531  sync_pbuffer();
532  pbump(cur);
533  }
534  }
536  //- Sync put buffer pointers to agree with list dimensions
537  // Sets put pointer to the begin (rewind).
538  void sync_pbuffer()
539  {
540  resetp(storage_.data(), storage_.size());
541  }
542 
543  //- Clear storage
544  void clearStorage()
545  {
546  storage_.clear();
547  sync_pbuffer();
548  }
549 
550  //- Shrink storage to addressed storage
551  void shrink()
552  {
553  const auto cur = span_tellp(); // Addressed length
554 
555  storage_.resize(cur);
556  sync_pbuffer();
557  pbump(cur);
558  }
559 
560  //- Exchange buffer content and parameter contents, reset positions
561  void swap(List<char>& other)
562  {
563  const auto cur = span_tellp(); // Output length
564  other.swap(storage_);
565  other.resize(cur); // Truncate to output length
566  sync_pbuffer();
567  }
568 
569  //- Exchange buffer content and parameter contents, reset positions
570  template<int SizeMin>
572  {
573  const auto cur = span_tellp(); // Output length
574 
575  other.resize(other.capacity()); // Use entire space
576  other.swap(storage_); // NB: not storage_.swap(other)
577  other.resize(cur); // Restrict to output length
578  sync_pbuffer();
579  }
580 
581  //- Reset buffer and return contents as a DynamicList.
582  //- The list size corresponds to the region of output.
584  {
585  const auto cur = span_tellp(); // Output length
586  DynamicList<char> chars(std::move(storage_));
587  chars.resize(cur); // Restrict to output length
588 
589  if (chars.empty()) chars.clearStorage(); // Can destroy now
590  sync_pbuffer();
591  return chars;
592  }
593 };
594 
596 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
597 
598 } // End namespace Foam
599 
600 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
601 
602 #endif
603 
604 // ************************************************************************* //
void swap(UList< T > &list) noexcept
Swap content with another UList of the same type in constant time.
Definition: UListI.H:505
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
void resetg(char *s, std::streamsize n)
Reset get buffer with character data (can be nullptr) and count.
DynamicList< char > release()
Reset buffer and return contents.
std::streamsize span_capacity() const
The put buffer capacity.
virtual int overflow(int_type c=traits_type::eof())
Handle overflow.
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition: List.C:326
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
std::streamsize span_capacity() const
The get buffer capacity.
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:666
T * data() noexcept
Return pointer to the underlying array serving as data storage.
Definition: UListI.H:272
void resize(const label len)
Alter addressable list size, allocating new space if required while recovering old content...
Definition: DynamicListI.H:353
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:175
char * data_bytes() const
The span data (start of output characters)
out_base()=default
Default construct.
virtual std::streamsize xsgetn(char *s, std::streamsize n)
Get sequence of characters from a fixed region.
void info(Ostream &os) const
Some information about the output buffer position/capacity.
label capacity() const noexcept
Size of the underlying storage.
Definition: DynamicList.H:225
void swap(List< char > &other)
Exchange buffer content and parameter contents, reset positions.
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
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:51
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:137
void shrink()
Shrink storage to addressed storage.
The base input streambuf with memory access.
std::streamsize span_remaining() const
The number of characters remaining in the get area.
virtual std::streampos seekpos(std::streampos pos, std::ios_base::openmode which=std::ios_base::in|std::ios_base::out)
Set position pointer to absolute position.
virtual std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which=std::ios_base::in|std::ios_base::out)
Set position pointer to relative position.
An output streambuf for memory access.
void swap(List< char > &other)
Exchange buffer content and parameter contents, reset positions.
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
virtual std::streamsize xsputn(const char *s, std::streamsize n)
Put sequence of characters to a fixed region.
virtual std::streamsize xsputn(const char *s, std::streamsize n)
Put sequence of characters.
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:201
OBJstream os(runTime.globalPath()/outputName)
void reserve(const std::streamsize len)
Increment capacity (if needed) and adjust buffer pointers.
void swap(List< T > &list)
Swap with plain List content. Implies shrink_to_fit().
Definition: DynamicListI.H:456
DynamicList< char > release()
Reset buffer and return contents as a DynamicList. The list size corresponds to the region of output...
in_dynamic()=default
Default construct - empty.
void sync_pbuffer()
Sync put buffer pointers to agree with list dimensions.
std::streamsize span_tellp() const
The current buffer put position.
void resetp(char *s, std::streamsize n)
Reset put buffer with character data (can be nullptr) and count.
void sync_gbuffer()
Sync get buffer pointers to agree with list dimensions.
void reset(const char *s, std::streamsize n)
Reset content (copy)
out_dynamic(size_t nbytes=512)
Default construct with initial reserved number of bytes.
const dimensionedScalar c
Speed of light in a vacuum.
A streambuf for memory similar to std::spanbuf (C++23)
void clearStorage()
Clear the list and delete storage.
Definition: DynamicListI.H:412
Rudimentary functionality similar to std::span for holding memory view.
Definition: stdFoam.H:500
Includes some standard C++ headers, defines global macros and templates used in multiple places by Op...
stdFoam::span< const char > view() const
label n
std::streamsize size_bytes() const
The span size (number of input characters)
void info(Ostream &os) const
Some information about the input buffer position/capacity.
std::streamsize size_bytes() const
The span size (size of output buffer)
void clearStorage()
Clear storage.
stdFoam::span< const char > view() const
An output streambuf for memory access.
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))
An output streambuf for memory access.
in_base()=default
Default construct.
char * data_bytes() const
The span data (start of input characters)
std::streamsize span_tellg() const
The current buffer get position.
Namespace for OpenFOAM.