1 // -*- related-file-name: "../../liblcdf/straccum.cc" -*-
2 #ifndef LCDF_STRACCUM_HH
3 #define LCDF_STRACCUM_HH
4 #include <string.h>
5 #include <assert.h>
6 #include <lcdf/string.hh>
7 #if HAVE_PERMSTRING
8 # include <lcdf/permstr.hh>
9 #endif
10 #if __GNUC__ > 4
11 # define LCDF_SNPRINTF_ATTR __attribute__((__format__(__printf__, 3, 4)))
12 #else
13 # define LCDF_SNPRINTF_ATTR /* nothing */
14 #endif
15 template<typename T> class Vector;
16 
17 /** @file <lcdf/straccum.hh>
18     @brief Click's StringAccum class, used to construct Strings efficiently from pieces.
19 */
20 
21 class StringAccum { public:
22 
23     /** @brief Construct an empty StringAccum (with length 0). */
StringAccum()24     StringAccum()
25 	: _s(0), _len(0), _cap(0) {
26     }
27 
28     /** @brief Construct a StringAccum with room for at least @a capacity
29      * characters.
30      * @param capacity initial capacity
31      *
32      * If @a capacity <= 0, the StringAccum is created empty.  If @a capacity
33      * is too large (so that @a capacity bytes of memory can't be allocated),
34      * the StringAccum falls back to a smaller capacity (possibly zero). */
35     explicit inline StringAccum(int capacity);
36 
37     /** @brief Construct a StringAccum containing the characters in @a s. */
StringAccum(const char * cstr)38     explicit inline StringAccum(const char *cstr)
39 	: _s(0), _len(0), _cap(0) {
40 	append(cstr);
41     }
42 
43     /** @brief Construct a StringAccum containing the characters in @a s. */
StringAccum(const char * s,int len)44     inline StringAccum(const char *s, int len)
45 	: _s(0), _len(0), _cap(0) {
46 	append(s, len);
47     }
48 
49     /** @brief Construct a StringAccum containing the characters in @a str. */
StringAccum(const String & str)50     StringAccum(const String &str)
51 	: _s(0), _len(0), _cap(0) {
52 	append(str.begin(), str.end());
53     }
54 
55     /** @brief Construct a StringAccum containing a copy of @a x. */
StringAccum(const StringAccum & x)56     StringAccum(const StringAccum &x)
57 	: _s(0), _len(0), _cap(0) {
58 	append(x.data(), x.length());
59     }
60 
61     /** @brief Destroy a StringAccum, freeing its memory. */
~StringAccum()62     ~StringAccum() {
63 	if (_cap > 0)
64 	    delete[] (_s - MEMO_SPACE);
65     }
66 
67 
68     /** @brief Return the contents of the StringAccum.
69      * @return The StringAccum's contents.
70      *
71      * The return value is null if the StringAccum is empty or out-of-memory.
72      * The returned data() value points to writable memory (unless the
73      * StringAccum itself is const). */
data() const74     inline const char *data() const {
75 	return reinterpret_cast<const char *>(_s);
76     }
77 
78     /** @overload */
data()79     inline char *data() {
80 	return reinterpret_cast<char *>(_s);
81     }
82 
udata() const83     inline const unsigned char* udata() const {
84 	return _s;
85     }
86 
udata()87     inline unsigned char* udata() {
88 	return _s;
89     }
90 
91     /** @brief Return true iff the StringAccum is empty or out-of-memory. */
empty() const92     bool empty() const {
93 	return _len == 0;
94     }
95 
96     /** @brief Return the length of the StringAccum. */
length() const97     int length() const {
98 	return _len;
99     }
100 
101     /** @brief Return the StringAccum's current capacity.
102      *
103      * The capacity is the maximum length the StringAccum can hold without
104      * incurring a memory allocation.  Returns -1 for out-of-memory
105      * StringAccums. */
capacity() const106     int capacity() const {
107 	return _cap;
108     }
109 
110 
111     typedef const char *const_iterator;
112     typedef char *iterator;
113 
114     /** @brief Return an iterator for the first character in the StringAccum.
115      *
116      * StringAccum iterators are simply pointers into string data, so they are
117      * quite efficient.  @sa StringAccum::data */
begin() const118     inline const_iterator begin() const {
119 	return reinterpret_cast<char *>(_s);
120     }
121 
122     /** @overload */
begin()123     inline iterator begin() {
124 	return reinterpret_cast<char *>(_s);
125     }
126 
127     /** @brief Return an iterator for the end of the StringAccum.
128      *
129      * The return value points one character beyond the last character in the
130      * StringAccum. */
end() const131     inline StringAccum::const_iterator end() const {
132 	return reinterpret_cast<char *>(_s + _len);
133     }
134 
135     /** @overload */
end()136     inline iterator end() {
137 	return reinterpret_cast<char *>(_s + _len);
138     }
139 
140 
141     typedef int (StringAccum::*unspecified_bool_type)() const;
142 
143     /** @brief Return true iff the StringAccum contains characters.
144      *
145      * Returns false for empty and out-of-memory StringAccums. */
operator unspecified_bool_type() const146     operator unspecified_bool_type() const {
147 	return _len != 0 ? &StringAccum::capacity : 0;
148     }
149 
150     /** @brief Return true iff the StringAccum does not contain characters.
151      *
152      * Returns true for empty and out-of-memory StringAccums. */
operator !() const153     bool operator!() const {
154 	return _len == 0;
155     }
156 
157     /** @brief Return true iff the StringAccum is out-of-memory. */
out_of_memory() const158     bool out_of_memory() const {
159 	return _cap < 0;
160     }
161 
162 
163     /** @brief Null-terminate this StringAccum and return its data.
164      *
165      * Note that the null character does not contribute to the StringAccum's
166      * length(), and later append() and similar operations can overwrite it.
167      * If appending the null character fails, the StringAccum becomes
168      * out-of-memory and the returned value is a null string. */
169     const char *c_str();
170 
171 
172     /** @brief Return the <a>i</a>th character in the string.
173      * @param i character index
174      * @pre 0 <= @a i < length() */
operator [](int i) const175     char operator[](int i) const {
176 	assert((unsigned) i < (unsigned) _len);
177 	return static_cast<char>(_s[i]);
178     }
179 
180     /** @brief Return a reference to the <a>i</a>th character in the string.
181      * @param i character index
182      * @pre 0 <= @a i < length() */
operator [](int i)183     char &operator[](int i) {
184 	assert((unsigned) i < (unsigned) _len);
185 	return reinterpret_cast<char &>(_s[i]);
186     }
187 
188     /** @brief Return the first character in the string.
189      * @pre length() > 0 */
front() const190     char front() const {
191 	assert(_len > 0);
192 	return static_cast<char>(_s[0]);
193     }
194 
195     /** @brief Return a reference to the first character in the string.
196      * @pre length() > 0 */
front()197     char &front() {
198 	assert(_len > 0);
199 	return reinterpret_cast<char &>(_s[0]);
200     }
201 
202     /** @brief Return the last character in the string.
203      * @pre length() > 0 */
back() const204     char back() const {
205 	assert(_len > 0);
206 	return static_cast<char>(_s[_len - 1]);
207     }
208 
209     /** @brief Return a reference to the last character in the string.
210      * @pre length() > 0 */
back()211     char &back() {
212 	assert(_len > 0);
213 	return reinterpret_cast<char &>(_s[_len - 1]);
214     }
215 
216 
217     /** @brief Clear the StringAccum's comments.
218      *
219      * All characters in the StringAccum are erased.  Also resets the
220      * StringAccum's out-of-memory status. */
clear()221     inline void clear() {
222 	if (_cap < 0) {
223 	    _cap = 0;
224 	    _s = 0;
225 	}
226 	_len = 0;
227     }
228 
229 
230     /** @brief Reserve space for at least @a n characters.
231      * @return a pointer to at least @a n characters, or null if allocation
232      * fails
233      * @pre @a n >= 0
234      *
235      * reserve() does not change the string's length(), only its capacity().
236      * In a frequent usage pattern, code calls reserve(), passing an upper
237      * bound on the characters that could be written by a series of
238      * operations.  After writing into the returned buffer, adjust_length() is
239      * called to account for the number of characters actually written.
240      *
241      * On failure, null is returned and errno is set to ENOMEM. */
reserve(int n)242     inline char *reserve(int n) {
243 	assert(n >= 0);
244 	if (_len + n <= _cap)
245 	    return reinterpret_cast<char *>(_s + _len);
246 	else
247 	    return grow(_len + n);
248     }
249 
250     /** @brief Set the StringAccum's length to @a len.
251      * @param len new length in characters
252      * @pre 0 <= @a len <= capacity()
253      * @sa adjust_length */
set_length(int len)254     inline void set_length(int len) {
255 	assert(len >= 0 && _len <= _cap);
256 	_len = len;
257     }
258 
259     /** @brief Set the StringAccum's length to @a len.
260      * @pre @a len >= 0
261      * @return 0 on success, -ENOMEM on failure */
262     int resize(int len);
263 
264     /** @brief Adjust the StringAccum's length.
265      * @param delta  length adjustment
266      * @pre If @a delta > 0, then length() + @a delta <= capacity().
267      *      If @a delta < 0, then length() + delta >= 0.
268      *
269      * The StringAccum's length after adjust_length(@a delta) equals its old
270      * length plus @a delta.  Generally adjust_length() is used after a call
271      * to reserve().  @sa set_length */
adjust_length(int delta)272     inline void adjust_length(int delta) {
273 	assert(_len + delta >= 0 && _len + delta <= _cap);
274 	_len += delta;
275     }
276 
277     /** @brief Reserve space and adjust length in one operation.
278      * @param nadjust number of characters to reserve and adjust length
279      * @param nreserve additional characters to reserve
280      * @pre @a nadjust >= 0 and @a nreserve >= 0
281      *
282      * This operation combines the effects of reserve(@a nadjust + @a
283      * nreserve) and adjust_length(@a nadjust).  Returns the result of the
284      * reserve() call. */
extend(int nadjust,int nreserve=0)285     inline char *extend(int nadjust, int nreserve = 0) {
286 	assert(nadjust >= 0 && nreserve >= 0);
287 	if (_len + nadjust + nreserve <= _cap) {
288 	    char *x = reinterpret_cast<char *>(_s + _len);
289 	    _len += nadjust;
290 	    return x;
291 	} else
292 	    return hard_extend(nadjust, nreserve);
293     }
294 
295 
296     /** @brief Remove characters from the end of the StringAccum.
297      * @param n number of characters to remove
298      * @pre @a n >= 0 and @a n <= length()
299      *
300      * Same as adjust_length(-@a n). */
pop_back(int n=1)301     inline void pop_back(int n = 1) {
302 	assert(n >= 0 && _len >= n);
303 	_len -= n;
304     }
305 
306 
307 
308     /** @brief Append character @a c to the StringAccum.
309      * @param c character to append */
append(char c)310     inline void append(char c) {
311 	if (_len < _cap || grow(_len))
312 	    _s[_len++] = c;
313     }
314     /** @overload */
append(unsigned char c)315     inline void append(unsigned char c) {
316 	append(static_cast<char>(c));
317     }
318 
319     /** @brief Append @a len copies of character @a c to the StringAccum. */
320     void append_fill(int c, int len);
321 
322     /** @brief Append the UTF-8 encoding of Unicode character @a ch. */
append_utf8(unsigned ch)323     inline void append_utf8(unsigned ch) {
324 	if (ch < 0x80)
325 	    append((unsigned char) ch);
326 	else
327 	    append_utf8_hard(ch);
328     }
329 
330     /** @brief Append the null-terminated C string @a s to this StringAccum.
331      * @param s data to append */
332     void append(const char *s);
333     /** @brief Append the first @a len characters of @a s to this StringAccum.
334      * @param s data to append
335      * @param len length of data
336      * @pre @a len >= 0 */
337     inline void append(const char *s, int len);
338     /** @overload */
339     inline void append(const unsigned char *s, int len);
340 
341     /** @brief Append the data from @a begin to @a end to the end of this
342      * StringAccum.
343      *
344      * Does nothing if @a begin >= @a end. */
345     inline void append(const char *begin, const char *end);
346     /** @overload */
347     inline void append(const unsigned char *begin, const unsigned char *end);
348 
349     // word joining
350     void append_break_lines(const String &text, int linelen, const String &leftmargin = String());
351 
352     /** @brief Append result of snprintf() to this StringAccum.
353      * @param n maximum number of characters to print
354      * @param format format argument to snprintf()
355      *
356      * The terminating null character is not appended to the string.
357      *
358      * @note The safe vsnprintf() variant is called if it exists.  It does in
359      * the Linux kernel, and on modern Unix variants.  However, if it does not
360      * exist on your machine, then this function is actually unsafe, and you
361      * should make sure that the printf() invocation represented by your
362      * arguments will never write more than @a n characters, not including the
363      * terminating null. */
364     StringAccum &snprintf(int n, const char *format, ...) LCDF_SNPRINTF_ATTR;
365 
366 
367     /** @brief Return a String object with this StringAccum's contents.
368      *
369      * This operation donates the StringAccum's memory to the returned String.
370      * After a call to take_string(), the StringAccum object becomes empty,
371      * and any future append() operations may cause memory allocations.  If
372      * the StringAccum is out-of-memory, the returned String is also
373      * out-of-memory, but the StringAccum's out-of-memory state is reset. */
374     String take_string();
375 
376 
377     /** @brief Assign this StringAccum to @a x. */
operator =(const StringAccum & x)378     StringAccum &operator=(const StringAccum &x) {
379 	if (&x != this) {
380 	    if (out_of_memory())
381 		_s = 0, _cap = 0;
382 	    _len = 0;
383 	    append(x.data(), x.length());
384 	}
385 	return *this;
386     }
387 
388     /** @brief Swap this StringAccum's contents with @a x. */
389     void swap(StringAccum &x);
390 
391     // see also operator<< declarations below
392 
393   private:
394 
395     enum {
396 	MEMO_SPACE = String::MEMO_SPACE
397     };
398 
399     unsigned char *_s;
400     int _len;
401     int _cap;
402 
403     char *grow(int);
404     void assign_out_of_memory();
405 
406     char *hard_extend(int nadjust, int nreserve);
407     void hard_append(const char *s, int len);
408     void append_utf8_hard(unsigned ch);
409 
410     friend StringAccum &operator<<(StringAccum &sa, const char *s);
411     friend StringAccum &operator<<(StringAccum &sa, const String &str);
412 #if HAVE_PERMSTRING
413     friend StringAccum &operator<<(StringAccum &sa, PermString s);
414 #endif
415 
416 };
417 
418 inline StringAccum &operator<<(StringAccum &, char);
419 inline StringAccum &operator<<(StringAccum &, unsigned char);
420 inline StringAccum &operator<<(StringAccum &, const char *);
421 inline StringAccum &operator<<(StringAccum &, const String &);
422 inline StringAccum &operator<<(StringAccum &, const StringAccum &);
423 #ifdef HAVE_PERMSTRING
424 inline StringAccum &operator<<(StringAccum &, PermString);
425 #endif
426 
427 inline StringAccum &operator<<(StringAccum &, bool);
428 inline StringAccum &operator<<(StringAccum &, short);
429 inline StringAccum &operator<<(StringAccum &, unsigned short);
430 inline StringAccum &operator<<(StringAccum &, int);
431 inline StringAccum &operator<<(StringAccum &, unsigned);
432 StringAccum &operator<<(StringAccum &, long);
433 StringAccum &operator<<(StringAccum &, unsigned long);
434 StringAccum &operator<<(StringAccum &, double);
435 
436 
437 inline
StringAccum(int capacity)438 StringAccum::StringAccum(int capacity)
439     : _len(0)
440 {
441     assert(capacity >= 0);
442     if (capacity
443 	&& (_s = new unsigned char[capacity + MEMO_SPACE])) {
444 	_s += MEMO_SPACE;
445 	_cap = capacity;
446     } else {
447 	_s = 0;
448 	_cap = 0;
449     }
450 }
451 
append(const char * s,int len)452 inline void StringAccum::append(const char *s, int len) {
453     assert(len >= 0);
454     if (_len + len <= _cap) {
455 	memcpy(_s + _len, s, len);
456 	_len += len;
457     } else
458 	hard_append(s, len);
459 }
460 
append(const unsigned char * s,int len)461 inline void StringAccum::append(const unsigned char *s, int len) {
462     append(reinterpret_cast<const char *>(s), len);
463 }
464 
append(const char * begin,const char * end)465 inline void StringAccum::append(const char *begin, const char *end) {
466     if (begin < end)
467 	append(begin, end - begin);
468 }
469 
append(const unsigned char * begin,const unsigned char * end)470 inline void StringAccum::append(const unsigned char *begin, const unsigned char *end) {
471     if (begin < end)
472 	append(begin, end - begin);
473 }
474 
475 /** @relates StringAccum
476     @brief Append character @a c to StringAccum @a sa.
477     @return @a sa
478     @note Same as @a sa.append(@a c). */
479 inline StringAccum &
operator <<(StringAccum & sa,char c)480 operator<<(StringAccum &sa, char c)
481 {
482     sa.append(c);
483     return sa;
484 }
485 
486 /** @relates StringAccum
487     @brief Append character @a c to StringAccum @a sa.
488     @return @a sa
489     @note Same as @a sa.append(@a c). */
490 inline StringAccum &
operator <<(StringAccum & sa,unsigned char c)491 operator<<(StringAccum &sa, unsigned char c)
492 {
493     sa.append(c);
494     return sa;
495 }
496 
497 /** @relates StringAccum
498     @brief Append null-terminated C string @a cstr to StringAccum @a sa.
499     @return @a sa
500     @note Same as @a sa.append(@a cstr). */
501 inline StringAccum &
operator <<(StringAccum & sa,const char * cstr)502 operator<<(StringAccum &sa, const char *cstr)
503 {
504     sa.append(cstr);
505     return sa;
506 }
507 
508 /** @relates StringAccum
509     @brief Append "true" or "false" to @a sa, depending on @a b.
510     @return @a sa */
511 inline StringAccum &
operator <<(StringAccum & sa,bool b)512 operator<<(StringAccum &sa, bool b)
513 {
514     static const char truefalse[] = "truefalse";
515     if (b)
516 	sa.append(truefalse, 4);
517     else
518 	sa.append(truefalse + 4, 5);
519     return sa;
520 }
521 
522 /** @relates StringAccum
523     @brief Append decimal representation of @a i to @a sa.
524     @return @a sa */
525 inline StringAccum &
operator <<(StringAccum & sa,short i)526 operator<<(StringAccum &sa, short i)
527 {
528     return sa << static_cast<long>(i);
529 }
530 
531 /** @relates StringAccum
532     @brief Append decimal representation of @a u to @a sa.
533     @return @a sa */
534 inline StringAccum &
operator <<(StringAccum & sa,unsigned short u)535 operator<<(StringAccum &sa, unsigned short u)
536 {
537     return sa << static_cast<unsigned long>(u);
538 }
539 
540 /** @relates StringAccum
541     @brief Append decimal representation of @a i to @a sa.
542     @return @a sa */
543 inline StringAccum &
operator <<(StringAccum & sa,int i)544 operator<<(StringAccum &sa, int i)
545 {
546     return sa << static_cast<long>(i);
547 }
548 
549 /** @relates StringAccum
550     @brief Append decimal representation of @a u to @a sa.
551     @return @a sa */
552 inline StringAccum &
operator <<(StringAccum & sa,unsigned u)553 operator<<(StringAccum &sa, unsigned u)
554 {
555     return sa << static_cast<unsigned long>(u);
556 }
557 
558 /** @relates StringAccum
559     @brief Append the contents of @a str to @a sa.
560     @return @a sa */
561 inline StringAccum &
operator <<(StringAccum & sa,const String & str)562 operator<<(StringAccum &sa, const String &str)
563 {
564     if (!str.out_of_memory())
565 	sa.hard_append(str.begin(), str.length());
566     else
567 	sa.assign_out_of_memory();
568     return sa;
569 }
570 
571 #ifdef HAVE_PERMSTRING
572 inline StringAccum &
operator <<(StringAccum & sa,PermString s)573 operator<<(StringAccum &sa, PermString s)
574 {
575     sa.append(s.c_str(), s.length());
576     return sa;
577 }
578 #endif
579 
580 /** @relates StringAccum
581     @brief Append the contents of @a sb to @a sa.
582     @return @a sa */
583 inline StringAccum &
operator <<(StringAccum & sa,const StringAccum & sb)584 operator<<(StringAccum &sa, const StringAccum &sb)
585 {
586     sa.append(sb.begin(), sb.end());
587     return sa;
588 }
589 
590 inline bool
operator ==(StringAccum & sa,const char * s)591 operator==(StringAccum &sa, const char *s)
592 {
593     return strcmp(sa.c_str(), s) == 0;
594 }
595 
596 inline bool
operator !=(StringAccum & sa,const char * s)597 operator!=(StringAccum &sa, const char *s)
598 {
599     return strcmp(sa.c_str(), s) != 0;
600 }
601 
602 #undef LCDF_SNPRINTF_ATTR
603 #endif
604