• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 // An attempt to provide some of the C++ string functionality in C.
9 // Function names generally match those of corresponding C++ string methods.
10 // All buffers are copied so operations are relatively expensive.
11 // Internal character strings are always NULL-terminated.
12 // All bool functions return true on success, false on failure.
13 
14 #ifndef UPB_IO_STRING_H_
15 #define UPB_IO_STRING_H_
16 
17 #include <stdarg.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #include "upb/mem/arena.h"
22 #include "upb/port/vsnprintf_compat.h"
23 
24 // Must be last.
25 #include "upb/port/def.inc"
26 
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30 
31 // Do not directly access the fields of this struct - use the accessors only.
32 // TODO: Add a small (16 bytes, maybe?) internal buffer so we can avoid
33 // hitting the arena for short strings.
34 typedef struct {
35   size_t size_;
36   size_t capacity_;
37   char* data_;
38   upb_Arena* arena_;
39 } upb_String;
40 
41 // Initialize an already-allocated upb_String object.
upb_String_Init(upb_String * s,upb_Arena * a)42 UPB_INLINE bool upb_String_Init(upb_String* s, upb_Arena* a) {
43   static const int kDefaultCapacity = 16;
44 
45   s->size_ = 0;
46   s->capacity_ = kDefaultCapacity;
47   s->data_ = (char*)upb_Arena_Malloc(a, kDefaultCapacity);
48   s->arena_ = a;
49   if (!s->data_) return false;
50   s->data_[0] = '\0';
51   return true;
52 }
53 
upb_String_Clear(upb_String * s)54 UPB_INLINE void upb_String_Clear(upb_String* s) {
55   s->size_ = 0;
56   s->data_[0] = '\0';
57 }
58 
upb_String_Data(const upb_String * s)59 UPB_INLINE char* upb_String_Data(const upb_String* s) { return s->data_; }
60 
upb_String_Size(const upb_String * s)61 UPB_INLINE size_t upb_String_Size(const upb_String* s) { return s->size_; }
62 
upb_String_Empty(const upb_String * s)63 UPB_INLINE bool upb_String_Empty(const upb_String* s) { return s->size_ == 0; }
64 
upb_String_Erase(upb_String * s,size_t pos,size_t len)65 UPB_INLINE void upb_String_Erase(upb_String* s, size_t pos, size_t len) {
66   if (pos >= s->size_) return;
67   char* des = s->data_ + pos;
68   if (pos + len > s->size_) len = s->size_ - pos;
69   char* src = des + len;
70   memmove(des, src, s->size_ - (src - s->data_) + 1);
71   s->size_ -= len;
72 }
73 
upb_String_Reserve(upb_String * s,size_t size)74 UPB_INLINE bool upb_String_Reserve(upb_String* s, size_t size) {
75   if (s->capacity_ <= size) {
76     const size_t new_cap = size + 1;
77     s->data_ =
78         (char*)upb_Arena_Realloc(s->arena_, s->data_, s->capacity_, new_cap);
79     if (!s->data_) return false;
80     s->capacity_ = new_cap;
81   }
82   return true;
83 }
84 
upb_String_Append(upb_String * s,const char * data,size_t size)85 UPB_INLINE bool upb_String_Append(upb_String* s, const char* data,
86                                   size_t size) {
87   if (s->capacity_ <= s->size_ + size) {
88     const size_t new_cap = 2 * (s->size_ + size) + 1;
89     if (!upb_String_Reserve(s, new_cap)) return false;
90   }
91 
92   memcpy(s->data_ + s->size_, data, size);
93   s->size_ += size;
94   s->data_[s->size_] = '\0';
95   return true;
96 }
97 
98 UPB_PRINTF(2, 0)
upb_String_AppendFmtV(upb_String * s,const char * fmt,va_list args)99 UPB_INLINE bool upb_String_AppendFmtV(upb_String* s, const char* fmt,
100                                       va_list args) {
101   size_t capacity = 1000;
102   char* buf = (char*)malloc(capacity);
103   bool out = false;
104   for (;;) {
105     const int n = _upb_vsnprintf(buf, capacity, fmt, args);
106     if (n < 0) break;
107     if (n < capacity) {
108       out = upb_String_Append(s, buf, n);
109       break;
110     }
111     capacity *= 2;
112     buf = (char*)realloc(buf, capacity);
113   }
114   free(buf);
115   return out;
116 }
117 
118 UPB_PRINTF(2, 3)
upb_String_AppendFmt(upb_String * s,const char * fmt,...)119 UPB_INLINE bool upb_String_AppendFmt(upb_String* s, const char* fmt, ...) {
120   va_list args;
121   va_start(args, fmt);
122   const bool ok = upb_String_AppendFmtV(s, fmt, args);
123   va_end(args);
124   return ok;
125 }
126 
upb_String_Assign(upb_String * s,const char * data,size_t size)127 UPB_INLINE bool upb_String_Assign(upb_String* s, const char* data,
128                                   size_t size) {
129   upb_String_Clear(s);
130   return upb_String_Append(s, data, size);
131 }
132 
upb_String_Copy(upb_String * des,const upb_String * src)133 UPB_INLINE bool upb_String_Copy(upb_String* des, const upb_String* src) {
134   return upb_String_Assign(des, src->data_, src->size_);
135 }
136 
upb_String_PushBack(upb_String * s,char ch)137 UPB_INLINE bool upb_String_PushBack(upb_String* s, char ch) {
138   return upb_String_Append(s, &ch, 1);
139 }
140 
141 #ifdef __cplusplus
142 } /* extern "C" */
143 #endif
144 
145 #include "upb/port/undef.inc"
146 
147 #endif /* UPB_IO_STRING_H_ */
148