1 /*
2  * Geario - A cross-platform abstraction library with asynchronous I/O.
3  *
4  * Copyright (C) 2021-2022 Kerisy.com
5  *
6  * Website: https://www.kerisy.com
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module geario.util.StringBuilder;
13 
14 import geario.util.Appendable;
15 
16 import std.ascii;
17 import std.algorithm;
18 import std.array;
19 import std.exception;
20 import std.conv;
21 import std.string;
22 import std.uni;
23 
24 /**
25  * 
26  */
27 class StringBuilder : Appendable {
28     Appender!(byte[]) _buffer;
29 
30     this(size_t capacity = 16) {
31         _buffer.reserve(capacity);
32     }
33 
34     this(string data, size_t capacity = 16) {
35         _buffer.reserve(capacity);
36         this.Append(data);
37     }
38 
39     // void Append(in char[] s)
40     // {
41     //     _buffer.put(cast(string) s);
42     // }
43 
44     void Reset() {
45         _buffer.clear();
46     }
47 
48     StringBuilder SetCharAt(int index, char c) {
49         _buffer.data[index] = c;
50         return this;
51     }
52 
53     StringBuilder Append(char s) {
54         _buffer.put(s);
55         return this;
56     }
57 
58     StringBuilder Append(bool s) {
59         Append(s.to!string());
60         return this;
61     }
62 
63     StringBuilder Append(int i) {
64         _buffer.put(cast(byte[])(to!(string)(i)));
65         return this;
66     }
67 
68     StringBuilder Append(float f) {
69         _buffer.put(cast(byte[])(to!(string)(f)));
70         return this;
71     }
72 
73     StringBuilder Append(const(char)[] s) {
74         _buffer.put(cast(byte[]) s);
75         return this;
76     }
77 
78     StringBuilder Append(const(char)[] s, int start, int end) {
79         _buffer.put(cast(byte[]) s[start .. end]);
80         return this;
81     }
82 
83     // StringBuilder Append(byte[] s, int start, int end)
84     // {
85     //     _buffer.put(s[start..end]);
86     //     return this;
87     // }
88 
89     /// Warning: It's different from the previous one.
90     StringBuilder Append(byte[] str, int offset, int len) {
91         _buffer.put(str[offset .. offset + len]);
92         return this;
93     }
94 
95     StringBuilder Append(Object obj) {
96         _buffer.put(cast(byte[])(obj.toString));
97         return this;
98     }
99 
100     int Length() {
101         return cast(int) _buffer.data.length;
102     }
103 
104     void SetLength(int newLength) {
105         _buffer.shrinkTo(newLength);
106         // if (newLength < 0)
107         //     throw new StringIndexOutOfBoundsException(to!string(newLength));
108         // EnsureCapacityInternal(newLength);
109 
110         // if (count < newLength) {
111         //     Arrays.fill(value, count, newLength, '\0');
112         // }
113 
114         // count = newLength;
115     }
116 
117     private void EnsureCapacityInternal(size_t minimumCapacity) {
118         // overflow-conscious code
119         // if (minimumCapacity > value.length) {
120         //     value = Arrays.copyOf(value,
121         //             newCapacity(minimumCapacity));
122         // }
123     }
124 
125     int LastIndexOf(string s) {
126         string source = cast(string) _buffer.data;
127         return cast(int) source.lastIndexOf(s);
128     }
129 
130     char CharAt(int idx) {
131         if (Length() > idx)
132             return _buffer.data[idx];
133         else
134             return ' ';
135     }
136 
137     StringBuilder DeleteCharAt(int index) {
138         if (index < Length()) {
139             auto data = _buffer.data.idup;
140             for (int i = index + 1; i < data.length; i++) {
141                 _buffer.data[i - 1] = data[i];
142             }
143             SetLength(cast(int)(data.length - 1));
144         }
145         return this;
146     }
147 
148     StringBuilder Insert(int index, char c) {
149         if (index <= Length()) {
150             auto data = _buffer.data.idup;
151             for (int i = index; i < data.length; i++) {
152                 _buffer.data[i + 1] = data[i];
153             }
154             _buffer.data[index] = c;
155             SetLength(cast(int)(data.length + 1));
156         }
157         return this;
158     }
159 
160     StringBuilder Insert(int index, long data) {
161         auto bytes = cast(byte[])(to!string(data));
162         auto start = index;
163         foreach (b; bytes) {
164             Insert(start, cast(char) b);
165             start++;
166         }
167         return this;
168     }
169 
170     StringBuilder Replace(int start, int end, string str) {
171         if (start <= end && start < Length() && end < Length()) {
172             if (str.length >= end)
173                 _buffer.data[start .. end] = cast(byte[])(str[start .. end]);
174         }
175         return this;
176     }
177 
178     void Clear() {
179         _buffer = Appender!(byte[]).init;
180     }
181 
182     override string toString() {
183         string s = cast(string) _buffer.data.idup;
184         if (s is null)
185             return "";
186         else
187             return s;
188     }
189 }