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 <SYS/SYS_Inline.h>
20 #include <SYS/SYS_Math.h>
21 #include <limits>
22 
23 inline
25  std::ios_base::openmode mode,
26  const char *buf,
27  exint len)
28  : myGPos(-1), myPPos(-1)
29 {
30  if(buf)
31  {
32  if(len >= 0)
33  myBuffer.append(buf, len);
34  else
35  myBuffer.strcpy(buf);
36  }
37  else if(len > 0)
38  {
39  // +1 to avoid reallocating when adding a terminating null
40  myBuffer.reserve(len + 1);
41  }
42 
43  char *start = const_cast<char *>(buffer());
44  if(mode & std::ios_base::in)
45  setg64(start, start, start + length());
46  else
47  setg(nullptr, nullptr, nullptr);
48 
49  if(mode & std::ios_base::out)
50  {
51  setp64(start, start, start + length());
52  updateppos(length());
53  }
54  else
55  setp(nullptr, nullptr);
56 }
57 
58 inline void
60 {
61  myBuffer.clear();
62  init();
63 }
64 
65 inline const UT_WorkBuffer &
67 {
68  updateBufferEnd();
69  return myBuffer;
70 }
71 
72 inline void
74 {
75  updateBufferEnd();
76  buf.swap(myBuffer);
77  init();
78 }
79 
80 inline void
82 {
83  updateBufferEnd();
84  myBuffer.stealIntoString(s);
85  init();
86 }
87 
88 inline void
90 {
91  updateBufferEnd();
92  s = std::move(myBuffer);
93  init();
94 }
95 
96 inline std::streambuf::pos_type
97 UT_StringStreamBuffer::seekoff(
98  std::streambuf::off_type offset,
99  std::ios_base::seekdir dir,
100  std::ios_base::openmode mode)
101 {
102  pos_type result(-1);
103  if((mode & std::ios_base::in) && gptr())
104  {
105  exint pos;
106  if(dir == std::ios_base::beg)
107  pos = offset;
108  else if(dir == std::ios_base::cur)
109  pos = ((myGPos < 0) ? (gptr() - buffer()) : myGPos) + offset;
110  else if(dir == std::ios_base::end)
111  pos = length() + offset;
112  else
113  pos = -1;
114  if(pos >= 0)
115  {
116  updategpos(pos);
117  result = pos;
118  }
119  }
120  if((mode & std::ios_base::out) && pptr())
121  {
122  exint pos;
123  if(dir == std::ios_base::beg)
124  pos = offset;
125  else if(dir == std::ios_base::cur)
126  pos = ((myPPos < 0) ? (pptr() - buffer()) : myPPos) + offset;
127  else if(dir == std::ios_base::end)
128  pos = length() + offset;
129  else
130  pos = -1;
131  if(pos >= 0)
132  {
133  updateppos(pos);
134  result = pos;
135  }
136  }
137  return result;
138 }
139 
140 inline std::streambuf::pos_type
141 UT_StringStreamBuffer::seekpos(
142  std::streambuf::pos_type pos,
143  std::ios_base::openmode mode)
144 {
145  pos_type result(-1);
146  if(pos >= 0)
147  {
148  if((mode & std::ios_base::in) && gptr())
149  {
150  updategpos(pos);
151  result = pos;
152  }
153  if((mode & std::ios_base::out) && pptr())
154  {
155  updateppos(pos);
156  result = pos;
157  }
158  }
159  return result;
160 }
161 
162 inline std::streambuf::int_type
163 UT_StringStreamBuffer::underflow()
164 {
165  const char *cur = gptr();
166  if(cur)
167  {
168  updategpos((myGPos < 0) ? (cur - buffer()) : myGPos);
169  cur = gptr();
170  if(cur < egptr())
171  return *cur;
172  }
173  return traits_type::eof();
174 }
175 
176 inline std::streamsize
177 UT_StringStreamBuffer::xsgetn(
178  std::streambuf::char_type *dst,
179  std::streamsize num)
180 {
181  const char *cur = gptr();
182  if(!cur)
183  return traits_type::eof();
184 
185  if(myGPos < 0)
186  {
187  const char *start = buffer();
188  exint pos = cur - start;
189  exint avail = length() - pos;
190  if(num > avail)
191  num = avail;
192  if(num > 0)
193  {
194  ::memcpy(dst, start + pos, num);
195  updategpos(pos + num);
196  return num;
197  }
198  }
199  return 0;
200 }
201 
202 inline std::streamsize
203 UT_StringStreamBuffer::showmanyc()
204 {
205  const char *cur = gptr();
206  if(!cur)
207  return traits_type::eof();
208 
209  if(myGPos < 0)
210  return egptr() - cur;
211  return 0;
212 }
213 
214 inline std::streambuf::int_type
215 UT_StringStreamBuffer::pbackfail(std::streambuf::int_type c)
216 {
217  const char *cur = gptr();
218  if(cur)
219  {
220  const char *start = buffer();
221  exint pos = ((myGPos < 0) ? (cur - start) : myGPos) - 1;
222  if(pos >= 0 && pos < length() && start[pos] == c)
223  {
224  updategpos(pos);
225  return c;
226  }
227  }
228  return traits_type::eof();
229 }
230 
231 inline std::streambuf::int_type
232 UT_StringStreamBuffer::overflow(int_type c)
233 {
234  if(c != traits_type::eof())
235  {
236  char ch = char(c);
237  if(xsputn(&ch, 1) > 0)
238  return c;
239  }
240  return traits_type::eof();
241 }
242 
243 inline std::streamsize
244 UT_StringStreamBuffer::xsputn(
245  const std::streambuf::char_type *src,
246  std::streamsize num)
247 {
248  const char *old_start = buffer();
249  const char *cur_g = gptr();
250  exint pos = (myPPos < 0) ? (pptr() - old_start) : myPPos;
251  exint end = pos + num;
252  exint old_len = length();
253  exint len = old_len;
254  if(end > old_len)
255  {
256  // +1 to avoid reallocating when adding a terminating null
257  reserve(end + 1);
258  len = end;
259  }
260  char *buf = myBuffer.lock(0, end);
261  if(pos > old_len)
262  ::memset(buf + old_len, 0, pos - old_len);
263  ::memcpy(buf + pos, src, num);
264  myBuffer.releaseSetLength(len);
265  if(cur_g && end > old_len)
266  updategpos((myGPos < 0) ? (cur_g - old_start) : myGPos);
267  updateppos(pos + num);
268  return num;
269 }
270 
271 inline void
272 UT_StringStreamBuffer::init()
273 {
274  char *start = const_cast<char*>(buffer());
275  char *end = start + length();
276  if(gptr())
277  {
278  myGPos = -1;
279  setg64(start, start, end);
280  }
281  if(pptr())
282  {
283  myPPos = -1;
284  setp64(start, end, end);
285  }
286 }
287 
288 namespace
289 {
290  // Visual C++ streambuf implementation has a 32-bit limit.
291  // We clamp the buffer size to stay within this limit.
292  static inline void
293  utClampBuf(char *&start, char *&cur, char *&end)
294  {
295  const exint size_limit = std::numeric_limits<int>::max();
296  if(end - start <= size_limit)
297  return;
298 
299  // reduce the buffer size
300  // allow some backup room but keep cur within the buffer
301  const exint backup_limit = 1024;
302  if(cur - start > backup_limit)
303  {
304  start = cur - backup_limit;
305  if(end - start <= size_limit)
306  return;
307  }
308  end = start + size_limit;
309  }
310 }
311 
312 inline void
313 UT_StringStreamBuffer::setg64(char *start, char *cur, char *end)
314 {
315  UT_ASSERT(start && cur && end && start <= cur && cur <= end);
316  utClampBuf(start, cur, end);
317  setg(start, cur, end);
318 }
319 
320 inline void
321 UT_StringStreamBuffer::setp64(char *start, char *cur, char *end)
322 {
323  UT_ASSERT(start && cur && end && start <= cur && cur <= end);
324  utClampBuf(start, cur, end);
325  setp(start, end);
326 
327  // The streambuf designers did the moronic thing and left gbump()/pbump()
328  // with an int argument, thereby negating all benefits of using ptrdiff_t
329  // for the streamsize, even on a 64-bit platform. Sigh.
330  // Since utClampBuf limits the buffer size to std::numeric_limits<int>,
331  // we can use pbump() once instead of bumping by increments until the
332  // desired offset is reached.
333  pbump(cur - start);
334 }
335 
336 inline void
337 UT_StringStreamBuffer::updategpos(exint pos)
338 {
339  UT_ASSERT(gptr() && pos >= 0);
340  char *start = const_cast<char*>(buffer());
341  if(pos > length())
342  {
343  myGPos = pos;
344  setg64(start, start, start);
345  }
346  else
347  {
348  myGPos = -1;
349  setg64(start, start + pos, start + length());
350  }
351 }
352 
353 inline void
354 UT_StringStreamBuffer::updateppos(exint pos)
355 {
356  UT_ASSERT(pptr() && pos >= 0);
357  char *start = const_cast<char*>(buffer());
358  if(pos > length())
359  {
360  myPPos = pos;
361  setp64(start, start, start);
362  }
363  else
364  {
365  myPPos = -1;
366  setp64(start, start + pos, start + length());
367  }
368 }
369 
370 // Taken from UTbumpAlloc but with modifications to suit UT_WorkBuffer
371 // and minimize allocations for large writes.
372 namespace
373 {
374  static inline exint
375  utBumpAlloc(exint current_size)
376  {
377  static exint big_alloc_threshold = 1024 * 1024;
378  exint bump;
379 
380  // Less than the static buffer, leave as-is until exhausted and we move
381  // to heap storage.
382  if (current_size < UT_INITIAL_BUFFER_SIZE)
383  return current_size;
384 
385  // Less than a page, go up to a page.
386  if (current_size < 4096)
387  return 4096;
388 
389  // As the buffer get bigger, we make larger allocations, assuming that
390  // we're racing to write data, at which point the writes become
391  // more and more time-critical.
392  if (current_size < big_alloc_threshold)
393  bump = current_size / 8;
394  else if (current_size < big_alloc_threshold * 8)
395  bump = current_size / 4;
396  else
397  bump = current_size / 2;
398 
399  current_size += bump;
400  return current_size;
401  }
402 }
403 
404 inline void
405 UT_StringStreamBuffer::reserve(exint bytes)
406 {
407  exint a = myBuffer.getAllocatedSize();
408  if(bytes > a)
409  {
410  const char *old_start = buffer();
411  const char *cur_g = gptr();
412  const char *cur_p = pptr();
413  myBuffer.reserve(SYSmax(bytes, utBumpAlloc(a)));
414  if(cur_g)
415  updategpos((myGPos < 0) ? (cur_g - old_start) : myGPos);
416  if(cur_p)
417  updateppos((myPPos < 0) ? (cur_p - old_start) : myPPos);
418  }
419 }
420 
421 inline void
422 UT_StringStreamBuffer::updateBufferEnd()
423 {
424 #if 0
425  if(pptr())
426  {
427  exint len = length();
428  reserve(len + 1); // to ensure lock() doesn't reallocate!
429  (void) myBuffer.lock(0, len);
430  myBuffer.releaseSetLength(len); // just to force null termination
431  }
432 #endif
433 }
434 
435 #endif // UT_StringStreamImpl
void stealIntoStringHolder(UT_StringHolder &s)
#define SYSmax(a, b)
Definition: SYS_Math.h:1538
void reserve(exint bytes=0)
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2540
const char * buffer() const
SYS_FORCE_INLINE exint getAllocatedSize() const
void
Definition: png.h:1083
GLuint start
Definition: glcorearb.h:475
int64 exint
Definition: SYS_Types.h:125
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
GLdouble s
Definition: glad.h:3009
SYS_FORCE_INLINE void strcpy(const char *src)
**But if you need a result
Definition: thread.h:613
void releaseSetLength(exint new_length)
exint length() const
void swap(UT_WorkBuffer &other)
void stealIntoString(UT_String &str)
#define UT_INITIAL_BUFFER_SIZE
Definition: UT_WorkBuffer.h:63
GLintptr offset
Definition: glcorearb.h:665
UT_StringStreamBuffer(std::ios_base::openmode mode=(std::ios_base::in|std::ios_base::out), const char *buf=nullptr, exint len=-1)
GLuint GLuint end
Definition: glcorearb.h:475
char * lock(exint offset=0, exint reserve_bytes=0)
void swap(UT_WorkBuffer &buf)
GLenum mode
Definition: glcorearb.h:99
GLenum GLenum dst
Definition: glcorearb.h:1793
const UT_WorkBuffer & str()
SYS_FORCE_INLINE void append(char character)
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
SYS_FORCE_INLINE void clear()
void stealIntoString(UT_String &s)
Definition: format.h:2459
GLenum src
Definition: glcorearb.h:1793