HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_WorkBuffer.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_WorkBuffer.h ( Utility Library, C++ )
7  *
8  * COMMENTS:
9  * A growable string buffer that can be written into. A UT_String
10  * can be created with the contents of this buffer by calling
11  * copyIntoString().
12  *
13  * It's important that a non-const version of the raw buffer is not
14  * accessible since users could write past the end of the allocated
15  * buffer. Also note that the buffer location can change as it grows,
16  * so don't keep pointers to the buffer around.
17  *
18  * Most of the time, you want to allocate an object of this class on
19  * the stack and not on the heap.
20  *
21  * The buffer is kept null terminated by default. Functions exist
22  * to verify this. Note that the "length" of the buffer is the
23  * same as strlen - ie: it ignores the null termination!!!
24  *
25  * RELATION TO THE STL:
26  *
27  * Use UT_StringHolder, UT_WorkBuffer, etc., instead of std::string
28  * (see comments at the top of UT_StringHolder.h)
29  */
30 
31 #ifndef __UT_WorkBuffer_h__
32 #define __UT_WorkBuffer_h__
33 
34 #include "UT_API.h"
35 
36 #include "UT_Assert.h"
37 #include "UT_Format.h"
38 #include "UT_String.h"
39 #include "UT_StringHolder.h"
40 #include "UT_StringUtils.h"
41 #include "UT_StringView.h"
42 #include "UT_Swap.h"
43 #include "UT_Unicode.h"
44 
45 #include <SYS/SYS_Deprecated.h>
46 #include <SYS/SYS_Inline.h>
47 #include <SYS/SYS_String.h>
48 #include <SYS/SYS_Types.h>
49 
50 #include <iosfwd>
51 #include <string>
52 #include <utility>
53 
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 
58 
59 // The default page size on most systems is 4K. We choose a default
60 // buffer size less than half of that in the hopes that if we have
61 // functions with 2 work buffers or additional variables on the stack that we
62 // may not have to allocate multiple stack pages.
63 #define UT_INITIAL_BUFFER_SIZE 2000
64 
65 class UT_StringArray;
66 class UT_WorkArgs;
67 class UT_IStream;
68 class UT_Digits;
69 
70 template <typename T>
71 class UT_Array;
72 
74 {
75 public:
76  typedef char value_type;
77 
80  {
81  myBuffer[0] = '\0';
82  }
83 
85  explicit UT_WorkBuffer(const char *str)
86  : UT_WorkBuffer()
87  {
88  append(str);
89  }
90 
92  explicit UT_WorkBuffer(const char *data, exint size)
93  : UT_WorkBuffer()
94  {
95  append(data, size);
96  }
97 
99  explicit UT_WorkBuffer(const UT_String &str)
100  : UT_WorkBuffer()
101  {
102  append(str);
103  }
104 
106  explicit UT_WorkBuffer(const UT_StringRef &str)
107  : UT_WorkBuffer()
108  {
109  append(str);
110  }
111 
113  explicit UT_WorkBuffer(const UT_StringLit &str)
114  : UT_WorkBuffer()
115  {
116  append(str);
117  }
118 
121  : UT_WorkBuffer()
122  {
123  append(view);
124  }
125 
128  : UT_WorkBuffer()
129  {
130  append(other);
131  }
132 
135  {
136  if (myBuffer != myStackBuffer)
137  {
138  UT_ASSERT_P(myBuffer);
139  ::free(myBuffer);
140  }
141  }
142 
143  /// Create a work buffer to contain a UTF-16LE (little endian)
144  /// representation of the incoming UTF-8 string.
145  /// The work buffer will be zero-word terminated.
147  static UT_WorkBuffer
148  widen(const utf8 *str)
149  {
150  return UT_WorkBuffer(do_widen(), str);
151  }
152 
153  /// Create a work buffer to contain the UTF-8 representation of the
154  /// incoming UTF-16 string. The UTF-16 string is assumed to be
155  /// little-endian, unless prefixed with BOM that indicates endianness.
156  /// The incoming string should be zero-word terminated.
158  static UT_WorkBuffer
159  narrow(const utf16 *str)
160  {
161  return UT_WorkBuffer(do_narrow(), str);
162  }
163 
164  // It's important that there is no non-const access method to the buffer.
165  // Also note that the pointer to the buffer can change if the buffer
166  // grows.
168  const char *buffer() const { return myBuffer; }
169  /// Alias for the common string access across all string types (including
170  /// standard library)
172  const char *data() const { return buffer(); }
173 
174  // Having said that, if you need a non-const pointer you must lock
175  // the string. This prohibits ANY update which changes the myLength
176  // variable (and thus potentially a realloc)
177  // You must release the buffer before any such changes.
178  // The work buffer continues to own the memory and will free it when
179  // it goes out of scope so don't think this is the same as a "steal"
180  // in UT_String.
181  // Currently, to ensure people couple their locks & releases,
182  // it asserts there is no unaccounted locks on death. This is so
183  // people who think it is steal find out otherwise.
184  // Offset is where in the string to get the pointer from.
185  // This is only to be used when absolutely necessary.
186  // When releasing, if you have a string buffer, and you have modified the
187  // length, you should set the recompute_length flag to 1. This will adjust
188  // the internal length variable so that further concatenations will work
189  // properly.
190  // The reserve_bytes parameter tells the lock to ensure that there are at
191  // least that many bytes in the locked buffer.
192  // NOTE: Unlike other UT_WorkBuffer functions, it is the user's
193  // responsibility to maintain a NUL termination guarantee when manipulating
194  // the raw buffer.
195  char *lock(exint offset = 0, exint reserve_bytes=0);
196  void release(bool recompute_length = false);
197  void releaseSetLength(exint new_length);
198 
200  exint getAllocatedSize() const { return myAllocatedSize; }
201  int64 getMemoryUsage(bool inclusive) const;
202 
203  /// Class to handle auto-locking of the UT_WorkBuffer. This is not related
204  /// to multi-threading, but to the lock/release methods above.
205  ///
206  /// You should never append data to a locked buffer.
207  class AutoLock
208  {
209  public:
212  : myBuffer(buf)
213  {
214  myString = myBuffer.lock();
215  }
218  {
219  release();
220  }
221  /// @{
222  /// Get access to the non-const buffer. This may return nullptr if the
223  /// lock has been released.
225  char *operator*() const { return myString; }
227  char *string() const { return myString; }
228  /// @}
229 
230  /// You can manually release the buffer
232  void release(bool recompute_length=false)
233  {
234  if (myString)
235  {
236  myBuffer.release(recompute_length);
237  myString = nullptr;
238  }
239  }
240  /// If you've manually released the lock, you can relock the buffer
242  void relock()
243  {
244  UT_ASSERT(!myString);
245  myString = myBuffer.lock();
246  }
247  private:
248  UT_WorkBuffer &myBuffer;
249  char *myString;
250  };
251 
252  void reserve(exint bytes=0);
253 
254  // This is a read only operator. We are avoiding the writeable
255  // versions as they lead to problems when people do a:
256  // foo[pastend] = foo(start)
257  // causing an implicit realloc.
259  char operator()(exint idx) const
260  {
261  // We allow an index at myLength as if we have a null
262  // terminated buffer that is the null termination.
263  UT_ASSERT_P(idx >= 0 && idx <= myLength);
264  return myBuffer[idx];
265  }
266 
267  // Returns last character. Only valid if !isEmpty()
269  char first() const
270  {
271  UT_ASSERT_P(myLength > 0);
272  return myBuffer[0];
273  }
274  // Returns last character. Only valid if !isEmpty()
276  char last() const
277  {
278  UT_ASSERT_P(myLength > 0);
279  return myBuffer[myLength - 1];
280  }
281 
282  // This should always be true. It's here to act as a sanity function.
283  int isNullTerminated() const;
284 
287  {
288  strcpy(other);
289  return *this;
290  }
292  UT_WorkBuffer &operator=(const char *str)
293  {
294  clear();
295  append(str);
296  return *this;
297  }
300  {
301  clear();
302  append(str.c_str(), str.length());
303  return *this;
304  }
305 
306  /// Comparison operator. Null strings are considered as empty strings.
307  /// @{
309  bool operator==(const char *str) const
310  {
311  if (!str)
312  return isEmpty();
313  return (::strcmp(str, myBuffer) == 0);
314  }
316  bool operator==(const UT_String &str) const
317  {
318  if (!(const char *)str)
319  return isEmpty();
320  return (::strcmp(str, myBuffer) == 0);
321  }
323  bool operator==(const UT_StringRef &str) const
324  {
325  if (length() != str.length())
326  return false;
327  return (::memcmp(myBuffer, str.c_str(), myLength) == 0);
328  }
330  bool operator==(const UT_WorkBuffer &buf) const
331  {
332  if (buf.isEmpty())
333  return isEmpty();
334  if (length() != buf.length())
335  return false;
336  return (::memcmp(myBuffer, buf.myBuffer, myLength) == 0);
337  }
339  bool operator!=(const char *str) const
340  {
341  return !(*this == str);
342  }
344  bool operator!=(const UT_String &str) const
345  {
346  return !(*this == str);
347  }
349  bool operator!=(const UT_StringRef &str) const
350  {
351  return !(*this == str);
352  }
354  bool operator!=(const UT_WorkBuffer &buf) const
355  {
356  return !(*this == buf);
357  }
358  /// @}
359 
360 private:
361  // Reallocate the buffer until the allocated size is >= the length. This
362  // private method needs to come first so it can be inlined.
363  void growBufferIfNeeded()
364  {
365  // Using a while loop instead of computing an accurate size the
366  // first time is slower, but most of the time the loop will execute
367  // at most once.
368  // We need to use myLength+1 as we need room for the null.
369  while (myLength+1 > myAllocatedSize) // false most of the time
370  reserve(myAllocatedSize * 2);
371  }
372 
373 public:
374  // These are standard string operators people tend to use:
376  void strcpy(const char *src)
377  {
378  clear();
379  append(src);
380  }
382  void strcpy(const UT_String &src)
383  {
384  clear();
385  append(src);
386  }
388  void strcpy(const UT_StringRef &src)
389  {
390  clear();
391  append(src);
392  }
394  void strcpy(const UT_WorkBuffer &src)
395  {
396  clear();
397  append(src);
398  }
400  void strcpy(const UT_StringView &src)
401  {
402  clear();
403  append(src);
404  }
405 
406  // NOTE: unlike strncpy(), maxlen does not include the null terminator.
408  void strncpy(const char *src, exint maxlen)
409  {
410  clear();
411  // Ensure we have enough room:
412  myLength = maxlen+1;
413  growBufferIfNeeded();
414  myLength = 0;
415  SYSstrlcpy(myBuffer, src, maxlen+1);
416  myLength = ::strlen(myBuffer);
417  }
418 
419  // Note we can't just return myLength as there may be embedded NULLs.
421  exint strlen() const
422  {
423  UT_ASSERT_P(isNullTerminated());
424  return ::strlen(myBuffer);
425  }
426 
428  exint length() const
429  {
430  return myLength;
431  }
432 
434  void strcat(const char *src)
435  {
436  append(src);
437  }
438 
439  // protectedStrcat() will quote the string in double quotes if required and
440  // protect any enclosed double quotes or backslashes in the source. It
441  // will not escape any other characters.
442  void protectedStrcat(const char *str, bool force_quote=false);
443 
444  // fullyProtected*Strcat() is similar to protectedStrcat, except it escapes
445  // any non-printable characters. It will not escape single quotes, and if
446  // force_quote is true, it will add double-quotes. It will work with
447  // arbitrary binary data and uses the \xNN syntax to encode bytes.
448  // UT_IStream::read() is capable of loading strings encoded with this
449  // method, and these strings can also be decoded in Python. If
450  // fullyProtectedBinaryStrcat is called, this method can handle data
451  // containing null characters.
452  void fullyProtectedStrcat(const char *str, bool force_quote=false);
453  void fullyProtectedBinaryStrcat(
454  const char *str, exint size, bool force_quote=false);
455 
456  /// Append a string of a given maximum length to the current string.
457  /// Unlike the POSIX's strncat(3), we ignore any NUL bytes in the current
458  /// string and blindly append at the end of the work buffer.
460  void strncat(const char *src, exint len)
461  {
462  if (!src)
463  return;
464  append(src, ::strnlen(src, len));
465  }
466 
467  // Extract the first argument from the src and append it to the work
468  // buffer. This does NOT handle quotes properly (i.e. if the first word
469  // is quoted with spaces).
470  void strcatFirstWord(const char *src);
471 
473  int strcmp(const char *src) const
474  {
475  UT_ASSERT_P(isNullTerminated());
476  return ::strcmp(myBuffer, src);
477  }
478 
480  int strncmp(const char *src, exint n) const
481  {
482  UT_ASSERT_P(isNullTerminated());
483  return ::strncmp(myBuffer, src, n);
484  }
485 
487  char *strdup() const
488  {
489  UT_ASSERT(isNullTerminated());
490  return ::strdup(myBuffer);
491  }
492 
493  // Reset the buffer to an empty buffer.
495  void clear()
496  {
497  if (myLockCount) { UT_ASSERT(0); return; }
498  myLength = 0;
499  myBuffer[0] = '\0';
500  }
501 
503  bool isEmpty() const
504  {
505  return (myLength == 0);
506  }
508  bool isstring() const
509  {
510  return !isEmpty();
511  }
512 
513  // Write into the buffer at a specific place.
514  // This WILL expand the buffer if it is required and keep it null
515  // terminated.
517  void write(exint offset, char c)
518  {
519  UT_ASSERT(offset >= 0);
520  if (offset < 0) return;
521  if (offset >= myLength)
522  {
523  if (myLockCount) { UT_ASSERT(0); return; }
524  myLength = offset+1;
525  growBufferIfNeeded();
526  myBuffer[myLength] = '\0';
527  }
528  myBuffer[offset] = c;
529  if (c == '\0')
530  myLength = offset;
531  }
532 
533  // This does NOT write out the trailing NULL of src, but the buffer will
534  // still be null-terminated.
535  void write(exint offset, const char *src)
536  {
537  while (*src)
538  {
539  write(offset, *src);
540  src++;
541  offset++;
542  }
543  }
544 
546  {
547  write(offset, src.c_str());
548  }
549 
550  /// Load an entire file into the buffer. Returns @b false if there was an
551  /// error reading the file
552  bool readFile(const char *filename);
553 
554  // Read a line from an istream -- no matter how long the line is
555  // Returns 0 if the stream read failed or 1 otherwise
556  bool getline(std::istream &is);
557  bool getline(FILE *fp);
558 
559  // Much like getline() except that it has more features. The string itself
560  // is tokenized which the UT_WorkArgs points into.
561  // line_num is incremented for each line read.
562  // comment_chars is list of characters to treat as comments.
563  // this can be NULL if we don't want this feature.
564  // Returns false if the stream read failed.
565  bool cmdGetLine(std::istream &is, UT_WorkArgs &args, int &line_num,
566  const char *comment_chars = "#",
567  const char *separators = " \t\n\r");
568  bool cmdGetLine(UT_IStream &is, UT_WorkArgs &args, int &line_num,
569  const char *comment_chars = "#",
570  const char *separators = " \t\n\r");
571  bool cmdGetLine(FILE *fp, UT_WorkArgs &args, int &line_num,
572  const char *comment_chars = "#",
573  const char *separators = " \t\n\r");
574 
575  /// Fast integer to string conversion.
576  /// @{
577  void itoa(int64 i);
578  void utoa(uint64 i);
579  /// @}
580 
581  /// Format using the system sprintf. See also printf() which uses UT_printf
582  /// which is type-safe and can print floating point using std::to_chars.
583  int sprintf(const char *fmt, ...)
585  int appendSprintf(const char *fmt, ...)
587  int vsprintf(const char *fmt, va_list ap);
588 
589  /// Replace the contents of the work buffer using the same formatting as
590  /// UTformat. Returns the resulting length in bytes.
591  /// If fmt is nullptr will space-separate the arguments like python print.
592  template<typename... Args>
593  size_t format(const char *fmt, const Args &...args)
594  {
595  clear();
596  return appendFormat(fmt, {args...});
597  }
598  /// Append to the work buffer using the same formatting as UTformat.
599  /// Returns the size of the appended portion, in bytes.
600  /// If fmt is nullptr will space-separate the arguments like python print.
601  template<typename... Args>
602  size_t appendFormat(const char *fmt, const Args &...args)
603  {
604  return appendFormat(fmt, {args...});
605  }
606  size_t appendFormat(const char *fmt, std::initializer_list<UT::Format::ArgValue> args);
607 
608  // These tack stuff to the end of the buffer.
610  void append(char character)
611  {
612  if (myLockCount) { UT_ASSERT(0); return; }
613  UT_ASSERT_P(isNullTerminated());
614  myLength++;
615  growBufferIfNeeded();
616  myBuffer[myLength - 1] = character;
617  myBuffer[myLength] = '\0';
618  }
619 
620  void printMemory(int64 mem) { clear(); appendPrintMemory(mem); }
621  void appendPrintMemory(int64 mem);
622 
623  void append(exint n, char character)
624  {
625  if (myLockCount) { UT_ASSERT(0); return; }
626  UT_ASSERT_P(isNullTerminated());
627  myLength += n;
628  growBufferIfNeeded();
629  for (int i = n; i > 0; i--)
630  myBuffer[myLength - i] = character;
631  myBuffer[myLength] = '\0';
632  }
633 
634  /// Append a single Unicode code point, converted to UTF8
635  void append(utf32 cp)
636  {
638  int len = UT_Unicode::convert(cp, buf, sizeof(buf));
639  if (!len)
640  return;
641 
642  if (myLockCount) { UT_ASSERT(0); return; }
643  UT_ASSERT_P(isNullTerminated());
644  myLength += len;
645  growBufferIfNeeded();
646  ::memcpy(myBuffer + myLength - len, buf, len);
647  myBuffer[myLength] = '\0';
648  }
649 
650  void append(const char *data, exint size)
651  {
652  if (myLockCount) { UT_ASSERT(0); return; }
653  UT_ASSERT_P(data);
654  UT_ASSERT_P(isNullTerminated());
655  myLength += size;
656  growBufferIfNeeded();
657  ::memcpy(myBuffer + myLength - size, data, size);
658  myBuffer[myLength] = '\0';
659  }
660 
662  void append(const char *str)
663  {
664  if( UTisstring(str) )
665  append(str, ::strlen(str));
666  }
667 
669  void append(const UT_String &str)
670  {
671  if (str.isstring())
672  append((const char *)str);
673  }
674 
676  void append(const UT_StringRef &str)
677  {
678  if (str.isstring())
679  append(str.buffer(), str.length());
680  }
681 
683  void append(const UT_StringLit &str)
684  {
685  append(str.buffer(), str.length());
686  }
687 
688  void append(const UT_StringArray &strs, const UT_StringRef &sep);
689 
691  void append(const UT_WorkBuffer &wb)
692  {
693  append( wb.buffer(), wb.length() );
694  }
695 
697  void append(const UT_StringView &view)
698  {
699  // Avoid assertion if view is nullptr by testing for emptiness
700  if (!view.isEmpty())
701  append(view.data(), view.length());
702  }
703 
704  void append(const UT_Digits&);
705 
707  UT_WorkBuffer &operator+=(const char *str)
708  {
709  append(str);
710  return *this;
711  }
712 
715  {
716  append(str);
717  return *this;
718  }
719 
722  {
723  append(wb);
724  return *this;
725  }
726 
729  {
730  append(str);
731  return *this;
732  }
733 
736  {
737  append(str);
738  return *this;
739  }
740 
743  {
744  append(digits);
745  return *this;
746  }
747 
748  void prepend(char character)
749  {
750  if (myLockCount) { UT_ASSERT(0); return; }
751  UT_ASSERT_P(isNullTerminated());
752  myLength++;
753  growBufferIfNeeded();
754  ::memmove(myBuffer+1, myBuffer, myLength);
755  myBuffer[0] = character;
756  }
757  void prepend(const char *data, exint size)
758  {
759  if (myLockCount) { UT_ASSERT(0); return; }
760  UT_ASSERT_P(data);
761  UT_ASSERT_P(isNullTerminated());
762  myLength += size;
763  growBufferIfNeeded();
764  ::memmove(myBuffer+size, myBuffer, myLength+1 - size);
765  ::memcpy(myBuffer, data, size);
766  }
768  void prepend(const char *str)
769  {
770  UT_ASSERT_P(str);
771  prepend(str, ::strlen(str));
772  }
773 
775  void prepend(const UT_String &str)
776  {
777  if (str.isstring())
778  prepend((const char *)str);
779  }
781  void prepend(const UT_StringRef &str)
782  {
783  if (str)
784  prepend(str.buffer(), str.length());
785  }
786 
787  /// Insert @c slen characters from @c str, at location @c pos. If @c pos
788  /// exceeds the current length, the position is truncated and to an append.
789  void insert(exint pos, const char* str, exint slen);
790 
791  /// Erase @c len characters from location @c pos in the string.
792  void erase(exint pos, exint len);
793 
794  void rewind() { backup(myLength); }
795 
796  /// Rewind by the given length
798  void backup(exint by_length)
799  {
800  if (myLockCount) { UT_ASSERT(0); return; }
801  UT_ASSERT_P(isNullTerminated());
802  UT_ASSERT_P(by_length >= 0);
803  myLength -= by_length;
804  UT_ASSERT(myLength >= 0);
805  myBuffer[myLength] = '\0';
806  }
807 
808  /// Truncate the buffer to the specified length. Truncating to 0 is
809  /// identical to clear().
811  void truncate(exint new_length)
812  {
813  if (new_length >= myLength)
814  {
815  UT_ASSERT(0 && "Truncating beyond buffer extent");
816  return;
817  }
818  backup(myLength-new_length);
819  }
820 
821  // Delete characters off the end of the string until we hit the
822  // requested character.
823  void backupTo(char c)
824  {
825  if (myLockCount) { UT_ASSERT(0); return; }
826  UT_ASSERT_P(isNullTerminated());
827  while( myLength > 0 && myBuffer[myLength-1] != c )
828  myLength--;
829  myBuffer[myLength] = '\0';
830  }
831 
832  void advance(exint by_length)
833  {
834  if (myLockCount) { UT_ASSERT(0); return; }
835  UT_ASSERT_P(isNullTerminated());
836  UT_ASSERT_P(by_length >= 0);
837  myLength -= by_length;
838  UT_ASSERT(myLength >= 0);
839  for (int i=0; i<myLength; i++)
840  myBuffer[i] = myBuffer[by_length+i];
841  myBuffer[myLength] = '\0';
842  }
843 
844  // Finds the 'occurance_number'-th occurance of char c in the string.
846  const char *findChar(char c, int occurance_number = 1) const
847  {
848  return findCharFrom(c, 0, occurance_number);
849  }
850  // Same as findChar, but searches from the end of the string.
851  const char *lastChar(char c, int occurance_number = 1) const
852  {
853  if (myLockCount) { UT_ASSERT(0); return NULL; }
854 
855  UT_ASSERT_P(isNullTerminated());
856 
857  for (exint i = myLength; i --> 0;)
858  {
859  if(c == myBuffer[i])
860  {
861  occurance_number--;
862  if(occurance_number <= 0)
863  {
864  return (myBuffer + i);
865  }
866  }
867  }
868 
869  return NULL;
870  }
871  // Same and findChar, bu searches from given position in the string.
872  const char *findCharFrom(char c, exint position,
873  int occurance_number = 1) const
874  {
875  if (myLockCount) { UT_ASSERT(0); return NULL; }
876 
877  UT_ASSERT_P(isNullTerminated());
878 
879  if (position < 0 || position >= myLength) { return NULL; }
880 
881  for(exint i = position; i < myLength; ++i)
882  {
883  if(c == myBuffer[i])
884  {
885  occurance_number--;
886  if(occurance_number <= 0)
887  {
888  return (myBuffer + i);
889  }
890  }
891  }
892 
893  return NULL;
894  }
895 
896  /// Adopt a string from an outside source. The passed string is now
897  /// owned by the workbuffer.
898  void adoptFromMalloc(char* data, exint length);
899 
900  void adoptFromCharArray(UT_Array<char>& data);
901 
902  /// Count the occurrences of the text in the current string
903  exint count(const char *needle) const;
904 
905  // Get the next token pointed at by string and advance string past the
906  // token. Returns whether or not a token was retrieved successfully.
907  // Note that string is modified!!!
908  bool getNextToken(const char *(&string),
909  const UT_String separators = " \t\n");
910 
911  // Harden the contents of the buffer into a UT_String.
912  void copyIntoString(UT_String &str) const;
913 
914  // Copy the contents into a fixed length buffer.
915  // TODO: Get rid of this method, since it encourages fixed-length buffers.
916  void copyIntoString(char *str, exint max_length) const;
917 
918  // Steal the contents of this work buffer into the string.
919  void stealIntoString(UT_String &str);
920 
921  // Steal the contents of this work buffer into the string.
922  // NB: Use UT_StringHolder move constructor/assignment instead
923  // UT_StringHolder foo(std::move(buffer));
924  // foo = std::move(buffer);
925  SYS_DEPRECATED(19.0)
926  void stealIntoStringHolder(UT_StringHolder &str);
927 
928  // Return a string containing the contents of this work buffer, preserving
929  // any null characters in it.
930  std::string toStdString() const
931  { return std::string(buffer(), length()); }
932 
933  // Strips the characters after comment_char from the buffer. This method
934  // goes to some effort to enusre that the comment_char is not preceded by
935  // a backslash or is not in a quoted string. Returns true if it found a
936  // comment and modified the buffer, and false otherwise.
937  bool stripComments(char comment_char = '#');
938 
939  /// Strips out all characters found in 'chars'. The string length will be
940  /// reduced by the number of characters removed. The number of characters
941  /// removed is returned.
942  int strip(const char *chars);
943 
944  /// Remove trailing whitespace lines
945  void removeTrailingSpaceLines();
946 
947  /// Remove trailing whitespace, return true if whitespace was removed.
948  bool removeTrailingSpace();
949 
950  /// Remove leading white space, return true if whitespace was removed.
951  bool removeLeadingSpace();
952 
953  /// Remove trailing digits, return true if some were removed.
954  bool removeTrailingDigits();
955 
956  /// Convert string to lower case
957  void lower();
958 
959  /// Convert string to upper case
960  void upper();
961 
962  /// Create a string of tabs & spaces which represents the given indent
963  void makeIndentString(exint indent, exint tabstop=8);
964 
965  /// Remove the first n characters.
967  {
968  if (n < myLength)
969  {
970  myLength -= n;
971  ::memmove(myBuffer, myBuffer + n, myLength);
972  }
973  else
974  myLength = 0;
975 
976  myBuffer[myLength] = '\0';
977  }
978 
979  /// Replaces up to 'count' occurrences of 'find' with 'replacement',
980  /// and returns the number of substitutions that occurred.
981  /// If 'count' <= 0, all occurrences will be replaced.
982  int substitute(const char *find, const char *replacement, int count = -1);
983 
984  /// Convenience version of substitute() for all or single occurrence.
985  SYS_DEPRECATED_REPLACE(19.5, "Use 'count' variant")
986  int substitute(const char *find, const char *replacement, bool all)
987  {
988  return substitute(find, replacement, !all ? 1 : -1);
989  }
990 
991  /// Given from_name which is assumed to fit from_pattern, any assigned
992  /// wildcards are subsitituted in to_pattern, writing the result to this.
993  /// The wildcards may also be indexed. For example:
994  ///
995  /// to_pattern = b* from_name = apple from_pattern = a*le
996  /// ---> this = bpp
997  ///
998  /// to_pattern = *(1)_to_*(0) from_name = a_to_b from_pattern = *_to_*
999  /// ---> this = b_to_a
1000  bool subPatterns(
1001  const char *to_pattern,
1002  const char *from_name,
1003  const char *from_pattern);
1004 
1005  /// UTF-16 / UTF-8 conversions.
1006 
1007  /// Set the work buffer to contain the UTF-8 representation of the incoming UTF-16 string.
1008  /// The UTF-16 string is assumed to be little-endian, unless prefixed with BOM that
1009  /// indicates endianness.
1010  /// The incoming string should be zero-word terminated.
1011  void setFromUTF16(const utf16 *str);
1012 
1013  /// Set the work buffer to contain a UTF-16LE (little endian) representation of the
1014  /// incoming UTF-8 string.
1015  /// The work buffer will be zero-word terminated.
1016  void setAsUTF16(const utf8 *str);
1017 
1018  /// Once set as UTF16-LE, get it back as such a pointer.
1020  const utf16* castToUTF16() const { return (const utf16*) myBuffer; }
1021 
1022  /// Lock buffer for `len` utf-16 characters.
1024  {
1025  return (utf16*)lock(offset, len*sizeof(utf16));
1026  }
1027 
1028  void swap(UT_WorkBuffer &other)
1029  {
1030  // Warn if we're about to swap locked buffers.
1031  UT_ASSERT(myLockCount==0);
1032 
1033  bool this_stack = (myBuffer == myStackBuffer);
1034  bool other_stack = (other.myBuffer == other.myStackBuffer);
1035 
1036  if (this_stack && other_stack)
1037  {
1038  // If both buffers are using the stack buffer, just swap the
1039  // buffer contents.
1040  size_t max_size = (myLength > other.myLength) ? myLength
1041  : other.myLength;
1042 
1043  UTswap(myStackBuffer, other.myStackBuffer, max_size + 1);
1044  }
1045  else if (this_stack && !other_stack)
1046  {
1047  ::memcpy(other.myStackBuffer, myStackBuffer, myLength + 1);
1048  myBuffer = other.myBuffer;
1049  other.myBuffer = other.myStackBuffer;
1050  }
1051  else if (!this_stack && other_stack)
1052  {
1053  ::memcpy(myStackBuffer, other.myStackBuffer, other.myLength + 1);
1054  other.myBuffer = myBuffer;
1055  myBuffer = myStackBuffer;
1056  }
1057  else
1058  UTswap(myBuffer, other.myBuffer);
1059  UTswap(myAllocatedSize, other.myAllocatedSize);
1060  UTswap(myLength, other.myLength);
1061  UTswap(myLockCount, other.myLockCount);
1062  }
1063 public:
1064  /// Iterator compatibility.
1066  const char *begin() const { return myBuffer; }
1068  const char *end() const { return myBuffer + myLength; }
1069 
1070 private:
1071 
1072  struct do_widen {};
1073  struct do_narrow {};
1074  /// Private constructors to allow for the Return Value Optimization
1075  /// @{
1077  UT_WorkBuffer(do_widen, const utf8 *str)
1078  : UT_WorkBuffer()
1079  {
1080  setAsUTF16(str);
1081  }
1083  UT_WorkBuffer(do_narrow, const utf16 *str)
1084  : UT_WorkBuffer()
1085  {
1086  setFromUTF16(str);
1087  }
1088  /// @}
1089 
1090  friend UT_API std::ostream &operator<<(std::ostream &os,
1091  const UT_WorkBuffer &buffer);
1092 
1093 private: // Data:
1094 
1095  char *myBuffer = myStackBuffer;
1096  exint myAllocatedSize = UT_INITIAL_BUFFER_SIZE;
1097  exint myLength = 0;
1098  int myLockCount = 0;
1099  char myStackBuffer[UT_INITIAL_BUFFER_SIZE];
1100 };
1101 
1102 /// Direct equality operators for UT_WorkBuffer <> UT_StringLit for speed to
1103 /// avoid casting down to const char*.
1104 /// @{
1105 static SYS_FORCE_INLINE bool
1106 operator==(const UT_WorkBuffer &buf, const UT_StringLit &lit)
1107 {
1108  return buf.operator==(lit.asRef());
1109 }
1110 static SYS_FORCE_INLINE bool
1111 operator==(const UT_StringLit &lit, const UT_WorkBuffer &buf)
1112 {
1113  return buf.operator==(lit.asRef());
1114 }
1115 static SYS_FORCE_INLINE bool
1116 operator!=(const UT_WorkBuffer &buf, const UT_StringLit &lit)
1117 {
1118  return buf.operator!=(lit.asRef());
1119 }
1120 static SYS_FORCE_INLINE bool
1121 operator!=(const UT_StringLit &lit, const UT_WorkBuffer &buf)
1122 {
1123  return buf.operator!=(lit.asRef());
1124 }
1125 /// @}
1126 
1127 static inline size_t
1128 format(char *buffer, size_t buffer_size, const UT_WorkBuffer &v)
1129 {
1130  if (!buffer)
1131  return v.length();
1132  else
1133  {
1134  size_t len = std::min(size_t(v.length()), buffer_size);
1135  ::memcpy(buffer, v.buffer(), len);
1136  return len;
1137  }
1138 }
1139 
1140 #endif
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
SYS_FORCE_INLINE void append(const UT_StringRef &str)
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2540
std::string upper(string_view a)
Return an all-upper case version of a (locale-independent).
Definition: strutil.h:402
GT_API const UT_StringHolder filename
SYS_FORCE_INLINE exint length() const
#define SYS_DEPRECATED(__V__)
SYS_FORCE_INLINE constexpr exint length() const
SYS_FORCE_INLINE void strcpy(const UT_StringRef &src)
void write(exint offset, const UT_StringHolder &src)
SYS_FORCE_INLINE exint getAllocatedSize() const
SYS_FORCE_INLINE char * operator*() const
void UTswap(T &a, T &b)
Definition: UT_Swap.h:35
SYS_FORCE_INLINE bool operator==(const UT_StringRef &str) const
void
Definition: png.h:1083
SYS_FORCE_INLINE bool operator==(const UT_String &str) const
SYS_FORCE_INLINE UT_WorkBuffer(const char *data, exint size)
Definition: UT_WorkBuffer.h:92
const GLdouble * v
Definition: glcorearb.h:837
SYS_FORCE_INLINE void append(const UT_StringView &view)
SYS_FORCE_INLINE void strncat(const char *src, exint len)
GLsizei const GLchar *const * string
Definition: glcorearb.h:814
unsigned short utf16
Definition: SYS_Types.h:56
SYS_FORCE_INLINE UT_WorkBuffer(const UT_StringRef &str)
SYS_FORCE_INLINE UT_WorkBuffer(const char *str)
Definition: UT_WorkBuffer.h:85
int64 exint
Definition: SYS_Types.h:125
void append(exint n, char character)
SYS_FORCE_INLINE const char * buffer() const
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:795
SYS_FORCE_INLINE void strcpy(const char *src)
SYS_FORCE_INLINE void release(bool recompute_length=false)
You can manually release the buffer.
#define UT_API
Definition: UT_API.h:14
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
const char * findCharFrom(char c, exint position, int occurance_number=1) const
SYS_FORCE_INLINE bool operator!=(const UT_StringRef &str) const
void append(const char *data, exint size)
const char * lastChar(char c, int occurance_number=1) const
unsigned long long uint64
Definition: SYS_Types.h:117
OIIO_FORCEINLINE vbool4 insert(const vbool4 &a, bool val)
Helper: substitute val for a[i].
Definition: simd.h:3436
SYS_FORCE_INLINE char last() const
utf16 * lockUTF16(exint offset=0, exint len=0)
Lock buffer for len utf-16 characters.
SYS_FORCE_INLINE void relock()
If you've manually released the lock, you can relock the buffer.
GLuint buffer
Definition: glcorearb.h:660
SYS_FORCE_INLINE void append(const UT_String &str)
SIM_API const UT_StringHolder all
SYS_FORCE_INLINE const char * data() const
SYS_FORCE_INLINE void append(const UT_StringLit &str)
void swap(UT_WorkBuffer &other)
void eraseHead(exint n)
Remove the first n characters.
SYS_FORCE_INLINE void append(const UT_WorkBuffer &wb)
SYS_FORCE_INLINE bool operator==(const UT_WorkBuffer &buf) const
#define SYS_DEPRECATED_REPLACE(__V__, __R__)
std::ostream & operator<<(std::ostream &ostr, const DataType &a)
Definition: DataType.h:133
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const UT_WorkBuffer &wb)
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE const char * data() const noexcept
Returns a pointer to the first character of a view.
SYS_FORCE_INLINE void append(const char *str)
A utility class to do read-only operations on a subset of an existing string.
Definition: UT_StringView.h:39
static const utf8 * convert(const utf8 *str, utf32 &cp)
size_t appendFormat(const char *fmt, const Args &...args)
#define UT_INITIAL_BUFFER_SIZE
Definition: UT_WorkBuffer.h:63
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE bool isEmpty() const
Returns true if the string is empty.
GLdouble n
Definition: glcorearb.h:2008
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE exint length() const
Returns the length of the string in bytes.
SYS_FORCE_INLINE void strcpy(const UT_WorkBuffer &src)
GLintptr offset
Definition: glcorearb.h:665
Definition: core.h:760
SYS_FORCE_INLINE void strcpy(const UT_StringView &src)
exint length() const
SYS_FORCE_INLINE const char * buffer() const
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const UT_Digits &digits)
SYS_FORCE_INLINE const char * end() const
SYS_FORCE_INLINE UT_WorkBuffer & operator=(const UT_WorkBuffer &other)
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:155
unsigned int utf32
Definition: SYS_Types.h:58
void printMemory(int64 mem)
#define SYS_PRINTF_CHECK_ATTRIBUTE(string_index, first_to_check)
Definition: SYS_Types.h:447
SYS_FORCE_INLINE const char * begin() const
Iterator compatibility.
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
GLint GLint GLsizei GLint GLenum format
Definition: glcorearb.h:108
SYS_FORCE_INLINE void prepend(const UT_StringRef &str)
SYS_FORCE_INLINE UT_WorkBuffer(const UT_StringView &view)
bool operator!=(const Mat3< T0 > &m0, const Mat3< T1 > &m1)
Inequality operator, does exact floating point comparisons.
Definition: Mat3.h:556
void prepend(char character)
SYS_FORCE_INLINE bool isEmpty() const
SYS_FORCE_INLINE char * strdup() const
long long int64
Definition: SYS_Types.h:116
static SYS_FORCE_INLINE UT_WorkBuffer widen(const utf8 *str)
SYS_FORCE_INLINE const char * findChar(char c, int occurance_number=1) const
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const UT_String &str)
SYS_FORCE_INLINE exint strlen() const
SYS_FORCE_INLINE bool operator!=(const UT_WorkBuffer &buf) const
SYS_FORCE_INLINE UT_WorkBuffer & operator=(const std::string &str)
SYS_FORCE_INLINE const char * c_str() const
SYS_FORCE_INLINE void strcpy(const UT_String &src)
#define UT_UTF8_MAX_ENCODING_LEN
Definition: UT_Unicode.h:19
size_t SYSstrlcpy(char *dest, const char *src, size_t size)
Definition: SYS_String.h:180
SYS_FORCE_INLINE char * string() const
SYS_FORCE_INLINE void prepend(const UT_String &str)
SYS_FORCE_INLINE char operator()(exint idx) const
SYS_FORCE_INLINE UT_WorkBuffer(const UT_WorkBuffer &other)
SYS_FORCE_INLINE void strcat(const char *src)
SYS_FORCE_INLINE void truncate(exint new_length)
SYS_FORCE_INLINE const utf16 * castToUTF16() const
Once set as UTF16-LE, get it back as such a pointer.
auto reserve(std::back_insert_iterator< Container > it, size_t n) -> checked_ptr< typename Container::value_type >
Definition: format.h:357
SYS_FORCE_INLINE const UT_StringRef & asRef() const
void append(utf32 cp)
Append a single Unicode code point, converted to UTF8.
SYS_FORCE_INLINE int strcmp(const char *src) const
static SYS_FORCE_INLINE UT_WorkBuffer narrow(const utf16 *str)
GLsizeiptr size
Definition: glcorearb.h:664
SYS_FORCE_INLINE UT_WorkBuffer & operator=(const char *str)
SYS_FORCE_INLINE bool isstring() const
SYS_FORCE_INLINE void backup(exint by_length)
Rewind by the given length.
void write(exint offset, const char *src)
SYS_FORCE_INLINE UT_WorkBuffer(const UT_String &str)
Definition: UT_WorkBuffer.h:99
SYS_FORCE_INLINE AutoLock(UT_WorkBuffer &buf)
void backupTo(char c)
SYS_FORCE_INLINE bool operator==(const char *str) const
SYS_FORCE_INLINE UT_WorkBuffer(const UT_StringLit &str)
std::string lower(string_view a)
Return an all-upper case version of a (locale-independent).
Definition: strutil.h:395
void advance(exint by_length)
SYS_FORCE_INLINE bool operator!=(const char *str) const
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const char *str)
SIM_API const UT_StringHolder position
SYS_FORCE_INLINE bool UTisstring(const char *s)
SYS_FORCE_INLINE void append(char character)
Type-safe formatting, modeled on the Python str.format function.
void prepend(const char *data, exint size)
virtual bool readFile(GA_Detail &g, const char *filename, const GA_LoadOptions *opts, UT_StringArray *errors) const
Class which defines an I/O interface to save/load geometry.
**If you just want to fire and args
Definition: thread.h:609
auto vsprintf(const S &fmt, basic_format_args< basic_printf_context_t< type_identity_t< Char >>> args) -> std::basic_string< Char >
Definition: printf.h:554
Definition: core.h:982
bool isstring() const
Definition: UT_String.h:691
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
SYS_FORCE_INLINE ~UT_WorkBuffer()
SYS_FORCE_INLINE void clear()
char utf8
Definition: SYS_Types.h:52
SYS_FORCE_INLINE constexpr const char * buffer() const
SYS_FORCE_INLINE ~AutoLock()
#define const
Definition: zconf.h:214
auto sprintf(const S &fmt, const T &...args) -> std::basic_string< Char >
Definition: printf.h:574
string_view OIIO_UTIL_API strip(string_view str, string_view chars=string_view())
SYS_FORCE_INLINE char first() const
void write(T &out, bool v)
Definition: ImfXdr.h:287
SYS_FORCE_INLINE bool operator!=(const UT_String &str) const
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const UT_StringRef &str)
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const std::string &str)
Converts a double or float or half to the shortest accurate decimal possible.
Definition: UT_Digits.h:22
bool operator==(const Mat3< T0 > &m0, const Mat3< T1 > &m1)
Equality operator, does exact floating point comparisons.
Definition: Mat3.h:542
SYS_FORCE_INLINE void write(exint offset, char c)
GLint GLsizei count
Definition: glcorearb.h:405
SYS_FORCE_INLINE bool isstring() const
Definition: format.h:895
Definition: format.h:2459
SYS_FORCE_INLINE void prepend(const char *str)
SYS_FORCE_INLINE void strncpy(const char *src, exint maxlen)
SYS_FORCE_INLINE int strncmp(const char *src, exint n) const
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2089
GLenum src
Definition: glcorearb.h:1793
SYS_FORCE_INLINE UT_WorkBuffer()
Definition: UT_WorkBuffer.h:79