1/**************************************************************************/
2/* string_buffer.h */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#ifndef STRING_BUFFER_H
32#define STRING_BUFFER_H
33
34#include "core/string/ustring.h"
35
36template <int SHORT_BUFFER_SIZE = 64>
37class StringBuffer {
38 char32_t short_buffer[SHORT_BUFFER_SIZE];
39 String buffer;
40 int string_length = 0;
41
42 _FORCE_INLINE_ char32_t *current_buffer_ptr() {
43 return static_cast<String &>(buffer).is_empty() ? short_buffer : buffer.ptrw();
44 }
45
46public:
47 StringBuffer &append(char32_t p_char);
48 StringBuffer &append(const String &p_string);
49 StringBuffer &append(const char *p_str);
50 StringBuffer &append(const char32_t *p_str, int p_clip_to_len = -1);
51
52 _FORCE_INLINE_ void operator+=(char32_t p_char) {
53 append(p_char);
54 }
55
56 _FORCE_INLINE_ void operator+=(const String &p_string) {
57 append(p_string);
58 }
59
60 _FORCE_INLINE_ void operator+=(const char *p_str) {
61 append(p_str);
62 }
63
64 _FORCE_INLINE_ void operator+=(const char32_t *p_str) {
65 append(p_str);
66 }
67
68 StringBuffer &reserve(int p_size);
69
70 int length() const;
71
72 String as_string();
73
74 double as_double();
75 int64_t as_int();
76
77 _FORCE_INLINE_ operator String() {
78 return as_string();
79 }
80};
81
82template <int SHORT_BUFFER_SIZE>
83StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(char32_t p_char) {
84 reserve(string_length + 2);
85 current_buffer_ptr()[string_length++] = p_char;
86 return *this;
87}
88
89template <int SHORT_BUFFER_SIZE>
90StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const String &p_string) {
91 return append(p_string.get_data());
92}
93
94template <int SHORT_BUFFER_SIZE>
95StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const char *p_str) {
96 int len = strlen(p_str);
97 reserve(string_length + len + 1);
98
99 char32_t *buf = current_buffer_ptr();
100 for (const char *c_ptr = p_str; *c_ptr; ++c_ptr) {
101 buf[string_length++] = *c_ptr;
102 }
103 return *this;
104}
105
106template <int SHORT_BUFFER_SIZE>
107StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const char32_t *p_str, int p_clip_to_len) {
108 int len = 0;
109 while ((p_clip_to_len < 0 || len < p_clip_to_len) && p_str[len]) {
110 ++len;
111 }
112 reserve(string_length + len + 1);
113 memcpy(&(current_buffer_ptr()[string_length]), p_str, len * sizeof(char32_t));
114 string_length += len;
115
116 return *this;
117}
118
119template <int SHORT_BUFFER_SIZE>
120StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::reserve(int p_size) {
121 if (p_size < SHORT_BUFFER_SIZE || p_size < buffer.size()) {
122 return *this;
123 }
124
125 bool need_copy = string_length > 0 && buffer.is_empty();
126 buffer.resize(next_power_of_2(p_size));
127 if (need_copy) {
128 memcpy(buffer.ptrw(), short_buffer, string_length * sizeof(char32_t));
129 }
130
131 return *this;
132}
133
134template <int SHORT_BUFFER_SIZE>
135int StringBuffer<SHORT_BUFFER_SIZE>::length() const {
136 return string_length;
137}
138
139template <int SHORT_BUFFER_SIZE>
140String StringBuffer<SHORT_BUFFER_SIZE>::as_string() {
141 current_buffer_ptr()[string_length] = '\0';
142 if (buffer.is_empty()) {
143 return String(short_buffer);
144 } else {
145 buffer.resize(string_length + 1);
146 return buffer;
147 }
148}
149
150template <int SHORT_BUFFER_SIZE>
151double StringBuffer<SHORT_BUFFER_SIZE>::as_double() {
152 current_buffer_ptr()[string_length] = '\0';
153 return String::to_float(current_buffer_ptr());
154}
155
156template <int SHORT_BUFFER_SIZE>
157int64_t StringBuffer<SHORT_BUFFER_SIZE>::as_int() {
158 current_buffer_ptr()[string_length] = '\0';
159 return String::to_int(current_buffer_ptr());
160}
161
162#endif // STRING_BUFFER_H
163