HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_StringStreamImpl.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_StringStreamImpl.h ( UT Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 
12 #ifndef __UT_StringStreamImpl__
13 #define __UT_StringStreamImpl__
14 
15 #ifndef __UT_StringStream__
16 #error UT_StringStreamImpl.h should only be included by UT_StringStream.h
17 #endif
18 
19 #include "UT_ArrayHelp.h"
20 
21 #include <SYS/SYS_Inline.h>
22 #include <SYS/SYS_Math.h>
23 #include <limits>
24 
25 template<typename T>
26 inline
28 {
29  if ((myMode & std::ios_base::out) && T::autoTerminate())
30  updateBufferEnd();
31 }
32 
33 template<typename T>
34 inline void
36 {
37  // Init the write pointers. The output end is the next character after
38  // the allocated buffer size, less one for the null terminator.
39  char *rw_buffer = const_cast<char *>(buffer().buffer());
40  if (myMode & std::ios_base::out)
41  {
42  setp64(rw_buffer, rw_buffer + buffer().getAllocatedSize() - 1);
43 
44  // If handed a buffer, the output starts at the end of that buffer.
45  if (use_existing)
46  pbump64(buffer().length());
47  UT_ASSERT_P(validatePPtr());
48  }
49  else
50  {
51  setp64(nullptr, nullptr);
52  UT_ASSERT_P(validatePPtr());
53  }
54 
55  // Init the input pointers. The input end is the next character after
56  // the last readable.
57  if (myMode & std::ios_base::in)
58  setg64(rw_buffer, rw_buffer, rw_buffer + buffer().length());
59  else
60  setg64(pptr(), pptr(), pptr());
61  UT_ASSERT_P(validateGPtr());
62 }
63 
64 
65 template<typename T>
66 inline const UT_WorkBuffer &
68 {
69  SYSconst_cast(this)->updateBufferEnd();
70  return buffer();
71 }
72 
73 
74 
75 template<typename T>
76 inline void
78 {
79  // Ensure the buffer is properly terminated.
80  exint len;
81  if (egptr64() > pptr())
82  {
83  *egptr64() = 0;
84  len = egptr64() - eback();
85  }
86  else
87  {
88  *pptr() = 0;
89  len = pptr() - pbase();
90  }
91 
92  // Set the current length of the buffer. We can't have UT_WorkBuffer
93  // recompute it, since we want to support embedded null characters in
94  // the stream.
95  buffer().lock();
96  buffer().releaseSetLength(len);
97 }
98 
99 
100 template<typename T>
101 inline void
103 {
104  if (pptr() && pptr() > egptr64())
105  {
106  if (myMode & std::ios_base::in)
107  setg64(eback(), gptr(), pptr());
108  else
109  setg64(pptr(), pptr(), pptr());
110  UT_ASSERT_P(validateGPtr());
111  }
112 }
113 
114 template<typename T>
115 inline void
117 {
118  setp(first, last);
119  myEPPtr = last;
120 }
121 
122 template<typename T>
123 inline void
124 UT_StringStreamBufferBase<T>::setg64(char *first, char *next, char *last)
125 {
126  setg(first, next, last);
127  myEGPtr = last;
128 }
129 
130 template<typename T>
131 template<bool bump_write_ptr> inline void
133 {
134  // The streambuf designers did the moronic thing and left gbump()/pbump()
135  // with an int argument, thereby negating all benefits of using ptrdiff_t
136  // for the streamsize, even on a 64-bit platform. Sigh.
137  // So we bump in int.max() - 1 increments until the desired offset is
138  // reached.
139  // There are no checks for over/under-flow, so beware.
140  const int max_bump = std::numeric_limits<int>::max() - 1;
141  int sign = 1;
142 
143  if (offset < 0)
144  {
145  sign = -1;
146  offset = -offset;
147  }
148 
149  while(offset)
150  {
151  int bump = int(SYSmin(exint(max_bump), offset));
152  if (bump_write_ptr)
153  pbump(bump * sign);
154  else
155  gbump(bump * sign);
156  offset -= bump;
157  }
158 }
159 
160 
161 template<typename T>
162 inline void
164 {
165  bump64<false>(offset);
166 }
167 
168 
169 template<typename T>
170 inline void
172 {
173  bump64<true>(offset);
174 }
175 
176 template<typename T>
177 inline char *
179 {
180 #if 1
181  // Reimplementation of epptr() to avoid 32-bit limitation on Windows
182  UT_ASSERT_P(validatePPtr());
183  return myEPPtr;
184 #else
185  return epptr();
186 #endif
187 }
188 
189 template<typename T>
190 inline char *
192 {
193 #if 1
194  // Reimplementation of epptr() to avoid 32-bit limitation on Windows
195  UT_ASSERT_P(validateGPtr());
196  return myEGPtr;
197 #else
198  return egptr();
199 #endif
200 }
201 
202 template<typename T>
203 SYS_FORCE_INLINE bool
205 {
206  exint s = myEGPtr - gptr();
207  if (s < 0)
208  return false;
209  if (s < (exint(1) << 32) && myEGPtr != egptr())
210  return false;
211  return true;
212 }
213 
214 template<typename T>
215 SYS_FORCE_INLINE bool
217 {
218  exint s = myEPPtr - pptr();
219  if (s < 0)
220  return false;
221  if (s < (exint(1) << 32) && myEPPtr != epptr())
222  return false;
223  return true;
224 }
225 
226 namespace
227 {
228  // Taken from UTbumpAlloc but with modifications to suit UT_WorkBuffer
229  // and minimize allocations for large writes.
230  static inline exint
231  bumpAlloc(exint current_size)
232  {
233  static exint big_alloc_threshold = 1024 * 1024;
234  exint bump;
235 
236  // Less than the static buffer, leave as-is until exhausted and we move
237  // to heap storage.
238  if (current_size < UT_INITIAL_BUFFER_SIZE)
239  return current_size;
240 
241  // Less than a page, go up to a page.
242  if (current_size < 4096)
243  return 4096;
244 
245  // As the buffer get bigger, we make larger allocations, assuming that
246  // we're racing to write data, at which point the writes become
247  // more and more time-critical.
248  if (current_size < big_alloc_threshold)
249  bump = current_size / 8;
250  else if (current_size < big_alloc_threshold * 8)
251  bump = current_size / 4;
252  else
253  bump = current_size / 2;
254 
255  current_size += bump;
256  return current_size;
257  }
258 }
259 
260 template<typename T>
261 inline void
263 {
264  // This should never be called for read-only buffers.
265  UT_ASSERT_P(myMode & std::ios_base::out);
266 
267  exint ppos = exint(pptr() - pbase()); // Write pos
268  exint gpos = 0;
269 
270  if (myMode & std::ios_base::in)
271  gpos = exint(gptr() - eback());
272 
273  const char *old_buffer = buffer().buffer();
274  bool bumped_alloc = false;
275 
276  // Lock down large enough range for the incoming characters + a terminating
277  // null character + pad to avoid too many allocation on massive writes.
278  exint bytes_to_lock = ppos + bytes + 1;
279  if (bytes_to_lock > buffer().getAllocatedSize())
280  {
281  bytes_to_lock = bumpAlloc(bytes_to_lock);
282  bumped_alloc = true;
283  }
284  char *wr_buffer = buffer().lock(0, bytes_to_lock);
285  ::memcpy(wr_buffer + ppos, ptr, bytes);
286 
287  // If set to auto-terminate, put a null char here now, otherwise we may
288  // leave the underlying referenced buffer in a bad state. This would
289  // normally be handled in updateBufferEnd() when str() is called, but that
290  // is not the case for referenced buffers. This causes slightly different
291  // behavior in the presence of a seek back in the stream, where the ref
292  // buffer case will always terminate, but the non-ref case will simply
293  // overwrite what's there.
294  if (T::autoTerminate())
295  wr_buffer[ppos + bytes] = '\0';
296 
297  // Don't auto-compute since we may have binary data with null bytes.
298  buffer().releaseSetLength(ppos + bytes);
299 
300  // If the buffer size was bumped or the buffer location changed, re-adjust
301  // all stream pointers. Adjust the current read/write positions as well.
302  if (buffer().buffer() != old_buffer || bumped_alloc)
303  {
304  char *rw_buffer = const_cast<char *>(buffer().buffer());
305 
306  // Re-set the write pointers to correspond to the new location in
307  // memory of the UT_WorkBuffer data. However, unlike setg(),
308  // setp() does not take a third argument for current offset,
309  // so we call pbump to move the current write position :-/
310  // NB: less one for the null terminator.
311  setp64(rw_buffer, rw_buffer + buffer().getAllocatedSize() - 1);
312  pbump64(ppos);
313  UT_ASSERT_P(validatePPtr());
314 
315  char *ro_buffer_end = rw_buffer + buffer().length();
316  if (myMode & std::ios_base::in)
317  setg64(rw_buffer, rw_buffer + gpos, ro_buffer_end);
318  else
319  setg64(ro_buffer_end, ro_buffer_end, ro_buffer_end);
320  UT_ASSERT_P(validateGPtr());
321  }
322 }
323 
324 
325 template<typename T>
326 inline std::streambuf::pos_type
327 UT_StringStreamBufferBase<T>::seekoff(std::streambuf::off_type offset,
328  std::ios_base::seekdir dir,
329  std::ios_base::openmode mode)
330 {
331  pos_type result = pos_type(-1);
332  bool in = (myMode & mode & std::ios_base::in);
333  bool out = (myMode & mode & std::ios_base::out);
334 
335  if (!in && !out)
336  return result;
337 
338  // We can't do a offset from current for both in and out.
339  if (in && out && dir == std::ios_base::cur)
340  return result;
341 
342  const char *start = in ? eback() : pbase();
343  if (start || !offset)
344  {
345  updateReadEnd();
346 
347  exint end = egptr64() - start;
348  exint in_pos, out_pos;
349 
350  in_pos = out_pos = offset;
351  if (dir == std::ios_base::cur)
352  {
353  in_pos += gptr() - start;
354  out_pos += pptr() - start;
355  }
356  else if (dir == std::ios_base::end)
357  {
358  in_pos += end;
359  out_pos += end;
360  }
361 
362  if (in && (in_pos >= 0) && (in_pos <= end))
363  {
364  gbump64(start - gptr() + in_pos);
365  result = in_pos;
366  }
367  if (out && (out_pos >= 0) && (out_pos <= end))
368  {
369  pbump64(start - pptr() + out_pos);
370  result = out_pos;
371  }
372  }
373 
374  return result;
375 }
376 
377 
378 template<typename T>
379 inline std::streambuf::pos_type
380 UT_StringStreamBufferBase<T>::seekpos(std::streambuf::pos_type pos,
381  std::ios_base::openmode mode)
382 {
383  pos_type result = pos_type(-1);
384  bool in = (myMode & mode & std::ios_base::in);
385  bool out = (myMode & mode & std::ios_base::out);
386  if (!in && !out)
387  return result;
388 
389  const char *start = in ? eback() : pbase();
390  if (start || !pos)
391  {
392  updateReadEnd();
393 
394  if (pos >= 0 && pos <= (egptr64() - start))
395  {
396  if (in)
397  gbump64(start - gptr() + pos);
398  if (out)
399  pbump64(start - pptr() + pos);
400  result = pos;
401  }
402  }
403 
404  return result;
405 }
406 
407 
408 template<typename T>
409 inline std::streambuf::int_type
411 {
412  if (!(myMode & std::ios_base::in))
413  return traits_type::eof();
414 
415  updateReadEnd();
416 
417  // Have we reached the end?
418  if (gptr() >= egptr64())
419  return traits_type::eof();
420 
421  return traits_type::to_int_type(*gptr());
422 }
423 
424 
425 template<typename T>
426 inline std::streamsize
427 UT_StringStreamBufferBase<T>::xsgetn(std::streambuf::char_type *dst,
428  std::streamsize num)
429 {
430  if (!(myMode & std::ios_base::in))
431  return traits_type::eof();
432 
433  updateReadEnd();
434 
435  exint max_to_read = SYSmin(exint(num), exint(egptr64() - gptr()));
436  if (max_to_read)
437  {
438  ::memcpy(dst, gptr(), max_to_read);
439  gbump64(max_to_read);
440  }
441 
442  return max_to_read;
443 }
444 
445 
446 template<typename T>
447 inline std::streamsize
449 {
450  if (!(myMode & std::ios_base::in))
451  return -1;
452 
453  updateReadEnd();
454  return egptr64() - gptr();
455 }
456 
457 
458 template<typename T>
459 inline std::streambuf::int_type
460 UT_StringStreamBufferBase<T>::overflow(std::streambuf::int_type c)
461 {
462  if (!(myMode & std::ios_base::out))
463  return traits_type::eof();
464 
465  if (c != traits_type::eof())
466  {
467  char ch = traits_type::to_char_type(c);
468 
469  writeToBuffer(&ch, 1);
470  pbump64(1);
471  }
472  return c;
473 }
474 
475 
476 template<typename T>
477 inline std::streamsize
478 UT_StringStreamBufferBase<T>::xsputn(const std::streambuf::char_type *src,
479  std::streamsize num)
480 {
481  if (!(myMode & std::ios_base::out))
482  return 0;
483 
484  writeToBuffer(src, num);
485  pbump64(num);
486 
487  return num;
488 }
489 
490 // Specializations
491 inline void
492 UT_StringStreamBuffer::init(const char *buf, exint len)
493 {
494  if (buf)
495  {
496  if (len >= 0)
497  myBuffer.append(buf, len);
498  else
499  myBuffer.strcpy(buf);
500  }
501  else if (len > 0)
502  {
503  myBuffer.reserve(len);
504  }
505 
506  Base::init(buf != NULL);
507 }
508 
509 inline void
511 {
513 
514  buf.swap(myBuffer);
515  Base::init();
516 }
517 
518 inline void
520 {
522 
523  myBuffer.stealIntoString(str);
524  Base::init();
525 }
526 
527 inline int
529 {
530  // Init the write pointers. The output end is the next character after
531  // the allocated buffer size, less one for the null terminator.
532  char *rw_buffer = const_cast<char *>(myBuffer.buffer());
533  if (mode() & std::ios_base::out)
534  {
535  char *rw_buffer_end = rw_buffer + buffer().getAllocatedSize() - 1;
536  exint len = pptr() - pbase();
537 
538  if (pbase() == rw_buffer && epptr64() == rw_buffer_end &&
539  len == buffer().length())
540  {
541  // If the buffer didn't change externally, then assume the user
542  // is asking that the buffer is made externally valid by null
543  // terminating it.
545  }
546  else
547  {
548  // Otherwise, update the write pointers.
549  setp64(rw_buffer, rw_buffer_end);
550 
551  // Put the output location to the end of the buffer.
552  pbump64(buffer().length());
554  }
555  }
556  else
557  {
558  setp64(nullptr, nullptr);
559  }
560 
561  if (mode() & std::ios_base::in)
562  {
563  exint l = myBuffer.length();
564  ptrdiff_t pos = gptr() - eback();
565 
566  // If the input pos is still within the buffer area, just update
567  // the pointers, otherwise mark the buffer as being EOF.
568  if (pos < l)
569  setg64(rw_buffer, rw_buffer + pos, rw_buffer + buffer().length());
570  else
571  setg64(pptr(), pptr(), pptr());
573  }
574  else
575  {
576  setg64(pptr(), pptr(), pptr());
578  }
579 
580  return 0;
581 }
582 
583 
584 
585 #endif // UT_StringStreamImpl
GLint first
Definition: glcorearb.h:404
void reserve(exint bytes=0)
SYS_FORCE_INLINE exint length() const
void init(bool use_existing=false)
SYS_FORCE_INLINE exint getAllocatedSize() const
GLuint start
Definition: glcorearb.h:474
png_voidp ptr
Definition: png.h:2145
SYS_FORCE_INLINE T * SYSconst_cast(const T *foo)
Definition: SYS_Types.h:127
SYS_FORCE_INLINE const char * buffer() const
SYS_FORCE_INLINE void strcpy(const char *src)
virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode=in_out)
void setg64(char *first, char *next, char *last)
GLuint buffer
Definition: glcorearb.h:659
void swap(UT_WorkBuffer &other)
void stealIntoString(UT_String &str)
virtual streamsize xsputn(const char_type *src, streamsize num)
#define UT_INITIAL_BUFFER_SIZE
Definition: UT_WorkBuffer.h:55
virtual streamsize showmanyc()
virtual pos_type seekoff(off_type offset, std::ios_base::seekdir dir, openmode mode=in_out)
int64 exint
Definition: SYS_Types.h:116
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:125
GLuint GLuint end
Definition: glcorearb.h:474
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
GLintptr offset
Definition: glcorearb.h:664
Base class for the memory storage and stream buffering.
const UT_WorkBuffer & str() const
int sign(T a)
Definition: ImathFun.h:63
void swap(UT_WorkBuffer &buf)
GLenum mode
Definition: glcorearb.h:98
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2539
GLenum GLenum dst
Definition: glcorearb.h:1792
virtual int_type overflow(int_type c)
void setp64(char *first, char *last)
typedef int
Definition: png.h:1175
virtual streamsize xsgetn(char_type *dst, streamsize num)
SYS_FORCE_INLINE void append(char character)
void steal(UT_String &str)
virtual int sync()
std::streambuf helpers.
png_infop png_uint_32 int num
Definition: png.h:2158
#define SYSmin(a, b)
Definition: SYS_Math.h:1368
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:794
UT_WorkBuffer & buffer()
GLenum src
Definition: glcorearb.h:1792