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